private IEnumerable <string> GetFolders(string fullPath, IProjectTreeServiceState state) { // Roslyn wants the effective set of folders from the source up to, but not including the project // root to handle the cases where linked files have a different path in the tree than what its path // on disk is. It uses these folders for things that create files alongside others, such as extract // interface. IProjectTree tree = state.TreeProvider.FindByPath(state.Tree, fullPath); if (tree == null) { yield break; // We got a tree that is out-of-date than what our evaluation is based on } IProjectTree parent = tree; do { // Source files can be nested under other files if (parent.IsFolder) { yield return(parent.Caption); } parent = parent.Parent; } while (!parent.IsRoot()); }
private async Task <IProjectItemTree?> FindCompileItemByMonikerAsync(string documentMoniker) { IProjectTreeServiceState result = await _projectTree.Value.TreeService.PublishAnyNonLoadingTreeAsync(); if (result.TreeProvider.FindByPath(result.Tree, documentMoniker) is IProjectItemTree treeItem && treeItem.Parent?.Flags.Contains(ProjectTreeFlags.SourceFile) == false && StringComparers.ItemTypes.Equals(treeItem.Item?.ItemType, Compile.SchemaName)) { return(treeItem); } return(null); }
private void AddSourceFile(string fullPath, IProjectTreeServiceState state = null) { if (!_sourceFiles.Contains(fullPath)) { string[] folderNames = Array.Empty <string>(); if (state != null) // We're looking at a generated file, which doesn't appear in a tree. { folderNames = GetFolders(fullPath, state).ToArray(); } _sourceFiles.Add(fullPath); _context.AddSourceFile(fullPath, folderNames: folderNames); // TODO: IsInCurrentContext } }
public virtual async Task <string?> GetFileAsync(SpecialFiles fileId, SpecialFileFlags flags, CancellationToken cancellationToken = default) { // Make sure at least have a tree before we start searching it IProjectTreeServiceState state = await _treeService.PublishAnyNonLoadingTreeAsync(cancellationToken); // Attempt to find an existing file/folder first string?path = await FindFileAsync(state.TreeProvider, state.Tree, flags); if (path == null) { // Otherwise, fall back and create it path = await CreateDefaultFileAsync(state.TreeProvider, state.Tree, flags); } return(path); }
public async Task HandleAsync(IProjectVersionedValue <IProjectSubscriptionUpdate> e, IProjectChangeDescription projectChange) { Requires.NotNull(e, nameof(e)); Requires.NotNull(projectChange, nameof(projectChange)); IProjectChangeDiff diff = projectChange.Difference; foreach (string filePath in diff.RemovedItems) { // Item includes are always relative to csproj/vbproj string fullPath = _project.MakeRooted(filePath); RemoveSourceFile(fullPath); } if (diff.AddedItems.Count > 0 || diff.RenamedItems.Count > 0 || diff.ChangedItems.Count > 0) { // Make sure the tree matches the same version of the evaluation that we're handling IProjectTreeServiceState treeState = await _projectTree.TreeService.PublishTreeAsync(e.ToRequirements(), blockDuringLoadingTree : true) .ConfigureAwait(true); // TODO: https://github.com/dotnet/roslyn-project-system/issues/353 foreach (string filePath in diff.AddedItems) { string fullPath = _project.MakeRooted(filePath); AddSourceFile(fullPath, treeState); } foreach (KeyValuePair <string, string> filePaths in diff.RenamedItems) { string beforeFullPath = _project.MakeRooted(filePaths.Key); string afterFullPath = _project.MakeRooted(filePaths.Value); RemoveSourceFile(beforeFullPath); AddSourceFile(afterFullPath, treeState); } foreach (string filePath in diff.ChangedItems) { // We add and then remove ChangedItems to handle Linked metadata changes string fullPath = _project.MakeRooted(filePath); RemoveSourceFile(fullPath); AddSourceFile(fullPath); } } }
public override async Task HandleAsync(IProjectVersionedValue <IProjectSubscriptionUpdate> e, IProjectChangeDescription projectChange, IWorkspaceProjectContext context, bool isActiveContext) { Requires.NotNull(e, nameof(e)); Requires.NotNull(projectChange, nameof(projectChange)); IProjectChangeDiff diff = projectChange.Difference; foreach (string filePath in diff.RemovedItems) { RemoveSourceFile(filePath, context); } if (diff.AddedItems.Count > 0 || diff.RenamedItems.Count > 0 || diff.ChangedItems.Count > 0) { // Make sure the tree matches the same version of the evaluation that we're handling for active project context. // If we are dealing with non- active project context, then just use the latest published tree. IProjectTreeServiceState treeState = isActiveContext ? await PublishTreeAsync(e).ConfigureAwait(true) : // TODO: https://github.com/dotnet/roslyn-project-system/issues/353 await _projectTree.TreeService.PublishLatestTreeAsync(blockDuringLoadingTree : true).ConfigureAwait(true); foreach (string filePath in diff.AddedItems) { AddSourceFile(filePath, context, isActiveContext, treeState); } foreach (KeyValuePair <string, string> filePaths in diff.RenamedItems) { RemoveSourceFile(filePaths.Key, context); AddSourceFile(filePaths.Value, context, isActiveContext, treeState); } foreach (string filePath in diff.ChangedItems) { // We add and then remove ChangedItems to handle Linked metadata changes RemoveSourceFile(filePath, context); AddSourceFile(filePath, context, isActiveContext); } } }
private void AddSourceFile(string fullPath, IWorkspaceProjectContext context, bool isActiveContext, IProjectTreeServiceState state = null) { fullPath = _project.MakeRooted(fullPath); if (!_sourceFilesByContext.TryGetValue(context, out HashSet <string> sourceFiles)) { sourceFiles = new HashSet <string>(StringComparers.Paths); _sourceFilesByContext.Add(context, sourceFiles); } else if (sourceFiles.Contains(fullPath)) { return; } string[] folderNames = Array.Empty <string>(); if (state != null) // We're looking at a generated file, which doesn't appear in a tree. { folderNames = GetFolders(fullPath, state).ToArray(); } sourceFiles.Add(fullPath); context.AddSourceFile(fullPath, folderNames: folderNames, isInCurrentContext: isActiveContext); }