config: enforce browser preflight and generated DTOs
This commit is contained in:
@@ -25,6 +25,8 @@
|
||||
let baseRevision = $state(0);
|
||||
let baseDigest = $state("");
|
||||
let renamePath = $state("");
|
||||
let baseSnapshot = $state<WorkspaceConfigTreeResponse["snapshot"] | null>(null);
|
||||
let preflightDigest = $state("");
|
||||
let toolchain: ConfigSourceToolchain | null = null;
|
||||
|
||||
const paths = $derived(
|
||||
@@ -34,6 +36,7 @@
|
||||
treeState && selectedPath ? treeState.snapshot.entries[selectedPath] : undefined,
|
||||
);
|
||||
const dirty = $derived(draftChanges.length > 0 || (selected ? source !== selected.content : source.length > 0));
|
||||
const commitReady = $derived(dirty && preflightDigest === treeState?.snapshot.digest);
|
||||
|
||||
onMount(() => {
|
||||
toolchain = new ConfigSourceToolchain();
|
||||
@@ -48,6 +51,7 @@
|
||||
selectedPath = Object.keys(treeState.snapshot.entries).toSorted()[0] ?? "";
|
||||
}
|
||||
source = selectedPath ? treeState.snapshot.entries[selectedPath].content : "";
|
||||
baseSnapshot = structuredClone(treeState.snapshot);
|
||||
baseRevision = treeState.snapshot.revision;
|
||||
baseDigest = treeState.snapshot.digest;
|
||||
await toolchain?.setSnapshot(treeState.snapshot);
|
||||
@@ -65,13 +69,10 @@
|
||||
async function stageCurrent() {
|
||||
const change = currentChange();
|
||||
if (!change || !toolchain) return;
|
||||
draftChanges = [...draftChanges.filter((item) => !changeTouches(item, selectedPath)), change];
|
||||
const candidate = await toolchain.applyChanges([change]);
|
||||
if (treeState) treeState = { ...treeState, snapshot: candidate };
|
||||
}
|
||||
|
||||
function changeTouches(change: ConfigTreeChange, path: string): boolean {
|
||||
return change.kind === "rename" ? change.from === path || change.to === path : change.path === path;
|
||||
if (baseSnapshot) draftChanges = await toolchain.changesBetween(baseSnapshot, candidate);
|
||||
preflightDigest = "";
|
||||
}
|
||||
|
||||
async function select(path: string) {
|
||||
@@ -144,6 +145,7 @@
|
||||
toolchain_fingerprint: treeState.contract.fingerprint,
|
||||
});
|
||||
diagnostics = [];
|
||||
preflightDigest = candidate.snapshot.digest;
|
||||
status = `Preview valid · projection ${candidate.evaluation.projection_digest.slice(0, 20)}…`;
|
||||
} catch (error) {
|
||||
status = String(error);
|
||||
@@ -159,6 +161,10 @@
|
||||
status = "No draft changes to commit.";
|
||||
return;
|
||||
}
|
||||
if (preflightDigest !== treeState.snapshot.digest) {
|
||||
status = "Preview the complete candidate successfully before Commit.";
|
||||
return;
|
||||
}
|
||||
busy = true;
|
||||
try {
|
||||
treeState = await commitConfigTree(workspaceId, {
|
||||
@@ -169,6 +175,8 @@
|
||||
toolchain_fingerprint: treeState.contract.fingerprint,
|
||||
});
|
||||
draftChanges = [];
|
||||
preflightDigest = "";
|
||||
baseSnapshot = structuredClone(treeState.snapshot);
|
||||
baseRevision = treeState.snapshot.revision;
|
||||
baseDigest = treeState.snapshot.digest;
|
||||
await toolchain?.setSnapshot(treeState.snapshot);
|
||||
@@ -198,9 +206,10 @@
|
||||
path: selectedPath,
|
||||
expected_digest: selected.content_digest,
|
||||
};
|
||||
draftChanges = [...draftChanges.filter((item) => !changeTouches(item, selectedPath)), change];
|
||||
const candidate = await toolchain.applyChanges([change]);
|
||||
treeState = { ...treeState, snapshot: candidate };
|
||||
if (baseSnapshot) draftChanges = await toolchain.changesBetween(baseSnapshot, candidate);
|
||||
preflightDigest = "";
|
||||
selectedPath = Object.keys(candidate.entries).toSorted()[0] ?? "";
|
||||
source = selectedPath ? candidate.entries[selectedPath].content : "";
|
||||
renamePath = selectedPath;
|
||||
@@ -218,9 +227,10 @@
|
||||
to,
|
||||
expected_digest: selected.content_digest,
|
||||
};
|
||||
draftChanges = [...draftChanges.filter((item) => !changeTouches(item, selectedPath)), change];
|
||||
const candidate = await toolchain.applyChanges([change]);
|
||||
treeState = { ...treeState, snapshot: candidate };
|
||||
if (baseSnapshot) draftChanges = await toolchain.changesBetween(baseSnapshot, candidate);
|
||||
preflightDigest = "";
|
||||
selectedPath = to;
|
||||
source = candidate.entries[to]?.content ?? "";
|
||||
status = `Rename to ${to} staged. Preview and Commit to persist.`;
|
||||
@@ -261,7 +271,7 @@
|
||||
<button type="button" onclick={format} disabled={!selectedPath || busy}>Format</button>
|
||||
<button type="button" onclick={analyze} disabled={!selectedPath || busy}>Analyze</button>
|
||||
<button type="button" onclick={preview} disabled={!dirty || busy}>Preview</button>
|
||||
<button class="primary" type="button" onclick={commit} disabled={!dirty || busy}>Commit</button>
|
||||
<button class="primary" type="button" onclick={commit} disabled={!commitReady || busy}>Commit</button>
|
||||
<button class="danger" type="button" onclick={deleteEntry} disabled={!selected || busy}>Delete</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
+4
-1
@@ -5,7 +5,9 @@ export function analyze_snapshot(snapshot: any, entrypoint: string, source_overr
|
||||
|
||||
export function apply_changes(changes: any): any;
|
||||
|
||||
export function complete_current(entrypoint: string, source: string, utf8_byte_offset: number, explicit: boolean): any;
|
||||
export function changes_between(base: any, candidate: any): any;
|
||||
|
||||
export function complete_current(entrypoint: string, source: string, utf16_offset: number, explicit: boolean): any;
|
||||
|
||||
export function evaluate_current(contract: any): any;
|
||||
|
||||
@@ -23,6 +25,7 @@ export interface InitOutput {
|
||||
readonly memory: WebAssembly.Memory;
|
||||
readonly analyze_snapshot: (a: any, b: number, c: number, d: number, e: number) => [number, number, number];
|
||||
readonly apply_changes: (a: any) => [number, number, number];
|
||||
readonly changes_between: (a: any, b: any) => [number, number, number];
|
||||
readonly complete_current: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number, number];
|
||||
readonly evaluate_current: (a: any) => [number, number, number];
|
||||
readonly evaluate_snapshot: (a: any, b: any) => [number, number, number];
|
||||
|
||||
@@ -30,19 +30,32 @@ export function apply_changes(changes) {
|
||||
return takeFromExternrefTable0(ret[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} base
|
||||
* @param {any} candidate
|
||||
* @returns {any}
|
||||
*/
|
||||
export function changes_between(base, candidate) {
|
||||
const ret = wasm.changes_between(base, candidate);
|
||||
if (ret[2]) {
|
||||
throw takeFromExternrefTable0(ret[1]);
|
||||
}
|
||||
return takeFromExternrefTable0(ret[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} entrypoint
|
||||
* @param {string} source
|
||||
* @param {number} utf8_byte_offset
|
||||
* @param {number} utf16_offset
|
||||
* @param {boolean} explicit
|
||||
* @returns {any}
|
||||
*/
|
||||
export function complete_current(entrypoint, source, utf8_byte_offset, explicit) {
|
||||
export function complete_current(entrypoint, source, utf16_offset, explicit) {
|
||||
const ptr0 = passStringToWasm0(entrypoint, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
const len0 = WASM_VECTOR_LEN;
|
||||
const ptr1 = passStringToWasm0(source, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
const len1 = WASM_VECTOR_LEN;
|
||||
const ret = wasm.complete_current(ptr0, len0, ptr1, len1, utf8_byte_offset, explicit);
|
||||
const ret = wasm.complete_current(ptr0, len0, ptr1, len1, utf16_offset, explicit);
|
||||
if (ret[2]) {
|
||||
throw takeFromExternrefTable0(ret[1]);
|
||||
}
|
||||
|
||||
Binary file not shown.
+1
@@ -3,6 +3,7 @@
|
||||
export const memory: WebAssembly.Memory;
|
||||
export const analyze_snapshot: (a: any, b: number, c: number, d: number, e: number) => [number, number, number];
|
||||
export const apply_changes: (a: any) => [number, number, number];
|
||||
export const changes_between: (a: any, b: any) => [number, number, number];
|
||||
export const complete_current: (a: number, b: number, c: number, d: number, e: number, f: number) => [number, number, number];
|
||||
export const evaluate_current: (a: any) => [number, number, number];
|
||||
export const evaluate_snapshot: (a: any, b: any) => [number, number, number];
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ConfigTreeChange } from "./ConfigTreeChange";
|
||||
import type { VirtualPath } from "./VirtualPath";
|
||||
|
||||
export type ConfigCommitRequest = { base_revision: number, base_digest: string, changes: Array<ConfigTreeChange>, entrypoints: Array<VirtualPath>, toolchain_fingerprint: string, };
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type ConfigContentType = "decodal" | "text";
|
||||
@@ -0,0 +1,6 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ConfigDiagnosticLabel } from "./ConfigDiagnosticLabel";
|
||||
import type { ConfigSpan } from "./ConfigSpan";
|
||||
import type { VirtualPath } from "./VirtualPath";
|
||||
|
||||
export type ConfigDiagnostic = { path: VirtualPath, revision: number, tree_digest: string, kind: string, span: ConfigSpan, message: string, labels: Array<ConfigDiagnosticLabel>, notes: Array<string>, };
|
||||
@@ -0,0 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ConfigSpan } from "./ConfigSpan";
|
||||
|
||||
export type ConfigDiagnosticLabel = { span: ConfigSpan, message: string, };
|
||||
@@ -0,0 +1,5 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ConfigContentType } from "./ConfigContentType";
|
||||
import type { VirtualPath } from "./VirtualPath";
|
||||
|
||||
export type ConfigEntry = { path: VirtualPath, content_type: ConfigContentType, content: string, content_digest: string, };
|
||||
@@ -0,0 +1,5 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ConfigTreeChange } from "./ConfigTreeChange";
|
||||
import type { VirtualPath } from "./VirtualPath";
|
||||
|
||||
export type ConfigPreviewRequest = { changes: Array<ConfigTreeChange>, entrypoints: Array<VirtualPath>, };
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type ConfigSpan = { start_byte: number, end_byte: number, };
|
||||
@@ -0,0 +1,5 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ConfigContentType } from "./ConfigContentType";
|
||||
import type { VirtualPath } from "./VirtualPath";
|
||||
|
||||
export type ConfigTreeChange = { "kind": "create", path: VirtualPath, content_type: ConfigContentType, content: string, } | { "kind": "update", path: VirtualPath, expected_digest: string, content: string, } | { "kind": "rename", from: VirtualPath, to: VirtualPath, expected_digest: string, } | { "kind": "delete", path: VirtualPath, expected_digest: string, };
|
||||
@@ -0,0 +1,5 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ConfigEntry } from "./ConfigEntry";
|
||||
import type { VirtualPath } from "./VirtualPath";
|
||||
|
||||
export type ConfigTreeSnapshot = { revision: number, digest: string, entries: { [key in VirtualPath]: ConfigEntry }, };
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ConfigTreeSnapshot } from "./ConfigTreeSnapshot";
|
||||
import type { EvaluationResult } from "./EvaluationResult";
|
||||
import type { ToolchainContract } from "./ToolchainContract";
|
||||
|
||||
export type EvaluatedConfigCandidate = { base_revision: number, base_digest: string, snapshot: ConfigTreeSnapshot, contract: ToolchainContract, evaluation: EvaluationResult, };
|
||||
@@ -0,0 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { VirtualPath } from "./VirtualPath";
|
||||
|
||||
export type EvaluatedProjection = { entrypoint: VirtualPath, data_json: unknown, projection_digest: string, };
|
||||
@@ -0,0 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { EvaluatedProjection } from "./EvaluatedProjection";
|
||||
|
||||
export type EvaluationResult = { projections: Array<EvaluatedProjection>, projection_digest: string, };
|
||||
@@ -0,0 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { VirtualPath } from "./VirtualPath";
|
||||
|
||||
export type ToolchainContract = { contract_version: number, decodal_version: string, schema_version: number, entrypoints: Array<VirtualPath>, import_policy_version: number, fingerprint: string, };
|
||||
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type VirtualPath = string;
|
||||
@@ -0,0 +1,5 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ConfigTreeSnapshot } from "./ConfigTreeSnapshot";
|
||||
import type { ToolchainContract } from "./ToolchainContract";
|
||||
|
||||
export type WorkspaceConfigState = { snapshot: ConfigTreeSnapshot, contract: ToolchainContract, projection_digest: string, };
|
||||
@@ -4,6 +4,7 @@ import type { ConfigSourceWorkerRequest, ConfigSourceWorkerResponse } from "./to
|
||||
type Command =
|
||||
| Omit<Extract<ConfigSourceWorkerRequest, { kind: "set_snapshot" }>, "id">
|
||||
| Omit<Extract<ConfigSourceWorkerRequest, { kind: "apply_changes" }>, "id">
|
||||
| Omit<Extract<ConfigSourceWorkerRequest, { kind: "changes_between" }>, "id">
|
||||
| Omit<Extract<ConfigSourceWorkerRequest, { kind: "analyze" }>, "id">
|
||||
| Omit<Extract<ConfigSourceWorkerRequest, { kind: "evaluate" }>, "id">
|
||||
| Omit<Extract<ConfigSourceWorkerRequest, { kind: "complete" }>, "id">
|
||||
@@ -31,14 +32,17 @@ export class ConfigSourceToolchain {
|
||||
applyChanges(changes: ConfigTreeChange[]): Promise<ConfigTreeSnapshot> {
|
||||
return this.#request({ kind: "apply_changes", changes });
|
||||
}
|
||||
changesBetween(base: ConfigTreeSnapshot, candidate: ConfigTreeSnapshot): Promise<ConfigTreeChange[]> {
|
||||
return this.#request({ kind: "changes_between", base, candidate });
|
||||
}
|
||||
analyze(path: string, source?: string): Promise<ConfigDiagnostic[]> {
|
||||
return this.#request({ kind: "analyze", path, source });
|
||||
}
|
||||
evaluate(contract: ToolchainContract) {
|
||||
return this.#request({ kind: "evaluate", contract });
|
||||
}
|
||||
complete(path: string, source: string, utf8ByteOffset: number, explicit = false): Promise<import("@codemirror/autocomplete").CompletionResult | null> {
|
||||
return this.#request({ kind: "complete", path, source, utf8ByteOffset, explicit });
|
||||
complete(path: string, source: string, utf16Offset: number, explicit = false): Promise<import("@codemirror/autocomplete").CompletionResult | null> {
|
||||
return this.#request({ kind: "complete", path, source, utf16Offset, explicit });
|
||||
}
|
||||
format(source: string): Promise<string> {
|
||||
return this.#request({ kind: "format", source });
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import init, {
|
||||
analyze_snapshot,
|
||||
apply_changes,
|
||||
changes_between,
|
||||
complete_current,
|
||||
evaluate_current,
|
||||
format_source,
|
||||
@@ -11,9 +12,10 @@ import type { ConfigTreeChange } from "./types.ts";
|
||||
export type ConfigSourceWorkerRequest =
|
||||
| { id: number; kind: "set_snapshot"; snapshot: unknown }
|
||||
| { id: number; kind: "apply_changes"; changes: ConfigTreeChange[] }
|
||||
| { id: number; kind: "changes_between"; base: unknown; candidate: unknown }
|
||||
| { id: number; kind: "analyze"; path: string; source?: string }
|
||||
| { id: number; kind: "evaluate"; contract: unknown }
|
||||
| { id: number; kind: "complete"; path: string; source: string; utf8ByteOffset: number; explicit: boolean }
|
||||
| { id: number; kind: "complete"; path: string; source: string; utf16Offset: number; explicit: boolean }
|
||||
| { id: number; kind: "format"; source: string };
|
||||
|
||||
export type ConfigSourceWorkerResponse =
|
||||
@@ -38,6 +40,9 @@ self.onmessage = async (event: MessageEvent<ConfigSourceWorkerRequest>): Promise
|
||||
snapshot = apply_changes(request.changes);
|
||||
result = snapshot;
|
||||
break;
|
||||
case "changes_between":
|
||||
result = changes_between(request.base, request.candidate);
|
||||
break;
|
||||
case "analyze":
|
||||
if (!snapshot) throw new Error("config source snapshot is not initialized");
|
||||
result = analyze_snapshot(snapshot, request.path, request.source);
|
||||
@@ -46,7 +51,7 @@ self.onmessage = async (event: MessageEvent<ConfigSourceWorkerRequest>): Promise
|
||||
result = evaluate_current(request.contract);
|
||||
break;
|
||||
case "complete":
|
||||
result = complete_current(request.path, request.source, request.utf8ByteOffset, request.explicit);
|
||||
result = complete_current(request.path, request.source, request.utf16Offset, request.explicit);
|
||||
break;
|
||||
case "format":
|
||||
result = format_source(request.source);
|
||||
|
||||
@@ -1,93 +1,16 @@
|
||||
export type VirtualPath = string;
|
||||
|
||||
export type ConfigContentType = "decodal" | "text";
|
||||
|
||||
export interface ConfigEntry {
|
||||
path: VirtualPath;
|
||||
content_type: ConfigContentType;
|
||||
content: string;
|
||||
content_digest: string;
|
||||
}
|
||||
|
||||
export interface ConfigTreeSnapshot {
|
||||
revision: number;
|
||||
digest: string;
|
||||
entries: Record<VirtualPath, ConfigEntry>;
|
||||
}
|
||||
|
||||
export type ConfigTreeChange =
|
||||
| {
|
||||
kind: "create";
|
||||
path: VirtualPath;
|
||||
content_type: ConfigContentType;
|
||||
content: string;
|
||||
}
|
||||
| {
|
||||
kind: "update";
|
||||
path: VirtualPath;
|
||||
expected_digest: string;
|
||||
content: string;
|
||||
}
|
||||
| {
|
||||
kind: "rename";
|
||||
from: VirtualPath;
|
||||
to: VirtualPath;
|
||||
expected_digest: string;
|
||||
}
|
||||
| {
|
||||
kind: "delete";
|
||||
path: VirtualPath;
|
||||
expected_digest: string;
|
||||
};
|
||||
|
||||
export interface ToolchainContract {
|
||||
contract_version: number;
|
||||
decodal_version: string;
|
||||
schema_version: number;
|
||||
entrypoints: VirtualPath[];
|
||||
import_policy_version: number;
|
||||
fingerprint: string;
|
||||
}
|
||||
|
||||
export interface ConfigDiagnostic {
|
||||
path: VirtualPath;
|
||||
revision: number;
|
||||
tree_digest: string;
|
||||
kind: string;
|
||||
span: { start_byte: number; end_byte: number };
|
||||
message: string;
|
||||
labels: Array<{
|
||||
span: { start_byte: number; end_byte: number };
|
||||
message: string;
|
||||
}>;
|
||||
notes: string[];
|
||||
}
|
||||
|
||||
export interface WorkspaceConfigTreeResponse {
|
||||
snapshot: ConfigTreeSnapshot;
|
||||
contract: ToolchainContract;
|
||||
projection_digest: string;
|
||||
}
|
||||
|
||||
export interface EvaluatedConfigCandidate {
|
||||
base_revision: number;
|
||||
base_digest: string;
|
||||
snapshot: ConfigTreeSnapshot;
|
||||
contract: ToolchainContract;
|
||||
evaluation: {
|
||||
projections: Array<{
|
||||
entrypoint: VirtualPath;
|
||||
data_json: unknown;
|
||||
projection_digest: string;
|
||||
}>;
|
||||
projection_digest: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ConfigCommitRequest {
|
||||
base_revision: number;
|
||||
base_digest: string;
|
||||
changes: ConfigTreeChange[];
|
||||
entrypoints: VirtualPath[];
|
||||
toolchain_fingerprint: string;
|
||||
}
|
||||
// Core and HTTP DTOs are generated from Rust with ts-rs.
|
||||
export type { ConfigContentType } from "./generated/types/ConfigContentType.ts";
|
||||
export type { ConfigDiagnostic } from "./generated/types/ConfigDiagnostic.ts";
|
||||
export type { ConfigDiagnosticLabel } from "./generated/types/ConfigDiagnosticLabel.ts";
|
||||
export type { ConfigEntry } from "./generated/types/ConfigEntry.ts";
|
||||
export type { ConfigSpan } from "./generated/types/ConfigSpan.ts";
|
||||
export type { ConfigTreeChange } from "./generated/types/ConfigTreeChange.ts";
|
||||
export type { ConfigTreeSnapshot } from "./generated/types/ConfigTreeSnapshot.ts";
|
||||
export type { EvaluatedProjection } from "./generated/types/EvaluatedProjection.ts";
|
||||
export type { EvaluationResult } from "./generated/types/EvaluationResult.ts";
|
||||
export type { ToolchainContract } from "./generated/types/ToolchainContract.ts";
|
||||
export type { VirtualPath } from "./generated/types/VirtualPath.ts";
|
||||
export type { ConfigCommitRequest } from "./generated/types/ConfigCommitRequest.ts";
|
||||
export type { ConfigPreviewRequest } from "./generated/types/ConfigPreviewRequest.ts";
|
||||
export type { EvaluatedConfigCandidate } from "./generated/types/EvaluatedConfigCandidate.ts";
|
||||
export type { WorkspaceConfigState as WorkspaceConfigTreeResponse } from "./generated/types/WorkspaceConfigState.ts";
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
readonly?: boolean;
|
||||
ariaLabel?: string;
|
||||
onChange?: (value: string) => void;
|
||||
onComplete?: (source: string, utf8ByteOffset: number, explicit: boolean) => Promise<CompletionResult | null>;
|
||||
onComplete?: (source: string, utf16Offset: number, explicit: boolean) => Promise<CompletionResult | null>;
|
||||
} = $props();
|
||||
|
||||
let host = $state<HTMLDivElement | null>(null);
|
||||
@@ -54,8 +54,7 @@
|
||||
decodal(),
|
||||
...(handleComplete ? [autocompletion({ override: [async (context: CompletionContext) => {
|
||||
const doc = context.state.doc.toString();
|
||||
const utf8ByteOffset = new TextEncoder().encode(doc.slice(0, context.pos)).byteLength;
|
||||
return await handleComplete(doc, utf8ByteOffset, context.explicit);
|
||||
return await handleComplete(doc, context.pos, context.explicit);
|
||||
}] })] : []),
|
||||
keymap.of([]),
|
||||
EditorState.readOnly.of(initialReadonly),
|
||||
|
||||
Reference in New Issue
Block a user