/// <summary> /// This function is the callback used to execute the command when the menu item is clicked. /// See the constructor to see how the menu item is associated with this function using /// OleMenuCommandService service and MenuCommand class. /// </summary> /// <param name="sender">Event sender.</param> /// <param name="e">Event args.</param> private void Execute(object sender, EventArgs e) { // Verify the current thread is the UI thread. ThreadHelper.ThrowIfNotOnUIThread(); string name = ScrubXsdCommand.environment.ActiveDocument.FullName; string extension = Path.GetExtension(ScrubXsdCommand.environment.ActiveDocument.FullName).ToUpperInvariant(); if (extension == ".XSD") { // Get the selected text from the environment and make a note of where we are in the document. TextSelection selection = ScrubXsdCommand.environment.ActiveDocument.Selection as TextSelection; int line = selection.ActivePoint.Line; int offset = selection.ActivePoint.LineCharOffset; // Get the start end points (round down and up to the start of a line). EditPoint startPoint = selection.AnchorPoint.CreateEditPoint(); startPoint.StartOfDocument(); // The initial endpoint is one line below the start. EditPoint endPoint = selection.ActivePoint.CreateEditPoint(); endPoint.EndOfDocument(); // This will replace the XML in the current module with the scrubbed and beautified XML. startPoint.ReplaceText( endPoint, ScrubXsdCommand.ScrubDocument(startPoint.GetText(endPoint), extension), (int)(vsEPReplaceTextOptions.vsEPReplaceTextNormalizeNewlines | vsEPReplaceTextOptions.vsEPReplaceTextTabsSpaces)); // There will likely be some dramatic changes to the format of the document. This will restore the cursor to where it was in the // document before we beautified it. selection.MoveToLineAndOffset(line, offset); } }
/// <summary> /// Initializes the singleton instance of the command. /// </summary> /// <param name="package">Owner package, not null.</param> /// <returns>An awaitable task.</returns> public static async Task InitializeAsync(AsyncPackage package) { // Execute this method on the UI thread. await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); // Instantiate the command. OleMenuCommandService commandService = await package.GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService; ScrubXsdCommand.instance = new ScrubXsdCommand(package, commandService); }
/// <summary> /// Initialization of the package; this method is called right after the package is sited, so this is the place /// where you can put all the initialization code that rely on services provided by VisualStudio. /// </summary> /// <param name="cancellationToken">A cancellation token to monitor for initialization cancellation, which can occur when VS is shutting down.</param> /// <param name="progress">A provider for progress updates.</param> /// <returns>A task representing the async work of package initialization, or an already completed task if there is none. Do not return null from this method.</returns> protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress <ServiceProgressData> progress) { // When initialized asynchronously, the current thread may be a background thread at this point. // Do any initialization that requires the UI thread after switching to the UI thread. await this.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); await FormatCommentCommand.InitializeAsync(this); await FormatXmlCommand.InitializeAsync(this); await InsertModuleHeaderCommand.InitializeAsync(this); await InsertConstructorHeaderCommand.InitializeAsync(this); await SetModuleHeaderCommand.InitializeAsync(this); await SetWrapMarginCommand.InitializeAsync(this); await ScrubXsdCommand.InitializeAsync(this); }
/// <summary> /// Orders and beautifies an XML document. /// </summary> /// <param name="source">The source XML document to order and beautify.</param> /// <param name="extension">The extension. Used to determine tab spacing.</param> /// <returns>The text of the scrubbed and beautified document.</returns> private static string ScrubDocument(string source, string extension) { // Used to write the final document in the form of a long string. using (Utf8StringWriter stringWriter = new Utf8StringWriter()) { try { // Read the source document. using (StringReader stringReader = new StringReader(source)) { XmlSchemaDocument xmlSchemaDocument = new XmlSchemaDocument(stringReader.ReadToEnd()); // Regurgitate the schema as an XDocument XElement schemaElement = new XElement( ScrubXsdCommand.xs + "schema", new XAttribute("id", xmlSchemaDocument.Name), new XAttribute("targetNamespace", xmlSchemaDocument.TargetNamespace)); XDocument targetDocument = new XDocument(schemaElement); // This will populate the namespace manager from the namespaces in the root element. foreach (XAttribute xAttribute in xmlSchemaDocument.Root.Attributes()) { if (xAttribute.IsNamespaceDeclaration) { // Place the remaining namespace attributes in the root element of the schema description. schemaElement.Add(new XAttribute(xAttribute.Name, xAttribute.Value)); } } // <xs:element name="Domain"> XElement dataModelElement = new XElement(ScrubXsdCommand.xs + "element", new XAttribute("name", xmlSchemaDocument.Name)); // This specifies the data domain used by the REST generated code. if (xmlSchemaDocument.Domain != null) { dataModelElement.SetAttributeValue(XmlSchemaDocument.DomainName, xmlSchemaDocument.Domain); } // This flag indicates that the API uses tokens for authentication. if (xmlSchemaDocument.IsSecure.HasValue) { dataModelElement.SetAttributeValue(XmlSchemaDocument.IsSecureName, xmlSchemaDocument.IsSecure.Value); } // This flag indicates that the interface is not committed to a peristent store. if (xmlSchemaDocument.IsVolatile.HasValue) { dataModelElement.SetAttributeValue(XmlSchemaDocument.IsVolatileName, xmlSchemaDocument.IsVolatile.Value); } // <xs:complexType> XElement dataModelComlexTypeElement = new XElement(ScrubXsdCommand.xs + "complexType"); // <xs:choice maxOccurs="unbounded"> XElement dataModelChoices = new XElement(ScrubXsdCommand.xs + "choice", new XAttribute("maxOccurs", "unbounded")); // This will scrub and add each of the tables to the schema in alphabetical order. foreach (TableElement tableElement in xmlSchemaDocument.Tables.OrderBy(t => t.Name)) { dataModelChoices.Add(ScrubXsdCommand.CreateTable(tableElement)); } // The complex types that define the tables. dataModelComlexTypeElement.Add(dataModelChoices); dataModelElement.Add(dataModelComlexTypeElement); // This will order the primary keys. List <UniqueKeyElement> primaryKeyList = new List <UniqueKeyElement>(); foreach (TableElement tableElement in xmlSchemaDocument.Tables) { primaryKeyList.AddRange(tableElement.UniqueKeys); } foreach (UniqueKeyElement uniqueConstraintSchema in primaryKeyList.OrderBy(pke => pke.Name)) { dataModelElement.Add(CreateUniqueKey(uniqueConstraintSchema)); } // This will order the foreign primary keys. List <ForeignKeyElement> foreignKeyList = new List <ForeignKeyElement>(); foreach (TableElement tableElement in xmlSchemaDocument.Tables) { foreignKeyList.AddRange(tableElement.ForeignKeys); } foreach (ForeignKeyElement foreignConstraintSchema in foreignKeyList.OrderBy(fke => fke.Name)) { dataModelElement.Add(CreateForeignKey(foreignConstraintSchema)); } // Add the data model element to the document. schemaElement.Add(dataModelElement); // Save the regurgitated output. targetDocument.Save(stringWriter); } } catch (Exception exception) { // Show a message box to prove we were here VsShellUtilities.ShowMessageBox( ScrubXsdCommand.serviceProvider, exception.Message, Resources.EditorExtensionsTitle, OLEMSGICON.OLEMSGICON_CRITICAL, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST); } // The result of beautifying a long string of XML is another long string that is scrubbed and beautified. This string will be used // to replace the original content of the module. return(stringWriter.ToString()); } }