diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index a95ddbaf2..787f98668 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -160,7 +160,7 @@ namespace ICSharpCode.Decompiler.Ast RunTransformations(); astCompileUnit.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true }); - var outputFormatter = new TextOutputFormatter(output); + var outputFormatter = new TextOutputFormatter(output) { FoldBraces = context.Settings.FoldBraces }; var formattingPolicy = context.Settings.CSharpFormattingOptions; astCompileUnit.AcceptVisitor(new CSharpOutputVisitor(outputFormatter, formattingPolicy)); } diff --git a/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs b/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs index b17e24656..5e3cef994 100644 --- a/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs +++ b/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs @@ -36,6 +36,8 @@ namespace ICSharpCode.Decompiler.Ast bool firstUsingDeclaration; bool lastUsingDeclaration; + public bool FoldBraces = false; + public TextOutputFormatter(ITextOutput output) { if (output == null) @@ -183,7 +185,7 @@ namespace ICSharpCode.Decompiler.Ast { if (braceLevelWithinType >= 0 || nodeStack.Peek() is TypeDeclaration) braceLevelWithinType++; - if (nodeStack.OfType().Count() <= 1) { + if (nodeStack.OfType().Count() <= 1 || FoldBraces) { output.MarkFoldStart(defaultCollapsed: braceLevelWithinType == 1); } output.WriteLine(); @@ -195,7 +197,7 @@ namespace ICSharpCode.Decompiler.Ast { output.Unindent(); output.Write('}'); - if (nodeStack.OfType().Count() <= 1) + if (nodeStack.OfType().Count() <= 1 || FoldBraces) output.MarkFoldEnd(); if (braceLevelWithinType >= 0) braceLevelWithinType--; diff --git a/ICSharpCode.Decompiler/DecompilerSettings.cs b/ICSharpCode.Decompiler/DecompilerSettings.cs index f78194a6f..36c91745c 100644 --- a/ICSharpCode.Decompiler/DecompilerSettings.cs +++ b/ICSharpCode.Decompiler/DecompilerSettings.cs @@ -254,6 +254,18 @@ namespace ICSharpCode.Decompiler } } } + + bool foldBraces = false; + + public bool FoldBraces { + get { return foldBraces; } + set { + if (foldBraces != value) { + foldBraces = value; + OnPropertyChanged("FoldBraces"); + } + } + } #region Options to aid VB decompilation bool introduceIncrementAndDecrement = true; diff --git a/ILSpy/ContextMenuEntry.cs b/ILSpy/ContextMenuEntry.cs index 0f47af847..b00d54124 100644 --- a/ILSpy/ContextMenuEntry.cs +++ b/ILSpy/ContextMenuEntry.cs @@ -21,6 +21,8 @@ using System.ComponentModel.Composition; using System.Linq; using System.Windows; using System.Windows.Controls; + +using ICSharpCode.AvalonEdit; using ICSharpCode.ILSpy.TextView; using ICSharpCode.TreeView; @@ -59,15 +61,23 @@ namespace ICSharpCode.ILSpy /// public ReferenceSegment Reference { get; private set; } + /// + /// Returns the position in TextView the mouse cursor is currently hovering above. + /// Returns null, if TextView returns null; + /// + public TextViewPosition? Position { get; private set; } + public static TextViewContext Create(SharpTreeView treeView = null, DecompilerTextView textView = null) { var reference = textView != null ? textView.GetReferenceSegmentAtMousePosition() : null; + var position = textView != null ? textView.GetPositionFromMousePosition() : null; var selectedTreeNodes = treeView != null ? treeView.GetTopLevelSelection().ToArray() : null; return new TextViewContext { TreeView = treeView, SelectedTreeNodes = selectedTreeNodes, TextView = textView, - Reference = reference + Reference = reference, + Position = position }; } } diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 7e57b2eff..b95e2d357 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -177,6 +177,7 @@ Code + diff --git a/ILSpy/Options/DecompilerSettingsPanel.xaml b/ILSpy/Options/DecompilerSettingsPanel.xaml index f72c387d8..e6a60055d 100644 --- a/ILSpy/Options/DecompilerSettingsPanel.xaml +++ b/ILSpy/Options/DecompilerSettingsPanel.xaml @@ -9,5 +9,6 @@ Decompile query expressions Use variable names from debug symbols, if available Show XML documentation in decompiled code + Enable folding on all blocks in braces \ No newline at end of file diff --git a/ILSpy/Options/DecompilerSettingsPanel.xaml.cs b/ILSpy/Options/DecompilerSettingsPanel.xaml.cs index e665f5eac..c686152f3 100644 --- a/ILSpy/Options/DecompilerSettingsPanel.xaml.cs +++ b/ILSpy/Options/DecompilerSettingsPanel.xaml.cs @@ -57,6 +57,7 @@ namespace ICSharpCode.ILSpy.Options s.QueryExpressions = (bool?)e.Attribute("queryExpressions") ?? s.QueryExpressions; s.UseDebugSymbols = (bool?)e.Attribute("useDebugSymbols") ?? s.UseDebugSymbols; s.ShowXmlDocumentation = (bool?)e.Attribute("xmlDoc") ?? s.ShowXmlDocumentation; + s.FoldBraces = (bool?)e.Attribute("foldBraces") ?? s.FoldBraces; return s; } @@ -70,6 +71,7 @@ namespace ICSharpCode.ILSpy.Options section.SetAttributeValue("queryExpressions", s.QueryExpressions); section.SetAttributeValue("useDebugSymbols", s.UseDebugSymbols); section.SetAttributeValue("xmlDoc", s.ShowXmlDocumentation); + section.SetAttributeValue("foldBraces", s.FoldBraces); XElement existingElement = root.Element("DecompilerSettings"); if (existingElement != null) diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs index 05eefd431..b13e15db4 100644 --- a/ILSpy/TextView/DecompilerTextView.cs +++ b/ILSpy/TextView/DecompilerTextView.cs @@ -763,13 +763,18 @@ namespace ICSharpCode.ILSpy.TextView internal ReferenceSegment GetReferenceSegmentAtMousePosition() { - TextViewPosition? position = textEditor.TextArea.TextView.GetPosition(Mouse.GetPosition(textEditor.TextArea.TextView) + textEditor.TextArea.TextView.ScrollOffset); + TextViewPosition? position = GetPositionFromMousePosition(); if (position == null) return null; int offset = textEditor.Document.GetOffset(position.Value.Location); return referenceElementGenerator.References.FindSegmentsContaining(offset).FirstOrDefault(); } - + + internal TextViewPosition? GetPositionFromMousePosition() + { + return textEditor.TextArea.TextView.GetPosition(Mouse.GetPosition(textEditor.TextArea.TextView) + textEditor.TextArea.TextView.ScrollOffset); + } + public DecompilerTextViewState GetState() { if (decompiledNodes == null) @@ -809,6 +814,13 @@ namespace ICSharpCode.ILSpy.TextView // scroll to textEditor.ScrollTo(lineNumber, 0); } + + public FoldingManager FoldingManager + { + get { + return foldingManager; + } + } #endregion } diff --git a/ILSpy/TextView/FoldingCommands.cs b/ILSpy/TextView/FoldingCommands.cs new file mode 100644 index 000000000..314a1412b --- /dev/null +++ b/ILSpy/TextView/FoldingCommands.cs @@ -0,0 +1,90 @@ +/* + * Created by SharpDevelop. + * User: Ronny Klier + * Date: 24.05.2012 + * Time: 23:44 + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ +using System; +using System.Collections.Generic; +using System.Linq; + +using ICSharpCode.AvalonEdit; +using ICSharpCode.AvalonEdit.Folding; + +namespace ICSharpCode.ILSpy.TextView +{ + [ExportContextMenuEntryAttribute(Header = "Toggle All Folding", Category = "Folding")] + internal sealed class ToggleAllContextMenuEntry : IContextMenuEntry + { + public bool IsVisible(TextViewContext context) + { + return context.TextView != null; + } + + public bool IsEnabled(TextViewContext context) + { + return context.TextView != null && context.TextView.FoldingManager != null; + } + + public void Execute(TextViewContext context) + { + if (null == context.TextView) + return; + FoldingManager foldingManager = context.TextView.FoldingManager; + if (null == foldingManager) + return; + bool doFold = true; + foreach (FoldingSection fm in foldingManager.AllFoldings) { + if (fm.IsFolded) { + doFold = false; + break; + } + } + foreach (FoldingSection fm in foldingManager.AllFoldings) { + fm.IsFolded = doFold; + } + } + } + + [ExportContextMenuEntryAttribute(Header = "Toggle Folding", Category = "Folding")] + internal sealed class ToggleContextMenuEntry : IContextMenuEntry + { + public bool IsVisible(TextViewContext context) + { + return context.TextView != null; + } + + public bool IsEnabled(TextViewContext context) + { + return context.TextView != null && context.TextView.FoldingManager != null; + } + + public void Execute(TextViewContext context) + { + var textView = context.TextView; + if (null == textView) + return; + var editor = textView.textEditor; + FoldingManager foldingManager = context.TextView.FoldingManager; + if (null == foldingManager) + return; + // TODO: or use Caret if position is not given? + var posBox = context.Position; + if (null == posBox) + return; + TextViewPosition pos = posBox.Value; + // look for folding on this line: + FoldingSection folding = foldingManager.GetNextFolding(editor.Document.GetOffset(pos.Line, 1)); + if (folding == null || editor.Document.GetLineByOffset(folding.StartOffset).LineNumber != pos.Line) { + // no folding found on current line: find innermost folding containing the mouse position + folding = foldingManager.GetFoldingsContaining(editor.Document.GetOffset(pos.Line, pos.Column)).LastOrDefault(); + } + if (folding != null) { + folding.IsFolded = !folding.IsFolded; + } + } + } + +}