예제 #1
0
 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;
     }));
 }
예제 #2
0
        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);
        }
예제 #3
0
        /// <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();
            }
        }
예제 #4
0
 /// <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;
 }
예제 #5
0
 /// <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();
 }
예제 #6
0
        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);
        }
예제 #7
0
 public void ShowNode(AvaloniaEditTextOutput textOutput, ILSpyTreeNode node, IHighlightingDefinition highlighting = null)
 {
     ShowNodes(textOutput, new[] { node }, highlighting);
 }
예제 #8
0
 public void ShowText(AvaloniaEditTextOutput textOutput)
 {
     ShowNodes(textOutput, null);
 }
예제 #9
0
        /// <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);
        }