private void DoSmartIndentOnEnter(ITextControl textControl) { var originalOffset = textControl.Caret.Offset(); var offset = TextControlToLexer(textControl, originalOffset); var mixedLexer = GetCachingLexer(textControl); // if there is something on that line, then use existing text if (offset <= 0 || !mixedLexer.FindTokenAt(offset - 1)) { return; } if (mixedLexer.TokenType == PsiTokenType.C_STYLE_COMMENT || mixedLexer.TokenType == PsiTokenType.STRING_LITERAL) { return; } if (offset <= 0 || !mixedLexer.FindTokenAt(offset)) { return; } while (mixedLexer.TokenType == PsiTokenType.WHITE_SPACE) { mixedLexer.Advance(); } offset = mixedLexer.TokenType == null ? offset : mixedLexer.TokenStart; var extraText = (mixedLexer.TokenType == PsiTokenType.NEW_LINE || mixedLexer.TokenType == null) ? "foo " : String.Empty; var projectItem = textControl.Document.GetPsiSourceFile(Solution); if (projectItem == null || !projectItem.IsValid()) { return; } using (PsiManager.GetInstance(Solution).DocumentTransactionManager.CreateTransactionCookie(DefaultAction.Commit, "Typing assist")) { // If the new line is empty, the do default indentation int lexerOffset = offset; if (extraText.Length > 0) { textControl.Document.InsertText(lexerOffset, extraText); } PsiServices.PsiManager.CommitAllDocuments(); var file = projectItem.GetPsiFile <PsiLanguage>(new DocumentRange(textControl.Document, offset)); if (file == null) { return; } var rangeInJsTree = file.Translate(new DocumentOffset(textControl.Document, offset)); if (!rangeInJsTree.IsValid()) { if (extraText.Length > 0) { textControl.Document.DeleteText(new TextRange(lexerOffset, lexerOffset + extraText.Length)); } return; } var tokenNode = file.FindTokenAt(rangeInJsTree) as ITokenNode; if (tokenNode == null) { if (extraText.Length > 0) { textControl.Document.DeleteText(new TextRange(lexerOffset, lexerOffset + extraText.Length)); } return; } PsiCodeFormatter codeFormatter = GetCodeFormatter(file); int offsetInToken = rangeInJsTree.Offset - tokenNode.GetTreeStartOffset().Offset; using (PsiTransactionCookie.CreateAutoCommitCookieWithCachesUpdate(PsiServices, "Typing assist")) { Lifetimes.Using( lifetime => { var boundSettingsStore = SettingsStore.CreateNestedTransaction(lifetime, "PsiTypingAssist").BindToContextTransient(textControl.ToContextRange()); var prevToken = tokenNode.GetPrevToken(); if (prevToken == null) { return; } if (tokenNode.Parent is IParenExpression || prevToken.Parent is IParenExpression) { var node = tokenNode.Parent; if (prevToken.Parent is IParenExpression) { node = prevToken.Parent; } codeFormatter.Format(node.FirstChild, node.LastChild, CodeFormatProfile.DEFAULT, NullProgressIndicator.Instance, boundSettingsStore); } else { codeFormatter.Format(prevToken, tokenNode, CodeFormatProfile.INDENT, NullProgressIndicator.Instance, boundSettingsStore); } }); offset = file.GetDocumentRange(tokenNode.GetTreeStartOffset()).TextRange.StartOffset + offsetInToken; } if (extraText.Length > 0) { lexerOffset = offset; textControl.Document.DeleteText(new TextRange(lexerOffset, lexerOffset + extraText.Length)); } } textControl.Caret.MoveTo(offset, CaretVisualPlacement.DontScrollIfVisible); }