|
25 | 25 | </div> |
26 | 26 |
|
27 | 27 | <div> |
| 28 | + @* Copy URL button *@ |
| 29 | + <FluentButton OnClick="() => CopyUrlToClipboardAsync()" Title="Copy URL to clipboard (Ctrl+;)" |
| 30 | + IconStart="@(urlCopied ? new Icons.Regular.Size20.Checkmark() : new Icons.Regular.Size20.ClipboardLink())" /> |
| 31 | + |
28 | 32 | @* Compile button *@ |
29 | 33 | <FluentButton Appearance="Appearance.Accent" OnClick="() => CompileAsync()" Loading="compilationInProgress" |
30 | 34 | Title="Compile (Ctrl+S)" IconStart="@(new Icons.Regular.Size20.FlashPlay())" Disabled="!initialized"> |
|
47 | 51 | <div style="flex-grow: 1"> |
48 | 52 | <div style="flex-grow: 1; min-width: 10rem"> |
49 | 53 | @* Outdated output info *@ |
50 | | - @if (outputOutdated) |
| 54 | + @if (IsOutputOutdated) |
51 | 55 | { |
52 | 56 | <FluentStack title="Output is outdated, click Compile or press Ctrl+S" |
53 | 57 | Style="font-size: 0.8rem; font-style: normal; width: auto" |
|
57 | 61 | </FluentStack> |
58 | 62 | } |
59 | 63 | @* Cached info *@ |
60 | | - else if (compiled is (_, _, { } cacheInfo)) |
| 64 | + else if (compiled is { CacheInfo: { } cacheInfo }) |
61 | 65 | { |
62 | 66 | var title = cacheInfo.Timestamp.HasValue |
63 | 67 | ? "The currently displayed output has been fetched from a server cache." |
|
234 | 238 | private Input? currentInput; |
235 | 239 | private EditorState? currentOutput; |
236 | 240 | private string? selectedOutputType; |
| 241 | + private int urlCopiedToken; |
| 242 | + private bool urlCopied; |
237 | 243 | private bool compilationInProgress; |
238 | | - private bool outputOutdated; |
| 244 | + private DateTimeOffset inputChanged; |
239 | 245 | private bool outputLoading; |
240 | | - private (CompilationInput Input, CompiledAssembly Output, CacheInfo? CacheInfo)? compiled; |
| 246 | + private (CompilationInput Input, CompiledAssembly Output, CacheInfo? CacheInfo, DateTimeOffset Start, DateTimeOffset End)? compiled; |
241 | 247 | private Settings settings = null!; |
242 | 248 | private bool wordWrap; |
243 | 249 | private bool useVim; |
|
317 | 323 | get => AllOutputs.Select(o => o.Type).JoinToString(","); |
318 | 324 | } |
319 | 325 |
|
| 326 | + /// <remarks> |
| 327 | + /// We don't check equality of last compiled input and current input |
| 328 | + /// because we might not have current input fully loaded |
| 329 | + /// (parts can live only in the editor until Compile is clicked). |
| 330 | + /// </remarks> |
| 331 | + private bool IsOutputOutdated |
| 332 | + => compiled is not { Start: var compileStart } || compileStart < inputChanged; |
| 333 | + |
320 | 334 | protected override void OnInitialized() |
321 | 335 | { |
322 | 336 | NavigationManager.LocationChanged += OnLocationChanged; |
|
379 | 393 | StateHasChanged(); |
380 | 394 | } |
381 | 395 |
|
| 396 | + [JSInvokable] |
| 397 | + public async Task CopyUrlToClipboardAsync() |
| 398 | + { |
| 399 | + await SaveStateToUrlAsync(); |
| 400 | + await module.InvokeVoidAsync("copyUrlToClipboard"); |
| 401 | + urlCopied = true; |
| 402 | + StateHasChanged(); |
| 403 | + var token = Interlocked.Increment(ref urlCopiedToken); |
| 404 | + _ = Task.Delay(TimeSpan.FromSeconds(2)).ContinueWith(_ => |
| 405 | + { |
| 406 | + if (token == urlCopiedToken) |
| 407 | + { |
| 408 | + urlCopied = false; |
| 409 | + StateHasChanged(); |
| 410 | + } |
| 411 | + }); |
| 412 | + } |
| 413 | + |
382 | 414 | private StandaloneEditorConstructionOptions InputConstructionOptions(StandaloneCodeEditor editor) |
383 | 415 | { |
384 | 416 | return EditorConstructionOptions(editor, output: false); |
|
656 | 688 | var state = await SaveStateToUrlAsync(); |
657 | 689 |
|
658 | 690 | // Compile. |
| 691 | + var startTime = DateTimeOffset.Now; |
659 | 692 | var input = state.ToCompilationInput(); |
660 | 693 | var output = await Worker.CompileAsync(input, languageServicesEnabled: LanguageServices.Enabled); |
661 | | - compiled = (input, output, null); |
662 | | - outputOutdated = false; |
| 694 | + compiled = (input, output, CacheInfo: null, Start: startTime, End: DateTimeOffset.Now); |
663 | 695 |
|
664 | 696 | await DisplaySquigglesAsync(); |
665 | 697 |
|
|
696 | 728 |
|
697 | 729 | public async Task DisplaySquigglesAsync() |
698 | 730 | { |
699 | | - // Prevent possibly delayed live diagnostics from a previous document version from overwriting the compiler diagnostics. |
700 | | - LanguageServices.CancelDiagnostics(); |
| 731 | + if (LanguageServices.Enabled) |
| 732 | + { |
| 733 | + if (IsOutputOutdated) |
| 734 | + { |
| 735 | + // Avoid overwriting live diagnostics which are newer. |
| 736 | + return; |
| 737 | + } |
| 738 | + |
| 739 | + // Prevent possibly delayed live diagnostics from a previous document version from overwriting the compiler diagnostics. |
| 740 | + LanguageServices.CancelDiagnostics(); |
| 741 | + } |
701 | 742 |
|
702 | 743 | foreach (var input in inputs) |
703 | 744 | { |
|
1007 | 1048 | private async Task TrySetCompiledFromCacheAsync(CompilationInput input, CompiledAssembly output, CacheInfo info, bool updateOutput) |
1008 | 1049 | { |
1009 | 1050 | // If the local compilation finishes before the cache is loaded, don't overwrite it. |
1010 | | - if (compiled is (var existingInput, _, null) && Equals(input, existingInput)) |
| 1051 | + if (compiled is { Input: var existingInput, CacheInfo: null } && Equals(input, existingInput)) |
1011 | 1052 | { |
1012 | 1053 | return; |
1013 | 1054 | } |
1014 | 1055 |
|
1015 | | - compiled = (input, output, info); |
1016 | | - outputOutdated = false; |
| 1056 | + var timestamp = DateTimeOffset.Now; |
| 1057 | + compiled = (input, output, info, Start: timestamp, End: timestamp); |
1017 | 1058 | StateHasChanged(); |
1018 | 1059 | await DisplaySquigglesAsync(); |
1019 | 1060 |
|
|
1055 | 1096 | /// </summary> |
1056 | 1097 | public Task OnWorkspaceChangedAsync() |
1057 | 1098 | { |
1058 | | - outputOutdated = true; |
| 1099 | + inputChanged = DateTimeOffset.Now; |
1059 | 1100 |
|
1060 | 1101 | if (!LanguageServices.Enabled) |
1061 | 1102 | { |
|
1094 | 1135 |
|
1095 | 1136 | private void OnDidChangeModelContent(ModelContentChangedEvent args) |
1096 | 1137 | { |
1097 | | - outputOutdated = true; |
| 1138 | + inputChanged = DateTimeOffset.Now; |
1098 | 1139 | LanguageServices.OnDidChangeModelContent(args); |
1099 | 1140 | } |
1100 | 1141 |
|
|
1111 | 1152 |
|
1112 | 1153 | public void OnSettingsInputChanged() |
1113 | 1154 | { |
1114 | | - outputOutdated = true; |
| 1155 | + inputChanged = DateTimeOffset.Now; |
1115 | 1156 | StateHasChanged(); |
1116 | 1157 | } |
1117 | 1158 |
|
|
0 commit comments