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
<!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> |