You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
241 lines
8.9 KiB
241 lines
8.9 KiB
4 years ago
|
<!DOCTYPE html>
|
||
|
<html>
|
||
|
<head>
|
||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||
|
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||
|
<style>
|
||
|
html, body {
|
||
|
height: 100%;
|
||
|
margin: 0;
|
||
|
}
|
||
|
/* Just have Monaco Fill All Available Space within control */
|
||
|
#container {
|
||
|
height: 100%;
|
||
|
width: 100%;
|
||
|
}
|
||
|
</style>
|
||
|
<style id="dynamic">
|
||
|
</style>
|
||
|
</head>
|
||
|
<body>
|
||
|
|
||
|
<div id="container" onkeydown="keyDown(event)"></div>
|
||
|
|
||
|
<script src="ms-appx-web:///Monaco/monaco-editor/min/vs/loader.js"></script>
|
||
|
<script>
|
||
|
var editor;
|
||
|
var model;
|
||
|
var contexts = {};
|
||
|
var decorations = [];
|
||
|
var modifingSelection = false; // Supress updates to selection when making edits.
|
||
|
|
||
|
Debug.log("Starting Monaco Load");
|
||
|
require.config({ paths: { 'vs': 'ms-appx-web:///Monaco/monaco-editor/min/vs' }});
|
||
|
require(['vs/editor/editor.main'], function () {
|
||
|
Debug.log("Grabbing Monaco Options");
|
||
|
|
||
|
let opt = getOptions();
|
||
|
opt["value"] = Parent.getValue("Text");
|
||
|
|
||
|
editor = monaco.editor.create(document.getElementById('container'), opt);
|
||
|
model = editor.getModel();
|
||
|
|
||
|
// Listen for Content Changes
|
||
|
model.onDidChangeContent((event) => {
|
||
|
Parent.setValue("Text", model.getValue());
|
||
|
//console.log("buffers: " + JSON.stringify(model._buffer._pieceTree._buffers));
|
||
|
//console.log("commandMgr: " + JSON.stringify(model._commandManager));
|
||
|
//console.log("viewState:" + JSON.stringify(editor.saveViewState()));
|
||
|
});
|
||
|
|
||
|
// Listen for Selection Changes
|
||
|
editor.onDidChangeCursorSelection((event) => {
|
||
|
if (!modifingSelection) {
|
||
|
console.log(event.source);
|
||
|
Parent.setValue("SelectedText", model.getValueInRange(event.selection));
|
||
|
Parent.setValue("SelectedRange", JSON.stringify(event.selection), "Selection");
|
||
|
}
|
||
|
})
|
||
|
|
||
|
// Set theme
|
||
|
let theme = Parent.getJsonValue("RequestedTheme");
|
||
|
theme = {
|
||
|
"0": "Default",
|
||
|
"1": "Light",
|
||
|
"2": "Dark"
|
||
|
}[theme];
|
||
|
if (theme == "Default") {
|
||
|
theme = Theme.currentThemeName.toString();
|
||
|
}
|
||
|
changeTheme(theme, Theme.isHighContrast.toString());
|
||
|
|
||
|
// Update Monaco Size when we receive a window resize event
|
||
|
window.addEventListener("resize", () => {
|
||
|
editor.layout();
|
||
|
});
|
||
|
|
||
|
// Disable WebView Scrollbar so Monaco Scrollbar can do heavy lifting
|
||
|
document.body.style.overflow = 'hidden';
|
||
|
|
||
|
// Callback to Parent that we're loaded
|
||
|
Debug.log("Loaded Monaco");
|
||
|
Parent.callAction("Loaded");
|
||
|
});
|
||
|
|
||
|
// TODO: Split these helper functions out into separate .js/.ts files.
|
||
|
var registerCompletionItemProvider = function (languageId, characters) {
|
||
|
return monaco.languages.registerCompletionItemProvider(languageId, {
|
||
|
triggerCharacters: characters,
|
||
|
provideCompletionItems: function (model, position, token, context) {
|
||
|
return Parent.callEvent("CompletionItemProvider" + languageId, [JSON.stringify(position), JSON.stringify(context)]).then(result => {
|
||
|
if (result) {
|
||
|
return JSON.parse(result);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
//// TODO: support resolve method as well.
|
||
|
});
|
||
|
}
|
||
|
|
||
|
var registerHoverProvider = function (languageId) {
|
||
|
return monaco.languages.registerHoverProvider(languageId, {
|
||
|
provideHover: function (model, position) {
|
||
|
return Parent.callEvent("HoverProvider" + languageId, [JSON.stringify(position)]).then(result => {
|
||
|
if (result) {
|
||
|
return JSON.parse(result);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
var addAction = function (action) {
|
||
|
action.run = function (ed) {
|
||
|
Parent.callAction("Action" + action.id)
|
||
|
};
|
||
|
|
||
|
editor.addAction(action);
|
||
|
};
|
||
|
|
||
|
var addCommand = function (keybindingStr, handlerName, context) {
|
||
|
return editor.addCommand(parseInt(keybindingStr), () => {
|
||
|
Parent.callAction(handlerName);
|
||
|
}, context);
|
||
|
};
|
||
|
|
||
|
var createContext = function (context) {
|
||
|
if (context) {
|
||
|
contexts[context.key] = editor.createContextKey(context.key, context.defaultValue);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var updateContext = function (key, value) {
|
||
|
contexts[key].set(value);
|
||
|
}
|
||
|
|
||
|
var updateContent = function (content) {
|
||
|
// Need to ignore updates from us notifying of a change
|
||
|
if (content != model.getValue()) {
|
||
|
model.setValue(content);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var updateSelectedContent = function (content) {
|
||
|
let selection = editor.getSelection();
|
||
|
|
||
|
// Need to ignore updates from us notifying of a change
|
||
|
if (content != model.getValueInRange(selection)) {
|
||
|
modifingSelection = true;
|
||
|
let range = new monaco.Range(selection.startLineNumber, selection.startColumn, selection.endLineNumber, selection.endColumn);
|
||
|
let op = { identifier: { major: 1, minor: 1 }, range, text: content, forceMoveMarkers: true };
|
||
|
|
||
|
// Make change to selection
|
||
|
model.pushEditOperations([], [op]);
|
||
|
|
||
|
// Update selection to new text.
|
||
|
selection.endLineNumber = selection.startLineNumber + content.split('\r').length - 1; // TODO: Not sure if line end is situational/platform specific... investigate more.
|
||
|
if (selection.startLineNumber === selection.endLineNumber) {
|
||
|
selection.endColumn = selection.startColumn + content.length;
|
||
|
} else {
|
||
|
selection.endColumn = content.length - content.lastIndexOf('\r');
|
||
|
}
|
||
|
|
||
|
// Update other selection bound for direction.
|
||
|
if (selection.getDirection() == monaco.SelectionDirection.LTR) {
|
||
|
selection.positionColumn = selection.endColumn;
|
||
|
selection.positionLineNumber = selection.endLineNumber;
|
||
|
} else {
|
||
|
selection.selectionStartColumn = selection.endColumn;
|
||
|
selection.selectionStartLineNumber = selection.endLineNumber;
|
||
|
}
|
||
|
|
||
|
modifingSelection = false;
|
||
|
editor.setSelection(selection);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var updateDecorations = function (newHighlights) {
|
||
|
if (newHighlights) {
|
||
|
decorations = editor.deltaDecorations(decorations, newHighlights);
|
||
|
} else {
|
||
|
decorations = editor.deltaDecorations(decorations, []);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var updateStyle = function (innerStyle) {
|
||
|
var style = document.getElementById("dynamic");
|
||
|
style.innerHTML = innerStyle;
|
||
|
};
|
||
|
|
||
|
var getOptions = function () {
|
||
|
let opt = null;
|
||
|
try {
|
||
|
opt = JSON.parse(Parent.getJsonValue("Options"));
|
||
|
} finally {
|
||
|
|
||
|
}
|
||
|
|
||
|
if (opt != null && typeof opt === "object") {
|
||
|
return opt;
|
||
|
}
|
||
|
|
||
|
return {};
|
||
|
};
|
||
|
|
||
|
var updateOptions = function (opt) {
|
||
|
if (opt != null && typeof opt === "object") {
|
||
|
editor.updateOptions(opt);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var updateLanguage = function (language) {
|
||
|
monaco.editor.setModelLanguage(model, language);
|
||
|
};
|
||
|
|
||
|
var changeTheme = function (theme, highcontrast) {
|
||
|
var newTheme = 'vs';
|
||
|
if (highcontrast == "True" || highcontrast == "true") {
|
||
|
newTheme = 'hc-black';
|
||
|
} else if (theme == "Dark") {
|
||
|
newTheme = 'vs-dark';
|
||
|
}
|
||
|
|
||
|
monaco.editor.setTheme(newTheme);
|
||
|
};
|
||
|
|
||
|
var keyDown = function (event) {
|
||
|
//Debug.log("Key Down:" + event.keyCode + " " + event.ctrlKey);
|
||
|
var result = Keyboard.keyDown(event.keyCode, event.ctrlKey, event.shiftKey, event.altKey, event.metaKey);
|
||
|
if (result) {
|
||
|
// TODO: Figure out which of these things actually works...
|
||
|
event.keyCode = 0;
|
||
|
event.cancelBubble = true;
|
||
|
event.preventDefault();
|
||
|
event.stopPropagation();
|
||
|
event.stopImmediatePropagation();
|
||
|
return false;
|
||
|
}
|
||
|
};
|
||
|
</script>
|
||
|
</body>
|
||
|
</html>
|