/// <summary> /// Determines whether a specified C# using directive can be removed. /// </summary> /// <param name="document">The document.</param> /// <param name="usingDirective">The using directive.</param> /// <returns><c>true</c> if the specified using directive can be removed; otherwise, <c>false</c>.</returns> /// <remarks>As long as the using is represented as a T4 import directive in the root file, it can be removed.</remarks> public bool CanRemoveUsing(IDocument document, IUsingDirective usingDirective) { TreeTextRange nameRange = GetNameRange(usingDirective); if (!nameRange.IsValid()) { return(false); } IFile containingFile = usingDirective.GetContainingFile(); if (containingFile == null) { return(false); } DocumentRange documentRange = containingFile.GetDocumentRange(nameRange); return(documentRange.IsValid() && documentRange.Document == document); // IReferenceName namespaceNode = usingDirective.GetUsedNamespaceNode(); // if (namespaceNode == null) // return false; // // var directive = namespaceNode.GetT4ContainerFromCSharpNode<IT4Directive>(); // return directive != null && directive.GetContainingNode<IT4Include>() == null; }
/// <summary> /// The process of generated document commit (in the case of primary document incremental reparse) can be overridden in this method. /// Returns null if full regeneration is required. /// This method is not allowed to do destructive changes due to interruptibility! /// </summary> public override ICollection <IPreCommitResult> ExecuteSecondaryDocumentCommitWork(PrimaryFileModificationInfo primaryFileModificationInfo, CachedPsiFile cachedPsiFile, TreeTextRange oldTreeRange, string newText) { var rangeTranslator = (RangeTranslatorWithGeneratedRangeMap)cachedPsiFile.PsiFile.SecondaryRangeTranslator; if (rangeTranslator == null) { return(null); } TreeTextRange range = rangeTranslator.OriginalToGenerated(oldTreeRange, JetPredicate <IUserDataHolder> .True); DocumentRange documentRange = cachedPsiFile.PsiFile.DocumentRangeTranslator.Translate(range); if (!documentRange.IsValid()) { return(null); } var documentChange = new DocumentChange(documentRange.Document, documentRange.TextRange.StartOffset, documentRange.TextRange.Length, newText, documentRange.Document.LastModificationStamp, TextModificationSide.NotSpecified); return(new IPreCommitResult[] { new PreCommitResult(cachedPsiFile.WorkIncrementalParse(documentChange), null, documentChange, null, TextRange.InvalidRange, string.Empty), new FixRangeTranslatorsOnSharedRangeCommitResult(rangeTranslator, null, new TreeTextRange <Original>(oldTreeRange), new TreeTextRange <Generated>(range), newText) }); }
/// <summary> /// Finds a valid presentable element represented at a given <see cref="DocumentRange"/>. /// </summary> /// <param name="documentRange">The document range where to find a <see cref="IDeclaredElement"/> or a <see cref="ILiteralExpression"/>.</param> /// <returns>A <see cref="PresentableInfo"/> which may not be valid if nothing was found.</returns> private PresentableInfo FindPresentable(DocumentRange documentRange) { IDocument document = documentRange.Document; if (document == null || !documentRange.IsValid()) { return(default);
internal static T GetT4ContainerFromCSharpNode <T>([CanBeNull] this ITreeNode cSharpNode) where T : ITreeNode { if (cSharpNode == null) { return(default(T)); } var cSharpFile = cSharpNode.GetContainingFile() as IFileImpl; if (cSharpFile == null || cSharpFile.SecondaryRangeTranslator == null) { return(default(T)); } DocumentRange range = cSharpNode.GetDocumentRange(); if (!range.IsValid()) { return(default(T)); } ITreeNode t4Node = cSharpFile.SecondaryRangeTranslator.OriginalFile.FindNodeAt(range); if (t4Node == null) { return(default(T)); } return(t4Node.GetContainingNode <T>(true)); }
private void DoFormatStatementOnSemicolon(ITextControl textControl) { IFile file = CommitPsi(textControl); if (file == null) { return; } int charPos = TextControlToLexer(textControl, textControl.Caret.Offset()); if (charPos < 0) { return; } var tokenNode = file.FindTokenAt(textControl.Document, charPos - 1) as ITokenNode; if (tokenNode == null || tokenNode.GetTokenType() != PsiTokenType.SEMICOLON) { return; } var node = tokenNode.Parent; // do format if semicolon finished the statement if (node == null || tokenNode.NextSibling != null) { return; } // Select the correct start node for formatting ITreeNode startNode = node.FindFormattingRangeToLeft(); if (startNode == null) { startNode = node.FirstChild; } PsiCodeFormatter codeFormatter = GetCodeFormatter(tokenNode); using (PsiTransactionCookie.CreateAutoCommitCookieWithCachesUpdate(PsiServices, "Format code")) { using (WriteLockCookie.Create()) { codeFormatter.Format(startNode, tokenNode, CodeFormatProfile.DEFAULT); } } DocumentRange newPosition = tokenNode.GetDocumentRange(); if (newPosition.IsValid()) { textControl.Caret.MoveTo(newPosition.TextRange.EndOffset, CaretVisualPlacement.DontScrollIfVisible); } }
public TreeTextRange Translate(DocumentRange documentRange) { if (!documentRange.IsValid() || _sourceFile == null || !_sourceFile.IsValid()) { return(TreeTextRange.InvalidRange); } if (documentRange.Document != _sourceFile.Document) { foreach (IT4Include include in _includes) { if (include.DocumentRangeTranslator != null) { TreeTextRange textRange = include.DocumentRangeTranslator.Translate(documentRange); if (textRange.IsValid()) { return(textRange); } } } return(TreeTextRange.InvalidRange); } TextRange range = documentRange.TextRange; TreeOffset rootStartOffset = _root.GetTreeStartOffset(); // no includes, tree and document are matching if (_includes.Count == 0) { return(new TreeTextRange(rootStartOffset + range.StartOffset, rootStartOffset + range.EndOffset)); } TreeOffset startOffset = Translate(range.StartOffset); if (!startOffset.IsValid()) { return(TreeTextRange.InvalidRange); } TreeOffset endOffset = Translate(range.EndOffset); if (!endOffset.IsValid()) { return(TreeTextRange.InvalidRange); } return(new TreeTextRange(startOffset, endOffset)); }
//------------------------------------------------------------------------------------------------------------------------ private static IList <IProjectFile> GetProjectFiles(DocumentManager documentManager, IDeclaredElement declaredElement) { IList <IProjectFile> results = new List <IProjectFile>(); foreach (var declaration in declaredElement.GetDeclarations()) { DocumentRange documentRange = declaration.GetNavigationRange(); if (!documentRange.IsValid()) { documentRange = TreeNodeExtensions.GetDocumentRange(declaration); } if (documentRange.IsValid()) { IProjectFile projectFile = documentManager.TryGetProjectFile(documentRange.Document); if (projectFile != null) { results.Add(projectFile); } } } return(results); }
public override ISpecificCodeCompletionContext GetCompletionContext(CodeCompletionContext context) { TreeOffset startOffset = context.SelectedTreeRange.StartOffset; ITokenNode tokenNode = GetTokenNode(context); if (tokenNode == null) { return(null); } int offset = tokenNode.GetTreeStartOffset().Offset; int start = startOffset.Offset - offset; if (start <= 2) { return(null); } string text = tokenNode.GetText(); if (start > text.Length) { return(null); } string commentText = text.Substring(2, start - 2); int emojiStart = commentText.LastIndexOf(':'); if (emojiStart < 0) { return(null); } for (int index = emojiStart + 1; index < commentText.Length; ++index) { if ((index != emojiStart + 1 || !IsEmojiChar(commentText[index])) && (index <= emojiStart + 1 || !IsEmojiChar(commentText[index]))) { return(null); } } DocumentRange documentRange = context.File.GetDocumentRange(new TreeTextRange(new TreeOffset(offset + emojiStart + 2), new TreeOffset(offset + start))); if (!documentRange.IsValid()) { return(null); } return(new ContextInDocComment(context, documentRange, new TextLookupRanges(documentRange.TextRange, documentRange.TextRange))); }
public TreeTextRange Translate(DocumentRange documentRange) { if (!documentRange.IsValid()) { return(TreeTextRange.InvalidRange); } if (!SourceFile.IsValid()) { return(TreeTextRange.InvalidRange); } if (!FileLikeNode.IsValid()) { return(TreeTextRange.InvalidRange); } if (documentRange.Document != SourceFile.Document) { // That document might appear among the includes var rangeFromIncludes = Includes .Select(include => include.DocumentRangeTranslator.Translate(documentRange)) .Where(textRange => textRange.IsValid()) // Allow FirstOrDefault to return null .Select <TreeTextRange, TreeTextRange?>(it => it) .FirstOrDefault(); return(rangeFromIncludes ?? TreeTextRange.InvalidRange); } // The range is in the same document as the source file we are responsible for, // so we have no choice but to handle the request ourselves (int documentStartOffset, int documentEndOffset) = documentRange.TextRange; var rootStartOffset = FileLikeNode.GetTreeStartOffset(); // No includes, tree and document are matching if (!Includes.Any()) { return(new TreeTextRange(rootStartOffset + documentStartOffset, rootStartOffset + documentEndOffset)); } var treeStartOffset = Translate(documentStartOffset); if (!treeStartOffset.IsValid()) { return(TreeTextRange.InvalidRange); } return(TreeTextRange.FromLength(treeStartOffset, documentRange.Length)); }
private DeclaredElementInfo FindDeclaredElement(DocumentRange documentRange) { IDocument document = documentRange.Document; if (document == null || !documentRange.IsValid()) { return(null); } IPsiServices psiServices = _solution.GetPsiServices(); if (!psiServices.Files.AllDocumentsAreCommitted || psiServices.Caches.HasDirtyFiles) { return(null); } return(document .GetPsiSourceFiles(_solution) .SelectMany( psiSourceFile => psiServices.Files.GetPsiFiles(psiSourceFile, documentRange), (psiSourceFile, file) => FindDeclaredElement(documentRange, file)) .FirstOrDefault(info => info != null && info.DeclaredElement.IsValid())); }
/// <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"); } } } }
private DeclaredElementInfo FindDeclaredElement(DocumentRange documentRange) { IDocument document = documentRange.Document; if (document == null || !documentRange.IsValid()) return null; IPsiServices psiServices = _solution.GetPsiServices(); if (!psiServices.Files.AllDocumentsAreCommitted || psiServices.Caches.HasDirtyFiles) return null; return document .GetPsiSourceFiles(_solution) .SelectMany( psiSourceFile => psiServices.Files.GetPsiFiles(psiSourceFile, documentRange), (psiSourceFile, file) => FindDeclaredElement(documentRange, file)) .FirstOrDefault(info => info != null && info.DeclaredElement.IsValid()); }
/*private bool HandleRightBraceTyped(ITypingContext typingContext) * { * var textControl = typingContext.TextControl; * using (CommandProcessor.UsingCommand("Smart LBRACE")) * { * typingContext.CallNext(); * * // check if typed char is a token * int charPos = TextControlToLexer(textControl, textControl.Caret.Offset() - 1); * CachingLexer lexer = GetCachingLexer(textControl); * if (charPos < 0 || !lexer.FindTokenAt(charPos) || lexer.TokenStart != charPos) * return true; * * if (NeedAutoinsertCloseBracket(lexer)) * { * if (typingContext.EnsureWritable() != EnsureWritableResult.SUCCESS) * return true; * * AutoinsertRBrace(textControl, lexer); * var position = charPos + 1; * if (position >= 0) * textControl.Caret.MoveTo(position, CaretVisualPlacement.DontScrollIfVisible); * } * } * return true; * }*/ private bool AutoinsertRBrace(ITextControl textControl, CachingLexer lexer) { int charPos = lexer.TokenEnd; int lBracePos = charPos - 1; if (lexer.TokenType != PsiTokenType.LBRACE) { return(false); } if (!NeedAutoinsertCloseBracket(lexer)) { return(false); } // insert RBRACE next to the LBRACE IDocument document = textControl.Document; int position = lBracePos; if (position < 0) { return(false); } document.InsertText(position + 1, "}"); // Commit PSI IFile file = CommitPsi(textControl); if (file == null) { return(false); } TreeTextRange treeLBraceRange = file.Translate(new DocumentRange(document, new TextRange(lBracePos + 1))); if (!treeLBraceRange.IsValid()) { return(false); } var rBraceToken = file.FindTokenAt(treeLBraceRange.StartOffset) as ITokenNode; if (rBraceToken == null || rBraceToken.GetTokenType() != PsiTokenType.RBRACE) { return(false); } TreeOffset positionForRBrace = rBraceToken.GetTreeTextRange().EndOffset; // move RBRACE to another position, if necessary DocumentRange documentRangeForRBrace = file.GetDocumentRange(positionForRBrace); if (documentRangeForRBrace.IsValid() && documentRangeForRBrace.TextRange.StartOffset != lBracePos + 1) { int pos = documentRangeForRBrace.TextRange.StartOffset; if (pos >= 0) { document.InsertText(pos, "}"); document.DeleteText(new TextRange(lBracePos + 1, lBracePos + 2)); } } return(true); }
public PostfixTemplateAcceptanceContext([NotNull] ITreeNode reference, [NotNull] ICSharpExpression expression, DocumentRange replaceRange, bool forceMode, [NotNull] PostfixExecutionContext context) { myReparsedContext = context.ReparsedContext; myMostInnerExpression = expression; PostfixReferenceNode = reference; ForceMode = forceMode; PsiModule = context.PsiModule; LookupItemsOwner = context.LookupItemsOwner; MostInnerReplaceRange = replaceRange; if (!replaceRange.IsValid()) { var referenceExpression = reference as IReferenceExpression; if (referenceExpression != null) { MostInnerReplaceRange = ToDocumentRange(referenceExpression.QualifierExpression.NotNull()).SetEndTo( ToDocumentRange(referenceExpression.Delimiter.NotNull()).TextRange.EndOffset); } var referenceName = reference as IReferenceName; if (referenceName != null) { MostInnerReplaceRange = ToDocumentRange(referenceName.Qualifier).SetEndTo( ToDocumentRange(referenceName.Delimiter).TextRange.EndOffset); } } // build expression contexts var expressionContexts = new List<PrefixExpressionContext>(); var endOffset = Math.Max( MostInnerReplaceRange.TextRange.EndOffset, ToDocumentRange(reference).TextRange.EndOffset); for (ITreeNode node = expression; node != null; node = node.Parent) { if (node is ICSharpStatement) break; var expr = node as ICSharpExpression; if (expr == null || expr == reference) continue; var exprRange = myReparsedContext.ToDocumentRange(expr); if (!exprRange.IsValid()) break; // stop when out of generated if (exprRange.TextRange.EndOffset > endOffset) break; // stop when 'a.var + b' // skip relational expressions like this: 'List<int.{here}>' if (CommonUtils.IsRelationalExpressionWithTypeOperand(expr)) continue; var expressionContext = new PrefixExpressionContext(this, expr); if (expressionContext.ReferencedElement is ITypeElement) { // skip types that are parts of 'List<T.>'-like expressions if (!CommonUtils.CanTypeBecameExpression(expression)) continue; } expressionContexts.Add(expressionContext); if (expressionContext.CanBeStatement) break; } Expressions = (expressionContexts.Count == 0) ? EmptyList<PrefixExpressionContext>.InstanceList : expressionContexts.AsReadOnly(); }
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); }
DocumentRange[] IMemberNavigationAspect.GetNavigationRanges() { DocumentRange navigationRange = NavigationRange; return(navigationRange.IsValid() ? new[] { navigationRange } : EmptyArray <DocumentRange> .Instance); }
public bool IsValid() { return(_range.IsValid()); }
public bool IsValid() { return(_documentRange.IsValid()); }
public override bool IsAvailable(IUserDataHolder cache) { return(_range.IsValid()); }
public TreeTextRange Translate(DocumentRange documentRange) { if (!documentRange.IsValid() || _sourceFile == null || !_sourceFile.IsValid()) return TreeTextRange.InvalidRange; if (documentRange.Document != _sourceFile.Document) { foreach (IT4Include include in _includes) { if (include.DocumentRangeTranslator != null) { TreeTextRange textRange = include.DocumentRangeTranslator.Translate(documentRange); if (textRange.IsValid()) return textRange; } } return TreeTextRange.InvalidRange; } TextRange range = documentRange.TextRange; TreeOffset rootStartOffset = _root.GetTreeStartOffset(); // no includes, tree and document are matching if (_includes.Count == 0) return new TreeTextRange(rootStartOffset + range.StartOffset, rootStartOffset + range.EndOffset); TreeOffset startOffset = Translate(range.StartOffset); if (!startOffset.IsValid()) return TreeTextRange.InvalidRange; TreeOffset endOffset = Translate(range.EndOffset); if (!endOffset.IsValid()) return TreeTextRange.InvalidRange; return new TreeTextRange(startOffset, endOffset); }
public static bool IsNotEmptyNormalized(this DocumentRange range) { var textRange = range.TextRange; return(range.IsValid() && (textRange.StartOffset < textRange.EndOffset)); }