
I'm using the SyntaxEditor with the Web languages add-on and I'm hitting a conflict between a custom behavior I've written and intelliprompt.
The behavior is for indenting. Specifically, let's say I type the element <Toys. When I type > to close the element, I want:
1. The end tag to appear automatically (already works).
2. The end tag to be two lines beneath the start tag so there's an empty line in between.
3. The cursor to be within the empty line in between, and be indented.
So, in the end, it should look like:
<Toys>
</Toys>
with the cursor beneath the 's' in <Toys>.
However, when the indent occurs and then the user presses < (at the new cursor position), a completion list doesn't appear as it should. I've narrowed the problem down to my behavior's use of InsertText to insert the newline. I suspect the intelliprompt logic treats the newline as user input, doesn't find a match, and thus doesn't pop-up on the following keypress of <.
What I'd like to know is:
1. Does the XML add-on have a built in way to provide this style of indenting so I don't need custom logic.
2. If it doesn't, is there a way to insert the new line without interferring with intelliprompt?
3. Do you have any recommendations on how can I improve my behavior's indenting logic?
Thanks,
-Craig
The behavior:[Modified at 07/13/2011 03:26 PM]
The behavior is for indenting. Specifically, let's say I type the element <Toys. When I type > to close the element, I want:
1. The end tag to appear automatically (already works).
2. The end tag to be two lines beneath the start tag so there's an empty line in between.
3. The cursor to be within the empty line in between, and be indented.
So, in the end, it should look like:
<Toys>
</Toys>
with the cursor beneath the 's' in <Toys>.
However, when the indent occurs and then the user presses < (at the new cursor position), a completion list doesn't appear as it should. I've narrowed the problem down to my behavior's use of InsertText to insert the newline. I suspect the intelliprompt logic treats the newline as user input, doesn't find a match, and thus doesn't pop-up on the following keypress of <.
What I'd like to know is:
1. Does the XML add-on have a built in way to provide this style of indenting so I don't need custom logic.
2. If it doesn't, is there a way to insert the new line without interferring with intelliprompt?
3. Do you have any recommendations on how can I improve my behavior's indenting logic?
Thanks,
-Craig
The behavior:
if (e.TextChange.Type == TextChangeTypes.Enter)
{
var editor = sender as SyntaxEditor;
if (editor == null)
{
return;
}
// Notice that the reader is processing the old snapshot.
// That way, we can see if the cursor is surrounded by matching xml tags on the same line.
// We can't use e.NewSnapshot since that will include the newline due to pressing Enter.
var snapshotOffset = new TextSnapshotOffset(e.ChangedSnapshotRange.Snapshot, e.ChangedSnapshotRange.StartOffset);
var reader = e.OldSnapshot.GetReader(snapshotOffset.Offset);
if (!reader.GoToPreviousToken())
{
return;
}
// Ensure the previous token is '>'.
if (reader.Token.Key != "StartTagEndDelimiter")
{
return;
}
// Search backward for a start element name
var elementName = string.Empty;
var lineIndex = 0;
var exitLoop = false;
while (reader.GoToPreviousToken() && !exitLoop)
{
switch (reader.Token.Key)
{
case "StartTagName":
elementName = reader.TokenText.Trim();
lineIndex = reader.Token.StartPosition.Line;
exitLoop = true;
break;
case "StartTagStartDelimiter":
case "EndTagEndDelimiter":
return;
}
}
// Ensure that the previous tag has a non empty element name.
if (string.IsNullOrWhiteSpace(elementName))
{
return;
}
// Ensure that the previous tag name token is on the same line as the changed snapshot.
if (lineIndex != e.ChangedSnapshotRange.StartLine.Index)
{
return;
}
reader.Offset = snapshotOffset.Offset;
var performSmartIndent = false;
if (!reader.GoToPreviousToken())
{
return;
}
// Ensure the next token is '<'.
if (reader.Token.Key != "StartTagEndDelimiter")
{
return;
}
exitLoop = false;
while (reader.GoToNextToken() && !exitLoop)
{
switch (reader.Token.Key)
{
case "EndTagText":
if (elementName == reader.TokenText.Trim() &&
reader.Token.StartPosition.Line == e.ChangedSnapshotRange.StartLine.Index)
{
// If the elementName matches the token's text
// and the token is on the same line as the changed snapshot,
// then the tags are <abc></abc> so we can perform a smart indent.
performSmartIndent = true;
exitLoop = true;
}
else
{
return;
}
break;
case "EndTagEndDelimiter":
case "StartTagStartDelimiter":
exitLoop = true;
break;
}
}
if (performSmartIndent)
{
var startTagLine = e.ChangedSnapshotRange.StartLine;
var startLineIndentAmount = startTagLine.Snapshot.Lines[startTagLine.Index].IndentAmount;
// Insert a new line after the current line.
editor.Document.InsertText(TextChangeTypes.Indent, startTagLine.EndOffset + 1, "\r\n");
// Move the caret to the inserted line and indent it.
var caretPosition = new TextPosition(startTagLine.Index + 1, startLineIndentAmount + editor.Document.TabSize);
editor.Caret.Position = caretPosition;
// On the end tag's line, indent so the end tag's indent matches the start tag's indent.
var endTagLine = editor.Document.CurrentSnapshot.Lines[startTagLine.Index + 2];
endTagLine.IndentAmount = startLineIndentAmount;
}
}