diff --git a/ILSpy/DecompilationOptions.cs b/ILSpy/DecompilationOptions.cs
index 162fbe29c..bada56620 100644
--- a/ILSpy/DecompilationOptions.cs
+++ b/ILSpy/DecompilationOptions.cs
@@ -51,7 +51,15 @@ namespace ICSharpCode.ILSpy
/// Gets the settings for the decompiler.
///
public DecompilerSettings DecompilerSettings { get; set; }
-
+
+ ///
+ /// Gets/sets an optional state of a decompiler text view.
+ ///
+ ///
+ /// This state is used to restore test view's state when decompilation is started by Go Back/Forward action.
+ ///
+ public ICSharpCode.ILSpy.TextView.DecompilerTextViewState TextViewState { get; set; }
+
public DecompilationOptions()
{
this.DecompilerSettings = DecompilerSettingsPanel.CurrentDecompilerSettings;
diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs
index 7243d4001..abff3d499 100644
--- a/ILSpy/MainWindow.xaml.cs
+++ b/ILSpy/MainWindow.xaml.cs
@@ -46,7 +46,8 @@ namespace ICSharpCode.ILSpy
///
partial class MainWindow : Window
{
- NavigationHistory history = new NavigationHistory();
+ NavigationHistory, DecompilerTextViewState>> history =
+ new NavigationHistory, DecompilerTextViewState>>();
ILSpySettings spySettings;
SessionSettings sessionSettings;
AssemblyListManager assemblyListManager;
@@ -254,7 +255,7 @@ namespace ICSharpCode.ILSpy
{
if (e.OldItems != null)
foreach (LoadedAssembly asm in e.OldItems)
- history.RemoveAll(n => n.AncestorsAndSelf().OfType().Any(a => a.LoadedAssembly == asm));
+ history.RemoveAll(n => n.Item1.Any(nd => nd.AncestorsAndSelf().OfType().Any(a => a.LoadedAssembly == asm)));
}
void LoadInitialAssemblies()
@@ -284,7 +285,7 @@ namespace ICSharpCode.ILSpy
{
RefreshTreeViewFilter();
if (e.PropertyName == "Language") {
- TreeView_SelectionChanged(null, null);
+ DecompileSelectedNodes();
}
}
@@ -311,7 +312,7 @@ namespace ICSharpCode.ILSpy
if (obj != null) {
SharpTreeNode oldNode = treeView.SelectedItem as SharpTreeNode;
if (oldNode != null && recordNavigationInHistory)
- history.Record(oldNode);
+ history.Record(Tuple.Create(treeView.SelectedItems.OfType().ToList(), decompilerTextView.GetState()));
// Set both the selection and focus to ensure that keyboard navigation works as expected.
treeView.FocusNode(obj);
treeView.SelectedItem = obj;
@@ -426,12 +427,22 @@ namespace ICSharpCode.ILSpy
#region Decompile (TreeView_SelectionChanged)
void TreeView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
+ DecompileSelectedNodes();
+ }
+
+ private bool ignoreDecompilationRequests;
+
+ private void DecompileSelectedNodes(DecompilerTextViewState state = null)
+ {
+ if (ignoreDecompilationRequests)
+ return;
+
if (treeView.SelectedItems.Count == 1) {
ILSpyTreeNode node = treeView.SelectedItem as ILSpyTreeNode;
if (node != null && node.View(decompilerTextView))
return;
}
- decompilerTextView.Decompile(this.CurrentLanguage, this.SelectedNodes, new DecompilationOptions());
+ decompilerTextView.Decompile(this.CurrentLanguage, this.SelectedNodes, new DecompilationOptions() { TextViewState = state });
}
void SaveCommandExecuted(object sender, ExecutedRoutedEventArgs e)
@@ -447,7 +458,7 @@ namespace ICSharpCode.ILSpy
public void RefreshDecompiledView()
{
- TreeView_SelectionChanged(null, null);
+ DecompileSelectedNodes();
}
public DecompilerTextView TextView {
@@ -478,7 +489,7 @@ namespace ICSharpCode.ILSpy
{
if (history.CanNavigateBack) {
e.Handled = true;
- SelectNode(history.GoBack(treeView.SelectedItem as SharpTreeNode), false);
+ NavigateHistory(false);
}
}
@@ -492,9 +503,27 @@ namespace ICSharpCode.ILSpy
{
if (history.CanNavigateForward) {
e.Handled = true;
- SelectNode(history.GoForward(treeView.SelectedItem as SharpTreeNode), false);
+ NavigateHistory(true);
}
}
+
+ void NavigateHistory(bool forward)
+ {
+ var currentSelection = treeView.SelectedItems.OfType().ToList();
+ var state = decompilerTextView.GetState();
+ var combinedState = Tuple.Create(currentSelection, state);
+ var newState = forward ? history.GoForward(combinedState) : history.GoBack(combinedState);
+
+ this.ignoreDecompilationRequests = true;
+ treeView.SelectedItems.Clear();
+ foreach (var node in newState.Item1)
+ {
+ treeView.SelectedItems.Add(node);
+ }
+ ignoreDecompilationRequests = false;
+ DecompileSelectedNodes(newState.Item2);
+ }
+
#endregion
#region Analyzer
diff --git a/ILSpy/NavigationHistory.cs b/ILSpy/NavigationHistory.cs
index f15cfa732..26118321d 100644
--- a/ILSpy/NavigationHistory.cs
+++ b/ILSpy/NavigationHistory.cs
@@ -10,10 +10,10 @@ namespace ICSharpCode.ILSpy
///
/// Stores the navigation history.
///
- sealed class NavigationHistory
+ sealed class NavigationHistory
{
- List back = new List();
- List forward = new List();
+ List back = new List();
+ List forward = new List();
public bool CanNavigateBack {
get { return back.Count > 0; }
@@ -23,27 +23,27 @@ namespace ICSharpCode.ILSpy
get { return forward.Count > 0; }
}
- public SharpTreeNode GoBack(SharpTreeNode oldNode)
+ public T GoBack(T oldNode)
{
if (oldNode != null)
forward.Add(oldNode);
- SharpTreeNode node = back[back.Count - 1];
+ T node = back[back.Count - 1];
back.RemoveAt(back.Count - 1);
return node;
}
- public SharpTreeNode GoForward(SharpTreeNode oldNode)
+ public T GoForward(T oldNode)
{
if (oldNode != null)
back.Add(oldNode);
- SharpTreeNode node = forward[forward.Count - 1];
+ T node = forward[forward.Count - 1];
forward.RemoveAt(forward.Count - 1);
return node;
}
- public void RemoveAll(Predicate predicate)
+ public void RemoveAll(Predicate predicate)
{
back.RemoveAll(predicate);
forward.RemoveAll(predicate);
@@ -55,7 +55,7 @@ namespace ICSharpCode.ILSpy
forward.Clear();
}
- public void Record(SharpTreeNode node)
+ public void Record(T node)
{
forward.Clear();
back.Add(node);
diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs
index 928f11348..6315e8891 100644
--- a/ILSpy/TextView/DecompilerTextView.cs
+++ b/ILSpy/TextView/DecompilerTextView.cs
@@ -267,9 +267,9 @@ namespace ICSharpCode.ILSpy.TextView
///
/// Shows the given output in the text view.
///
- void ShowOutput(AvalonEditTextOutput textOutput, IHighlightingDefinition highlighting = null)
+ void ShowOutput(AvalonEditTextOutput textOutput, IHighlightingDefinition highlighting = null, DecompilerTextViewState state = null)
{
- Debug.WriteLine("Showing {0} characters of output", textOutput.TextLength);
+ Debug.WriteLine("Showing {0} characters of output", textOutput.TextLength);
Stopwatch w = Stopwatch.StartNew();
textEditor.ScrollToHome();
@@ -287,6 +287,11 @@ namespace ICSharpCode.ILSpy.TextView
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();
@@ -349,7 +354,7 @@ namespace ICSharpCode.ILSpy.TextView
delegate (Task task) { // handling the result
try {
AvalonEditTextOutput textOutput = task.Result;
- ShowOutput(textOutput, context.Language.SyntaxHighlighting);
+ ShowOutput(textOutput, context.Language.SyntaxHighlighting, context.Options.TextViewState);
} catch (AggregateException aggregateException) {
textEditor.SyntaxHighlighting = null;
Debug.WriteLine("Decompiler crashed: " + aggregateException.ToString());
@@ -598,5 +603,37 @@ namespace ICSharpCode.ILSpy.TextView
return text;
}
#endregion
+
+ public DecompilerTextViewState GetState()
+ {
+ var state = new DecompilerTextViewState();
+ if (foldingManager != null)
+ state.SaveFoldingsState(foldingManager.AllFoldings);
+ state.VerticalOffset = textEditor.VerticalOffset;
+ state.HorizontalOffset = textEditor.HorizontalOffset;
+ return state;
+ }
+ }
+
+ public class DecompilerTextViewState
+ {
+ private List> ExpandedFoldings;
+ private int FoldingsChecksum;
+ public double VerticalOffset;
+ public double HorizontalOffset;
+
+ public void SaveFoldingsState(IEnumerable foldings)
+ {
+ ExpandedFoldings = foldings.Where(f => !f.IsFolded).Select(f => Tuple.Create(f.StartOffset, f.EndOffset)).ToList();
+ FoldingsChecksum = foldings.Select(f => f.StartOffset * 3 - f.EndOffset).Aggregate((a, b) => a + b);
+ }
+
+ internal void RestoreFoldings(List list)
+ {
+ var checksum = list.Select(f => f.StartOffset * 3 - f.EndOffset).Aggregate((a, b) => a + b);
+ if (FoldingsChecksum == checksum)
+ foreach (var folding in list)
+ folding.DefaultClosed = !ExpandedFoldings.Any(f => f.Item1 == folding.StartOffset && f.Item2 == folding.EndOffset);
+ }
}
}