VScode + XML

At Red Hat, we look forward to creating and updating tools to improve the developer experience for users of various language servers. Visual Studio Code is one of the most popular tools for developers. The rich ecosystem of multiple extensions makes it more powerful.

We are excited to announce the release of VSCode XML Extension 0.22.0 in Visual Studio Code Marketplace and OpenVSX Registry and the addition of more improvements and features to work with XML and improve the overall developer experience.

A little VSCode XML history

The VSCode team has continuously worked with the community and received user feedback and requests. It is interesting to see the evolution of the software based on these requests. The extension was originally created to manage pom.xml files of maven projects with the VSCode Java extension and provide XML and XSD support.

VSCode XML uses the LemMinx language server written in Java to provide the various language features. However, this required Java installation. Over time, we received more and more requests from users to use the extension without Java. That's why we provided the binary feature to run the language server without Java.

Because of multiple feature requests for RelaxNG support, we integrated Jing to implement RelaxNG support in the VSCode XML extension. This has been a great addition to the extension's feature list and has shown an upward trend in usage after the release.

Since then, we have made multiple improvements. In this blog, we will focus on two important features added to the current release.

  1. RelaxNG support provides completion, hover, and validation in XML files based on RelaxNG schemas.
  2. We have made improvements to our experimental XML formatter.

1. RelaxNG support

RelaxNG support provides completion, hover, and validation in XML files based on RelaxNG schemas (XML syntax and compact syntax). Figure 1 explains the workflow:

An illustration of relax-ng-support.
Figure 1: The RelaxNG support workflow.

Validation

XML validation based on RelaxNG (rng and rnc) is supported as shown in Figure 2:

An illustration xml-validation process based on RelaxNG.
Figure 2: The XML validation process based on RelaxNG.

Completion

It supports XML completion based on RelaxNG (rng, rnc). The completion for rng displays the documentation in Figure 3:

The xml-completion process based on RelaxNG.
Figure 3: The XML completion process based on RelaxNG.

 

Hover

Hover based on RelaxNG rng shows the documentation in Figure 4:

An illustration of xml-hover based on RelaxNG.
Figure 4: Hover based on RelaxNG.

Go to type definition

From the XML document, you can go to the type definition to navigate to the element/attribute declaration for rnc and

To do this, select an XML element/attribute and use the contextual menu Go to Type Definition as shown in Figure 5.

The XML Go To Type Definition action.
Figure 5: The XML Go To Type Definition action.

 

When you click on this menu item, VS Code will open the rng or rnc grammar file and place the cursor on the proper element/attribute declaration as shown in Figure 6.

An illustration of the xml-grammar file support.
Figure 6: The XML grammar file support.

2. The experimental formatter

The current XML formatter works correctly when XML is valid. For instance, given the following XML content:

<foo><bar></bar></foo>

The XML is formatted like this:

<foo>

  <bar></bar>

</foo>

But when XML content is invalid, as in the following example:

<foo><bar'</bar></foo>

The XML is formatted like the following:

<foo>

  <bar

The formatter will lose all the invalid content, which can be extremely annoying. It is one reason we re-implemented a formatter from scratch with a new strategy. Here is the invalid content from above reformatted with the new experimental formatter:

<foo>

<bar'</bar></foo>

To activate the experimental formatter, set “xml > Format: Experimental” to “true” on the VS Code Settings Page or add the following to your settings.json:

"xml.format.experimental": true

This also opens the extension to the possibility of supporting XML with various embedded content within XML documents (eg. EJS).

Our goal is to make this new formatter the default once it supports all features of the current formatter. Please don’t hesitate to create any issues to improve the experimental formatter.

How the new formatter works

The current formatter gets the DOM document, the abstract representation of the XML document that vscode-xml uses and rewrites the content of the document in one text edit:

[
    {
        "range": {
            "start": {
                "line": 0,
                "character": 0
            },
            "end": {
                "line": 0,
                "character": 22
            }
        },
        "newText": "<foo>\r\n\t<bar></bar>\r\n</foo>"
    }
]

The new experimental formatter preserves all non-whitespace content and inserts or removes spaces to correctly indent the XML content. In the following sample, two TextEdit are generated. The insert/replace characters avoid losing invalid content.

[
    {
        "range": {
            "start": {
                "line": 0,
                "character": 5
            },
            "end": {
                "line": 0,
                "character": 5
            }
        },
        "newText": "\r\n\t"
    },
    {
        "range": {
            "start": {
                "line": 0,
                "character": 16
            },
            "end": {
                "line": 0,
                "character": 16
            }
        },
        "newText": "\r\n"
    }
]

New experimental formatter settings

In addition to a list of default elements where whitespace will be preserved, users may choose to modify this with their own set of elements. Refer to the documentation preserve space page for more information.

The following example shows two ways in which whitespaces will be preserved.

(Note: XML remains the same after formatting.)

Method #1: Figure 7 shows literallayout in the list of default elements where whitespaces will be preserved.

The xml-literal-layout tag support.
Figure 7: The literallayout tag support.

 

Method #2: Figure 8 shows that any element with xml:space = “preserve” will preserve whitespaces.

Preserve space support in XML.
Figure 8: Preserve space support in XML.

 

Support for the ability to set a maximum line width has been requested and upvoted by many users. Currently, this setting works with text content and comments. We are on track to extend this feature to cover other use cases such as attributes and ensure its behavior is consistent when applied in combination with other settings. Refer to the documentation for maximum line width formatting.

The example in Figure 9 shows formatting with maxLineWidth set to the default value of 80.

The XML max line width support.
Figure 9: The XML max line width support.

 

There are a growing number of use cases supported with this setting. This option enables the formatter to consider XML Schema/DTD grammar information when making decisions. For instance, an element defined as “xs:string” in the schema will preserve any whitespace in the content when formatting.

For more information on the specific use cases, visit the official VSCode XML GitHub page.

Contribute and get support

This is an open-source project available to anyone. Contributions are extremely welcome! To get started, refer to the contributing instructions.

If you encounter any bugs, confusing commands, or unclear documentation, or if you would like to propose a feature request, you can:

We are actively working to improve the developer experience with XML. Stay tuned for more features coming soon!

Last updated: November 8, 2023