In This Article

Indent Providers (Auto-Indent)

Indent providers are classes that implement IIndentProvider and contain code to perform automatic indentation when the Enter key is pressed.

Indent Mode

SyntaxEditor has been designed such that customized auto-indent behavior can be implemented to suit the language being edited.

If a class that implements IIndentProvider is registered with a syntax language as an IIndentProvider service, the indent provider's Mode property will be queried by SyntaxEditor to determine the type of indentation it should be performing when Enter is pressed.

There are three mode options:

Mode Description
None When selected, no automatic indenting occurs when the end user presses Enter to move to a new line of text, and the cursor is placed at the first column of the next line.
Block When selected and the end user presses Enter, the new line of text is automatically indented to the same indentation as the line preceding it.
Smart When selected and the end user presses Enter, the new line of text is automatically indented based on what the current language's IIndentProvider service determines the context to be.

Default Auto-Indent Behavior

If do not you have an indent provider registered with your syntax language, a default "Block" mode will be used. When the end user presses Enter, the new line of text is automatically indented to the same indentation as the line preceding it.

Smart Indent Logic

When an IIndentProvider is registered with the language and the Smart indent mode is set, the GetIndentAmount method will be invoked whenever the Enter key is pressed.

The method is passed a TextSnapshotOffset and the default "block" indent amount. The result of this method should always be the number of columns (spaces) to indent the line, as opposed to tabs. Upon returning from the method, SyntaxEditor will automatically indent the first non-whitespace character on the line to the desired column.

The TextSnapshotOffset.Snapshot property gives access to its ITextSnapshot. Likewise, the ITextSnapshot.Document provides access to its owner ITextDocument. The ITextDocument.TabSize property tells how many spaces are in a tab, in case that information is useful while determining the amount to indent.

If the ITextDocument is an ICodeDocument, the ICodeDocument.ParseData property may also contain AST or other language-specific information that can be useful when determining the indent amount.

Indent providers are free to use any custom logic in the GetIndentAmount implementation to perform the indentation. They typically will create an ITextSnapshotReader (see the Scanning Text Using a Reader topic), will scan backwards from the indicated offset and will determine how the passed-in "block" indent amount value should be altered, if at all.

For instance, in C#, if while scanning backwards the first non-whitespace character encountered is a {, then the indent amount returned should be the "block" indent amount plus an additional tab stop (usually calculated by adding the ITextDocument.TabSize value).

Registering with a Language

This code demonstrates registering an XmlIndentProvider service with the syntax language that is already declared in the language variable:

XmlIndentProvider indentProvider = new XmlIndentProvider();
language.RegisterService<IIndentProvider>(indentProvider);

Curly Brace Auto-Indent

Some languages like C# and JavaScript use curly braces as delimiters for code blocks. When the end user presses Enter while the caret is immediately between a curly brace pair, it is handy for the caret to be moved to the next line, indented, and for the close curly brace to be moved to the line following the caret. This aids in typing efficiency.

This example, where the | character denotes the caret, demonstrates the before and after what is described above:

function Foo() {|}
function Foo() {
	|
}

A pre-built DelimiterIndentProvider class is included that implements IIndentProvider. While it doesn't actually do anything other than block indent, it does have the code necessary to support curly brace auto-indent, as long as its CanAutoIndentCurlyBraces property is set to true (the default).

Note

This class is ideal for use as a base class for your own indent providers, as long as your language should have curly brace auto-indent features.

By default, DelimiterIndentProvider will just perform basic text scanning when determining if delimiters are valid for auto-indent. However, this can cause issues when examining an open curly brace and the character is within a string or comment, meaning it's not really a code-oriented brace. Thus, the indent provider also provides optional token IDs that can be set for each character. When a potential open/close delimiter pair is found and related token IDs are specified, it will double-check that the tokens have those token IDs. This eliminates the problem. Properties such as DelimiterIndentProvider.OpenCurlyBraceTokenId and DelimiterIndentProvider.CloseCurlyBraceTokenId are available for indicating the token IDs.

In some lexers such as dynamic lexers, token ID's might not be known and string-based token keys might only be set. In these cases, it's easy to handle. Instead of specifying values to the various token ID properties on DelimiterIndentProvider, override its IsValidStartDelimiter and IsValidEndDelimiter methods. An example of this concept is given in the Delimiter Auto-Completion topic.

Square Brace Auto-Indent

The pre-built DelimiterIndentProvider class described above also fully supports square brace auto-indent. This feature can be activated by setting the CanAutoIndentSquareBraces property is set to true.

As with curly braces, DelimiterIndentProvider will just perform basic text scanning when determining if delimiters are valid for auto-indent. However, this can cause issues when examining an open curly brace and the character is within a string or comment, meaning it's not really a code-oriented brace. Thus, the indent provider also provides optional token IDs that can be set for each character. When a potential open/close delimiter pair is found and related token IDs are specified, it will double-check that the tokens have those token IDs. This eliminates the problem. Properties such as DelimiterIndentProvider.OpenSquareBraceTokenId and DelimiterIndentProvider.CloseSquareBraceTokenId are available for indicating the token IDs.

In some lexers such as dynamic lexers, token ID's might not be known and string-based token keys might only be set. In these cases, it's easy to handle. Instead of specifying values to the various token ID properties on DelimiterIndentProvider, override its IsValidStartDelimiter and IsValidEndDelimiter methods. An example of this concept is given in the Delimiter Auto-Completion topic.

Close Delimiter Indentation Level

When using the DelimiterIndentProvider class described above, the close delimiter will normally flow to the same indent level as the line upon which Enter was pressed, such as:

function Foo() {|}
function Foo() {
	|
}

If the DelimiterIndentProvider.CloseDelimiterIndentLevel property is set to 1, the close delimiter indent an additional level:

function Foo() {|}
function Foo() {
	|
	}