mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-02 06:41:14 +00:00

Markers are show inline when errors occur during compilation. But when those errors are fixed, the markers should go away.
254 lines
No EOL
9.2 KiB
TypeScript
254 lines
No EOL
9.2 KiB
TypeScript
/* LICENSE BEGIN
|
|
This file is part of the SixtyFPS Project -- https://sixtyfps.io
|
|
Copyright (c) 2020 Olivier Goffart <olivier.goffart@sixtyfps.io>
|
|
Copyright (c) 2020 Simon Hausmann <simon.hausmann@sixtyfps.io>
|
|
|
|
SPDX-License-Identifier: GPL-3.0-only
|
|
This file is also available under commercial licensing terms.
|
|
Please contact info@sixtyfps.io for more information.
|
|
LICENSE END */
|
|
import { sixtyfps_language } from "./highlighting";
|
|
import type * as monaco from 'monaco-editor';
|
|
(async function () {
|
|
let [monaco, sixtyfps] = await Promise.all([import('monaco-editor'), import("../../api/sixtyfps-wasm-interpreter/pkg/index.js")]);
|
|
|
|
monaco.languages.register({
|
|
id: 'sixtyfps'
|
|
});
|
|
monaco.languages.onLanguage('sixtyfps', () => {
|
|
monaco.languages.setMonarchTokensProvider('sixtyfps', sixtyfps_language);
|
|
});
|
|
var editor = monaco.editor.create(document.getElementById("editor"), {
|
|
language: 'sixtyfps'
|
|
});
|
|
var base_url = "";
|
|
|
|
interface ModelAndViewState {
|
|
model: monaco.editor.ITextModel,
|
|
view_state: monaco.editor.ICodeEditorViewState
|
|
}
|
|
|
|
/// Index by url. Inline documents will use the empty string.
|
|
var editor_documents: Map<string, ModelAndViewState> = new Map;
|
|
|
|
let hello_world = `
|
|
import { SpinBox, Button, CheckBox, Slider, GroupBox } from "sixtyfps_widgets.60";
|
|
export Demo := Window {
|
|
width: 300px; // Width in logical pixels. All 'px' units are automatically scaled with screen resolution.
|
|
height: 300px;
|
|
t:= Text {
|
|
text: "Hello World";
|
|
font-size: 24px;
|
|
}
|
|
Image {
|
|
y: 50px;
|
|
source: img!"https://sixtyfps.io/resources/logo_scaled.png";
|
|
}
|
|
}
|
|
`
|
|
|
|
function load_from_url(url: string) {
|
|
clearTabs();
|
|
fetch(url).then(
|
|
x => x.text().then(y => {
|
|
base_url = url;
|
|
let model = createMainModel(y, url);
|
|
addTab(model, url);
|
|
})
|
|
);
|
|
}
|
|
|
|
let select = (<HTMLInputElement>document.getElementById("select_combo"));
|
|
function select_combo_changed() {
|
|
if (select.value) {
|
|
load_from_url("https://raw.githubusercontent.com/sixtyfpsui/sixtyfps/master/" + select.value);
|
|
} else {
|
|
clearTabs();
|
|
base_url = "";
|
|
let model = createMainModel(hello_world, "");
|
|
addTab(model);
|
|
}
|
|
}
|
|
select.onchange = select_combo_changed;
|
|
|
|
let compile_button = (<HTMLButtonElement>document.getElementById("compile_button"));
|
|
compile_button.onclick = function () {
|
|
update_preview();
|
|
};
|
|
|
|
let auto_compile = (<HTMLInputElement>document.getElementById("auto_compile"));
|
|
auto_compile.onchange = function () {
|
|
if (auto_compile.checked) {
|
|
update_preview()
|
|
}
|
|
};
|
|
|
|
function tabTitleFromURL(url: string): string {
|
|
if (url === "") {
|
|
return "unnamed.60";
|
|
}
|
|
try {
|
|
let parsed_url = new URL(url);
|
|
let path = parsed_url.pathname;
|
|
return path.substring(path.lastIndexOf('/') + 1);
|
|
} catch (e) {
|
|
return url;
|
|
}
|
|
}
|
|
|
|
function maybe_update_preview_automatically() {
|
|
if (auto_compile.checked) {
|
|
if (keystroke_timeout_handle) {
|
|
clearTimeout(keystroke_timeout_handle);
|
|
}
|
|
keystroke_timeout_handle = setTimeout(update_preview, 500);
|
|
}
|
|
}
|
|
|
|
function createMainModel(source: string, url: string): monaco.editor.ITextModel {
|
|
let model = monaco.editor.createModel(source, "sixtyfps");
|
|
model.onDidChangeContent(function () {
|
|
let permalink = (<HTMLAnchorElement>document.getElementById("permalink"));
|
|
let params = new URLSearchParams();
|
|
params.set("snippet", editor.getModel().getValue());
|
|
let this_url = new URL(window.location.toString());
|
|
this_url.search = params.toString();
|
|
permalink.href = this_url.toString();
|
|
maybe_update_preview_automatically();
|
|
});
|
|
editor_documents.set(url, { model, view_state: null });
|
|
update_preview();
|
|
return model;
|
|
}
|
|
|
|
function clearTabs() {
|
|
let tab_bar = document.getElementById("tabs") as HTMLUListElement;
|
|
tab_bar.innerHTML = "";
|
|
editor_documents.clear();
|
|
}
|
|
|
|
function addTab(model: monaco.editor.ITextModel, url: string = "") {
|
|
let tab_bar = document.getElementById("tabs") as HTMLUListElement;
|
|
let tab = document.createElement("li");
|
|
tab.setAttribute("class", "nav-item");
|
|
tab.dataset["url"] = url;
|
|
tab.innerHTML = `<span class="nav-link">${tabTitleFromURL(url)}</span>`;
|
|
tab_bar.appendChild(tab);
|
|
$(tab).on("click", (e) => {
|
|
e.preventDefault();
|
|
setCurrentTab(url);
|
|
});
|
|
if (tab_bar.childElementCount == 1) {
|
|
setCurrentTab(url);
|
|
}
|
|
}
|
|
|
|
function setCurrentTab(url: string) {
|
|
let current_tab = document.querySelector(`#tabs li[class~="nav-item"] span[class~="nav-link"][class~="active"]`);
|
|
if (current_tab != undefined) {
|
|
current_tab.className = "nav-link";
|
|
let url = current_tab.parentElement.dataset.url;
|
|
if (url != undefined) {
|
|
let model_and_state = editor_documents.get(url);
|
|
model_and_state.view_state = editor.saveViewState();
|
|
editor_documents.set(url, model_and_state);
|
|
}
|
|
}
|
|
let new_current = document.querySelector(`#tabs li[class~="nav-item"][data-url="${url}"] span[class~="nav-link"]`);
|
|
if (new_current != undefined) {
|
|
new_current.className = "nav-link active";
|
|
}
|
|
let model_and_state = editor_documents.get(url);
|
|
if (model_and_state != undefined) {
|
|
editor.setModel(model_and_state.model);
|
|
if (model_and_state.view_state != null) {
|
|
editor.restoreViewState(model_and_state.view_state);
|
|
}
|
|
editor.focus();
|
|
}
|
|
}
|
|
|
|
function update_preview() {
|
|
let main_model_and_state = editor_documents.get(base_url);
|
|
if (main_model_and_state === undefined) {
|
|
return;
|
|
}
|
|
let source = main_model_and_state.model.getValue();
|
|
let div = document.getElementById("preview") as HTMLDivElement;
|
|
setTimeout(function () { render_or_error(source, base_url, div); }, 1);
|
|
}
|
|
|
|
async function render_or_error(source: string, base_url: string, div: HTMLDivElement) {
|
|
let canvas_id = 'canvas_' + Math.random().toString(36).substr(2, 9);
|
|
let canvas = document.createElement("canvas");
|
|
canvas.width = 800;
|
|
canvas.height = 600;
|
|
canvas.id = canvas_id;
|
|
div.innerHTML = "";
|
|
div.appendChild(canvas);
|
|
var markers = [];
|
|
try {
|
|
var compiled_component = await sixtyfps.compile_from_string(source, base_url, (file_name: string) => {
|
|
let u = new URL(file_name, base_url || undefined);
|
|
return u.toString();
|
|
}, async (url: string): Promise<string> => {
|
|
let model_and_state = editor_documents.get(url);
|
|
if (model_and_state === undefined) {
|
|
const response = await fetch(url);
|
|
let doc = await response.text();
|
|
let model = monaco.editor.createModel(doc, "sixtyfps");
|
|
model.onDidChangeContent(function () {
|
|
maybe_update_preview_automatically();
|
|
});
|
|
editor_documents.set(url, { model, view_state: null });
|
|
addTab(model, url);
|
|
return doc;
|
|
}
|
|
return model_and_state.model.getValue();
|
|
});
|
|
} catch (e) {
|
|
let text = document.createTextNode(e.message);
|
|
let p = document.createElement('pre');
|
|
p.appendChild(text);
|
|
div.innerHTML = "<pre style='color: red; background-color:#fee; margin:0'>" + p.innerHTML + "</pre>";
|
|
|
|
if (e.errors) {
|
|
markers = e.errors.map(function (x) {
|
|
return {
|
|
severity: 3 - x.level,
|
|
message: x.message,
|
|
source: x.fileName,
|
|
startLineNumber: x.lineNumber,
|
|
startColumn: x.columnNumber,
|
|
endLineNumber: x.lineNumber,
|
|
endColumn: -1,
|
|
}
|
|
});
|
|
}
|
|
|
|
throw e;
|
|
} finally {
|
|
monaco.editor.setModelMarkers(editor.getModel(), "sixtyfps", markers);
|
|
}
|
|
compiled_component.run(canvas_id)
|
|
}
|
|
|
|
let keystroke_timeout_handle: number;
|
|
|
|
const params = new URLSearchParams(window.location.search);
|
|
const code = params.get("snippet");
|
|
const load_url = params.get("load_url");
|
|
if (code) {
|
|
clearTabs();
|
|
let model = createMainModel(code, "");
|
|
addTab(model);
|
|
} else if (load_url) {
|
|
load_from_url(load_url);
|
|
} else {
|
|
clearTabs();
|
|
base_url = "";
|
|
let model = createMainModel(hello_world, "");
|
|
addTab(model);
|
|
}
|
|
|
|
})(); |