Browse Source

Preserving all selected nodes, foldings state and position of decompiler text view in the navigation history.

pull/100/head
Artur Zgodziński 14 years ago committed by Daniel Grunwald
parent
commit
bc6e2ddaca
  1. 10
      ILSpy/DecompilationOptions.cs
  2. 45
      ILSpy/MainWindow.xaml.cs
  3. 18
      ILSpy/NavigationHistory.cs
  4. 43
      ILSpy/TextView/DecompilerTextView.cs

10
ILSpy/DecompilationOptions.cs

@ -51,7 +51,15 @@ namespace ICSharpCode.ILSpy @@ -51,7 +51,15 @@ namespace ICSharpCode.ILSpy
/// Gets the settings for the decompiler.
/// </summary>
public DecompilerSettings DecompilerSettings { get; set; }
/// <summary>
/// Gets/sets an optional state of a decompiler text view.
/// </summary>
/// <remarks>
/// This state is used to restore test view's state when decompilation is started by Go Back/Forward action.
/// </remarks>
public ICSharpCode.ILSpy.TextView.DecompilerTextViewState TextViewState { get; set; }
public DecompilationOptions()
{
this.DecompilerSettings = DecompilerSettingsPanel.CurrentDecompilerSettings;

45
ILSpy/MainWindow.xaml.cs

@ -46,7 +46,8 @@ namespace ICSharpCode.ILSpy @@ -46,7 +46,8 @@ namespace ICSharpCode.ILSpy
/// </summary>
partial class MainWindow : Window
{
NavigationHistory history = new NavigationHistory();
NavigationHistory<Tuple<List<SharpTreeNode>, DecompilerTextViewState>> history =
new NavigationHistory<Tuple<List<SharpTreeNode>, DecompilerTextViewState>>();
ILSpySettings spySettings;
SessionSettings sessionSettings;
AssemblyListManager assemblyListManager;
@ -254,7 +255,7 @@ namespace ICSharpCode.ILSpy @@ -254,7 +255,7 @@ namespace ICSharpCode.ILSpy
{
if (e.OldItems != null)
foreach (LoadedAssembly asm in e.OldItems)
history.RemoveAll(n => n.AncestorsAndSelf().OfType<AssemblyTreeNode>().Any(a => a.LoadedAssembly == asm));
history.RemoveAll(n => n.Item1.Any(nd => nd.AncestorsAndSelf().OfType<AssemblyTreeNode>().Any(a => a.LoadedAssembly == asm)));
}
void LoadInitialAssemblies()
@ -284,7 +285,7 @@ namespace ICSharpCode.ILSpy @@ -284,7 +285,7 @@ namespace ICSharpCode.ILSpy
{
RefreshTreeViewFilter();
if (e.PropertyName == "Language") {
TreeView_SelectionChanged(null, null);
DecompileSelectedNodes();
}
}
@ -311,7 +312,7 @@ namespace ICSharpCode.ILSpy @@ -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<SharpTreeNode>().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 @@ -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 @@ -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 @@ -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 @@ -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<SharpTreeNode>().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

18
ILSpy/NavigationHistory.cs

@ -10,10 +10,10 @@ namespace ICSharpCode.ILSpy @@ -10,10 +10,10 @@ namespace ICSharpCode.ILSpy
/// <summary>
/// Stores the navigation history.
/// </summary>
sealed class NavigationHistory
sealed class NavigationHistory<T>
{
List<SharpTreeNode> back = new List<SharpTreeNode>();
List<SharpTreeNode> forward = new List<SharpTreeNode>();
List<T> back = new List<T>();
List<T> forward = new List<T>();
public bool CanNavigateBack {
get { return back.Count > 0; }
@ -23,27 +23,27 @@ namespace ICSharpCode.ILSpy @@ -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<SharpTreeNode> predicate)
public void RemoveAll(Predicate<T> predicate)
{
back.RemoveAll(predicate);
forward.RemoveAll(predicate);
@ -55,7 +55,7 @@ namespace ICSharpCode.ILSpy @@ -55,7 +55,7 @@ namespace ICSharpCode.ILSpy
forward.Clear();
}
public void Record(SharpTreeNode node)
public void Record(T node)
{
forward.Clear();
back.Add(node);

43
ILSpy/TextView/DecompilerTextView.cs

@ -267,9 +267,9 @@ namespace ICSharpCode.ILSpy.TextView @@ -267,9 +267,9 @@ namespace ICSharpCode.ILSpy.TextView
/// <summary>
/// Shows the given output in the text view.
/// </summary>
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 @@ -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 @@ -349,7 +354,7 @@ namespace ICSharpCode.ILSpy.TextView
delegate (Task<AvalonEditTextOutput> 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 @@ -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<Tuple<int, int>> ExpandedFoldings;
private int FoldingsChecksum;
public double VerticalOffset;
public double HorizontalOffset;
public void SaveFoldingsState(IEnumerable<FoldingSection> 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<NewFolding> 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);
}
}
}

Loading…
Cancel
Save