From 6ff259e9de55a372739419f2cd594a8dedb79103 Mon Sep 17 00:00:00 2001 From: Andreas Weizel Date: Mon, 19 May 2014 01:43:31 +0200 Subject: [PATCH 1/7] IndentationSize and ConvertTabsToSpaces settings can now be defined in separate policies together with other formatting options. --- .../Src/FormattingStrategy/CSharpFormatter.cs | 9 +- .../CSharpFormattingOptionsContainer.cs | 138 ++++++++++++++++-- .../CSharpFormattingStrategy.cs | 67 ++++++--- .../FormattingOptionBinding.cs | 53 ++++--- .../OptionPanels/CSharpFormattingEditor.xaml | 35 ++++- .../CSharpFormattingEditor.xaml.cs | 33 +++-- .../TextEditorOptions.cs | 12 +- 7 files changed, 275 insertions(+), 72 deletions(-) diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormatter.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormatter.cs index 028a43e6a8..7d3c9c5d76 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormatter.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormatter.cs @@ -31,7 +31,14 @@ namespace CSharpBinding.FormattingStrategy /// public static void Format(ITextEditor editor, int offset, int length, CSharpFormattingOptionsContainer optionsContainer) { - var formatter = new CSharpFormatter(optionsContainer.GetEffectiveOptions(), editor.ToEditorOptions()); + TextEditorOptions editorOptions = editor.ToEditorOptions(); + int? indentationSize = optionsContainer.GetEffectiveIndentationSize(); + if (indentationSize.HasValue) + editorOptions.IndentSize = indentationSize.Value; + bool? convertTabsToSpaces = optionsContainer.GetEffectiveConvertTabsToSpaces(); + if (convertTabsToSpaces.HasValue) + editorOptions.TabsToSpaces = convertTabsToSpaces.Value; + var formatter = new CSharpFormatter(optionsContainer.GetEffectiveOptions(), editorOptions); formatter.AddFormattingRegion(new DomRegion(editor.Document.GetLocation(offset), editor.Document.GetLocation(offset + length))); var changes = formatter.AnalyzeFormatting(editor.Document, SyntaxTree.Parse(editor.Document)); changes.ApplyChanges(offset, length); diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingOptionsContainer.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingOptionsContainer.cs index f3bc043736..e2f94692e4 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingOptionsContainer.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingOptionsContainer.cs @@ -34,8 +34,13 @@ namespace CSharpBinding.FormattingStrategy /// internal class CSharpFormattingOptionsContainer : INotifyPropertyChanged { + private const string IndentationSizePropertyName = "IndentationSize"; + private const string ConvertTabsToSpacesPropertyName = "ConvertTabsToSpaces"; + CSharpFormattingOptionsContainer parent; CSharpFormattingOptions cachedOptions; + int? indentationSize; + bool? convertTabsToSpaces; readonly HashSet activeOptions; @@ -106,6 +111,8 @@ namespace CSharpBinding.FormattingStrategy foreach (var activeOption in options.activeOptions) activeOptions.Add(activeOption); cachedOptions = options.cachedOptions.Clone(); + indentationSize = options.indentationSize; + convertTabsToSpaces = options.convertTabsToSpaces; OnPropertyChanged(null); } @@ -128,6 +135,14 @@ namespace CSharpBinding.FormattingStrategy // All properties might have changed -> update everything cachedOptions = CreateCachedOptions(); OnPropertyChanged(e.PropertyName); + } else if (e.PropertyName == IndentationSizePropertyName) { + if (!indentationSize.HasValue) { + indentationSize = GetEffectiveIndentationSize(); + } + } else if (e.PropertyName == ConvertTabsToSpacesPropertyName) { + if (!convertTabsToSpaces.HasValue) { + convertTabsToSpaces = GetEffectiveConvertTabsToSpaces(); + } } else { // Some other property has changed, check if we have our own value for it if (!activeOptions.Contains(e.PropertyName)) { @@ -150,10 +165,18 @@ namespace CSharpBinding.FormattingStrategy public object GetOption(string option) { // Run up the hierarchy until we find a defined value for property - if (activeOptions.Contains(option)) { - PropertyInfo propertyInfo = typeof(CSharpFormattingOptions).GetProperty(option); - if (propertyInfo != null) { - return propertyInfo.GetValue(cachedOptions); + if (option == IndentationSizePropertyName) { + if (indentationSize.HasValue) + return indentationSize.Value; + } else if (option == ConvertTabsToSpacesPropertyName) { + if (convertTabsToSpaces.HasValue) + return convertTabsToSpaces.Value; + } else { + if (activeOptions.Contains(option)) { + PropertyInfo propertyInfo = typeof(CSharpFormattingOptions).GetProperty(option); + if (propertyInfo != null) { + return propertyInfo.GetValue(cachedOptions); + } } } @@ -188,6 +211,68 @@ namespace CSharpBinding.FormattingStrategy return null; } + public int? IndentationSize + { + get { + return indentationSize; + } + set { + indentationSize = value; + OnPropertyChanged(IndentationSizePropertyName); + } + } + + /// + /// Retrieves the value of "IndentationSize" option by looking at current and (if nothing set here) parent + /// containers. + /// + public int? GetEffectiveIndentationSize() + { + // Run up the hierarchy until we find a defined value for property + CSharpFormattingOptionsContainer container = this; + do + { + int? val = container.indentationSize; + if (val.HasValue) { + return val.Value; + } + container = container.parent; + } while (container != null); + + return null; + } + + public bool? ConvertTabsToSpaces + { + get { + return convertTabsToSpaces; + } + set { + convertTabsToSpaces = value; + OnPropertyChanged(ConvertTabsToSpacesPropertyName); + } + } + + /// + /// Retrieves the value of v option by looking at current and (if nothing set here) parent + /// containers. + /// + public bool? GetEffectiveConvertTabsToSpaces() + { + // Run up the hierarchy until we find a defined value for property + CSharpFormattingOptionsContainer container = this; + do + { + bool? val = container.convertTabsToSpaces; + if (val.HasValue) { + return val.Value; + } + container = container.parent; + } while (container != null); + + return null; + } + /// /// Sets an option. /// @@ -197,18 +282,32 @@ namespace CSharpBinding.FormattingStrategy { if (value != null) { // Save value in option values and cached options - activeOptions.Add(option); - PropertyInfo propertyInfo = typeof(CSharpFormattingOptions).GetProperty(option); - if ((propertyInfo != null) && (propertyInfo.PropertyType == value.GetType())) { - propertyInfo.SetValue(cachedOptions, value); + if (option == IndentationSizePropertyName) { + if (value is int) + indentationSize = (int) value; + } else if (option == ConvertTabsToSpacesPropertyName) { + if (value is bool) + convertTabsToSpaces = (bool) value; + } else { + activeOptions.Add(option); + PropertyInfo propertyInfo = typeof(CSharpFormattingOptions).GetProperty(option); + if ((propertyInfo != null) && (propertyInfo.PropertyType == value.GetType())) { + propertyInfo.SetValue(cachedOptions, value); + } } } else { // Reset this option - activeOptions.Remove(option); - // Update formatting options object from parents - PropertyInfo propertyInfo = typeof(CSharpFormattingOptions).GetProperty(option); - if (propertyInfo != null) { - propertyInfo.SetValue(cachedOptions, GetEffectiveOption(option)); + if (option == IndentationSizePropertyName) { + indentationSize = null; + } else if (option == ConvertTabsToSpacesPropertyName) { + convertTabsToSpaces = null; + } else { + activeOptions.Remove(option); + // Update formatting options object from parents + PropertyInfo propertyInfo = typeof(CSharpFormattingOptions).GetProperty(option); + if (propertyInfo != null) { + propertyInfo.SetValue(cachedOptions, GetEffectiveOption(option)); + } } } OnPropertyChanged(option); @@ -221,6 +320,11 @@ namespace CSharpBinding.FormattingStrategy /// Option's type. public Type GetOptionType(string option) { + if (option == IndentationSizePropertyName) + return typeof(int); + if (option == ConvertTabsToSpacesPropertyName) + return typeof(bool); + PropertyInfo propertyInfo = typeof(CSharpFormattingOptions).GetProperty(option); if (propertyInfo != null) { return propertyInfo.PropertyType; @@ -275,6 +379,9 @@ namespace CSharpBinding.FormattingStrategy // Silently ignore loading error, then this property will be "as parent" automatically } } + + indentationSize = formatProperties.Get(IndentationSizePropertyName, new int?()); + convertTabsToSpaces = formatProperties.Get(ConvertTabsToSpacesPropertyName, new bool?()); } } @@ -291,8 +398,13 @@ namespace CSharpBinding.FormattingStrategy formatProperties.Set(activeOption, val); } } + if (indentationSize.HasValue) + formatProperties.Set(IndentationSizePropertyName, indentationSize.Value); + if (convertTabsToSpaces.HasValue) + formatProperties.Set(ConvertTabsToSpacesPropertyName, convertTabsToSpaces.Value); parentProperties.SetNestedProperties("CSharpFormatting", formatProperties); } } } + \ No newline at end of file diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingStrategy.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingStrategy.cs index 5c365b2f66..e84c9b0ea1 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingStrategy.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingStrategy.cs @@ -48,7 +48,7 @@ namespace CSharpBinding.FormattingStrategy DocumentAccessor acc = new DocumentAccessor(editor.Document, lineNr, lineNr); CSharpIndentationStrategy indentStrategy = new CSharpIndentationStrategy(); - indentStrategy.IndentationString = editor.Options.IndentationString; + indentStrategy.IndentationString = GetIndentationString(editor); indentStrategy.Indent(acc, false); string t = acc.Text; @@ -62,33 +62,64 @@ namespace CSharpBinding.FormattingStrategy { DocumentAccessor acc = new DocumentAccessor(editor.Document, beginLine, endLine); CSharpIndentationStrategy indentStrategy = new CSharpIndentationStrategy(); - indentStrategy.IndentationString = editor.Options.IndentationString; + indentStrategy.IndentationString = GetIndentationString(editor); indentStrategy.Indent(acc, true); } + CSharpFormattingOptionsContainer GetOptionsContainerForEditor(ITextEditor editor) + { + var currentProject = SD.ProjectService.FindProjectContainingFile(editor.FileName); + if (currentProject != null) { + var persistence = CSharpFormattingOptionsPersistence.GetProjectOptions(currentProject); + if (persistence != null) { + return persistence.OptionsContainer; + } + } + + return null; + } + + string GetIndentationString(ITextEditor editor) + { + // Get current indentation option values + int indentationSize = editor.Options.IndentationSize; + bool convertTabsToSpaces = editor.Options.ConvertTabsToSpaces; + var container = GetOptionsContainerForEditor(editor); + if (container != null) { + int? effectiveIndentationSize = container.GetEffectiveIndentationSize(); + if (effectiveIndentationSize.HasValue) + indentationSize = effectiveIndentationSize.Value; + bool? effectiveConvertTabsToSpaces = container.GetEffectiveConvertTabsToSpaces(); + if (effectiveConvertTabsToSpaces.HasValue) + convertTabsToSpaces = effectiveConvertTabsToSpaces.Value; + } + + return ICSharpCode.AvalonEdit.TextEditorOptions.GetIndentationString(1, indentationSize, convertTabsToSpaces); + } + /* NR indent engine (temporarily?) disabled as per #447 static void IndentSingleLine(CacheIndentEngine engine, IDocument document, IDocumentLine line) { - engine.Update(line.EndOffset); - if (engine.NeedsReindent) { - var indentation = TextUtilities.GetWhitespaceAfter(document, line.Offset); - // replacing the indentation in two steps is necessary to make the caret move accordingly. - document.Replace(indentation.Offset, indentation.Length, ""); - document.Replace(indentation.Offset, 0, engine.ThisLineIndent); - engine.ResetEngineToPosition(line.Offset); - } + engine.Update(line.EndOffset); + if (engine.NeedsReindent) { + var indentation = TextUtilities.GetWhitespaceAfter(document, line.Offset); + // replacing the indentation in two steps is necessary to make the caret move accordingly. + document.Replace(indentation.Offset, indentation.Length, ""); + document.Replace(indentation.Offset, 0, engine.ThisLineIndent); + engine.ResetEngineToPosition(line.Offset); + } } static CacheIndentEngine CreateIndentEngine(IDocument document, TextEditorOptions options) { - IProject currentProject = null; - var projectService = SD.GetService(); - if (projectService != null) { - currentProject = projectService.FindProjectContainingFile(new FileName(document.FileName)); - } - var formattingOptions = CSharpFormattingOptionsPersistence.GetProjectOptions(currentProject); - var engine = new CSharpIndentEngine(document, options, formattingOptions.OptionsContainer.GetEffectiveOptions()); - return new CacheIndentEngine(engine); + IProject currentProject = null; + var projectService = SD.GetService(); + if (projectService != null) { + currentProject = projectService.FindProjectContainingFile(new FileName(document.FileName)); + } + var formattingOptions = CSharpFormattingOptionsPersistence.GetProjectOptions(currentProject); + var engine = new CSharpIndentEngine(document, options, formattingOptions.OptionsContainer.GetEffectiveOptions()); + return new CacheIndentEngine(engine); } */ #endregion diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/FormattingOptionBinding.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/FormattingOptionBinding.cs index 9caa50b055..b36677c142 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/FormattingOptionBinding.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/FormattingOptionBinding.cs @@ -22,6 +22,7 @@ using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; using ICSharpCode.NRefactory.CSharp; +using CSharpBinding.OptionPanels; namespace CSharpBinding.FormattingStrategy { @@ -32,11 +33,8 @@ namespace CSharpBinding.FormattingStrategy { public static readonly DependencyProperty ContainerProperty = DependencyProperty.RegisterAttached("Container", typeof(CSharpFormattingOptionsContainer), - typeof(FormattingOptionBinding), - new FrameworkPropertyMetadata()); - public static readonly DependencyProperty OptionProperty = - DependencyProperty.RegisterAttached("Option", typeof(string), typeof(FormattingOptionBinding), - new FrameworkPropertyMetadata(OnOptionPropertyChanged)); + typeof(FormattingOptionBinding), + new FrameworkPropertyMetadata((o, e) => UpdateOptionBinding(o))); public static CSharpFormattingOptionsContainer GetContainer(Selector element) { @@ -48,21 +46,26 @@ namespace CSharpBinding.FormattingStrategy element.SetValue(ContainerProperty, container); } - public static string GetOption(Selector element) + public static readonly DependencyProperty FormattingOptionProperty = + DependencyProperty.RegisterAttached("FormattingOption", typeof(FormattingOption), + typeof(FormattingOptionBinding), + new FrameworkPropertyMetadata((o, e) => UpdateOptionBinding(o))); + + public static FormattingOption GetFormattingOption(Selector element) { - return (string) element.GetValue(OptionProperty); + return (FormattingOption) element.GetValue(FormattingOptionProperty); } - public static void SetOption(Selector element, string option) + public static void SetFormattingOption(Selector element, FormattingOption container) { - element.SetValue(OptionProperty, option); + element.SetValue(FormattingOptionProperty, container); } - static void OnOptionPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) + static void UpdateOptionBinding(DependencyObject o) { - string option = e.NewValue as string; ComboBox comboBox = o as ComboBox; CSharpFormattingOptionsContainer container = GetContainer(comboBox); + FormattingOption option = GetFormattingOption(comboBox); if ((option != null) && (comboBox != null) && (container != null)) { if (container != null) { if (container.Parent != null) { @@ -72,17 +75,24 @@ namespace CSharpBinding.FormattingStrategy Tag = null }); comboBox.SelectedIndex = 0; + } else if (option.AlwaysAllowDefault) { + // Also add "default" entry, but without changeable text by container + comboBox.Items.Add(new ComboBoxItem { + Content = "(default)", + Tag = null + }); + comboBox.SelectedIndex = 0; } - Type optionType = container.GetOptionType(option); + Type optionType = container.GetOptionType(option.Option); FillComboValues(comboBox, optionType); - UpdateComboBoxValue(container, option, comboBox); + UpdateComboBoxValue(container, option.Option, comboBox); comboBox.SelectionChanged += ComboBox_SelectionChanged; container.PropertyChanged += (sender, eventArgs) => { - if ((eventArgs.PropertyName == null) || (eventArgs.PropertyName == option)) - UpdateComboBoxValue(container, option, comboBox); + if ((eventArgs.PropertyName == null) || (eventArgs.PropertyName == option.Option)) + UpdateComboBoxValue(container, option.Option, comboBox); }; } } @@ -98,13 +108,13 @@ namespace CSharpBinding.FormattingStrategy { ComboBox comboBox = sender as ComboBox; if (comboBox != null) { - string option = GetOption(comboBox); + FormattingOption option = GetFormattingOption(comboBox); CSharpFormattingOptionsContainer container = GetContainer(comboBox); if ((container != null) && (option != null)) { ComboBoxItem selectedItem = comboBox.SelectedItem as ComboBoxItem; if (selectedItem != null) { // Set option to appropriate value - container.SetOption(option, selectedItem.Tag); + container.SetOption(option.Option, selectedItem.Tag); } } } @@ -140,11 +150,10 @@ namespace CSharpBinding.FormattingStrategy static void FillIntComboValues(ComboBox comboBox) { - comboBox.Items.Add(new ComboBoxItem { Content = "0", Tag = 0 }); - comboBox.Items.Add(new ComboBoxItem { Content = "1", Tag = 1 }); - comboBox.Items.Add(new ComboBoxItem { Content = "2", Tag = 2 }); - comboBox.Items.Add(new ComboBoxItem { Content = "3", Tag = 3 }); - comboBox.Items.Add(new ComboBoxItem { Content = "4", Tag = 4 }); + for (int i = 0; i < 11; i++) + { + comboBox.Items.Add(new ComboBoxItem { Content = i.ToString(), Tag = i }); + } } static void FillBraceStyleComboValues(ComboBox comboBox) diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingEditor.xaml b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingEditor.xaml index 259702aa7d..8398ae1e49 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingEditor.xaml +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingEditor.xaml @@ -274,13 +274,13 @@ - + + format:FormattingOptionBinding.FormattingOption="{Binding}" /> + + + + + + + + + + + + + DockPanel.Dock="Top" Margin="0,5,0,0"> diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingEditor.xaml.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingEditor.xaml.cs index cd2c4cdf70..5180a1b404 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingEditor.xaml.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingEditor.xaml.cs @@ -29,21 +29,13 @@ using CSharpBinding.FormattingStrategy; namespace CSharpBinding.OptionPanels { - /// - /// Marker interface for group or option container. - /// It doesn't need to have any members. - /// - internal interface IFormattingItemContainer - { - } - /// /// Represents a container item for other container items in formatting editor list /// [ContentProperty("Children")] - internal class FormattingGroupContainer : DependencyObject, IFormattingItemContainer + internal class FormattingGroupContainer : DependencyObject { - readonly ObservableCollection children = new ObservableCollection(); + readonly ObservableCollection children = new ObservableCollection(); public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(FormattingGroupContainer), @@ -54,7 +46,7 @@ namespace CSharpBinding.OptionPanels set { SetValue(TextProperty, value); } } - public ObservableCollection Children + public ObservableCollection Children { get { return children; @@ -66,7 +58,7 @@ namespace CSharpBinding.OptionPanels /// Represents a container for formatting options. /// [ContentProperty("Children")] - internal class FormattingOptionContainer : DependencyObject, IFormattingItemContainer + internal class FormattingOptionContainer : DependencyObject { readonly ObservableCollection children = new ObservableCollection(); @@ -91,11 +83,26 @@ namespace CSharpBinding.OptionPanels set { SetValue(TextProperty, value); } } +// public static readonly DependencyProperty AlwaysAllowDefaultProperty = +// DependencyProperty.Register("AlwaysAllowDefault", typeof(bool), typeof(FormattingOption), +// new FrameworkPropertyMetadata()); +// +// public bool AlwaysAllowDefault { +// get { return (bool)GetValue(AlwaysAllowDefaultProperty); } +// set { SetValue(AlwaysAllowDefaultProperty, value); } +// } + public string Option { get; set; } + + public bool AlwaysAllowDefault + { + get; + set; + } } /// @@ -197,7 +204,7 @@ namespace CSharpBinding.OptionPanels } } - public ObservableCollection RootChildren + public ObservableCollection RootChildren { get { // rootEntries object is only the root container, its children should be shown directly diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/TextEditorOptions.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/TextEditorOptions.cs index 5b0fa5538e..e771f10e3c 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/TextEditorOptions.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/TextEditorOptions.cs @@ -264,11 +264,19 @@ namespace ICSharpCode.AvalonEdit /// Gets text required to indent from the specified to the next indentation level. /// public virtual string GetIndentationString(int column) + { + return GetIndentationString(column, IndentationSize, ConvertTabsToSpaces); + } + + /// + /// Gets text required to indent from the specified to the next indentation level, + /// considering given and settings. + /// + public static string GetIndentationString(int column, int indentationSize, bool convertTabsToSpaces) { if (column < 1) throw new ArgumentOutOfRangeException("column", column, "Value must be at least 1."); - int indentationSize = this.IndentationSize; - if (ConvertTabsToSpaces) { + if (convertTabsToSpaces) { return new string(' ', indentationSize - ((column - 1) % indentationSize)); } else { return "\t"; From 519d5735c967eb4e909f5b80ce3e7b54d4fe61d6 Mon Sep 17 00:00:00 2001 From: Andreas Weizel Date: Fri, 23 May 2014 01:56:40 +0200 Subject: [PATCH 2/7] Tried implementing automatical updating of editors after changing policy-specific indentation changes + some refactoring. --- .../CSharpBinding/Project/CSharpBinding.addin | 4 +- .../Project/Src/CSharpLanguageBinding.cs | 24 ++++ .../Src/Completion/CSharpCompletionBinding.cs | 2 +- .../Src/Completion/CSharpInsightItem.cs | 2 +- .../Src/Completion/OverrideCompletionData.cs | 2 +- ...OverrideEqualsGetHashCodeCompletionData.cs | 2 +- .../OverrideToStringCompletionData.cs | 2 +- .../Src/Completion/PartialCompletionData.cs | 2 +- .../Src/FormattingStrategy/CSharpFormatter.cs | 7 +- .../CSharpFormattingOptionsContainer.cs | 16 ++- .../CSharpFormattingOptionsPersistence.cs | 112 ++++++++++++------ .../CSharpFormattingStrategy.cs | 6 +- .../FormsDesigner/CSharpDesignerGenerator.cs | 2 +- .../OptionPanels/CSharpFormattingEditor.xaml | 3 +- .../CSharpFormattingEditor.xaml.cs | 9 ++ .../CSharpFormattingOptionPanel.xaml | 2 +- .../CSharpFormattingOptionPanel.xaml.cs | 15 +-- .../CSharpProjectFormattingOptions.xaml.cs | 15 +-- .../Src/Refactoring/InsertCtorDialog.xaml.cs | 2 +- .../MoveTypeToFileContextAction.cs | 2 +- .../Src/Refactoring/SDRefactoringContext.cs | 9 +- 21 files changed, 165 insertions(+), 75 deletions(-) diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin index f2e4adf86b..c9bea23cba 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin @@ -510,7 +510,7 @@ - + diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs index 411279933f..8c6912e98b 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs @@ -70,6 +70,13 @@ namespace CSharpBinding codeManipulation = new CodeManipulation(editor); renderer = new CaretReferenceHighlightRenderer(editor); + // Patch editor options (indentation) to project-specific settings + var optionsContainer = CSharpFormattingPolicies.Instance.GetProjectOptions( + SD.ProjectService.FindProjectContainingFile(editor.FileName)); + CustomizeEditorOptions(optionsContainer.OptionsContainer, editor.Options); + CSharpFormattingPolicies.Instance.FormattingPolicyUpdated += + (sender, e) => CustomizeEditorOptions(optionsContainer.OptionsContainer, this.editor.Options); + if (!editor.ContextActionProviders.IsReadOnly) { contextActionProviders = AddInTree.BuildItems("/SharpDevelop/ViewContent/TextEditor/C#/ContextActions", null); editor.ContextActionProviders.AddRange(contextActionProviders); @@ -89,5 +96,22 @@ namespace CSharpBinding renderer.Dispose(); this.editor = null; } + + private void CustomizeEditorOptions(CSharpFormattingOptionsContainer container, ITextEditorOptions editorOptions) + { + if (container == null) + return; + var textEditorOptions = editorOptions as ICSharpCode.AvalonEdit.TextEditorOptions; + if (textEditorOptions == null) + return; + + int? indentationSize = container.GetEffectiveIndentationSize(); + if (indentationSize.HasValue) { + textEditorOptions.IndentationSize = indentationSize.Value; + } + bool? convertTabsToSpaces = container.GetEffectiveConvertTabsToSpaces(); + if (convertTabsToSpaces.HasValue) + textEditorOptions.ConvertTabsToSpaces = convertTabsToSpaces.Value; + } } } diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionBinding.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionBinding.cs index 3f3323cfbe..c81f2b3349 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionBinding.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpCompletionBinding.cs @@ -99,7 +99,7 @@ namespace CSharpBinding.Completion completionContext.ProjectContent, completionContext.TypeResolveContextAtCaret ); - var formattingOptions = CSharpFormattingOptionsPersistence.GetProjectOptions(completionContext.Compilation.GetProject()); + var formattingOptions = CSharpFormattingPolicies.Instance.GetProjectOptions(completionContext.Compilation.GetProject()); cce.FormattingPolicy = formattingOptions.OptionsContainer.GetEffectiveOptions(); cce.EolMarker = DocumentUtilities.GetLineTerminator(completionContext.Document, currentLocation.Line); diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpInsightItem.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpInsightItem.cs index 939333a453..7d1eb15a51 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpInsightItem.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/CSharpInsightItem.cs @@ -72,7 +72,7 @@ namespace CSharpBinding.Completion ambience.ConversionFlags = ConversionFlags.StandardConversionFlags; var stringBuilder = new StringBuilder(); var formatter = new ParameterHighlightingOutputFormatter(stringBuilder, highlightedParameterIndex); - ambience.ConvertSymbol(Method, formatter, CSharpFormattingOptionsPersistence.GlobalOptions.OptionsContainer.GetEffectiveOptions()); + ambience.ConvertSymbol(Method, formatter, CSharpFormattingPolicies.Instance.GlobalOptions.OptionsContainer.GetEffectiveOptions()); var documentation = XmlDocumentationElement.Get(Method); ambience.ConversionFlags = ConversionFlags.ShowTypeParameterList; diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/OverrideCompletionData.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/OverrideCompletionData.cs index ede72ab53e..f3d5c57eb4 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/OverrideCompletionData.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/OverrideCompletionData.cs @@ -98,7 +98,7 @@ namespace CSharpBinding.Completion var document = context.Editor.Document; StringWriter w = new StringWriter(); - var formattingOptions = CSharpFormattingOptionsPersistence.GetProjectOptions(contextAtCaret.Compilation.GetProject()); + var formattingOptions = CSharpFormattingPolicies.Instance.GetProjectOptions(contextAtCaret.Compilation.GetProject()); var segmentDict = SegmentTrackingOutputFormatter.WriteNode( w, entityDeclaration, formattingOptions.OptionsContainer.GetEffectiveOptions(), context.Editor.Options); diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/OverrideEqualsGetHashCodeCompletionData.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/OverrideEqualsGetHashCodeCompletionData.cs index 7b0ae25f0e..78f1ca6e89 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/OverrideEqualsGetHashCodeCompletionData.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/OverrideEqualsGetHashCodeCompletionData.cs @@ -84,7 +84,7 @@ namespace CSharpBinding.Completion var document = context.Editor.Document; StringWriter w = new StringWriter(); - var formattingOptions = CSharpFormattingOptionsPersistence.GetProjectOptions(contextAtCaret.Compilation.GetProject()); + var formattingOptions = CSharpFormattingPolicies.Instance.GetProjectOptions(contextAtCaret.Compilation.GetProject()); var segmentDict = SegmentTrackingOutputFormatter.WriteNode( w, entityDeclaration, formattingOptions.OptionsContainer.GetEffectiveOptions(), context.Editor.Options); diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/OverrideToStringCompletionData.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/OverrideToStringCompletionData.cs index 0d75f8f133..f0bcd41674 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/OverrideToStringCompletionData.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/OverrideToStringCompletionData.cs @@ -81,7 +81,7 @@ namespace CSharpBinding.Completion var document = context.Editor.Document; StringWriter w = new StringWriter(); - var formattingOptions = CSharpFormattingOptionsPersistence.GetProjectOptions(contextAtCaret.Compilation.GetProject()); + var formattingOptions = CSharpFormattingPolicies.Instance.GetProjectOptions(contextAtCaret.Compilation.GetProject()); var segmentDict = SegmentTrackingOutputFormatter.WriteNode( w, entityDeclaration, formattingOptions.OptionsContainer.GetEffectiveOptions(), context.Editor.Options); diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/PartialCompletionData.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/PartialCompletionData.cs index 7cd6f37a43..d05ff650c0 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/PartialCompletionData.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Completion/PartialCompletionData.cs @@ -64,7 +64,7 @@ namespace CSharpBinding.Completion var document = context.Editor.Document; StringWriter w = new StringWriter(); - var formattingOptions = CSharpFormattingOptionsPersistence.GetProjectOptions(contextAtCaret.Compilation.GetProject()); + var formattingOptions = CSharpFormattingPolicies.Instance.GetProjectOptions(contextAtCaret.Compilation.GetProject()); var segmentDict = SegmentTrackingOutputFormatter.WriteNode( w, entityDeclaration, formattingOptions.OptionsContainer.GetEffectiveOptions(), context.Editor.Options); diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormatter.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormatter.cs index 7d3c9c5d76..65bec18aca 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormatter.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormatter.cs @@ -32,12 +32,7 @@ namespace CSharpBinding.FormattingStrategy public static void Format(ITextEditor editor, int offset, int length, CSharpFormattingOptionsContainer optionsContainer) { TextEditorOptions editorOptions = editor.ToEditorOptions(); - int? indentationSize = optionsContainer.GetEffectiveIndentationSize(); - if (indentationSize.HasValue) - editorOptions.IndentSize = indentationSize.Value; - bool? convertTabsToSpaces = optionsContainer.GetEffectiveConvertTabsToSpaces(); - if (convertTabsToSpaces.HasValue) - editorOptions.TabsToSpaces = convertTabsToSpaces.Value; + optionsContainer.CustomizeEditorOptions(editorOptions); var formatter = new CSharpFormatter(optionsContainer.GetEffectiveOptions(), editorOptions); formatter.AddFormattingRegion(new DomRegion(editor.Document.GetLocation(offset), editor.Document.GetLocation(offset + length))); var changes = formatter.AnalyzeFormatting(editor.Document, SyntaxTree.Parse(editor.Document)); diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingOptionsContainer.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingOptionsContainer.cs index e2f94692e4..be31b21acd 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingOptionsContainer.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingOptionsContainer.cs @@ -324,7 +324,7 @@ namespace CSharpBinding.FormattingStrategy return typeof(int); if (option == ConvertTabsToSpacesPropertyName) return typeof(bool); - + PropertyInfo propertyInfo = typeof(CSharpFormattingOptions).GetProperty(option); if (propertyInfo != null) { return propertyInfo.PropertyType; @@ -364,6 +364,19 @@ namespace CSharpBinding.FormattingStrategy return outputOptions; } + public void CustomizeEditorOptions(TextEditorOptions editorOptions) + { + int? indentationSize = GetEffectiveIndentationSize(); + if (indentationSize.HasValue) { + editorOptions.IndentSize = indentationSize.Value; + editorOptions.TabSize = indentationSize.Value; + editorOptions.ContinuationIndent = indentationSize.Value; + } + bool? convertTabsToSpaces = GetEffectiveConvertTabsToSpaces(); + if (convertTabsToSpaces.HasValue) + editorOptions.TabsToSpaces = convertTabsToSpaces.Value; + } + public void Load(Properties parentProperties) { if (parentProperties == null) @@ -407,4 +420,3 @@ namespace CSharpBinding.FormattingStrategy } } } - \ No newline at end of file diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingOptionsPersistence.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingOptionsPersistence.cs index df5b11e2aa..cd380eea9a 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingOptionsPersistence.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingOptionsPersistence.cs @@ -18,6 +18,7 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using ICSharpCode.Core; using ICSharpCode.NRefactory.CSharp; using ICSharpCode.SharpDevelop; @@ -25,42 +26,41 @@ using ICSharpCode.SharpDevelop.Project; namespace CSharpBinding.FormattingStrategy { - public class CSharpFormattingOptionsPersistenceInitCommand : SimpleCommand + public class CSharpFormattingOptionsPoliciesInitCommand : SimpleCommand { public override void Execute(object parameter) { // Initialize CSharpFormattingOptionsPersistence as early as possible (before solution is opened) - CSharpFormattingOptionsPersistence.Initialize(); + CSharpFormattingPolicies.Instance.Initialize(); } } /// - /// Persistence helper for C# formatting options. + /// Management class for formatting policies. /// - internal class CSharpFormattingOptionsPersistence + internal class CSharpFormattingPolicies { - static bool initialized; - static Dictionary projectOptions; + public static readonly CSharpFormattingPolicies Instance = new CSharpFormattingPolicies(); - static CSharpFormattingOptionsPersistence() - { - Initialize(); - } + public event EventHandler FormattingPolicyUpdated; + + static bool initialized; + static Dictionary projectOptions; - public static void Initialize() + public void Initialize() { if (initialized) return; initialized = true; - projectOptions = new Dictionary(); + projectOptions = new Dictionary(); // Load global settings - GlobalOptions = new CSharpFormattingOptionsPersistence( - SD.PropertyService.MainPropertiesContainer, new CSharpFormattingOptionsContainer() - { + GlobalOptions = new CSharpFormattingPolicy( + SD.PropertyService.MainPropertiesContainer, new CSharpFormattingOptionsContainer() { DefaultText = StringParser.Parse("${res:CSharpBinding.Formatting.GlobalOptionReference}") }); + GlobalOptions.FormattingPolicyUpdated += OnFormattingPolicyUpdated; GlobalOptions.Load(); // Handlers for solution loading/unloading @@ -71,8 +71,7 @@ namespace CSharpBinding.FormattingStrategy } } - public static bool AutoFormatting - { + public static bool AutoFormatting { get { return SD.PropertyService.Get("CSharpBinding.Formatting.AutoFormatting", false); } @@ -81,31 +80,32 @@ namespace CSharpBinding.FormattingStrategy } } - public static CSharpFormattingOptionsPersistence GlobalOptions - { + public CSharpFormattingPolicy GlobalOptions { get; private set; } - public static CSharpFormattingOptionsPersistence SolutionOptions - { + public CSharpFormattingPolicy SolutionOptions { get; private set; } - public static CSharpFormattingOptionsPersistence GetProjectOptions(IProject project) + public CSharpFormattingPolicy GetProjectOptions(IProject project) { + if (projectOptions == null) + return null; + var csproject = project as CSharpProject; if (csproject != null) { string key = project.FileName; if (!projectOptions.ContainsKey(key)) { // Lazily create options container for project - var projectFormattingPersistence = new CSharpFormattingOptionsPersistence( + var projectFormattingPersistence = new CSharpFormattingPolicy( csproject.GlobalPreferences, - new CSharpFormattingOptionsContainer((SolutionOptions ?? GlobalOptions).OptionsContainer) - { + new CSharpFormattingOptionsContainer((SolutionOptions ?? GlobalOptions).OptionsContainer) { DefaultText = StringParser.Parse("${res:CSharpBinding.Formatting.ProjectOptionReference}") }); + projectFormattingPersistence.FormattingPolicyUpdated += OnFormattingPolicyUpdated; projectFormattingPersistence.Load(); projectOptions[key] = projectFormattingPersistence; } @@ -116,34 +116,70 @@ namespace CSharpBinding.FormattingStrategy return SolutionOptions ?? GlobalOptions; } - static void SolutionOpened(object sender, SolutionEventArgs e) + void SolutionOpened(object sender, SolutionEventArgs e) { // Load solution settings - SolutionOptions = new CSharpFormattingOptionsPersistence( + SolutionOptions = new CSharpFormattingPolicy( e.Solution.SDSettings, - new CSharpFormattingOptionsContainer(GlobalOptions.OptionsContainer) - { + new CSharpFormattingOptionsContainer(GlobalOptions.OptionsContainer) { DefaultText = StringParser.Parse("${res:CSharpBinding.Formatting.SolutionOptionReference}") }); + SolutionOptions.FormattingPolicyUpdated += OnFormattingPolicyUpdated; SolutionOptions.Load(); } - static void SolutionClosed(object sender, SolutionEventArgs e) + void SolutionClosed(object sender, SolutionEventArgs e) { + SolutionOptions.FormattingPolicyUpdated -= OnFormattingPolicyUpdated; SolutionOptions = null; projectOptions.Clear(); } + void OnFormattingPolicyUpdated(object sender, CSharpFormattingPolicyUpdateEventArgs e) + { + if (FormattingPolicyUpdated != null) { + FormattingPolicyUpdated(sender, e); + } + } + } + + /// + /// Contains event data for formatting policy update events. + /// + internal class CSharpFormattingPolicyUpdateEventArgs : EventArgs + { + public CSharpFormattingPolicyUpdateEventArgs(CSharpFormattingOptionsContainer container) + { + OptionsContainer = container; + } + + /// + /// Returns updated options container. + /// + public CSharpFormattingOptionsContainer OptionsContainer + { + get; + private set; + } + } + + /// + /// Persistence helper for C# formatting options of a certain policy (e.g. global, solution, project). + /// + internal class CSharpFormattingPolicy + { + public event EventHandler FormattingPolicyUpdated; + readonly Properties propertiesContainer; - CSharpFormattingOptionsContainer optionsContainer; + readonly CSharpFormattingOptionsContainer optionsContainer; CSharpFormattingOptionsContainer optionsContainerWorkingCopy; /// - /// Creates a new instance of formatting options persistence helper, using given options to predefine the options container. + /// Creates a new instance of formatting options policy, using given options to predefine the options container. /// /// Properties container to load from and save to. /// Initial (empty) instance of formatting options container. - public CSharpFormattingOptionsPersistence(Properties propertiesContainer, CSharpFormattingOptionsContainer initialContainer) + public CSharpFormattingPolicy(Properties propertiesContainer, CSharpFormattingOptionsContainer initialContainer) { if (initialContainer == null) throw new ArgumentNullException("initialContainer"); @@ -153,7 +189,7 @@ namespace CSharpBinding.FormattingStrategy } /// - /// Returns the option container managed by this helper. + /// Returns the option container for this policy. /// public CSharpFormattingOptionsContainer OptionsContainer { @@ -196,7 +232,15 @@ namespace CSharpBinding.FormattingStrategy // Convert to SD properties optionsContainer.Save(propertiesContainer); + OnFormattingPolicyUpdated(this, optionsContainer); return true; } + + void OnFormattingPolicyUpdated(object sender, CSharpFormattingOptionsContainer container) + { + if (FormattingPolicyUpdated != null) { + FormattingPolicyUpdated(sender, new CSharpFormattingPolicyUpdateEventArgs(container)); + } + } } } diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingStrategy.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingStrategy.cs index e84c9b0ea1..2ab802e950 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingStrategy.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingStrategy.cs @@ -70,7 +70,7 @@ namespace CSharpBinding.FormattingStrategy { var currentProject = SD.ProjectService.FindProjectContainingFile(editor.FileName); if (currentProject != null) { - var persistence = CSharpFormattingOptionsPersistence.GetProjectOptions(currentProject); + var persistence = CSharpFormattingPolicies.Instance.GetProjectOptions(currentProject); if (persistence != null) { return persistence.OptionsContainer; } @@ -333,11 +333,11 @@ namespace CSharpBinding.FormattingStrategy { if ((offset > textArea.Document.TextLength) || ((offset + length) > textArea.Document.TextLength)) return false; - if (respectAutoFormattingSetting && !CSharpFormattingOptionsPersistence.AutoFormatting) + if (respectAutoFormattingSetting && !CSharpFormattingPolicies.AutoFormatting) return false; using (textArea.Document.OpenUndoGroup()) { - var formattingOptions = CSharpFormattingOptionsPersistence.GetProjectOptions(SD.ProjectService.CurrentProject); + var formattingOptions = CSharpFormattingPolicies.Instance.GetProjectOptions(SD.ProjectService.CurrentProject); try { CSharpFormatterHelper.Format(textArea, offset, length, formattingOptions.OptionsContainer); } catch (Exception) { diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormsDesigner/CSharpDesignerGenerator.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormsDesigner/CSharpDesignerGenerator.cs index 2fd3560e6f..cc769eb9ee 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormsDesigner/CSharpDesignerGenerator.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormsDesigner/CSharpDesignerGenerator.cs @@ -155,7 +155,7 @@ namespace CSharpBinding.FormsDesigner IDocument document = context.GetDocument(fileNameObj); var ctx = SDRefactoringContext.Create(fileNameObj, document); - var formattingOptions = CSharpFormattingOptionsPersistence.GetProjectOptions(compilation.GetProject()); + var formattingOptions = CSharpFormattingPolicies.Instance.GetProjectOptions(compilation.GetProject()); script = new DocumentScript(document, formattingOptions.OptionsContainer.GetEffectiveOptions(), new TextEditorOptions()); scripts.Add(fileNameObj, script); return script; diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingEditor.xaml b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingEditor.xaml index 8398ae1e49..fa5b5e54e0 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingEditor.xaml +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingEditor.xaml @@ -297,7 +297,8 @@ - + diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingEditor.xaml.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingEditor.xaml.cs index 5180a1b404..b1a6bba1ac 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingEditor.xaml.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingEditor.xaml.cs @@ -140,6 +140,15 @@ namespace CSharpBinding.OptionPanels set { SetValue(AllowPresetsProperty, value); } } + public static readonly DependencyProperty OverrideGlobalIndentationProperty = + DependencyProperty.Register("OverrideGlobalIndentation", typeof(bool), typeof(CSharpFormattingEditor), + new FrameworkPropertyMetadata()); + + public bool OverrideGlobalIndentation { + get { return (bool)GetValue(OverrideGlobalIndentationProperty); } + set { SetValue(OverrideGlobalIndentationProperty, value); } + } + static void OnOptionsContainerPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) { var editor = o as CSharpFormattingEditor; diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingOptionPanel.xaml b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingOptionPanel.xaml index 4620821994..05e73ee15e 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingOptionPanel.xaml +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingOptionPanel.xaml @@ -19,7 +19,7 @@ diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingOptionPanel.xaml.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingOptionPanel.xaml.cs index 56df385daa..346b2c02b1 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingOptionPanel.xaml.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingOptionPanel.xaml.cs @@ -40,7 +40,7 @@ namespace CSharpBinding.OptionPanels internal class CSharpGlobalFormattingOptionPanel : CSharpFormattingOptionPanel { public CSharpGlobalFormattingOptionPanel() - : base(CSharpFormattingOptionsPersistence.GlobalOptions, true) + : base(CSharpFormattingPolicies.Instance.GlobalOptions, true, false) { autoFormattingCheckBox.Visibility = Visibility.Visible; } @@ -52,7 +52,7 @@ namespace CSharpBinding.OptionPanels internal class CSharpSolutionFormattingOptionPanel : CSharpFormattingOptionPanel { public CSharpSolutionFormattingOptionPanel() - : base(CSharpFormattingOptionsPersistence.SolutionOptions, true) + : base(CSharpFormattingPolicies.Instance.SolutionOptions, true, true) { autoFormattingCheckBox.Visibility = Visibility.Collapsed; } @@ -63,28 +63,29 @@ namespace CSharpBinding.OptionPanels /// internal partial class CSharpFormattingOptionPanel : OptionPanel { - readonly CSharpFormattingOptionsPersistence persistenceHelper; + readonly CSharpFormattingPolicy formattingPolicy; - public CSharpFormattingOptionPanel(CSharpFormattingOptionsPersistence persistenceHelper, bool allowPresets) + public CSharpFormattingOptionPanel(CSharpFormattingPolicy persistenceHelper, bool allowPresets, bool overrideGlobalIndentation) { if (persistenceHelper == null) throw new ArgumentNullException("persistenceHelper"); - this.persistenceHelper = persistenceHelper; + this.formattingPolicy = persistenceHelper; InitializeComponent(); formattingEditor.AllowPresets = allowPresets; + formattingEditor.OverrideGlobalIndentation = overrideGlobalIndentation; } public override void LoadOptions() { base.LoadOptions(); - formattingEditor.OptionsContainer = persistenceHelper.StartEditing(); + formattingEditor.OptionsContainer = formattingPolicy.StartEditing(); } public override bool SaveOptions() { - return persistenceHelper.Save() && base.SaveOptions(); + return formattingPolicy.Save() && base.SaveOptions(); } } } \ No newline at end of file diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpProjectFormattingOptions.xaml.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpProjectFormattingOptions.xaml.cs index d3ca858d81..e12bdeaa8d 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpProjectFormattingOptions.xaml.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpProjectFormattingOptions.xaml.cs @@ -35,7 +35,7 @@ namespace CSharpBinding.OptionPanels /// internal partial class CSharpProjectFormattingOptionPanel : ProjectOptionPanel { - CSharpFormattingOptionsPersistence persistenceHelper; + CSharpFormattingPolicy formattingPolicy; public CSharpProjectFormattingOptionPanel() { @@ -45,18 +45,19 @@ namespace CSharpBinding.OptionPanels protected override void Load(ICSharpCode.SharpDevelop.Project.MSBuildBasedProject project, string configuration, string platform) { base.Load(project, configuration, platform); - if (persistenceHelper != null) { - persistenceHelper.OptionsContainer.PropertyChanged -= ContainerPropertyChanged; + if (formattingPolicy != null) { + formattingPolicy.OptionsContainer.PropertyChanged -= ContainerPropertyChanged; } - persistenceHelper = CSharpFormattingOptionsPersistence.GetProjectOptions(project); - formattingEditor.OptionsContainer = persistenceHelper.OptionsContainer; + formattingPolicy = CSharpFormattingPolicies.Instance.GetProjectOptions(project); + formattingEditor.OptionsContainer = formattingPolicy.OptionsContainer; formattingEditor.AllowPresets = true; - persistenceHelper.OptionsContainer.PropertyChanged += ContainerPropertyChanged; + formattingEditor.OverrideGlobalIndentation = true; + formattingPolicy.OptionsContainer.PropertyChanged += ContainerPropertyChanged; } protected override bool Save(ICSharpCode.SharpDevelop.Project.MSBuildBasedProject project, string configuration, string platform) { - bool success = (persistenceHelper != null) && persistenceHelper.Save(); + bool success = (formattingPolicy != null) && formattingPolicy.Save(); return base.Save(project, configuration, platform) && success; } diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/InsertCtorDialog.xaml.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/InsertCtorDialog.xaml.cs index 2ff47fa0b7..973dbd97c7 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/InsertCtorDialog.xaml.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/InsertCtorDialog.xaml.cs @@ -171,7 +171,7 @@ namespace CSharpBinding.Refactoring using (StringWriter textWriter = new StringWriter(pList)) { // Output parameter list as string - var formattingOptions = CSharpFormattingOptionsPersistence.GetProjectOptions(refactoringContext.Compilation.GetProject()); + var formattingOptions = CSharpFormattingPolicies.Instance.GetProjectOptions(refactoringContext.Compilation.GetProject()); CSharpOutputVisitor outputVisitor = new CSharpOutputVisitor(textWriter, formattingOptions.OptionsContainer.GetEffectiveOptions()); for (int i = 0; i < parameters.Count; i++) { if (i > 0) diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/MoveTypeToFileContextAction.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/MoveTypeToFileContextAction.cs index 6e42276226..014ea3a7cc 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/MoveTypeToFileContextAction.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/MoveTypeToFileContextAction.cs @@ -109,7 +109,7 @@ namespace CSharpBinding.Refactoring || ch is UsingAliasDeclaration || ch is ExternAliasDeclaration); StringBuilder newCode = new StringBuilder(header); - var formattingOptions = CSharpFormattingOptionsPersistence.GetProjectOptions(compilation.GetProject()); + var formattingOptions = CSharpFormattingPolicies.Instance.GetProjectOptions(compilation.GetProject()); CSharpOutputVisitor visitor = new CSharpOutputVisitor(new StringWriter(newCode), formattingOptions.OptionsContainer.GetEffectiveOptions()); foreach (var topLevelUsing in topLevelUsings) diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SDRefactoringContext.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SDRefactoringContext.cs index 134f7fc14a..1fa3af1f23 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SDRefactoringContext.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SDRefactoringContext.cs @@ -119,13 +119,16 @@ namespace CSharpBinding.Refactoring public Script StartScript() { - var formattingOptions = CSharpFormattingOptionsPersistence.GetProjectOptions(resolver.Compilation.GetProject()); + var formattingOptions = CSharpFormattingPolicies.Instance.GetProjectOptions(resolver.Compilation.GetProject()); if (editor != null) return new EditorScript(editor, this, formattingOptions.OptionsContainer.GetEffectiveOptions()); else if (document == null || document is ReadOnlyDocument) throw new InvalidOperationException("Cannot start a script in a read-only context"); - else - return new DocumentScript(document, formattingOptions.OptionsContainer.GetEffectiveOptions(), this.TextEditorOptions); + else { + var textEditorOptions = this.TextEditorOptions; + formattingOptions.OptionsContainer.CustomizeEditorOptions(textEditorOptions); + return new DocumentScript(document, formattingOptions.OptionsContainer.GetEffectiveOptions(), textEditorOptions); + } } public IDocument Document { From 0c1a36503fbd967f94d3c1f1325afe94fa786712 Mon Sep 17 00:00:00 2001 From: Andreas Weizel Date: Sat, 24 May 2014 02:13:52 +0200 Subject: [PATCH 3/7] Fixed CSharpBinding tests. --- .../Project/CSharpBinding.csproj | 2 +- .../Project/Src/CSharpLanguageBinding.cs | 15 ++++---- ...istence.cs => CSharpFormattingPolicies.cs} | 34 ++++++++++++------- 3 files changed, 30 insertions(+), 21 deletions(-) rename src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/{CSharpFormattingOptionsPersistence.cs => CSharpFormattingPolicies.cs} (93%) diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj index 2762300961..dbbd1b7739 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj @@ -93,7 +93,7 @@ - + diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs index 8c6912e98b..5c53535de9 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs @@ -73,9 +73,9 @@ namespace CSharpBinding // Patch editor options (indentation) to project-specific settings var optionsContainer = CSharpFormattingPolicies.Instance.GetProjectOptions( SD.ProjectService.FindProjectContainingFile(editor.FileName)); - CustomizeEditorOptions(optionsContainer.OptionsContainer, editor.Options); + CustomizeEditorOptions(optionsContainer.OptionsContainer, editor.Options, this.editor); CSharpFormattingPolicies.Instance.FormattingPolicyUpdated += - (sender, e) => CustomizeEditorOptions(optionsContainer.OptionsContainer, this.editor.Options); + (sender, e) => CustomizeEditorOptions(optionsContainer.OptionsContainer, this.editor.Options, this.editor); if (!editor.ContextActionProviders.IsReadOnly) { contextActionProviders = AddInTree.BuildItems("/SharpDevelop/ViewContent/TextEditor/C#/ContextActions", null); @@ -97,7 +97,7 @@ namespace CSharpBinding this.editor = null; } - private void CustomizeEditorOptions(CSharpFormattingOptionsContainer container, ITextEditorOptions editorOptions) + private void CustomizeEditorOptions(CSharpFormattingOptionsContainer container, ITextEditorOptions editorOptions, ITextEditor editor) { if (container == null) return; @@ -107,11 +107,12 @@ namespace CSharpBinding int? indentationSize = container.GetEffectiveIndentationSize(); if (indentationSize.HasValue) { - textEditorOptions.IndentationSize = indentationSize.Value; +// textEditorOptions.IndentationSize = indentationSize.Value; } - bool? convertTabsToSpaces = container.GetEffectiveConvertTabsToSpaces(); - if (convertTabsToSpaces.HasValue) - textEditorOptions.ConvertTabsToSpaces = convertTabsToSpaces.Value; +// bool? convertTabsToSpaces = container.GetEffectiveConvertTabsToSpaces(); +// if (convertTabsToSpaces.HasValue) { +// textEditorOptions.ConvertTabsToSpaces = convertTabsToSpaces.Value; +// } } } } diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingOptionsPersistence.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingPolicies.cs similarity index 93% rename from src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingOptionsPersistence.cs rename to src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingPolicies.cs index cd380eea9a..5999f1dd1f 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingOptionsPersistence.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/FormattingStrategy/CSharpFormattingPolicies.cs @@ -30,7 +30,7 @@ namespace CSharpBinding.FormattingStrategy { public override void Execute(object parameter) { - // Initialize CSharpFormattingOptionsPersistence as early as possible (before solution is opened) + // Initialize CSharpFormattingPolicies as early as possible (before solution is opened) CSharpFormattingPolicies.Instance.Initialize(); } } @@ -40,21 +40,20 @@ namespace CSharpBinding.FormattingStrategy /// internal class CSharpFormattingPolicies { - public static readonly CSharpFormattingPolicies Instance = new CSharpFormattingPolicies(); + static readonly Lazy LazyInstance = + new Lazy(() => new CSharpFormattingPolicies()); + + public static CSharpFormattingPolicies Instance { + get { return LazyInstance.Value; } + } public event EventHandler FormattingPolicyUpdated; - static bool initialized; - static Dictionary projectOptions; + bool initialized; + Dictionary projectOptions; - public void Initialize() + public CSharpFormattingPolicies() { - if (initialized) - return; - - initialized = true; - projectOptions = new Dictionary(); - // Load global settings GlobalOptions = new CSharpFormattingPolicy( SD.PropertyService.MainPropertiesContainer, new CSharpFormattingOptionsContainer() { @@ -62,6 +61,15 @@ namespace CSharpBinding.FormattingStrategy }); GlobalOptions.FormattingPolicyUpdated += OnFormattingPolicyUpdated; GlobalOptions.Load(); + } + + public void Initialize() + { + if (initialized) + return; + + initialized = true; + projectOptions = new Dictionary(); // Handlers for solution loading/unloading var projectService = SD.GetService(); @@ -92,8 +100,8 @@ namespace CSharpBinding.FormattingStrategy public CSharpFormattingPolicy GetProjectOptions(IProject project) { - if (projectOptions == null) - return null; + if (!initialized) + return GlobalOptions; var csproject = project as CSharpProject; if (csproject != null) { From c365dc4c6c62b2bbdafdd3a12d73008a91a7694c Mon Sep 17 00:00:00 2001 From: Andreas Weizel Date: Fri, 6 Jun 2014 01:18:22 +0200 Subject: [PATCH 4/7] Redesigned replacement of editor options by language binding, now all C# code editors are updated, when changing IndentationSize or ConvertTabsToSpaces options in any policy. --- .../Project/Src/CSharpLanguageBinding.cs | 270 ++++++++++++++++-- .../OptionPanels/CSharpFormattingEditor.xaml | 2 +- .../AvalonEdit.AddIn/Src/CodeEditorAdapter.cs | 12 + 3 files changed, 264 insertions(+), 20 deletions(-) diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs index 5c53535de9..f34f52145c 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs @@ -19,7 +19,9 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Threading; +using ICSharpCode.AvalonEdit; using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.NRefactory; using ICSharpCode.NRefactory.TypeSystem; @@ -62,6 +64,7 @@ namespace CSharpBinding IList contextActionProviders; CodeManipulation codeManipulation; CaretReferenceHighlightRenderer renderer; + CodeEditorFormattingOptionsAdapter options; public void Attach(ITextEditor editor) { @@ -71,20 +74,44 @@ namespace CSharpBinding renderer = new CaretReferenceHighlightRenderer(editor); // Patch editor options (indentation) to project-specific settings - var optionsContainer = CSharpFormattingPolicies.Instance.GetProjectOptions( - SD.ProjectService.FindProjectContainingFile(editor.FileName)); - CustomizeEditorOptions(optionsContainer.OptionsContainer, editor.Options, this.editor); - CSharpFormattingPolicies.Instance.FormattingPolicyUpdated += - (sender, e) => CustomizeEditorOptions(optionsContainer.OptionsContainer, this.editor.Options, this.editor); - if (!editor.ContextActionProviders.IsReadOnly) { contextActionProviders = AddInTree.BuildItems("/SharpDevelop/ViewContent/TextEditor/C#/ContextActions", null); editor.ContextActionProviders.AddRange(contextActionProviders); } + + // Create instance of options adapter and register it as service + var formattingPolicy = CSharpFormattingPolicies.Instance.GetProjectOptions( + SD.ProjectService.FindProjectContainingFile(editor.FileName)); + options = new CodeEditorFormattingOptionsAdapter(editor.Options, formattingPolicy.OptionsContainer); + var textEditor = editor.GetService(); + if (textEditor != null) { + var textViewServices = textEditor.TextArea.TextView.Services; + + // Unregister any previous ITextEditorOptions instance from editor, if existing, register our impl. + textViewServices.RemoveService(typeof(ITextEditorOptions)); + textViewServices.AddService(typeof(ITextEditorOptions), options); + + // Set TextEditor's options to same object + textEditor.Options = options; + } } public void Detach() { + var textEditor = editor.GetService(); + if (textEditor != null) { + var textView = textEditor.TextArea.TextView; + + // Unregister our ITextEditorOptions instance from editor + var optionsService = textView.GetService(); + if ((optionsService != null) && (optionsService == options)) + textView.Services.RemoveService(typeof(ITextEditorOptions)); + + // TODO Reset TextEditor options, too? + // if ((textEditor.Options != null) && (textEditor.Options == options)) + // textEditor.Options = SD.EditorControlService.GlobalOptions; + } + codeManipulation.Dispose(); if (inspectionManager != null) { inspectionManager.Dispose(); @@ -94,25 +121,230 @@ namespace CSharpBinding editor.ContextActionProviders.RemoveAll(contextActionProviders.Contains); } renderer.Dispose(); + options = null; this.editor = null; } + } + + class CodeEditorFormattingOptionsAdapter : TextEditorOptions, ITextEditorOptions, ICodeEditorOptions + { + CSharpFormattingOptionsContainer container; + readonly ITextEditorOptions globalOptions; + readonly ICodeEditorOptions globalCodeEditorOptions; - private void CustomizeEditorOptions(CSharpFormattingOptionsContainer container, ITextEditorOptions editorOptions, ITextEditor editor) + public CodeEditorFormattingOptionsAdapter(ITextEditorOptions globalOptions, CSharpFormattingOptionsContainer container) { + if (globalOptions == null) + throw new ArgumentNullException("globalOptions"); if (container == null) - return; - var textEditorOptions = editorOptions as ICSharpCode.AvalonEdit.TextEditorOptions; - if (textEditorOptions == null) - return; + throw new ArgumentNullException("container"); + + this.globalOptions = globalOptions; + this.globalCodeEditorOptions = globalOptions as ICodeEditorOptions; + this.container = container; - int? indentationSize = container.GetEffectiveIndentationSize(); - if (indentationSize.HasValue) { -// textEditorOptions.IndentationSize = indentationSize.Value; - } -// bool? convertTabsToSpaces = container.GetEffectiveConvertTabsToSpaces(); -// if (convertTabsToSpaces.HasValue) { -// textEditorOptions.ConvertTabsToSpaces = convertTabsToSpaces.Value; -// } + CSharpFormattingPolicies.Instance.FormattingPolicyUpdated += OnFormattingPolicyUpdated; + globalOptions.PropertyChanged += OnGlobalOptionsPropertyChanged; + } + + void OnFormattingPolicyUpdated(object sender, CSharpBinding.FormattingStrategy.CSharpFormattingPolicyUpdateEventArgs e) + { + OnPropertyChanged("IndentationSize"); + OnPropertyChanged("ConvertTabsToSpaces"); + } + + void OnGlobalOptionsPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) + { + OnPropertyChanged(e.PropertyName); + } + + #region ITextEditorOptions implementation + + public override int IndentationSize { + get { + return container.GetEffectiveIndentationSize() ?? globalOptions.IndentationSize; + } + } + + public override bool ConvertTabsToSpaces { + get { + return container.GetEffectiveConvertTabsToSpaces() ?? globalOptions.ConvertTabsToSpaces; + } + } + + public bool AutoInsertBlockEnd { + get { + return globalOptions.AutoInsertBlockEnd; + } + } + + public int VerticalRulerColumn { + get { + return globalOptions.VerticalRulerColumn; + } + } + + public bool UnderlineErrors { + get { + return globalOptions.UnderlineErrors; + } + } + + public string FontFamily { + get { + return globalOptions.FontFamily; + } + } + + public double FontSize { + get { + return globalOptions.FontSize; + } + } + + #endregion + + public override bool AllowScrollBelowDocument { + get { + return (globalCodeEditorOptions != null) ? globalCodeEditorOptions.AllowScrollBelowDocument : default(bool); + } + set { + if (globalCodeEditorOptions != null) { + globalCodeEditorOptions.AllowScrollBelowDocument = value; + } + } + } + + public bool ShowLineNumbers { + get { + return (globalCodeEditorOptions != null) ? globalCodeEditorOptions.ShowLineNumbers : default(bool); + } + set { + if (globalCodeEditorOptions != null) { + globalCodeEditorOptions.ShowLineNumbers = value; + } + } + } + + public bool EnableChangeMarkerMargin { + get { + return (globalCodeEditorOptions != null) ? globalCodeEditorOptions.EnableChangeMarkerMargin : default(bool); + } + set { + if (globalCodeEditorOptions != null) { + globalCodeEditorOptions.EnableChangeMarkerMargin = value; + } + } + } + + public bool WordWrap { + get { + return (globalCodeEditorOptions != null) ? globalCodeEditorOptions.WordWrap : default(bool); + } + set { + if (globalCodeEditorOptions != null) { + globalCodeEditorOptions.WordWrap = value; + } + } + } + + public bool CtrlClickGoToDefinition { + get { + return (globalCodeEditorOptions != null) ? globalCodeEditorOptions.CtrlClickGoToDefinition : default(bool); + } + set { + if (globalCodeEditorOptions != null) { + globalCodeEditorOptions.CtrlClickGoToDefinition = value; + } + } + } + + public bool MouseWheelZoom { + get { + return (globalCodeEditorOptions != null) ? globalCodeEditorOptions.MouseWheelZoom : default(bool); + } + set { + if (globalCodeEditorOptions != null) { + globalCodeEditorOptions.MouseWheelZoom = value; + } + } + } + + public bool HighlightBrackets { + get { + return (globalCodeEditorOptions != null) ? globalCodeEditorOptions.HighlightBrackets : default(bool); + } + set { + if (globalCodeEditorOptions != null) { + globalCodeEditorOptions.HighlightBrackets = value; + } + } + } + + public bool HighlightSymbol { + get { + return (globalCodeEditorOptions != null) ? globalCodeEditorOptions.HighlightSymbol : default(bool); + } + set { + if (globalCodeEditorOptions != null) { + globalCodeEditorOptions.HighlightSymbol = value; + } + } + } + + public bool EnableAnimations { + get { + return (globalCodeEditorOptions != null) ? globalCodeEditorOptions.EnableAnimations : default(bool); + } + set { + if (globalCodeEditorOptions != null) { + globalCodeEditorOptions.EnableAnimations = value; + } + } + } + + public bool UseSmartIndentation { + get { + return (globalCodeEditorOptions != null) ? globalCodeEditorOptions.UseSmartIndentation : default(bool); + } + set { + if (globalCodeEditorOptions != null) { + globalCodeEditorOptions.UseSmartIndentation = value; + } + } + } + + public bool EnableFolding { + get { + return (globalCodeEditorOptions != null) ? globalCodeEditorOptions.EnableFolding : default(bool); + } + set { + if (globalCodeEditorOptions != null) { + globalCodeEditorOptions.EnableFolding = value; + } + } + } + + public bool EnableQuickClassBrowser { + get { + return (globalCodeEditorOptions != null) ? globalCodeEditorOptions.EnableQuickClassBrowser : default(bool); + } + set { + if (globalCodeEditorOptions != null) { + globalCodeEditorOptions.EnableQuickClassBrowser = value; + } + } + } + + public bool ShowHiddenDefinitions { + get { + return (globalCodeEditorOptions != null) ? globalCodeEditorOptions.ShowHiddenDefinitions : default(bool); + } + set { + if (globalCodeEditorOptions != null) { + globalCodeEditorOptions.ShowHiddenDefinitions = value; + } + } } } } diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingEditor.xaml b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingEditor.xaml index fa5b5e54e0..4db4b5233e 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingEditor.xaml +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/OptionPanels/CSharpFormattingEditor.xaml @@ -300,7 +300,7 @@ - + diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorAdapter.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorAdapter.cs index 0873442d6d..df87075e87 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorAdapter.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorAdapter.cs @@ -38,12 +38,14 @@ namespace ICSharpCode.AvalonEdit.AddIn sealed class CodeEditorAdapter : CodeCompletionEditorAdapter { readonly CodeEditor codeEditor; + ITextEditorOptions options; public CodeEditorAdapter(CodeEditor codeEditor, CodeEditorView textEditor) : base(textEditor) { if (codeEditor == null) throw new ArgumentNullException("codeEditor"); this.codeEditor = codeEditor; + options = CodeEditorOptions.Instance; } public override FileName FileName { @@ -81,6 +83,9 @@ namespace ICSharpCode.AvalonEdit.AddIn foreach (var extension in extensions) extension.Detach(); } + + // Switch to global options, if no specific options service is registered + options = this.GetService() ?? CodeEditorOptions.Instance; } @@ -90,6 +95,13 @@ namespace ICSharpCode.AvalonEdit.AddIn foreach (var extension in extensions) extension.Attach(this); } + + // If we have any registered ITextEditorOptions service now, use it, otherwise global options + options = this.GetService() ?? CodeEditorOptions.Instance; + } + + public override ITextEditorOptions Options { + get { return options; } } sealed class OptionControlledIndentationStrategy : IndentationStrategyAdapter From 5c084ed695401eb7147e9f8c653dc86c68586c39 Mon Sep 17 00:00:00 2001 From: Andreas Weizel Date: Sat, 7 Jun 2014 12:47:09 +0200 Subject: [PATCH 5/7] Corrected reverting of editor options when C# binding's editor extension is detached. --- .../CSharpBinding/Project/Src/CSharpLanguageBinding.cs | 8 +++++--- .../AvalonEdit.AddIn/Src/CodeEditorAdapter.cs | 6 ++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs index f34f52145c..48103a5acf 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs @@ -65,6 +65,7 @@ namespace CSharpBinding CodeManipulation codeManipulation; CaretReferenceHighlightRenderer renderer; CodeEditorFormattingOptionsAdapter options; + TextEditorOptions originalEditorOptions; public void Attach(ITextEditor editor) { @@ -92,6 +93,7 @@ namespace CSharpBinding textViewServices.AddService(typeof(ITextEditorOptions), options); // Set TextEditor's options to same object + originalEditorOptions = textEditor.Options; textEditor.Options = options; } } @@ -107,9 +109,9 @@ namespace CSharpBinding if ((optionsService != null) && (optionsService == options)) textView.Services.RemoveService(typeof(ITextEditorOptions)); - // TODO Reset TextEditor options, too? - // if ((textEditor.Options != null) && (textEditor.Options == options)) - // textEditor.Options = SD.EditorControlService.GlobalOptions; + // Reset TextEditor options, too? + if ((textEditor.Options != null) && (textEditor.Options == options)) + textEditor.Options = originalEditorOptions; } codeManipulation.Dispose(); diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorAdapter.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorAdapter.cs index df87075e87..e747ab6177 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorAdapter.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorAdapter.cs @@ -80,8 +80,10 @@ namespace ICSharpCode.AvalonEdit.AddIn internal void DetachExtensions() { if (extensions != null) { - foreach (var extension in extensions) - extension.Detach(); + // Detach extensions in reverse order + for (int i = extensions.Count - 1; i >= 0; i--) { + extensions[i].Detach(); + } } // Switch to global options, if no specific options service is registered From 8591ab44fb75d3df5f2d5b5a6989dc45b2d66df7 Mon Sep 17 00:00:00 2001 From: tbulle Date: Mon, 9 Jun 2014 11:42:17 +0200 Subject: [PATCH 6/7] Temporary fix for bug introduced with new snapline behaviour --- .../Project/Extensions/SnaplinePlacementBehavior.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/SnaplinePlacementBehavior.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/SnaplinePlacementBehavior.cs index b145816386..5b48048f6b 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/SnaplinePlacementBehavior.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/SnaplinePlacementBehavior.cs @@ -183,7 +183,7 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions yield return designItem; if (designItem.ContentProperty.Value != null) { yield return designItem.ContentProperty.Value; - designItem = designItem.ContentProperty.Value; + designItem = ExtendedItem; //set designitem back to current control after yield } } } From 2ce1a82a475d55545a7ec23ec7e4b820da5ab941 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Wed, 11 Jun 2014 22:55:10 +0100 Subject: [PATCH 7/7] Log messages in Package Management Console. The Package Management Console now shows messages logged during the execution of the install, uninstall or update cmdlets. The messages logged are the same ones that Visual Studio shows in its console. --- .../Project/Src/InstallPackageCmdlet.cs | 4 +- .../Project/Src/PackageManagementCmdlet.cs | 7 +- .../Project/Src/UninstallPackageCmdlet.cs | 4 +- .../Project/Src/UpdatePackageCmdlet.cs | 4 +- .../Test/Src/InstallPackageCmdletTests.cs | 14 +++ .../Test/Src/UninstallPackageCmdletTests.cs | 16 +++- .../Test/Src/UpdatePackageCmdletTests.cs | 14 +++ .../Project/PackageManagement.csproj | 3 + .../Project/Src/Scripting/ICmdletLogger.cs | 31 +++++++ .../IPackageManagementConsoleHost.cs | 1 + .../Scripting/PackageManagementConsoleHost.cs | 5 ++ .../PackageManagementConsoleHostLogger.cs | 75 ++++++++++++++++ .../Scripting/PowerShellMissingConsoleHost.cs | 5 ++ .../Test/PackageManagement.Tests.csproj | 2 + .../Test/Src/Helpers/FakeCmdletLogger.cs | 55 ++++++++++++ .../FakePackageManagementConsoleHost.cs | 16 ++++ ...PackageManagementConsoleHostLoggerTests.cs | 85 +++++++++++++++++++ 17 files changed, 336 insertions(+), 5 deletions(-) create mode 100644 src/AddIns/Misc/PackageManagement/Project/Src/Scripting/ICmdletLogger.cs create mode 100644 src/AddIns/Misc/PackageManagement/Project/Src/Scripting/PackageManagementConsoleHostLogger.cs create mode 100644 src/AddIns/Misc/PackageManagement/Test/Src/Helpers/FakeCmdletLogger.cs create mode 100644 src/AddIns/Misc/PackageManagement/Test/Src/Scripting/PackageManagementConsoleHostLoggerTests.cs diff --git a/src/AddIns/Misc/PackageManagement/Cmdlets/Project/Src/InstallPackageCmdlet.cs b/src/AddIns/Misc/PackageManagement/Cmdlets/Project/Src/InstallPackageCmdlet.cs index ac57cae245..93dab21b5e 100644 --- a/src/AddIns/Misc/PackageManagement/Cmdlets/Project/Src/InstallPackageCmdlet.cs +++ b/src/AddIns/Misc/PackageManagement/Cmdlets/Project/Src/InstallPackageCmdlet.cs @@ -66,7 +66,9 @@ namespace ICSharpCode.PackageManagement.Cmdlets { ThrowErrorIfProjectNotOpen(); using (IConsoleHostFileConflictResolver resolver = CreateFileConflictResolver()) { - InstallPackage(); + using (IDisposable logger = ConsoleHost.CreateLogger(this)) { + InstallPackage(); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Cmdlets/Project/Src/PackageManagementCmdlet.cs b/src/AddIns/Misc/PackageManagement/Cmdlets/Project/Src/PackageManagementCmdlet.cs index 8681445d15..32eba1779e 100644 --- a/src/AddIns/Misc/PackageManagement/Cmdlets/Project/Src/PackageManagementCmdlet.cs +++ b/src/AddIns/Misc/PackageManagement/Cmdlets/Project/Src/PackageManagementCmdlet.cs @@ -25,7 +25,7 @@ using NuGet; namespace ICSharpCode.PackageManagement.Cmdlets { - public abstract class PackageManagementCmdlet : PSCmdlet, ITerminatingCmdlet, IPackageScriptSession, IPackageScriptRunner + public abstract class PackageManagementCmdlet : PSCmdlet, ITerminatingCmdlet, IPackageScriptSession, IPackageScriptRunner, ICmdletLogger { IPackageManagementConsoleHost consoleHost; ICmdletTerminatingError terminatingError; @@ -114,5 +114,10 @@ namespace ICSharpCode.PackageManagement.Cmdlets script.Run(this); } } + + void ICmdletLogger.WriteLine(string message) + { + Host.UI.WriteLine(message); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Cmdlets/Project/Src/UninstallPackageCmdlet.cs b/src/AddIns/Misc/PackageManagement/Cmdlets/Project/Src/UninstallPackageCmdlet.cs index 513cfc8be7..1584992b0e 100644 --- a/src/AddIns/Misc/PackageManagement/Cmdlets/Project/Src/UninstallPackageCmdlet.cs +++ b/src/AddIns/Misc/PackageManagement/Cmdlets/Project/Src/UninstallPackageCmdlet.cs @@ -59,7 +59,9 @@ namespace ICSharpCode.PackageManagement.Cmdlets protected override void ProcessRecord() { ThrowErrorIfProjectNotOpen(); - UninstallPackage(); + using (IDisposable logger = ConsoleHost.CreateLogger(this)) { + UninstallPackage(); + } } void UninstallPackage() diff --git a/src/AddIns/Misc/PackageManagement/Cmdlets/Project/Src/UpdatePackageCmdlet.cs b/src/AddIns/Misc/PackageManagement/Cmdlets/Project/Src/UpdatePackageCmdlet.cs index 91aeb5abc6..4c920e79ef 100644 --- a/src/AddIns/Misc/PackageManagement/Cmdlets/Project/Src/UpdatePackageCmdlet.cs +++ b/src/AddIns/Misc/PackageManagement/Cmdlets/Project/Src/UpdatePackageCmdlet.cs @@ -73,7 +73,9 @@ namespace ICSharpCode.PackageManagement.Cmdlets { ThrowErrorIfProjectNotOpen(); using (IConsoleHostFileConflictResolver resolver = CreateFileConflictResolver()) { - RunUpdate(); + using (IDisposable logger = ConsoleHost.CreateLogger(this)) { + RunUpdate(); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Cmdlets/Test/Src/InstallPackageCmdletTests.cs b/src/AddIns/Misc/PackageManagement/Cmdlets/Test/Src/InstallPackageCmdletTests.cs index dfacfdab29..8dbbe66d67 100644 --- a/src/AddIns/Misc/PackageManagement/Cmdlets/Test/Src/InstallPackageCmdletTests.cs +++ b/src/AddIns/Misc/PackageManagement/Cmdlets/Test/Src/InstallPackageCmdletTests.cs @@ -321,5 +321,19 @@ namespace PackageManagement.Cmdlets.Tests operationAwareRepository.AssertOperationWasStartedAndDisposed(RepositoryOperationNames.Install, "Test"); } + + [Test] + public void ProcessRecord_PackageIdSpecified_ConsoleHostLoggerIsDisposed() + { + CreateCmdletWithoutActiveProject(); + AddDefaultProjectToConsoleHost(); + AddPackageSourceToConsoleHost(); + SetIdParameter("Test"); + + RunCmdlet(); + + fakeConsoleHost.AssertLoggerIsDisposed(); + Assert.AreEqual(cmdlet, fakeConsoleHost.CmdletLoggerUsedToCreateLogger); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Cmdlets/Test/Src/UninstallPackageCmdletTests.cs b/src/AddIns/Misc/PackageManagement/Cmdlets/Test/Src/UninstallPackageCmdletTests.cs index 840d132397..2ff8092318 100644 --- a/src/AddIns/Misc/PackageManagement/Cmdlets/Test/Src/UninstallPackageCmdletTests.cs +++ b/src/AddIns/Misc/PackageManagement/Cmdlets/Test/Src/UninstallPackageCmdletTests.cs @@ -237,8 +237,22 @@ namespace PackageManagement.Cmdlets.Tests RunCmdlet(); IPackageScriptRunner scriptRunner = uninstallPackageAction.PackageScriptRunner; - + Assert.AreEqual(cmdlet, scriptRunner); } + + [Test] + public void ProcessRecord_PackageIdSpecified_ConsoleHostLoggerIsDisposed() + { + CreateCmdletWithoutActiveProject(); + AddDefaultProjectToConsoleHost(); + AddPackageSourceToConsoleHost(); + SetIdParameter("Test"); + + RunCmdlet(); + + fakeConsoleHost.AssertLoggerIsDisposed(); + Assert.AreEqual(cmdlet, fakeConsoleHost.CmdletLoggerUsedToCreateLogger); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Cmdlets/Test/Src/UpdatePackageCmdletTests.cs b/src/AddIns/Misc/PackageManagement/Cmdlets/Test/Src/UpdatePackageCmdletTests.cs index 59cdc7d7fc..e683100c35 100644 --- a/src/AddIns/Misc/PackageManagement/Cmdlets/Test/Src/UpdatePackageCmdletTests.cs +++ b/src/AddIns/Misc/PackageManagement/Cmdlets/Test/Src/UpdatePackageCmdletTests.cs @@ -832,5 +832,19 @@ namespace PackageManagement.Cmdlets.Tests operationAwareRepository.AssertOperationWasStartedAndDisposed(RepositoryOperationNames.Update, "Test2"); } + + [Test] + public void ProcessRecord_PackageIdSpecified_ConsoleHostLoggerIsDisposed() + { + CreateCmdletWithoutActiveProject(); + AddDefaultProjectToConsoleHost(); + AddPackageSourceToConsoleHost(); + SetIdParameter("Test"); + + RunCmdlet(); + + fakeConsoleHost.AssertLoggerIsDisposed(); + Assert.AreEqual(cmdlet, fakeConsoleHost.CmdletLoggerUsedToCreateLogger); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj b/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj index cdb4f112ec..7875954521 100644 --- a/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj +++ b/src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj @@ -58,6 +58,7 @@ 3.5 + 4.0 @@ -243,6 +244,7 @@ + @@ -250,6 +252,7 @@ + diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/Scripting/ICmdletLogger.cs b/src/AddIns/Misc/PackageManagement/Project/Src/Scripting/ICmdletLogger.cs new file mode 100644 index 0000000000..f557d7c7be --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/Scripting/ICmdletLogger.cs @@ -0,0 +1,31 @@ +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Management.Automation; + +namespace ICSharpCode.PackageManagement.Scripting +{ + public interface ICmdletLogger + { + void WriteError(ErrorRecord error); + void WriteLine(string message); + void WriteVerbose(string message); + void WriteWarning(string message); + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/Scripting/IPackageManagementConsoleHost.cs b/src/AddIns/Misc/PackageManagement/Project/Src/Scripting/IPackageManagementConsoleHost.cs index 0695932eeb..d4d4c3f7ca 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/Scripting/IPackageManagementConsoleHost.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/Scripting/IPackageManagementConsoleHost.cs @@ -42,6 +42,7 @@ namespace ICSharpCode.PackageManagement.Scripting void SetDefaultRunspace(); IConsoleHostFileConflictResolver CreateFileConflictResolver(FileConflictAction fileConflictAction); + IDisposable CreateLogger(ICmdletLogger logger); IPackageManagementProject GetProject(string packageSource, string projectName); IPackageManagementProject GetProject(IPackageRepository sourceRepository, string projectName); diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/Scripting/PackageManagementConsoleHost.cs b/src/AddIns/Misc/PackageManagement/Project/Src/Scripting/PackageManagementConsoleHost.cs index 6fec26b929..5742c26bf7 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/Scripting/PackageManagementConsoleHost.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/Scripting/PackageManagementConsoleHost.cs @@ -295,5 +295,10 @@ namespace ICSharpCode.PackageManagement.Scripting { return new ConsoleHostFileConflictResolver(packageEvents, fileConflictAction); } + + public IDisposable CreateLogger(ICmdletLogger logger) + { + return new PackageManagementConsoleHostLogger(logger, packageEvents); + } } } diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/Scripting/PackageManagementConsoleHostLogger.cs b/src/AddIns/Misc/PackageManagement/Project/Src/Scripting/PackageManagementConsoleHostLogger.cs new file mode 100644 index 0000000000..dc07b3357b --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Project/Src/Scripting/PackageManagementConsoleHostLogger.cs @@ -0,0 +1,75 @@ +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Management.Automation; +using NuGet; + +namespace ICSharpCode.PackageManagement.Scripting +{ + public class PackageManagementConsoleHostLogger : IDisposable + { + ICmdletLogger logger; + IPackageManagementEvents packageEvents; + + public PackageManagementConsoleHostLogger(ICmdletLogger logger, IPackageManagementEvents packageEvents) + { + this.logger = logger; + this.packageEvents = packageEvents; + + packageEvents.PackageOperationMessageLogged += PackageOperationMessageLogged; + } + + void PackageOperationMessageLogged(object sender, PackageOperationMessageLoggedEventArgs e) + { + Log(e.Message.Level, e.Message.ToString()); + } + + void Log(MessageLevel level, string message) + { + switch (level) { + case MessageLevel.Debug: + logger.WriteVerbose(message); + break; + case MessageLevel.Warning: + logger.WriteWarning(message); + break; + case MessageLevel.Error: + logger.WriteError(CreateErrorRecord(message)); + break; + default: + logger.WriteLine(message); + break; + } + } + + ErrorRecord CreateErrorRecord(string message) + { + return new ErrorRecord( + new ApplicationException(message), + "PackageManagementError", + ErrorCategory.NotSpecified, + null); + } + + public void Dispose() + { + packageEvents.PackageOperationMessageLogged -= PackageOperationMessageLogged; + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Project/Src/Scripting/PowerShellMissingConsoleHost.cs b/src/AddIns/Misc/PackageManagement/Project/Src/Scripting/PowerShellMissingConsoleHost.cs index 45beafca8d..050dca3086 100644 --- a/src/AddIns/Misc/PackageManagement/Project/Src/Scripting/PowerShellMissingConsoleHost.cs +++ b/src/AddIns/Misc/PackageManagement/Project/Src/Scripting/PowerShellMissingConsoleHost.cs @@ -100,5 +100,10 @@ namespace ICSharpCode.PackageManagement.Scripting { return null; } + + public IDisposable CreateLogger(ICmdletLogger logger) + { + return null; + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj b/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj index fb3cc11e72..0a2c80e407 100644 --- a/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj +++ b/src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj @@ -108,6 +108,7 @@ + @@ -194,6 +195,7 @@ + diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/FakeCmdletLogger.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/FakeCmdletLogger.cs new file mode 100644 index 0000000000..bf87c211c9 --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/FakeCmdletLogger.cs @@ -0,0 +1,55 @@ +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Management.Automation; +using ICSharpCode.PackageManagement.Scripting; + +namespace PackageManagement.Tests.Helpers +{ + public class FakeCmdletLogger : ICmdletLogger + { + public ErrorRecord ErrorRecordLogged; + + public void WriteError(ErrorRecord error) + { + ErrorRecordLogged = error; + } + + public string LineLogged; + + public void WriteLine(string message) + { + LineLogged = message; + } + + public string VerboseMessageLogged; + + public void WriteVerbose(string message) + { + VerboseMessageLogged = message; + } + + public string WarningMessageLogged; + + public void WriteWarning(string message) + { + WarningMessageLogged = message; + } + } +} diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/FakePackageManagementConsoleHost.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/FakePackageManagementConsoleHost.cs index caad95b80b..db0f583351 100644 --- a/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/FakePackageManagementConsoleHost.cs +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Helpers/FakePackageManagementConsoleHost.cs @@ -169,5 +169,21 @@ namespace PackageManagement.Tests.Helpers { FakeFileConflictResolver.AssertWasCalled(resolver => resolver.Dispose()); } + + public IDisposable FakeConsoleHostLogger = + MockRepository.GenerateStub(); + + public void AssertLoggerIsDisposed() + { + FakeConsoleHostLogger.AssertWasCalled(logger => logger.Dispose()); + } + + public ICmdletLogger CmdletLoggerUsedToCreateLogger; + + public IDisposable CreateLogger(ICmdletLogger logger) + { + CmdletLoggerUsedToCreateLogger = logger; + return FakeConsoleHostLogger; + } } } diff --git a/src/AddIns/Misc/PackageManagement/Test/Src/Scripting/PackageManagementConsoleHostLoggerTests.cs b/src/AddIns/Misc/PackageManagement/Test/Src/Scripting/PackageManagementConsoleHostLoggerTests.cs new file mode 100644 index 0000000000..d1e6ad884f --- /dev/null +++ b/src/AddIns/Misc/PackageManagement/Test/Src/Scripting/PackageManagementConsoleHostLoggerTests.cs @@ -0,0 +1,85 @@ +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Management.Automation; +using ICSharpCode.PackageManagement; +using ICSharpCode.PackageManagement.Scripting; +using NuGet; +using NUnit.Framework; +using PackageManagement.Tests.Helpers; + +namespace PackageManagement.Tests.Scripting +{ + [TestFixture] + public class PackageManagementConsoleHostLoggerTests + { + FakeCmdletLogger cmdletLogger; + PackageManagementConsoleHostLogger consoleHostLogger; + PackageManagementEvents packageEvents; + + void CreateConsoleHostLogger() + { + cmdletLogger = new FakeCmdletLogger(); + packageEvents = new PackageManagementEvents(); + consoleHostLogger = new PackageManagementConsoleHostLogger(cmdletLogger, packageEvents); + } + + [Test] + public void OnPackageOperationMessageLogged_DebugMessage_WrittenAsVerboseMessageToCmdlet() + { + CreateConsoleHostLogger(); + + packageEvents.OnPackageOperationMessageLogged(MessageLevel.Debug, "test"); + + Assert.AreEqual("test", cmdletLogger.VerboseMessageLogged); + } + + [Test] + public void OnPackageOperationMessageLogged_WarningMessage_WrittenAsWarningMessageToCmdlet() + { + CreateConsoleHostLogger(); + + packageEvents.OnPackageOperationMessageLogged(MessageLevel.Warning, "test"); + + Assert.AreEqual("test", cmdletLogger.WarningMessageLogged); + } + + [Test] + public void OnPackageOperationMessageLogged_InfoMessage_WrittenAsLineToCmdlet() + { + CreateConsoleHostLogger(); + + packageEvents.OnPackageOperationMessageLogged(MessageLevel.Info, "test"); + + Assert.AreEqual("test", cmdletLogger.LineLogged); + } + + [Test] + public void OnPackageOperationMessageLogged_ErrorMessage_WrittenAsErrorRecordCmdlet() + { + CreateConsoleHostLogger(); + + packageEvents.OnPackageOperationMessageLogged(MessageLevel.Error, "test"); + + Assert.IsNotNull(cmdletLogger.ErrorRecordLogged); + Assert.AreEqual("test", cmdletLogger.ErrorRecordLogged.Exception.Message); + Assert.AreEqual(ErrorCategory.NotSpecified, cmdletLogger.ErrorRecordLogged.CategoryInfo.Category); + } + } +}