private CustomAnalysisTag RepurposeTagForSupplementaryAction(CustomAnalysisTag tag, AnalysisAction suppAction, string elementXaml) { var ae = RapidXamlElementExtractor.GetElement(elementXaml, tag.AnalyzedElement.Location.Start); var catd = new CustomAnalysisTagDependencies { AnalyzedElement = ae, Action = suppAction, ElementName = ae.Name, FileName = tag.FileName, InsertPos = tag.InsertPosition, Logger = tag.Logger, ProjectFilePath = tag.ProjectFilePath, Snapshot = tag.Snapshot, //// Don't need to set VsAbstraction as tags only need it for referencing settings but supplementary actions don't need to know about settings. }; if (suppAction.Location == null) { if (tag.Action == ActionType.RenameElement) { catd.Span = new Span(tag.Span.Start, tag.Name.Length); } else { catd.Span = tag.Span; } } else { catd.Span = suppAction.Location.ToSpanPlusStartPos(tag.InsertPosition); } return(new CustomAnalysisTag(catd)); }
private CustomAnalysisTag RepurposeTagForSupplementaryAction(CustomAnalysisTag tag, AnalysisAction suppAction) { var catd = new CustomAnalysisTagDependencies { AnalyzedElement = tag.AnalyzedElement, Action = suppAction, ElementName = tag.ElementName, FileName = tag.FileName, InsertPos = tag.InsertPosition, Logger = tag.Logger, ProjectFilePath = tag.ProjectFilePath, Snapshot = tag.Snapshot, //// Don't need to set VsAbstraction as tags only need it for referencing settings but supplementary actions don't need to know about settings. }; if (suppAction.Location == null) { catd.Span = tag.Span; } else { catd.Span = suppAction.Location.ToSpanPlusStartPos(tag.InsertPosition); } return(new CustomAnalysisTag(catd)); }
public CustomAnalysisAction(string file, CustomAnalysisTag tag) : base(file) { this.Tag = tag; this.DisplayText = tag.ActionText; this.CustomFeatureUsageOverride = tag.CustomFeatureUsageOverride; }
public static CustomAnalysisAction[] Create(CustomAnalysisTag tag, string file) { var result = new List <CustomAnalysisAction> { new CustomAnalysisAction(file, tag), }; foreach (var altAction in tag.AlternativeActions) { result.Add(new CustomAnalysisAction(file, tag.RecreateForAlternativeAction(altAction))); } return(result.ToArray()); }
private string AddXmlns(CustomAnalysisTag faTag, string xaml, List <string> output) { var element = RapidXamlElementExtractor.GetElement(xaml); bool exists = false; foreach (var attr in element.InlineAttributes) { if (attr.Name.StartsWith("xmlns:")) { var alias = attr.Name.Substring(6); if (alias == faTag.Name) { if (attr.StringValue == faTag.Value) { output.Add("XMLNS is already specified in the document."); } else { output.Add("XMLNS is already specified in the document but with a different value."); } exists = true; break; } } } if (!exists) { var insertPos = element.InlineAttributes?.LastOrDefault()?.Location?.End(); output.Add($"Adding xmlns alias for '{faTag.Name}'"); if (insertPos != null) { xaml = xaml.Insert(insertPos.Value, $" xmlns:{faTag.Name}=\"{faTag.Value}\""); } else { xaml = xaml.Insert( element.Location.Start + element.Name.Length + 1, $" xmlns:{faTag.Name}=\"{faTag.Value}\""); } } return(xaml); }
public CustomAnalysisAction(string file, CustomAnalysisTag tag) : base(file) { this.Tag = tag; if (string.IsNullOrWhiteSpace(tag.ActionText)) { this.DisplayText = Resources.StringRes.UI_XamlAnalysisFixUnavailable; this.IsEnabled = false; } else { this.DisplayText = tag.ActionText; } this.CustomFeatureUsageOverride = tag.CustomFeatureUsageOverride; }
private CustomAnalysisTag RepurposeTagForSupplementaryAction(CustomAnalysisTag tag, AnalysisAction suppAction) { var catd = new CustomAnalysisTagDependencies { AnalyzedElement = tag.AnalyzedElement, Action = suppAction, ElementName = tag.ElementName, FileName = tag.FileName, InsertPos = tag.InsertPosition, Logger = tag.Logger, Snapshot = tag.Snapshot, }; if (suppAction.Location == null) { catd.Span = tag.Span; } else { catd.Span = suppAction.Location.ToSpanPlusStartPos(tag.InsertPosition); } return(new CustomAnalysisTag(catd)); }
#pragma warning disable IDE0060 // Remove unused parameter - cancellationToken private void InnerExecute(VisualStudioTextManipulation vs, CustomAnalysisTag tag, CancellationToken cancellationToken) #pragma warning restore IDE0060 // Remove unused parameter { switch (tag.Action) { case RapidXaml.ActionType.AddAttribute: var lineNumber = tag.Snapshot.GetLineNumberFromPosition(tag.InsertPosition) + 1; // Can't rely on the original element name as this may be supplemental after it's been renamed if (XamlElementProcessor.IsSelfClosing(tag.AnalyzedElement.OriginalString.AsSpan())) { var before = $"/>"; var after = $"{tag.Name}=\"{tag.Value}\" />"; vs.ReplaceInActiveDocOnLine(before, after, lineNumber); } else { var before = $">"; var after = $"{tag.Name}=\"{tag.Value}\" /"; vs.ReplaceInActiveDocOnLine(before, after, lineNumber); } break; case RapidXaml.ActionType.AddChild: var origXaml = tag.AnalyzedElement.OriginalString; // Allow for self-closing elements if (origXaml.EndsWith("/>")) { var replacementXaml = $">{Environment.NewLine}{tag.Content}{Environment.NewLine}</{tag.ElementName}>"; var insertLine = tag.Snapshot.GetLineNumberFromPosition(tag.InsertPosition) + 1; vs.ReplaceInActiveDocOnLine("/>", replacementXaml, insertLine); } else { // Allows for opening and closing tags on same or different lines var insertLine = tag.Snapshot.GetLineNumberFromPosition(tag.InsertPosition) + 1; vs.InsertIntoActiveDocOnLineAfterClosingTag(insertLine, tag.Content); } break; case RapidXaml.ActionType.HighlightWithoutAction: // As the name implies, do nothing. break; case RapidXaml.ActionType.RemoveAttribute: if (tag.IsInlineAttribute ?? false) { var currentAttribute = $" {tag.Name}=\"{tag.Value}\""; vs.RemoveInActiveDocOnLine(currentAttribute, tag.GetDesignerLineNumber()); } else { var attrs = tag.AnalyzedElement.GetAttributes(tag.Name).ToList(); if (attrs.Count() == 1) { var attr = attrs.First(); var toRemove = tag.AnalyzedElement.OriginalString.Substring( attr.Location.Start - tag.InsertPosition, attr.Location.Length); vs.RemoveInActiveDocOnLine(toRemove, tag.GetDesignerLineNumber()); } } break; case RapidXaml.ActionType.RemoveChild: vs.RemoveInActiveDocOnLine(tag.Element.OriginalString, tag.GetDesignerLineNumber()); break; case RapidXaml.ActionType.ReplaceElement: vs.ReplaceInActiveDocOnLine( tag.AnalyzedElement.OriginalString, tag.Content, tag.Snapshot.GetLineNumberFromPosition(tag.AnalyzedElement.Location.Start)); break; case RapidXaml.ActionType.RenameElement: // Just change opening tags as Visual Studio will change closing tags automatically var renameLineNumber = tag.Snapshot.GetLineNumberFromPosition(tag.InsertPosition); vs.ReplaceInActiveDocOnLine(tag.ElementName, tag.Name, renameLineNumber); foreach (var childAttr in tag.AnalyzedElement.ChildAttributes) { renameLineNumber = tag.Snapshot.GetLineNumberFromPosition(childAttr.Location.Start); vs.ReplaceInActiveDocOnLine($"{tag.ElementName}.{childAttr.Name}", $"{tag.Name}.{childAttr.Name}", renameLineNumber); } break; } }
private string UpdateElementXaml(CustomAnalysisTag cat, List <string> output) { var orig = cat.AnalyzedElement.OriginalString; var newXaml = orig; switch (cat.Action) { case ActionType.AddAttribute: output.Add($"Adding attribute '{cat.Name}' to {cat.ElementName}"); if (orig.EndsWith("/>")) { newXaml = orig.Substring(0, orig.Length - 2) + $"{cat.Name}=\"{cat.Value}\" />"; } else { newXaml = orig.Substring(0, cat.Span.End - cat.AnalyzedElement.Location.Start) + $" {cat.Name}=\"{cat.Value}\"" + orig.Substring(cat.Span.End - cat.AnalyzedElement.Location.Start); } break; case ActionType.AddChild: output.Add($"Adding child element to {cat.ElementName}"); if (orig.EndsWith("/>")) { var replacementXaml = $">{Environment.NewLine}{cat.Content}{Environment.NewLine}</{cat.ElementName}>"; newXaml = orig.Substring(0, orig.Length - 2) + replacementXaml; } else { var insertPos = orig.IndexOf('>'); newXaml = orig.Substring(0, insertPos + 1) + $"{Environment.NewLine}{cat.Content}" + orig.Substring(insertPos + 1); } break; case ActionType.HighlightWithoutAction: // NOOP - Nothing to fix here break; case ActionType.RemoveAttribute: var attrs = cat.AnalyzedElement.GetAttributes(cat.Name).ToList(); if (attrs.Count() == 1) { output.Add($"Removing attribute '{cat.Name}' from {cat.ElementName}"); var attr = attrs.First(); newXaml = orig.Substring(0, attr.Location.Start - cat.AnalyzedElement.Location.Start) + orig.Substring(attr.Location.End() - cat.AnalyzedElement.Location.Start); } else { output.Add($"Not removing attribute '{cat.Name}' from {cat.ElementName} as it doesn't exist"); } break; case ActionType.RemoveChild: var children = cat.AnalyzedElement.GetChildren(cat.Element.Name).ToList(); if (children.Count() >= 1) { children.Reverse(); foreach (var child in children) { output.Add($"Removing child '{cat.Element.Name}' from {cat.ElementName}"); newXaml = newXaml.Substring(0, child.Location.Start - cat.AnalyzedElement.Location.Start) + newXaml.Substring(child.Location.End() - cat.AnalyzedElement.Location.Start); } } else { output.Add($"Not removing child '{cat.Name}' from {cat.ElementName} as it doesn't exist"); } break; case ActionType.RenameElement: output.Add($"Renaming an instance of {cat.ElementName} to {cat.Name}"); if (orig.EndsWith("/>")) { newXaml = $"<{cat.Name}" + orig.Substring(cat.Span.End - cat.AnalyzedElement.Location.Start); } else { var startNameEnd = cat.ElementName.Length + 1; var endNameStart = orig.LastIndexOf("</"); var updated = $"<{cat.Name}" + orig.Substring(startNameEnd, endNameStart - startNameEnd) + $"</{cat.Name}>"; newXaml = updated; } break; case ActionType.ReplaceElement: output.Add($"Replacing {cat.ElementName}"); newXaml = cat.Content; break; default: break; } return(newXaml); }