Task DoDecompile(DecompilationContext context, int outputLengthLimit) { return(RunWithCancellation( delegate(CancellationToken ct) { // creation of the background task context.Options.CancellationToken = ct; return DecompileAsync(context, outputLengthLimit); }) .Then( delegate(AvaloniaEditTextOutput textOutput) { // handling the result ShowOutput(textOutput, context.Language.SyntaxHighlighting, context.Options.TextViewState); decompiledNodes = context.TreeNodes; }) .Catch <Exception>(exception => { textEditor.SyntaxHighlighting = null; Debug.WriteLine("Decompiler crashed: " + exception.ToString()); AvaloniaEditTextOutput output = new AvaloniaEditTextOutput(); if (exception is OutputLengthExceededException) { WriteOutputLengthExceededMessage(output, context, outputLengthLimit == DefaultOutputLengthLimit); } else { output.WriteLine(exception.ToString()); } ShowOutput(output); decompiledNodes = context.TreeNodes; })); }
Task <AvaloniaEditTextOutput> DecompileAsync(DecompilationContext context, int outputLengthLimit) { Debug.WriteLine("Start decompilation of {0} tree nodes", context.TreeNodes.Length); TaskCompletionSource <AvaloniaEditTextOutput> tcs = new TaskCompletionSource <AvaloniaEditTextOutput>(); if (context.TreeNodes.Length == 0) { // If there's nothing to be decompiled, don't bother starting up a thread. // (Improves perf in some cases since we don't have to wait for the thread-pool to accept our task) tcs.SetResult(new AvaloniaEditTextOutput()); return(tcs.Task); } Thread thread = new Thread(new ThreadStart( delegate { try { AvaloniaEditTextOutput textOutput = new AvaloniaEditTextOutput(); textOutput.LengthLimit = outputLengthLimit; DecompileNodes(context, textOutput); textOutput.PrepareDocument(); tcs.SetResult(textOutput); } catch (OperationCanceledException) { tcs.SetCanceled(); } catch (Exception ex) { tcs.SetException(ex); } })); thread.Start(); return(tcs.Task); }
/// <summary> /// Shows the given output in the text view. /// </summary> void ShowOutput(AvaloniaEditTextOutput textOutput, IHighlightingDefinition highlighting = null, DecompilerTextViewState state = null) { Debug.WriteLineIf(Dispatcher.UIThread.CheckAccess(), "Runing on UI Thread"); Debug.WriteLine("Showing {0} characters of output", textOutput.TextLength); Stopwatch w = Stopwatch.StartNew(); ClearLocalReferenceMarks(); textEditor.ScrollToHome(); if (foldingManager != null) { FoldingManager.Uninstall(foldingManager); foldingManager = null; } textEditor.Document = null; // clear old document while we're changing the highlighting uiElementGenerator.UIElements = textOutput.UIElemnts; referenceElementGenerator.References = textOutput.References; references = textOutput.References; definitionLookup = textOutput.DefinitionLookup; textEditor.SyntaxHighlighting = highlighting; if (activeRichTextColorizer != null) { textEditor.TextArea.TextView.LineTransformers.Remove(activeRichTextColorizer); } if (textOutput.HighlightingModel != null) { activeRichTextColorizer = new RichTextColorizer(textOutput.HighlightingModel); textEditor.TextArea.TextView.LineTransformers.Insert(highlighting == null ? 0 : 1, activeRichTextColorizer); } // Change the set of active element generators: foreach (var elementGenerator in activeCustomElementGenerators) { textEditor.TextArea.TextView.ElementGenerators.Remove(elementGenerator); } activeCustomElementGenerators.Clear(); foreach (var elementGenerator in textOutput.elementGenerators) { textEditor.TextArea.TextView.ElementGenerators.Add(elementGenerator); activeCustomElementGenerators.Add(elementGenerator); } Debug.WriteLine(" Set-up: {0}", w.Elapsed); w.Restart(); textEditor.Document = textOutput.GetDocument(); Debug.WriteLine(" Assigning document: {0}", w.Elapsed); w.Restart(); if (textOutput.Foldings.Count > 0) { if (state != null) { state.RestoreFoldings(textOutput.Foldings); textEditor.ScrollToVerticalOffset(state.VerticalOffset); textEditor.ScrollToHorizontalOffset(state.HorizontalOffset); } foldingManager = FoldingManager.Install(textEditor.TextArea); foldingManager.UpdateFoldings(textOutput.Foldings.OrderBy(f => f.StartOffset), -1); Debug.WriteLine(" Updating folding: {0}", w.Elapsed); w.Restart(); } }
/// <summary> /// Shows the given output in the text view. /// Cancels any currently running decompilation tasks. /// </summary> public void ShowNodes(AvaloniaEditTextOutput textOutput, ILSpyTreeNode[] nodes, IHighlightingDefinition highlighting = null) { // Cancel the decompilation task: if (currentCancellationTokenSource != null) { currentCancellationTokenSource.Cancel(); currentCancellationTokenSource = null; // prevent canceled task from producing output } if (this.nextDecompilationRun != null) { // remove scheduled decompilation run this.nextDecompilationRun.TaskCompletionSource.TrySetCanceled(); this.nextDecompilationRun = null; } ShowOutput(textOutput, highlighting); decompiledNodes = nodes; }
/// <summary> /// Starts the decompilation of the given nodes. /// The result will be saved to the given file name. /// </summary> void SaveToDisk(DecompilationContext context, string fileName) { RunWithCancellation( delegate(CancellationToken ct) { context.Options.CancellationToken = ct; return(SaveToDiskAsync(context, fileName)); }) .Then(output => ShowOutput(output)) .Catch((Exception ex) => { textEditor.SyntaxHighlighting = null; Debug.WriteLine("Decompiler crashed: " + ex.ToString()); // Unpack aggregate exceptions as long as there's only a single exception: // (assembly load errors might produce nested aggregate exceptions) AvaloniaEditTextOutput output = new AvaloniaEditTextOutput(); output.WriteLine(ex.ToString()); ShowOutput(output); }).HandleExceptions(); }
Task <AvaloniaEditTextOutput> SaveToDiskAsync(DecompilationContext context, string fileName) { TaskCompletionSource <AvaloniaEditTextOutput> tcs = new TaskCompletionSource <AvaloniaEditTextOutput>(); Thread thread = new Thread(new ThreadStart( delegate { try { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); using (StreamWriter w = new StreamWriter(fileName)) { try { DecompileNodes(context, new PlainTextOutput(w)); } catch (OperationCanceledException) { w.WriteLine(); w.WriteLine("Decompiled was cancelled."); throw; } } stopwatch.Stop(); AvaloniaEditTextOutput output = new AvaloniaEditTextOutput(); output.WriteLine("Decompilation complete in " + stopwatch.Elapsed.TotalSeconds.ToString("F1") + " seconds."); output.WriteLine(); output.AddButton(null, "Open Explorer", delegate { Process.Start("explorer", "/select,\"" + fileName + "\""); }); output.WriteLine(); tcs.SetResult(output); } catch (OperationCanceledException) { tcs.SetCanceled(); #if DEBUG } catch (AggregateException ex) { tcs.SetException(ex); #else } catch (Exception ex) { tcs.SetException(ex); #endif } })); thread.Start(); return(tcs.Task); }
public void ShowNode(AvaloniaEditTextOutput textOutput, ILSpyTreeNode node, IHighlightingDefinition highlighting = null) { ShowNodes(textOutput, new[] { node }, highlighting); }
public void ShowText(AvaloniaEditTextOutput textOutput) { ShowNodes(textOutput, null); }
/// <summary> /// Switches the GUI into "waiting" mode, then calls <paramref name="taskCreation"/> to create /// the task. /// If another task is started before the previous task finishes running, the previous task is cancelled. /// </summary> public Task <T> RunWithCancellation <T>(Func <CancellationToken, Task <T> > taskCreation) { if (waitAdorner.IsVisible != true) { waitAdorner.IsVisible = true; // Work around a WPF bug by setting IsIndeterminate only while the progress bar is visible. // https://github.com/icsharpcode/ILSpy/issues/593 progressBar.IsIndeterminate = true; waitAdorner.Opacity = 1; //TODO: animation //waitAdorner.BeginAnimation(OpacityProperty, new DoubleAnimation(0, 1, new Duration(TimeSpan.FromSeconds(0.5)), FillBehavior.Stop)); // TODO: taskbar progress //var taskBar = MainWindow.Instance.TaskbarItemInfo; //if (taskBar != null) { // taskBar.ProgressState = Avalonia.Shell.TaskbarItemProgressState.Indeterminate; //} } CancellationTokenSource previousCancellationTokenSource = currentCancellationTokenSource; var myCancellationTokenSource = new CancellationTokenSource(); currentCancellationTokenSource = myCancellationTokenSource; // cancel the previous only after current was set to the new one (avoid that the old one still finishes successfully) if (previousCancellationTokenSource != null) { previousCancellationTokenSource.Cancel(); } var tcs = new TaskCompletionSource <T>(); Task <T> task; try { task = taskCreation(myCancellationTokenSource.Token); } catch (OperationCanceledException) { task = TaskHelper.FromCancellation <T>(); } catch (Exception ex) { task = TaskHelper.FromException <T>(ex); } Action continuation = delegate { try { if (currentCancellationTokenSource == myCancellationTokenSource) { currentCancellationTokenSource = null; waitAdorner.IsVisible = false; progressBar.IsIndeterminate = false; // TODO: taskbar progress //var taskBar = MainWindow.Instance.TaskbarItemInfo; //if (taskBar != null) { // taskBar.ProgressState = TaskbarItemProgressState.None; //} if (task.IsCanceled) { AvaloniaEditTextOutput output = new AvaloniaEditTextOutput(); output.WriteLine("The operation was canceled."); ShowOutput(output); } tcs.SetFromTask(task); } else { tcs.SetCanceled(); } } finally { myCancellationTokenSource.Dispose(); } }; task.ContinueWith(delegate { Dispatcher.UIThread.InvokeAsync(continuation, DispatcherPriority.Normal); }); return(tcs.Task); }