private bool ReformatForSmartEnter(string dummyText, ITextControl textControl, IFile file, TreeTextRange reparseTreeOffset, TreeOffset lBraceTreePos, TreeOffset rBraceTreePos, bool insertEnterAfter = false) { // insert dummy text and reformat TreeOffset newCaretPos; var codeFormatter = GetCodeFormatter(file); using (PsiTransactionCookie.CreateAutoCommitCookieWithCachesUpdate(PsiServices, "Typing assist")) { string newLine = Environment.NewLine; string textToInsert = newLine + dummyText; if (insertEnterAfter) { textToInsert = textToInsert + newLine; } file = file.ReParse(reparseTreeOffset, textToInsert); if (file == null) { return(false); } ITreeNode lBraceNode = file.FindTokenAt(lBraceTreePos); if (lBraceNode == null) { return(false); } var dummyNode = file.FindTokenAt(reparseTreeOffset.StartOffset + newLine.Length) as ITokenNode; var languageService = file.Language.LanguageService(); if (languageService == null) { return(false); } while (dummyNode != null && languageService.IsFilteredNode(dummyNode)) { dummyNode = dummyNode.GetNextToken(); } if (dummyNode == null) { return(false); } var rBraceNode = file.FindTokenAt(rBraceTreePos + newLine.Length + dummyText.Length + (insertEnterAfter ? newLine.Length : 0)); var boundSettingsStore = SettingsStore.BindToContextTransient(textControl.ToContextRange()); codeFormatter.Format(lBraceNode, CodeFormatProfile.DEFAULT, null, boundSettingsStore); codeFormatter.Format( rBraceNode.FindFormattingRangeToLeft(), rBraceNode, CodeFormatProfile.DEFAULT, null, boundSettingsStore); codeFormatter.Format(lBraceNode.Parent, CodeFormatProfile.INDENT, null); newCaretPos = dummyNode.GetTreeStartOffset(); file = file.ReParse(new TreeTextRange(newCaretPos, newCaretPos + dummyText.Length), ""); Assertion.Assert(file != null, "file != null"); } // dposition cursor DocumentRange newCaretPosition = file.GetDocumentRange(newCaretPos); if (newCaretPosition.IsValid()) { textControl.Caret.MoveTo(newCaretPosition.TextRange.StartOffset, CaretVisualPlacement.DontScrollIfVisible); } return(true); }
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); }