private static bool TestNode <T>(CSharpReparseContext context, string text, bool strictStart = false) where T : ITreeNode { var node = context.Parse(text); var tokenAt1 = node.FindTokenAt(new TreeOffset(context.WholeTextLength - 1)); var treeTextOffset = new TreeOffset(context.OriginalTextLength); var tokenAt2 = node.FindTokenAt(treeTextOffset); if (tokenAt1 == null || tokenAt2 == null) { return(false); } var errorNodeFinder = new ErrorNodeFinder(tokenAt1); errorNodeFinder.FindLastError(node); if (errorNodeFinder.Error != null && errorNodeFinder.Error.GetTreeStartOffset().Offset >= context.OriginalTextLength) { return(false); } ITreeNode commonParent = tokenAt2.FindCommonParent(tokenAt1); if (!(commonParent is T)) { return(false); } if (strictStart) { return(commonParent.GetTreeTextRange().StartOffset == treeTextOffset); } return(true); }
/// <summary> /// Too lazy to implement full ITemplateScopePoint /// </summary> public IEnumerable <string> ProvideScopePoints(TemplateAcceptanceContext tacContext) { var solution = tacContext.Solution; var document = tacContext.SelectionRange.Document; if (document == null) { yield break; } var psiSource = tacContext.SourceFile; if (psiSource == null) { yield break; } using (ReadLockCookie.Create()) { var psiFiles = solution.GetPsiServices().Files; if (!psiFiles.AllDocumentsAreCommitted) { psiFiles.CommitAllDocuments(); } int caretOffset = tacContext.CaretOffset.Offset; string prefix = LiveTemplatesManager.GetPrefix(document, caretOffset); var documentRange = new DocumentRange(document, caretOffset - prefix.Length); if (!documentRange.IsValid()) { yield break; } yield return(psiSource.PrimaryPsiLanguage.Name); var file = psiSource.GetPsiFile <CSharpLanguage>(documentRange); if (file == null || !Equals(file.Language, CSharpLanguage.Instance)) { yield break; } var element = file.FindTokenAt(document, caretOffset - prefix.Length); if (element == null) { yield break; } yield return("InCSharpFile"); var treeNode = element; if (treeNode.GetContainingNode <IDocCommentNode>(true) != null) { yield break; } if (treeNode is ICSharpCommentNode || treeNode is IPreprocessorDirective) { treeNode = treeNode.PrevSibling; } if (treeNode == null) { yield break; } var context = CSharpReparseContext.FindContext(treeNode); if (context == null) { yield break; } if (treeNode.GetContainingNode <IEnumDeclaration>() != null) { yield return("InCSharpEnum"); } var containingType = treeNode.GetContainingNode <ICSharpTypeDeclaration>(true); if (containingType == null && TestNode <ICSharpNamespaceDeclaration>(context, "namespace N {}", false)) { yield return("InCSharpTypeAndNamespace"); } else if (TestNode <IMethodDeclaration>(context, "void foo() {}", false)) { yield return("InCSharpTypeMember"); // Extend here: // Already in type member, if (treeNode.GetContainingNode <IInterfaceDeclaration>() != null) { yield return("InCSharpInterface"); } if (treeNode.GetContainingNode <IClassDeclaration>() != null) { yield return("InCSharpClass"); } if (treeNode.GetContainingNode <IStructDeclaration>() != null) { yield return("InCSharpStruct"); } } else { bool acceptsExpression = TestNode <IPostfixOperatorExpression>(context, "a++", true); if (TestNode <IBreakStatement>(context, "break;", false)) { yield return("InCSharpStatement"); } else if (acceptsExpression) { yield return("InCSharpExpression"); } if (!acceptsExpression && TestNode <IQuerySelectClause>(context, "select x", false)) { yield return("InCSharpQuery"); } } } }