diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/wwwroot/js/monaco-init.js b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/wwwroot/js/monaco-init.js index 68935d71..ed8710f7 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/wwwroot/js/monaco-init.js +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/wwwroot/js/monaco-init.js @@ -21,9 +21,127 @@ return readyPromise; } - // Task 9 fills these in (Roslyn-backed providers + real diagnostics fetch). - function registerCSharpProviders() { } - async function fetchDiagnostics(model) { return []; } + const KIND_MAP = { Method: 0, Field: 4, Property: 9, Event: 10, Class: 6, Module: 8, Variable: 4, Text: 18 }; + + function registerCSharpProviders() { + monaco.languages.registerCompletionItemProvider("csharp", { + triggerCharacters: [".", "(", "\""], + provideCompletionItems: async function (model, position) { + try { + const resp = await fetch("/api/script-analysis/completions", { + method: "POST", credentials: "same-origin", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ codeText: model.getValue(), line: position.lineNumber, column: position.column }) + }); + if (!resp.ok) return { suggestions: [] }; + const data = await resp.json(); + const word = model.getWordUntilPosition(position); + const range = { + startLineNumber: position.lineNumber, endLineNumber: position.lineNumber, + startColumn: word.startColumn, endColumn: word.endColumn + }; + return { + suggestions: (data.items || []).map(function (it) { + return { + label: it.label, insertText: it.insertText, detail: it.detail, + kind: KIND_MAP[it.kind] != null ? KIND_MAP[it.kind] : 18, + range: range + }; + }) + }; + } catch (e) { return { suggestions: [] }; } + } + }); + monaco.languages.registerHoverProvider("csharp", { + provideHover: async function (model, position) { + try { + const resp = await fetch("/api/script-analysis/hover", { + method: "POST", credentials: "same-origin", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ codeText: model.getValue(), line: position.lineNumber, column: position.column }) + }); + if (!resp.ok) return null; + const data = await resp.json(); + if (!data.markdown) return null; + return { contents: [{ value: data.markdown }] }; + } catch (e) { return null; } + } + }); + monaco.languages.registerDocumentFormattingEditProvider("csharp", { + provideDocumentFormattingEdits: async function (model) { + try { + const resp = await fetch("/api/script-analysis/format", { + method: "POST", credentials: "same-origin", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ code: model.getValue() }) + }); + if (!resp.ok) return []; + const data = await resp.json(); + if (typeof data.code !== "string" || data.code === model.getValue()) return []; + return [{ range: model.getFullModelRange(), text: data.code }]; + } catch (e) { return []; } + } + }); + monaco.languages.registerInlayHintsProvider("csharp", { + provideInlayHints: async function (model) { + try { + const resp = await fetch("/api/script-analysis/inlay-hints", { + method: "POST", credentials: "same-origin", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ code: model.getValue() }) + }); + if (!resp.ok) return { hints: [], dispose: function () {} }; + const data = await resp.json(); + return { + hints: (data.hints || []).map(function (h) { + return { position: { lineNumber: h.line, column: h.column }, label: h.label, kind: 2, paddingRight: true }; + }), + dispose: function () {} + }; + } catch (e) { return { hints: [], dispose: function () {} }; } + } + }); + monaco.languages.registerSignatureHelpProvider("csharp", { + signatureHelpTriggerCharacters: ["(", ","], + signatureHelpRetriggerCharacters: [","], + provideSignatureHelp: async function (model, position) { + try { + const resp = await fetch("/api/script-analysis/signature-help", { + method: "POST", credentials: "same-origin", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ codeText: model.getValue(), line: position.lineNumber, column: position.column }) + }); + if (!resp.ok) return null; + const data = await resp.json(); + if (!data.label) return null; + return { + value: { + signatures: [{ + label: data.label, + parameters: (data.parameters || []).map(function (p) { return { label: p.label, documentation: p.documentation }; }) + }], + activeSignature: 0, + activeParameter: data.activeParameter || 0 + }, + dispose: function () {} + }; + } catch (e) { return null; } + } + }); + } + + async function fetchDiagnostics(model) { + try { + const resp = await fetch("/api/script-analysis/diagnostics", { + method: "POST", credentials: "same-origin", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ code: model.getValue() }) + }); + if (!resp.ok) return []; + const data = await resp.json(); + return data.markers || []; + } catch (e) { return []; } + } async function createEditor(id, host, options, dotNetRef) { await ensureLoaded();