feat(m9/T31): Monaco JSON-schema hover/completion on value-entry surface
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// Blazor bridge for Monaco editor.
|
||||
// Exposes window.MonacoBlazor with createEditor / setValue / getValue / dispose / setMarkers.
|
||||
// Exposes window.MonacoBlazor with createEditor / setValue / getValue / dispose / setMarkers / setJsonSchema.
|
||||
// Lazy-loads Monaco's AMD bundle the first time createEditor is called.
|
||||
|
||||
(function () {
|
||||
@@ -285,12 +285,62 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ---- JSON schema wiring --------------------------------------------------
|
||||
|
||||
// Each json editor gets its own model URI so a schema can be scoped to just
|
||||
// that model via fileMatch — registering it in Monaco's global json defaults
|
||||
// without leaking onto other json editors on the page.
|
||||
function modelUriFor(id) {
|
||||
return monaco.Uri.parse("inmemory://scadabridge/value-" + id + ".json");
|
||||
}
|
||||
|
||||
// Replace (or remove) this editor's entry in the global json schema list,
|
||||
// then push the merged list back into jsonDefaults so Monaco's built-in JSON
|
||||
// language provides schema-driven hover/completion/diagnostics. A null/blank
|
||||
// schema simply drops the entry (the editor falls back to plain json).
|
||||
function applyJsonSchema(id, schemaJson) {
|
||||
if (!monaco.languages.json) return;
|
||||
const uri = modelUriFor(id).toString();
|
||||
const fileMatch = ["value-" + id + ".json"];
|
||||
const defaults = monaco.languages.json.jsonDefaults;
|
||||
const existing = (defaults.diagnosticsOptions && defaults.diagnosticsOptions.schemas) || [];
|
||||
const others = existing.filter(function (s) { return s.uri !== uri; });
|
||||
let schemas = others;
|
||||
if (schemaJson && schemaJson.trim().length > 0) {
|
||||
let parsed = null;
|
||||
try { parsed = JSON.parse(schemaJson); } catch (e) { parsed = null; }
|
||||
if (parsed) {
|
||||
schemas = others.concat([{ uri: uri, fileMatch: fileMatch, schema: parsed }]);
|
||||
}
|
||||
}
|
||||
defaults.setDiagnosticsOptions({
|
||||
validate: true,
|
||||
enableSchemaRequest: false,
|
||||
schemas: schemas
|
||||
});
|
||||
}
|
||||
|
||||
async function createEditor(id, host, options, dotNetRef) {
|
||||
await ensureLoaded();
|
||||
if (!host) return;
|
||||
const language = options.language || "csharp";
|
||||
const isJson = language === "json";
|
||||
|
||||
// A json editor with a schema needs an explicitly-URI'd model so the
|
||||
// schema's fileMatch can target exactly this editor.
|
||||
let model = null;
|
||||
if (isJson) {
|
||||
const uri = modelUriFor(id);
|
||||
model = monaco.editor.getModel(uri);
|
||||
if (model) { model.setValue(options.value || ""); }
|
||||
else { model = monaco.editor.createModel(options.value || "", "json", uri); }
|
||||
if (options.jsonSchema) { applyJsonSchema(id, options.jsonSchema); }
|
||||
}
|
||||
|
||||
const editor = monaco.editor.create(host, {
|
||||
value: options.value || "",
|
||||
language: options.language || "csharp",
|
||||
value: model ? undefined : (options.value || ""),
|
||||
model: model || undefined,
|
||||
language: model ? undefined : language,
|
||||
theme: "vs",
|
||||
minimap: { enabled: false },
|
||||
scrollBeyondLastLine: false,
|
||||
@@ -321,10 +371,16 @@
|
||||
dotNetRef.invokeMethodAsync("OnValueChanged", value).catch(function () {});
|
||||
if (options.language === "csharp") scheduleDiagnostics();
|
||||
});
|
||||
editors[id] = { editor: editor, dotNetRef: dotNetRef };
|
||||
editors[id] = { editor: editor, dotNetRef: dotNetRef, isJson: isJson };
|
||||
|
||||
// Run an initial diagnostic pass so existing scripts show their markers.
|
||||
if (options.language === "csharp") scheduleDiagnostics();
|
||||
if (language === "csharp") scheduleDiagnostics();
|
||||
}
|
||||
|
||||
function setJsonSchema(id, schemaJson) {
|
||||
const entry = editors[id];
|
||||
if (!entry || !entry.isJson) return;
|
||||
applyJsonSchema(id, schemaJson);
|
||||
}
|
||||
|
||||
function setEditorOption(id, optionName, value) {
|
||||
@@ -377,6 +433,15 @@
|
||||
function dispose(id) {
|
||||
const entry = editors[id];
|
||||
if (!entry) return;
|
||||
// Drop this editor's json schema entry and its explicitly-URI'd model so
|
||||
// a disposed json editor leaves nothing behind in the global defaults.
|
||||
if (entry.isJson) {
|
||||
try { applyJsonSchema(id, null); } catch (e) {}
|
||||
try {
|
||||
const model = monaco.editor.getModel(modelUriFor(id));
|
||||
if (model) model.dispose();
|
||||
} catch (e) {}
|
||||
}
|
||||
try { entry.editor.dispose(); } catch (e) {}
|
||||
delete editors[id];
|
||||
}
|
||||
@@ -386,6 +451,7 @@
|
||||
setValue: setValue,
|
||||
getValue: getValue,
|
||||
setMarkers: setMarkers,
|
||||
setJsonSchema: setJsonSchema,
|
||||
setEditorOption: setEditorOption,
|
||||
format: format,
|
||||
revealLine: revealLine,
|
||||
|
||||
Reference in New Issue
Block a user