From 3284781d8f2623e662e299a862b25c78dad8fca6 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 21 Jun 2009 12:11:55 +0000 Subject: [PATCH] Added some XAML PowerToys git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4333 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../XamlBinding/CompletionDataHelper.cs | 19 ++-- .../XamlBinding/XamlBinding/Extensions.cs | 31 ++++++ .../Commands/GroupIntoMenuBuilder.cs | 28 ++++++ .../PowerToys/Commands/RemoveMarginCommand.cs | 60 ++++++++++++ .../RemoveUnnecessaryAttributesCommand.cs | 31 ++++++ .../XamlBinding/PowerToys/XamlMenuCommand.cs | 52 ++++++++++ .../XamlBinding/XamlBinding/XamlBinding.addin | 23 ++++- .../XamlBinding/XamlBinding.csproj | 5 + .../XamlBinding/XamlCodeCompletionBinding.cs | 2 +- .../XamlBinding/XamlBinding/XamlColorizer.cs | 96 ++++++++++++------- .../XamlBinding/XamlColorizerServer.cs | 4 +- .../XamlBinding/XamlBinding/XamlResolver.cs | 2 - .../ParserService/ParseProjectContent.cs | 2 +- 13 files changed, 305 insertions(+), 50 deletions(-) create mode 100644 src/AddIns/BackendBindings/XamlBinding/XamlBinding/PowerToys/Commands/GroupIntoMenuBuilder.cs create mode 100644 src/AddIns/BackendBindings/XamlBinding/XamlBinding/PowerToys/Commands/RemoveMarginCommand.cs create mode 100644 src/AddIns/BackendBindings/XamlBinding/XamlBinding/PowerToys/Commands/RemoveUnnecessaryAttributesCommand.cs create mode 100644 src/AddIns/BackendBindings/XamlBinding/XamlBinding/PowerToys/XamlMenuCommand.cs diff --git a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/CompletionDataHelper.cs b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/CompletionDataHelper.cs index cefd3f59aa..dc242f4d18 100644 --- a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/CompletionDataHelper.cs +++ b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/CompletionDataHelper.cs @@ -5,7 +5,7 @@ // $Revision$ // -using ICSharpCode.SharpDevelop.Project; +using ICSharpCode.AvalonEdit.Document; using System; using System.Collections.Generic; using System.Diagnostics; @@ -16,6 +16,7 @@ using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Editor; using ICSharpCode.SharpDevelop.Editor.CodeCompletion; +using ICSharpCode.SharpDevelop.Project; using ICSharpCode.XmlEditor; using LoggingService = ICSharpCode.Core.LoggingService; @@ -45,11 +46,15 @@ namespace ICSharpCode.XamlBinding { int offset = Utils.GetOffsetFromFilePos(text, line, col); + if (offset == -1) + throw new InvalidOperationException("No valid file position: " + line + " " + col); ParseInformation info = ParserService.GetParseInformation(fileName); XmlElementPath path = XmlParser.GetActiveElementStartPathAtIndex(text, offset); string attribute = XmlParser.GetAttributeNameAtIndex(text, offset); - string attributeValue = XmlParser.GetAttributeValueAtIndex(text, offset); bool inAttributeValue = XmlParser.IsInsideAttributeValue(text, offset); + string attributeValue = ""; + if (inAttributeValue) + attributeValue = XmlParser.GetAttributeValueAtIndex(text, offset); int offsetFromValueStart = Utils.GetOffsetFromValueStart(text, offset); int elementStartIndex = XmlParser.GetActiveElementStartIndex(text, offset); AttributeValue value = MarkupExtensionParser.ParseValue(attributeValue); @@ -64,7 +69,7 @@ namespace ICSharpCode.XamlBinding if (text[offset] == '>') description = XamlContextDescription.None; - if (!string.IsNullOrEmpty(attribute) || (elementStartIndex > -1 && offset > 0 && char.IsWhiteSpace(text[offset - 1]))) + if (elementStartIndex > -1 && (char.IsWhiteSpace(text[offset]) || !string.IsNullOrEmpty(attribute) || Extensions.Is(text[offset], '"', '\''))) description = XamlContextDescription.InTag; if (inAttributeValue) { @@ -98,8 +103,6 @@ namespace ICSharpCode.XamlBinding ParseInformation = info }; - LoggingService.Debug(context); - return context; } @@ -157,12 +160,8 @@ namespace ICSharpCode.XamlBinding } foreach (string @namespace in content.NamespaceNames) { - if (!string.IsNullOrEmpty(@namespace)) { - if (string.IsNullOrEmpty(content.AssemblyName)) - list.Add(new XmlnsCompletionItem(@namespace, false)); - else + if (!string.IsNullOrEmpty(@namespace)) list.Add(new XmlnsCompletionItem(@namespace, content.AssemblyName)); - } } } diff --git a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/Extensions.cs b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/Extensions.cs index c419fce30e..af671fcecf 100644 --- a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/Extensions.cs +++ b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/Extensions.cs @@ -13,6 +13,7 @@ using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Editor.CodeCompletion; using ICSharpCode.XmlEditor; +using System.Xml; namespace ICSharpCode.XamlBinding { @@ -39,6 +40,36 @@ namespace ICSharpCode.XamlBinding return false; } + public static bool Is(char value, params char[] chars) + { + foreach (var c in chars) { + if (c == value) + return true; + } + + return false; + } + + public static void Remove(this XmlAttributeCollection coll, string name) + { + for (int i = 0; i < coll.Count; i++) { + if (coll[i].Name.Equals(name, StringComparison.Ordinal)) { + coll.RemoveAt(i); + i--; + } + } + } + + public static void Remove(this XmlAttributeCollection coll, string name, string namespaceURI) + { + for (int i = 0; i < coll.Count; i++) { + if (coll[i].LocalName.Equals(name, StringComparison.Ordinal) && coll[i].NamespaceURI.Equals(namespaceURI, StringComparison.Ordinal)) { + coll.RemoveAt(i); + i--; + } + } + } + public static IEnumerable RemoveEvents(this IEnumerable list) { foreach (var item in list) { diff --git a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/PowerToys/Commands/GroupIntoMenuBuilder.cs b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/PowerToys/Commands/GroupIntoMenuBuilder.cs new file mode 100644 index 0000000000..ed138edda4 --- /dev/null +++ b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/PowerToys/Commands/GroupIntoMenuBuilder.cs @@ -0,0 +1,28 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.Windows.Controls; + +namespace ICSharpCode.XamlBinding.PowerToys.Commands +{ + /// + /// Description of GroupIntoMenuBuilder + /// + public class GroupIntoMenuBuilder : XamlMenuBuilder + { + public override MenuItem[] BuildItems() + { + List list = new List(); + + + + return list.ToArray(); + } + } +} diff --git a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/PowerToys/Commands/RemoveMarginCommand.cs b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/PowerToys/Commands/RemoveMarginCommand.cs new file mode 100644 index 0000000000..7161933dd6 --- /dev/null +++ b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/PowerToys/Commands/RemoveMarginCommand.cs @@ -0,0 +1,60 @@ +// +// +// +// +// $Revision$ +// + +using ICSharpCode.Core; +using System; +using System.Linq; +using System.Xml; +using ICSharpCode.SharpDevelop.Editor; +using ICSharpCode.XamlBinding; + +namespace ICSharpCode.XamlBinding.PowerToys.Commands +{ + public class RemoveMarginCommand : XamlMenuCommand + { + protected override void Refactor(ITextEditor editor, XmlDocument document) + { + RemoveRecursive(document, "Margin"); + } + + protected void RemoveRecursive(XmlNode pNode, string name) + { + foreach (XmlNode node in pNode.ChildNodes) { + node.Attributes.Remove(name); + RemoveRecursive(node, name); + } + } + + protected void RemoveRecursive(XmlNode pNode, string name, string namespaceURI) + { + foreach (XmlNode node in pNode.ChildNodes) { + node.Attributes.Remove(name, namespaceURI); + RemoveRecursive(node, name, namespaceURI); + } + } + } + + public class GroupIntoMenuItem : XamlMenuCommand + { + protected sealed override void Refactor(ITextEditor editor, XmlDocument document) + { + if (editor.SelectionLength == 0) { + MessageService.ShowError("The selected XAML is invalid!"); + } + } + } + + public class ExtractPropertiesAsStyleCommand : XamlMenuCommand + { + protected override void Refactor(ITextEditor editor, XmlDocument document) + { + string[] attributes = Utils.GetListOfExistingAttributeNames(editor.Document.Text, editor.Caret.Line, editor.Caret.Column); + + + } + } +} diff --git a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/PowerToys/Commands/RemoveUnnecessaryAttributesCommand.cs b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/PowerToys/Commands/RemoveUnnecessaryAttributesCommand.cs new file mode 100644 index 0000000000..79ef91f4fa --- /dev/null +++ b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/PowerToys/Commands/RemoveUnnecessaryAttributesCommand.cs @@ -0,0 +1,31 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Windows.Forms; + +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop; + +namespace ICSharpCode.XamlBinding.PowerToys.Commands +{ + /// + /// Description of RemoveUnneccessaryAttributesCommand + /// + public class RemoveUnnecessaryAttributesCommand : RemoveMarginCommand + { + protected override void Refactor(ICSharpCode.SharpDevelop.Editor.ITextEditor editor, System.Xml.XmlDocument document) + { + RemoveRecursive(document, "Margin"); + RemoveRecursive(document, "Name"); + RemoveRecursive(document, "Name", CompletionDataHelper.XamlNamespace); + RemoveRecursive(document, "MinWidth"); + RemoveRecursive(document, "MinHeight"); + // set all row and column definitions to Auto + } + } +} diff --git a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/PowerToys/XamlMenuCommand.cs b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/PowerToys/XamlMenuCommand.cs new file mode 100644 index 0000000000..af81392158 --- /dev/null +++ b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/PowerToys/XamlMenuCommand.cs @@ -0,0 +1,52 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.IO; +using System.Windows.Forms; +using System.Xml; + +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Editor; +using ICSharpCode.SharpDevelop.Gui; + +namespace ICSharpCode.XamlBinding.PowerToys +{ + /// + /// Description of XamlMenuCommand + /// + public abstract class XamlMenuCommand : AbstractMenuCommand + { + /// + /// Starts the command + /// + public sealed override void Run() + { + try { + ITextEditorProvider provider = WorkbenchSingleton.Workbench.ActiveViewContent as ITextEditorProvider; + + if (provider != null) { + TextReader reader = provider.TextEditor.Document.CreateReader(); + XmlDocument document = new XmlDocument(); + document.Load(reader); + Refactor(provider.TextEditor, document); + StringWriter sWriter = new StringWriter(); + XmlTextWriter writer = new XmlTextWriter(sWriter); + writer.Formatting = Formatting.Indented; + document.WriteTo(writer); + writer.Flush(); + provider.TextEditor.Document.Text = sWriter.ToString(); + } + } catch (XmlException e) { + MessageService.ShowError(e.Message); + } + } + + protected abstract void Refactor(ITextEditor editor, XmlDocument document); + } +} diff --git a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlBinding.addin b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlBinding.addin index 493f267cfc..fff315dd2d 100644 --- a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlBinding.addin +++ b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlBinding.addin @@ -8,6 +8,8 @@ @@ -47,10 +49,29 @@ - + + + + + + + + + + + + + + + + diff --git a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlBinding.csproj b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlBinding.csproj index 815043fb90..bdb5aa3a44 100644 --- a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlBinding.csproj +++ b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlBinding.csproj @@ -74,6 +74,9 @@ Code + + + @@ -140,7 +143,9 @@ + + diff --git a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlCodeCompletionBinding.cs b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlCodeCompletionBinding.cs index cc4e2a59d7..0bb7ef7457 100644 --- a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlCodeCompletionBinding.cs +++ b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlCodeCompletionBinding.cs @@ -120,7 +120,7 @@ namespace ICSharpCode.XamlBinding } break; default: - if (context.Description != XamlContextDescription.None && !char.IsWhiteSpace(context.PressedKey)) { + if (context.Description != XamlContextDescription.None && !char.IsWhiteSpace(ch)) { editor.Document.Insert(editor.Caret.Offset, ch.ToString()); if (!context.AttributeName.StartsWith("xmlns")) this.CtrlSpace(editor); diff --git a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlColorizer.cs b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlColorizer.cs index 01f4c3b755..cc63362ffa 100644 --- a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlColorizer.cs +++ b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlColorizer.cs @@ -6,6 +6,7 @@ // using System; +using System.Linq; using System.Collections.Generic; using ICSharpCode.AvalonEdit.Document; using ICSharpCode.AvalonEdit.Rendering; @@ -14,6 +15,7 @@ using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Editor; using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.XmlEditor; +using System.Diagnostics; namespace ICSharpCode.XamlBinding { @@ -22,6 +24,7 @@ namespace ICSharpCode.XamlBinding static readonly XamlColorizerSettings defaultSettings = new XamlColorizerSettings(); XamlColorizerSettings settings = defaultSettings; string fileContent; + string fileName; public IViewContent Content { get; set; } @@ -30,55 +33,80 @@ namespace ICSharpCode.XamlBinding this.Content = content; } - protected override void ColorizeLine(DocumentLine line) + protected override void Colorize(ITextRunConstructionContext context) { - ParseInformation parseInfo = ParserService.GetParseInformation(Content.PrimaryFileName); - XamlResolver resolver = new XamlResolver(); - IFileDocumentProvider document = this.Content as IFileDocumentProvider; if (document == null) return; - this.fileContent = document.GetDocumentForFile(this.Content.PrimaryFile).Text; + this.fileContent = document.GetDocumentForFile(this.Content.PrimaryFile).CreateSnapshot().Text; + this.fileName = this.Content.PrimaryFileName; + + base.Colorize(context); + } + + protected override void ColorizeLine(DocumentLine line) + { + Stopwatch watch = new Stopwatch(); + watch.Start(); + + XamlResolver resolver = new XamlResolver(); if (!line.IsDeleted) { - HighlightingInfo[] infos = GetInfoForLine(line); - - foreach (HighlightingInfo info in infos) { - MemberResolveResult rr = resolver.Resolve(info.GetExpressionResult(), parseInfo, fileContent) as MemberResolveResult; + foreach (HighlightingInfo info in GetInfoForLine(fileContent, fileName, (string)line.Text.Clone(), line.LineNumber, line.Offset)) { + MemberResolveResult rr = resolver.Resolve(info.GetExpressionResult(), info.Context.ParseInformation, fileContent) as MemberResolveResult; IMember member = (rr != null) ? rr.ResolvedMember : null; - if (member != null) { - if (member is IEvent) - ChangeLinePart(line.Offset + info.StartOffset, line.Offset + info.EndOffset, HighlightEvent); - else - ChangeLinePart(line.Offset + info.StartOffset, line.Offset + info.EndOffset, HighlightProperty); - } else { - if (info.Token.StartsWith("xmlns")) - ChangeLinePart(line.Offset + info.StartOffset, line.Offset + info.EndOffset, HighlightNamespaceDeclaration); - } + Colorize(member, info, line.Offset); } } + + watch.Stop(); + Core.LoggingService.Debug("ColorizeLine line: " + line.LineNumber + " took: " + watch.ElapsedMilliseconds + "ms"); } - HighlightingInfo[] GetInfoForLine(DocumentLine line) + void Colorize(IMember member, HighlightingInfo info, int offset) { - int index = -1; - List infos = new List(); - /* - do { - index = line.Text.IndexOf('=', index + 1); - if (index > -1) { - string expr = XmlParser.GetAttributeNameAtIndex(this.fileContent, index + line.Offset); - XmlElementPath path = XmlParser.GetActiveElementStartPathAtIndex(this.fileContent, index + line.Offset); - if (!string.IsNullOrEmpty(expr) && path != null && path.Elements.Count > 0) { - int startIndex = line.Text.Substring(0, index).LastIndexOf(expr); - infos.Add(new HighlightingInfo(expr, startIndex, startIndex + expr.Length, line.Offset, path)); - } + try { + if (member != null) { + if (member is IEvent) + ChangeLinePart(offset + info.StartOffset, offset + info.EndOffset, HighlightEvent); + else + ChangeLinePart(offset + info.StartOffset, offset + info.EndOffset, HighlightProperty); + } else { + if (info.Token.StartsWith("xmlns")) + ChangeLinePart(offset + info.StartOffset, offset + info.EndOffset, HighlightNamespaceDeclaration); } - } while (index > -1);*/ + } catch (Exception e) { + Debug.Print(e.ToString()); + } + } + + static ParallelQuery GetInfoForLine(string fileContent, string fileName, string lineText, int line, int offset) + { + Stopwatch watch = new Stopwatch(); + watch.Start(); + + List indices = new List(); + List infos = new List(); + + int cIndex = lineText.IndexOf('='); - return infos.ToArray(); + while (cIndex > -1) { + indices.Add(cIndex); + cIndex = lineText.IndexOf('=', cIndex + 1); + } + + return indices.AsParallel() + .Select(index => new { Context = CompletionDataHelper.ResolveContext(fileContent, fileName, line, index + 1), Index = index, Offset = offset }) + .Where(item => !string.IsNullOrEmpty(item.Context.AttributeName)) + .Select(context => GetInfo(context.Index, lineText, line, context.Context)); + } + + static HighlightingInfo GetInfo(int index, string lineText, int line, XamlContext context) + { + int startIndex = lineText.Substring(0, index).LastIndexOf(context.AttributeName); + return new HighlightingInfo(context.AttributeName, startIndex, startIndex + context.AttributeName.Length, line, context); } void HighlightProperty(VisualLineElement element) @@ -101,6 +129,8 @@ namespace ICSharpCode.XamlBinding struct HighlightingInfo { + public static readonly HighlightingInfo Empty = new HighlightingInfo(string.Empty, 0, 0, 0, new XamlContext()); + string token; int startOffset; int endOffset; diff --git a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlColorizerServer.cs b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlColorizerServer.cs index 2064135ad3..16237151af 100644 --- a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlColorizerServer.cs +++ b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlColorizerServer.cs @@ -32,8 +32,8 @@ namespace ICSharpCode.XamlBinding ITextEditorProvider textEditor = e.Content as ITextEditorProvider; if (textEditor != null) { TextView textView = textEditor.TextEditor.GetService(typeof(TextView)) as TextView; -// if (textView != null) -// textView.LineTransformers.Add(new XamlColorizer(e.Content)); + //if (textView != null) + //textView.LineTransformers.Add(new XamlColorizer(e.Content)); } } } diff --git a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlResolver.cs b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlResolver.cs index 1d1598fb84..e2172fe9fd 100644 --- a/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlResolver.cs +++ b/src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlResolver.cs @@ -25,7 +25,6 @@ namespace ICSharpCode.XamlBinding public class XamlResolver : IResolver { IClass callingClass; - string fileContent; string resolveExpression; int caretLine, caretColumn; XamlContext context; @@ -35,7 +34,6 @@ namespace ICSharpCode.XamlBinding this.resolveExpression = expressionResult.Expression; this.caretLine = expressionResult.Region.BeginLine; this.caretColumn = expressionResult.Region.BeginColumn; - this.fileContent = fileContent; this.callingClass = parseInfo.BestCompilationUnit.GetInnermostClass(caretLine, caretColumn); this.context = expressionResult.Context as XamlContext ?? CompletionDataHelper.ResolveContext(fileContent, parseInfo.MostRecentCompilationUnit.FileName, caretLine, caretColumn); diff --git a/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs b/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs index 1324b079e3..1a9dcd9747 100644 --- a/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs +++ b/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs @@ -36,7 +36,7 @@ namespace ICSharpCode.SharpDevelop } } - public string AssemblyName { + public override string AssemblyName { get { return project.AssemblyName; } }