Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ package-lock.json
# Monaco Dependency (Download from https://microsoft.github.io/monaco-editor/)
MonacoEditorComponent/monaco-editor

# Webcomponents.js Dependency (Download from https://github.com/webcomponents/polyfills)
MonacoEditorComponent/webcomponents-js

# Build results
[Dd]ebug/
[Dd]ebugPublic/
Expand Down
7 changes: 4 additions & 3 deletions .vsts-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ jobs:
- job: Windows

pool:
vmImage: 'windows-2019'
vmImage: 'windows-2022'

steps:
- template: build/templates/gitversion.yml

- task: MSBuild@1
inputs:
solution: MonacoEditorComponent.sln
msbuildArguments: /r /p:Configuration=Release "/p:PackageOutputPath=$(build.artifactstagingdirectory)\nuget" "/p:PackageVersion=$(GITVERSION.FullSemVer)" "/p:InformationalVersion=$(GITVERSION.InformationalVersion)" /detailedsummary
solution: MonacoEditorComponent.slnf
msbuildArguments: /r /p:Configuration=Release "/p:PackageOutputPath=$(build.artifactstagingdirectory)\nuget" "/p:PackageVersion=$(GITVERSION.FullSemVer)" "/p:InformationalVersion=$(GITVERSION.InformationalVersion)" /detailedsummary /bl:$(build.artifactstagingdirectory)/build.binlog

- task: PowerShell@2
displayName: Authenticode Sign Packages
Expand All @@ -25,6 +25,7 @@ jobs:
condition: and(succeeded(), not(eq(variables['build.reason'], 'PullRequest')), not(eq(variables['SignClientSecret'], '')), not(eq(variables['SignClientUser'], '')))

- task: PublishBuildArtifacts@1
condition: always()
inputs:
PathtoPublish: $(build.artifactstagingdirectory)
ArtifactName: uno-monaco-editor-uwp-drop
Expand Down
4 changes: 2 additions & 2 deletions GenerateMonacoTypings/generate-typings.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Copy-Item $monaco_file -Destination (Join-Path $temp_dir_name "monaco.ts")
Push-Location $temp_dir_name

# Run typedoc to generate json representation
Write-Output '{"compilerOptions":{"target":"es2020"}}' > tsconfig.json
Invoke-Expression "npx typedoc monaco.ts --json monaco.json"

# Need TypedocConverter next
Expand All @@ -47,8 +48,7 @@ Write-Host "Extracting..."
Expand-Archive "TypedocConverter.zip" -DestinationPath .

# Now run TypedocConverter on our monaco.json

Invoke-Expression ".\TypedocConverter.exe --inputfile monaco.json --splitfiles true --outputdir ../$env:npm_package_config_outdir --promise-type WinRT"
Invoke-Expression ".\TypedocConverter.exe --inputfile monaco.json --splitfiles true --outputdir ../$env:npm_package_config_outdir --promise-type WinRT --nrt-disabled true"

Pop-Location

Expand Down
8 changes: 4 additions & 4 deletions GenerateMonacoTypings/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
"license": "MIT",
"config": {
"outdir": "../MonacoEditorComponent",
"typedocConverter": "https://github.com/hez2010/TypedocConverter/releases/download/v1.6/Windows_x64.zip"
"typedocConverter": "https://github.com/hez2010/TypedocConverter/releases/download/v2.6/Windows_x64_Native.zip"
},
"dependencies": {
"monaco-editor": "0.20.0"
"monaco-editor": "0.21.3"
},
"devDependencies": {
"typedoc": "^0.17.3",
"typescript": "^3.8.3"
"typedoc": "0.20.37",
"typescript": "4.2.4"
}
}
1 change: 1 addition & 0 deletions MonacoEditorComponent.sln
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
install-dependencies.ps1 = install-dependencies.ps1
MonacoEditorComponent\MonacoEditorComponent.nuspec = MonacoEditorComponent\MonacoEditorComponent.nuspec
README.md = README.md
ThirdPartyNotices.txt = ThirdPartyNotices.txt
EndProjectSection
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "MonacoEditorTestApp.Shared", "MonacoEditorTestApp.Shared\MonacoEditorTestApp.Shared.shproj", "{6279C845-92F8-4333-AB99-3D213163593C}"
Expand Down
10 changes: 10 additions & 0 deletions MonacoEditorComponent.slnf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"solution": {
"path": "MonacoEditorComponent.sln",
"projects": [
"MonacoEditorComponent\\MonacoEditorComponent.csproj",
"MonacoEditorTestApp.Shared\\MonacoEditorTestApp.Shared.shproj",
"MonacoEditorTestApp.Wasm\\MonacoEditorTestApp.Wasm.csproj"
]
}
}
53 changes: 43 additions & 10 deletions MonacoEditorComponent/CodeEditor/CodeEditor.Events.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Reflection;
using Windows.ApplicationModel.Activation;
using Windows.Foundation;
using Windows.System;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
Expand Down Expand Up @@ -42,19 +43,31 @@ public partial class CodeEditor
public new event WebKeyEventHandler KeyDown;

private ThemeListener _themeListener;
partial void LoadedPartial()
{
#if __WASM__
InitialiseWebObjects();

_view.Launch();
#endif
}

partial void SizeChangedPartial()
{
#if __WASM__
if (IsEditorLoaded)
{
_ = SendScriptAsync("EditorContext.getEditorForElement(element).editor.layout();");
}
#endif
}

private void WebView_DOMContentLoaded(ICodeEditorPresenter sender, WebViewDOMContentLoadedEventArgs args)
{
#if DEBUG
Debug.WriteLine("DOM Content Loaded");
#endif
_initialized = true;

#if __WASM__
InitialiseWebObjects();

_view.Launch();
#endif
}

private async void WebView_NavigationCompleted(ICodeEditorPresenter sender, WebViewNavigationCompletedEventArgs args)
Expand All @@ -65,7 +78,7 @@ private async void WebView_NavigationCompleted(ICodeEditorPresenter sender, WebV
IsEditorLoaded = true;

// Make sure inner editor is focused
await SendScriptAsync("editor.focus();");
await SendScriptAsync("EditorContext.getEditorForElement(element).editor.focus();");

// If we're supposed to have focus, make sure we try and refocus on our now loaded webview.
if (FocusManager.GetFocusedElement() == this)
Expand All @@ -92,18 +105,18 @@ private void InitialiseWebObjects() {
Debug.WriteLine($"InitialiseWebObjects");
try
{
_parentAccessor = new ParentAccessor(this);
_parentAccessor = new ParentAccessor(this, DispatcherQueue.GetForCurrentThread());
_parentAccessor.AddAssemblyForTypeLookup(typeof(Range).GetTypeInfo().Assembly);
_parentAccessor.RegisterAction("Loaded", CodeEditorLoaded);

_themeListener = new ThemeListener();
_themeListener.ThemeChanged += ThemeListener_ThemeChanged;
_themeToken = RegisterPropertyChangedCallback(RequestedThemeProperty, RequestedTheme_PropertyChanged);

_keyboardListener = new KeyboardListener(this);
_keyboardListener = new KeyboardListener(this, DispatcherQueue.GetForCurrentThread());

_view.AddWebAllowedObject("Debug", new DebugLogger());
_view.AddWebAllowedObject("Parent", _parentAccessor);
_view.AddWebAllowedObject("Accessor", _parentAccessor);
_view.AddWebAllowedObject("Theme", _themeListener);
_view.AddWebAllowedObject("Keyboard", _keyboardListener);
Debug.WriteLine($"InitialiseWebObjects - Completed");
Expand All @@ -116,6 +129,8 @@ private void InitialiseWebObjects() {

private async void CodeEditorLoaded()
{
_initialized = true;

if (Decorations != null && Decorations.Count > 0)
{
// Need to retrigger highlights after load if they were set before load.
Expand All @@ -125,6 +140,24 @@ private async void CodeEditorLoaded()
// Now we're done loading
Loading?.Invoke(this, new RoutedEventArgs());

// Make sure inner editor is focused
await SendScriptAsync("EditorContext.getEditorForElement(element).editor.focus();");

await SendScriptAsync("EditorContext.getEditorForElement(element).editor.layout();");

await InvokeScriptAsync("updateLanguage", Options.Language);
await InvokeScriptAsync("updateOptions", Options);

// If we're supposed to have focus, make sure we try and refocus on our now loaded webview.
if (FocusManager.GetFocusedElement() == this)
{
_view.Focus(FocusState.Programmatic);
}

IsEditorLoaded = true;

Loaded?.Invoke(this, new RoutedEventArgs());

#if __WASM__
Dispatcher.RunAsync(CoreDispatcherPriority.Low, () => WebView_NavigationCompleted(_view, null));
#endif
Expand Down
80 changes: 43 additions & 37 deletions MonacoEditorComponent/CodeEditor/CodeEditor.Methods.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
using Monaco.Editor;
using Microsoft.Toolkit.Uwp;
using Monaco.Editor;
using Monaco.Helpers;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading;
using System.Threading.Tasks;
using Windows.Foundation;

#if !NETSTANDARD2_0
Expand Down Expand Up @@ -68,37 +72,37 @@ public IAsyncAction RevealPositionAsync(IPosition position, bool revealVerticalI

public IAsyncAction RevealPositionAsync(IPosition position, bool revealVerticalInCenter, bool revealHorizontal)
{
return SendScriptAsync("editor.revealPosition(JSON.parse('" + position.ToJson() + "'), " + JsonConvert.ToString(revealVerticalInCenter) + ", " + JsonConvert.ToString(revealHorizontal) + ")").AsAsyncAction();
return SendScriptAsync("editor.revealPosition(JSON.parse('" + JsonConvert.SerializeObject(position) + "'), " + JsonConvert.ToString(revealVerticalInCenter) + ", " + JsonConvert.ToString(revealHorizontal) + ")").AsAsyncAction();
}

public IAsyncAction RevealPositionInCenterAsync(IPosition position)
{
return SendScriptAsync("editor.revealPositionInCenter(JSON.parse('" + position.ToJson() + "'))").AsAsyncAction();
return SendScriptAsync("editor.revealPositionInCenter(JSON.parse('" + JsonConvert.SerializeObject(position) + "'))").AsAsyncAction();
}

public IAsyncAction RevealPositionInCenterIfOutsideViewportAsync(IPosition position)
{
return SendScriptAsync("editor.revealPositionInCenterIfOutsideViewport(JSON.parse('" + position.ToJson() + "'))").AsAsyncAction();
return SendScriptAsync("editor.revealPositionInCenterIfOutsideViewport(JSON.parse('" + JsonConvert.SerializeObject(position) + "'))").AsAsyncAction();
}

public IAsyncAction RevealRangeAsync(IRange range)
{
return SendScriptAsync("editor.revealRange(JSON.parse('" + range.ToJson() + "'))").AsAsyncAction();
return SendScriptAsync("editor.revealRange(JSON.parse('" + JsonConvert.SerializeObject(range) + "'))").AsAsyncAction();
}

public IAsyncAction RevealRangeAtTopAsync(IRange range)
{
return SendScriptAsync("editor.revealRangeAtTop(JSON.parse('" + range.ToJson() + "'))").AsAsyncAction();
return SendScriptAsync("editor.revealRangeAtTop(JSON.parse('" + JsonConvert.SerializeObject(range) + "'))").AsAsyncAction();
}

public IAsyncAction RevealRangeInCenterAsync(IRange range)
{
return SendScriptAsync("editor.revealRangeInCenter(JSON.parse('" + range.ToJson() + "'))").AsAsyncAction();
return SendScriptAsync("editor.revealRangeInCenter(JSON.parse('" + JsonConvert.SerializeObject(range) + "'))").AsAsyncAction();
}

public IAsyncAction RevealRangeInCenterIfOutsideViewportAsync(IRange range)
{
return SendScriptAsync("editor.revealRangeInCenterIfOutsideViewport(JSON.parse('" + range.ToJson() + "'))").AsAsyncAction();
return SendScriptAsync("editor.revealRangeInCenterIfOutsideViewport(JSON.parse('" + JsonConvert.SerializeObject(range) + "'))").AsAsyncAction();
}
#endregion

Expand All @@ -119,14 +123,26 @@ public IAsyncOperation<string> InvokeScriptAsync(string script)
return _view.InvokeScriptAsync("eval", new[] { script });
}

private int _commandIndex = 0;

public IAsyncOperation<string> AddCommandAsync(CommandHandler handler)
{
return AddCommandAsync(0, handler, string.Empty);
}

public IAsyncOperation<string> AddCommandAsync(int keybinding, CommandHandler handler)
{
return AddCommandAsync(keybinding, handler, string.Empty);
}

public IAsyncOperation<string> AddCommandAsync(int keybinding, CommandHandler handler, string context)
{
var name = "Command" + keybinding;
if(_parentAccessor == null)
{
throw new InvalidOperationException($"_parentAccessor is not available");
}

var name = "Command" + Interlocked.Increment(ref _commandIndex);
_parentAccessor.RegisterActionWithParameters(name, (parameters) =>
{
if (parameters != null && parameters.Length > 0)
Expand All @@ -147,19 +163,18 @@ public IAsyncOperation<string> AddCommandAsync(int keybinding, CommandHandler ha
return InvokeScriptAsync<string>("addCommand", new object[] { keybinding, name, context }).AsAsyncOperation();
}

public IAsyncOperation<ContextKey> CreateContextKeyAsync(string key, bool defaultValue)
public async Task<ContextKey> CreateContextKeyAsync(string key, bool defaultValue)
{
var ck = new ContextKey(this, key, defaultValue);

return InvokeScriptAsync("createContext", ck).ContinueWith((noop) =>
{
return ck;
}).AsAsyncOperation();
await InvokeScriptAsync("createContext", ck);

return ck;
}

public IModel GetModel()
{
return _model;
return _model ?? throw new NotSupportedException($"Model is not available");
}

public IAsyncOperation<IEnumerable<Marker>> GetModelMarkersAsync() // TODO: Filter (string? owner, Uri? resource, int? take)
Expand All @@ -169,17 +184,17 @@ public IAsyncOperation<IEnumerable<Marker>> GetModelMarkersAsync() // TODO: Filt

public IAsyncAction SetModelMarkersAsync(string owner, [ReadOnlyArray] IMarkerData[] markers)
{
return SendScriptAsync("monaco.editor.setModelMarkers(model, " + JsonConvert.ToString(owner) + ", " + JsonConvert.SerializeObject(markers) + ");").AsAsyncAction();
return SendScriptAsync("monaco.editor.setModelMarkers(EditorContext.getEditorForElement(element).model, " + JsonConvert.ToString(owner) + ", " + JsonConvert.SerializeObject(markers) + ");").AsAsyncAction();
}

public IAsyncOperation<Position> GetPositionAsync()
{
return SendScriptAsync<Position>("editor.getPosition();").AsAsyncOperation();
return SendScriptAsync<Position>("EditorContext.getEditorForElement(element).editor.getPosition();").AsAsyncOperation();
}

public IAsyncAction SetPositionAsync(IPosition position)
{
return SendScriptAsync("editor.setPosition(" + JsonConvert.SerializeObject(position) + ");").AsAsyncAction();
return SendScriptAsync("EditorContext.getEditorForElement(element).editor.setPosition(" + JsonConvert.SerializeObject(position) + ");").AsAsyncAction();
}

/// <summary>
Expand All @@ -189,31 +204,22 @@ public IAsyncAction SetPositionAsync(IPosition position)
/// </summary>
/// <param name="newDecorations"></param>
/// <returns></returns>
private IAsyncAction DeltaDecorationsHelperAsync([ReadOnlyArray] IModelDeltaDecoration[] newDecorations)
private async Task DeltaDecorationsHelperAsync([ReadOnlyArray] IModelDeltaDecoration[] newDecorations)
{
var newDecorationsAdjust = newDecorations ?? Array.Empty<IModelDeltaDecoration>();
System.Diagnostics.Debug.WriteLine("associating decorations");
if (_cssBroker.AssociateStyles(newDecorations))
await _queue.EnqueueAsync(async () =>
{
System.Diagnostics.Debug.WriteLine("updating associated styles");
// Update Styles First
return InvokeScriptAsync("updateStyle", _cssBroker.GetStyles()).ContinueWith((noop) =>
var newDecorationsAdjust = newDecorations ?? Array.Empty<IModelDeltaDecoration>();

if (_cssBroker.AssociateStyles(newDecorations))
{
System.Diagnostics.Debug.WriteLine($"updating decorations {newDecorationsAdjust}");
// Update Styles First
await InvokeScriptAsync("updateStyle", _cssBroker.GetStyles());
}

// Send Command to Modify Decorations
// IMPORTANT: Need to cast to object here as we want this to be a single array object passed as a parameter, not a list of parameters to expand.
return InvokeScriptAsync("updateDecorations", (object)newDecorationsAdjust);
}).AsAsyncAction();
}
else
{
System.Diagnostics.Debug.WriteLine("updating unassociated decorations");

// Only Send Command to Modify Decorations themselves
// IMPORTANT: Need to cast to object here as we want this to be a single array object passed as a parameter, not a list of parameters to expand.
return InvokeScriptAsync("updateDecorations", (object)newDecorationsAdjust).AsAsyncAction();
}
await InvokeScriptAsync("updateDecorations", (object)newDecorationsAdjust);
});
}
}
}
Loading