{"action":"created","comment":{"url":"https://api.github.com/repos/dotnet/roslyn/pulls/comments/53205077","id":53205077,"diff_hunk":"@@ -207,79 +188,155 @@ public int OnBeforeLastDocumentUnlock(uint docCookie, uint dwRDTLockType, uint d\n         {\n             if (dwReadLocksRemaining + dwEditLocksRemaining == 0)\n             {\n-                TryRemoveDocumentFromMiscellaneousWorkspace(docCookie, _runningDocumentTable.GetDocumentMoniker(docCookie));\n+                TryUntrackClosingDocument(docCookie, _runningDocumentTable.GetDocumentMoniker(docCookie));\n             }\n \n             return VSConstants.S_OK;\n         }\n \n-        private void AddDocumentToMiscellaneousOrMetadataAsSourceWorkspace(uint docCookie, string moniker)\n+        private void TrackOpenedDocument(uint docCookie, string moniker)\n         {\n             var languageInformation = TryGetLanguageInformation(moniker);\n \n-            if (languageInformation != null &&\n-                !_filesInProjects.Any(d => StringComparer.OrdinalIgnoreCase.Equals(d.Moniker, moniker)) &&\n-                !_docCookiesToHostProject.ContainsKey(docCookie))\n+            if (languageInformation == null)\n             {\n-                // See if we should push to this to the metadata-to-source workspace instead.\n-                if (_runningDocumentTable.IsDocumentInitialized(docCookie))\n+                // We can never put this document in a workspace, so just bail\n+                return;\n+            }\n+\n+            if (_runningDocumentTable.IsDocumentInitialized(docCookie))\n+            {\n+                var vsTextBuffer = (IVsTextBuffer)_runningDocumentTable.GetDocumentData(docCookie);\n+                var textBuffer = _editorAdaptersFactoryService.GetDocumentBuffer(vsTextBuffer);\n+\n+                // As long as the buffer is initialized, then we should see if we should attach\n+                if (textBuffer != null)\n                 {\n-                    var vsTextBuffer = (IVsTextBuffer)_runningDocumentTable.GetDocumentData(docCookie);\n-                    var textBuffer = _editorAdaptersFactoryService.GetDocumentBuffer(vsTextBuffer);\n+                    var registration = Workspace.GetWorkspaceRegistration(textBuffer.AsTextContainer());\n \n-                    if (_fileTrackingMetadataAsSourceService.TryAddDocumentToWorkspace(moniker, textBuffer))\n+                    registration.WorkspaceChanged += Registration_WorkspaceChanged;\n+                    _docCookieToWorkspaceRegistration = _docCookieToWorkspaceRegistration.Add(docCookie, registration);\n+\n+                    if (!IsClaimedByAnotherWorkspace(registration))\n                     {\n-                        // We already added it, so we will keep it excluded from the misc files workspace\n-                        return;\n+                        AttachToDocument(docCookie, moniker);\n                     }\n                 }\n+            }\n+        }\n \n-                var parseOptions = languageInformation.ParseOptions;\n+        private void Registration_WorkspaceChanged(object sender, EventArgs e)\n+        {\n+            var workspaceRegistration = (WorkspaceRegistration)sender;\n+            uint docCookie;\n+            Contract.ThrowIfFalse(_docCookieToWorkspaceRegistration.TryGetKey(workspaceRegistration, out docCookie));\n+            var moniker = _runningDocumentTable.GetDocumentMoniker(docCookie);\n \n-                if (Path.GetExtension(moniker) == languageInformation.ScriptExtension)\n+            if (workspaceRegistration.Workspace == null)\n+            {\n+                // We should now claim this\n+                AttachToDocument(docCookie, moniker);\n+            }\n+            else if (IsClaimedByAnotherWorkspace(workspaceRegistration))\n+            {\n+                // It's now claimed by another workspace, so we should unclaim it\n+                if (_docCookiesToHostProject.ContainsKey(docCookie))\n                 {\n-                    parseOptions = parseOptions.WithKind(SourceCodeKind.Script);\n+                    DetachFromDocument(docCookie, moniker);\n                 }\n+            }\n+        }\n \n-                // First, create the project\n-                var hostProject = new HostProject(this, CurrentSolution.Id, languageInformation.LanguageName, parseOptions, _metadataReferences);\n+        /// <summary>\n+        /// Stops tracking a document in the RDT for whether we should attach to it.\n+        /// </summary>\n+        /// <returns>true if we were previously tracking it or not.</returns>\n+        private bool TryUntrackClosingDocument(uint docCookie, string moniker)\n+        {\n+            bool unregisteredRegistration = false;\n \n-                // Now try to find the document. We accept any text buffer, since we've already verified it's an appropriate file in ShouldIncludeFile.\n-                var document = _documentProvider.TryGetDocumentForFile(hostProject, (uint)VSConstants.VSITEMID.Nil, moniker, parseOptions.Kind, t => true);\n+            // Remove our registration changing before we call DetachFromDocument. Otherwise, calling DetachFromDocument\n+            // causes us to set the workspace to null, which we then respond to as an indication that we should\n+            // attach again.\n+            WorkspaceRegistration registration;\n+            if (_docCookieToWorkspaceRegistration.TryGetValue(docCookie, out registration))\n+            {\n+                registration.WorkspaceChanged -= Registration_WorkspaceChanged;\n+                _docCookieToWorkspaceRegistration = _docCookieToWorkspaceRegistration.RemoveKey(docCookie);\n+                unregisteredRegistration = true;\n+            }\n \n-                // If the buffer has not yet been initialized, we won't get a document.\n-                if (document == null)\n-                {\n-                    return;\n-                }\n+            DetachFromDocument(docCookie, moniker);\n+\n+            return unregisteredRegistration;\n+        }\n+\n+        private bool IsClaimedByAnotherWorkspace(WorkspaceRegistration registration)\n+        {\n+            // Currently, we are also responsible for pushing documents to the metadata as source workspace,\n+            // so we count that here as well\n+            return registration.Workspace != null && registration.Workspace.Kind != WorkspaceKind.MetadataAsSource && registration.Workspace.Kind != WorkspaceKind.MiscellaneousFiles;","path":"src/VisualStudio/Core/Def/Implementation/ProjectSystem/MiscellaneousFilesWorkspace.cs","position":189,"original_position":189,"commit_id":"6b49fdcd3577acb43b07dbe1cff2ea902d374126","original_commit_id":"6b49fdcd3577acb43b07dbe1cff2ea902d374126","user":{"login":"SLaks","id":313894,"avatar_url":"https://avatars.githubusercontent.com/u/313894?v=3","gravatar_id":"","url":"https://api.github.com/users/SLaks","html_url":"https://github.com/SLaks","followers_url":"https://api.github.com/users/SLaks/followers","following_url":"https://api.github.com/users/SLaks/following{/other_user}","gists_url":"https://api.github.com/users/SLaks/gists{/gist_id}","starred_url":"https://api.github.com/users/SLaks/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/SLaks/subscriptions","organizations_url":"https://api.github.com/users/SLaks/orgs","repos_url":"https://api.github.com/users/SLaks/repos","events_url":"https://api.github.com/users/SLaks/events{/privacy}","received_events_url":"https://api.github.com/users/SLaks/received_events","type":"User","site_admin":false},"body":"Yes; any kind of approach is dangerous, and may require changes with each Roslyn release.\r\nHowever, until you offer a way to opt-in to specific services, there is no better option.","created_at":"2016-02-17T18:08:03Z","updated_at":"2016-02-17T18:08:03Z","html_url":"https://github.com/dotnet/roslyn/pull/8780#discussion_r53205077","pull_request_url":"https://api.github.com/repos/dotnet/roslyn/pulls/8780","_links":{"self":{"href":"https://api.github.com/repos/dotnet/roslyn/pulls/comments/53205077"},"html":{"href":"https://github.com/dotnet/roslyn/pull/8780#discussion_r53205077"},"pull_request":{"href":"https://api.github.com/repos/dotnet/roslyn/pulls/8780"}}},"pull_request":{"url":"https://api.github.com/repos/dotnet/roslyn/pulls/8780","id":59576127,"html_url":"https://github.com/dotnet/roslyn/pull/8780","diff_url":"https://github.com/dotnet/roslyn/pull/8780.diff","patch_url":"https://github.com/dotnet/roslyn/pull/8780.patch","issue_url":"https://api.github.com/repos/dotnet/roslyn/issues/8780","number":8780,"state":"open","locked":false,"title":"Change how Miscellaneous Files chooses which documents to track","user":{"login":"jasonmalinowski","id":201340,"avatar_url":"https://avatars.githubusercontent.com/u/201340?v=3","gravatar_id":"","url":"https://api.github.com/users/jasonmalinowski","html_url":"https://github.com/jasonmalinowski","followers_url":"https://api.github.com/users/jasonmalinowski/followers","following_url":"https://api.github.com/users/jasonmalinowski/following{/other_user}","gists_url":"https://api.github.com/users/jasonmalinowski/gists{/gist_id}","starred_url":"https://api.github.com/users/jasonmalinowski/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jasonmalinowski/subscriptions","organizations_url":"https://api.github.com/users/jasonmalinowski/orgs","repos_url":"https://api.github.com/users/jasonmalinowski/repos","events_url":"https://api.github.com/users/jasonmalinowski/events{/privacy}","received_events_url":"https://api.github.com/users/jasonmalinowski/received_events","type":"User","site_admin":false},"body":"Our previous heuristic is we tracked any document that had a moniker\r\nthat wasn't contained within any project in VisualStudioWorkspace.\r\nThis was implemented with a private hook between the two systems. This\r\nblows up in the face of other parties wishing to create their own\r\nworkspaces against files in the RDT, since we stomp on them. The new\r\nheuristic is we attach to any file that's open and doesn't already have\r\na workspace, and we watch for registration changes to back off if\r\nsomething else has taken a file.\r\n\r\nFixes #8598.\r\n\r\n*Review:* @dotnet/roslyn-ide, @huizhonglong\r\n\r\nI can also imagine @JoshVarty or @Slaks might have some code that I should know about that I should test or might get broken by this.","created_at":"2016-02-17T00:04:52Z","updated_at":"2016-02-17T18:08:03Z","closed_at":null,"merged_at":null,"merge_commit_sha":"2eec8b822908043effba243b82b676bda036f80e","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/dotnet/roslyn/pulls/8780/commits","review_comments_url":"https://api.github.com/repos/dotnet/roslyn/pulls/8780/comments","review_comment_url":"https://api.github.com/repos/dotnet/roslyn/pulls/comments{/number}","comments_url":"https://api.github.com/repos/dotnet/roslyn/issues/8780/comments","statuses_url":"https://api.github.com/repos/dotnet/roslyn/statuses/6b49fdcd3577acb43b07dbe1cff2ea902d374126","head":{"label":"jasonmalinowski:let-miscellaneousfilesworkspace-play-nicely-with-other-workspaces","ref":"let-miscellaneousfilesworkspace-play-nicely-with-other-workspaces","sha":"6b49fdcd3577acb43b07dbe1cff2ea902d374126","user":{"login":"jasonmalinowski","id":201340,"avatar_url":"https://avatars.githubusercontent.com/u/201340?v=3","gravatar_id":"","url":"https://api.github.com/users/jasonmalinowski","html_url":"https://github.com/jasonmalinowski","followers_url":"https://api.github.com/users/jasonmalinowski/followers","following_url":"https://api.github.com/users/jasonmalinowski/following{/other_user}","gists_url":"https://api.github.com/users/jasonmalinowski/gists{/gist_id}","starred_url":"https://api.github.com/users/jasonmalinowski/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jasonmalinowski/subscriptions","organizations_url":"https://api.github.com/users/jasonmalinowski/orgs","repos_url":"https://api.github.com/users/jasonmalinowski/repos","events_url":"https://api.github.com/users/jasonmalinowski/events{/privacy}","received_events_url":"https://api.github.com/users/jasonmalinowski/received_events","type":"User","site_admin":false},"repo":{"id":30048558,"name":"roslyn","full_name":"jasonmalinowski/roslyn","owner":{"login":"jasonmalinowski","id":201340,"avatar_url":"https://avatars.githubusercontent.com/u/201340?v=3","gravatar_id":"","url":"https://api.github.com/users/jasonmalinowski","html_url":"https://github.com/jasonmalinowski","followers_url":"https://api.github.com/users/jasonmalinowski/followers","following_url":"https://api.github.com/users/jasonmalinowski/following{/other_user}","gists_url":"https://api.github.com/users/jasonmalinowski/gists{/gist_id}","starred_url":"https://api.github.com/users/jasonmalinowski/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jasonmalinowski/subscriptions","organizations_url":"https://api.github.com/users/jasonmalinowski/orgs","repos_url":"https://api.github.com/users/jasonmalinowski/repos","events_url":"https://api.github.com/users/jasonmalinowski/events{/privacy}","received_events_url":"https://api.github.com/users/jasonmalinowski/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/jasonmalinowski/roslyn","description":"The .NET Compiler Platform (\"Roslyn\") provides open-source C# and Visual Basic compilers with rich code analysis APIs.","fork":true,"url":"https://api.github.com/repos/jasonmalinowski/roslyn","forks_url":"https://api.github.com/repos/jasonmalinowski/roslyn/forks","keys_url":"https://api.github.com/repos/jasonmalinowski/roslyn/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jasonmalinowski/roslyn/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jasonmalinowski/roslyn/teams","hooks_url":"https://api.github.com/repos/jasonmalinowski/roslyn/hooks","issue_events_url":"https://api.github.com/repos/jasonmalinowski/roslyn/issues/events{/number}","events_url":"https://api.github.com/repos/jasonmalinowski/roslyn/events","assignees_url":"https://api.github.com/repos/jasonmalinowski/roslyn/assignees{/user}","branches_url":"https://api.github.com/repos/jasonmalinowski/roslyn/branches{/branch}","tags_url":"https://api.github.com/repos/jasonmalinowski/roslyn/tags","blobs_url":"https://api.github.com/repos/jasonmalinowski/roslyn/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jasonmalinowski/roslyn/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jasonmalinowski/roslyn/git/refs{/sha}","trees_url":"https://api.github.com/repos/jasonmalinowski/roslyn/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jasonmalinowski/roslyn/statuses/{sha}","languages_url":"https://api.github.com/repos/jasonmalinowski/roslyn/languages","stargazers_url":"https://api.github.com/repos/jasonmalinowski/roslyn/stargazers","contributors_url":"https://api.github.com/repos/jasonmalinowski/roslyn/contributors","subscribers_url":"https://api.github.com/repos/jasonmalinowski/roslyn/subscribers","subscription_url":"https://api.github.com/repos/jasonmalinowski/roslyn/subscription","commits_url":"https://api.github.com/repos/jasonmalinowski/roslyn/commits{/sha}","git_commits_url":"https://api.github.com/repos/jasonmalinowski/roslyn/git/commits{/sha}","comments_url":"https://api.github.com/repos/jasonmalinowski/roslyn/comments{/number}","issue_comment_url":"https://api.github.com/repos/jasonmalinowski/roslyn/issues/comments{/number}","contents_url":"https://api.github.com/repos/jasonmalinowski/roslyn/contents/{+path}","compare_url":"https://api.github.com/repos/jasonmalinowski/roslyn/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jasonmalinowski/roslyn/merges","archive_url":"https://api.github.com/repos/jasonmalinowski/roslyn/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jasonmalinowski/roslyn/downloads","issues_url":"https://api.github.com/repos/jasonmalinowski/roslyn/issues{/number}","pulls_url":"https://api.github.com/repos/jasonmalinowski/roslyn/pulls{/number}","milestones_url":"https://api.github.com/repos/jasonmalinowski/roslyn/milestones{/number}","notifications_url":"https://api.github.com/repos/jasonmalinowski/roslyn/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jasonmalinowski/roslyn/labels{/name}","releases_url":"https://api.github.com/repos/jasonmalinowski/roslyn/releases{/id}","deployments_url":"https://api.github.com/repos/jasonmalinowski/roslyn/deployments","created_at":"2015-01-30T00:33:25Z","updated_at":"2016-01-14T21:25:20Z","pushed_at":"2016-02-17T00:02:04Z","git_url":"git://github.com/jasonmalinowski/roslyn.git","ssh_url":"git@github.com:jasonmalinowski/roslyn.git","clone_url":"https://github.com/jasonmalinowski/roslyn.git","svn_url":"https://github.com/jasonmalinowski/roslyn","homepage":"","size":128032,"stargazers_count":0,"watchers_count":0,"language":"C#","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"dotnet:master","ref":"master","sha":"b53f909aaec14d2a39c8b7629c17fef51d10b85b","user":{"login":"dotnet","id":9141961,"avatar_url":"https://avatars.githubusercontent.com/u/9141961?v=3","gravatar_id":"","url":"https://api.github.com/users/dotnet","html_url":"https://github.com/dotnet","followers_url":"https://api.github.com/users/dotnet/followers","following_url":"https://api.github.com/users/dotnet/following{/other_user}","gists_url":"https://api.github.com/users/dotnet/gists{/gist_id}","starred_url":"https://api.github.com/users/dotnet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dotnet/subscriptions","organizations_url":"https://api.github.com/users/dotnet/orgs","repos_url":"https://api.github.com/users/dotnet/repos","events_url":"https://api.github.com/users/dotnet/events{/privacy}","received_events_url":"https://api.github.com/users/dotnet/received_events","type":"Organization","site_admin":false},"repo":{"id":29078997,"name":"roslyn","full_name":"dotnet/roslyn","owner":{"login":"dotnet","id":9141961,"avatar_url":"https://avatars.githubusercontent.com/u/9141961?v=3","gravatar_id":"","url":"https://api.github.com/users/dotnet","html_url":"https://github.com/dotnet","followers_url":"https://api.github.com/users/dotnet/followers","following_url":"https://api.github.com/users/dotnet/following{/other_user}","gists_url":"https://api.github.com/users/dotnet/gists{/gist_id}","starred_url":"https://api.github.com/users/dotnet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dotnet/subscriptions","organizations_url":"https://api.github.com/users/dotnet/orgs","repos_url":"https://api.github.com/users/dotnet/repos","events_url":"https://api.github.com/users/dotnet/events{/privacy}","received_events_url":"https://api.github.com/users/dotnet/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/dotnet/roslyn","description":"The .NET Compiler Platform (\"Roslyn\") provides open-source C# and Visual Basic compilers with rich code analysis APIs.","fork":false,"url":"https://api.github.com/repos/dotnet/roslyn","forks_url":"https://api.github.com/repos/dotnet/roslyn/forks","keys_url":"https://api.github.com/repos/dotnet/roslyn/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dotnet/roslyn/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dotnet/roslyn/teams","hooks_url":"https://api.github.com/repos/dotnet/roslyn/hooks","issue_events_url":"https://api.github.com/repos/dotnet/roslyn/issues/events{/number}","events_url":"https://api.github.com/repos/dotnet/roslyn/events","assignees_url":"https://api.github.com/repos/dotnet/roslyn/assignees{/user}","branches_url":"https://api.github.com/repos/dotnet/roslyn/branches{/branch}","tags_url":"https://api.github.com/repos/dotnet/roslyn/tags","blobs_url":"https://api.github.com/repos/dotnet/roslyn/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dotnet/roslyn/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dotnet/roslyn/git/refs{/sha}","trees_url":"https://api.github.com/repos/dotnet/roslyn/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dotnet/roslyn/statuses/{sha}","languages_url":"https://api.github.com/repos/dotnet/roslyn/languages","stargazers_url":"https://api.github.com/repos/dotnet/roslyn/stargazers","contributors_url":"https://api.github.com/repos/dotnet/roslyn/contributors","subscribers_url":"https://api.github.com/repos/dotnet/roslyn/subscribers","subscription_url":"https://api.github.com/repos/dotnet/roslyn/subscription","commits_url":"https://api.github.com/repos/dotnet/roslyn/commits{/sha}","git_commits_url":"https://api.github.com/repos/dotnet/roslyn/git/commits{/sha}","comments_url":"https://api.github.com/repos/dotnet/roslyn/comments{/number}","issue_comment_url":"https://api.github.com/repos/dotnet/roslyn/issues/comments{/number}","contents_url":"https://api.github.com/repos/dotnet/roslyn/contents/{+path}","compare_url":"https://api.github.com/repos/dotnet/roslyn/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dotnet/roslyn/merges","archive_url":"https://api.github.com/repos/dotnet/roslyn/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dotnet/roslyn/downloads","issues_url":"https://api.github.com/repos/dotnet/roslyn/issues{/number}","pulls_url":"https://api.github.com/repos/dotnet/roslyn/pulls{/number}","milestones_url":"https://api.github.com/repos/dotnet/roslyn/milestones{/number}","notifications_url":"https://api.github.com/repos/dotnet/roslyn/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dotnet/roslyn/labels{/name}","releases_url":"https://api.github.com/repos/dotnet/roslyn/releases{/id}","deployments_url":"https://api.github.com/repos/dotnet/roslyn/deployments","created_at":"2015-01-11T02:39:03Z","updated_at":"2016-02-17T12:22:33Z","pushed_at":"2016-02-17T17:53:30Z","git_url":"git://github.com/dotnet/roslyn.git","ssh_url":"git@github.com:dotnet/roslyn.git","clone_url":"https://github.com/dotnet/roslyn.git","svn_url":"https://github.com/dotnet/roslyn","homepage":"","size":158824,"stargazers_count":4440,"watchers_count":4440,"language":"C#","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1104,"mirror_url":null,"open_issues_count":2167,"forks":1104,"open_issues":2167,"watchers":4440,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/dotnet/roslyn/pulls/8780"},"html":{"href":"https://github.com/dotnet/roslyn/pull/8780"},"issue":{"href":"https://api.github.com/repos/dotnet/roslyn/issues/8780"},"comments":{"href":"https://api.github.com/repos/dotnet/roslyn/issues/8780/comments"},"review_comments":{"href":"https://api.github.com/repos/dotnet/roslyn/pulls/8780/comments"},"review_comment":{"href":"https://api.github.com/repos/dotnet/roslyn/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/dotnet/roslyn/pulls/8780/commits"},"statuses":{"href":"https://api.github.com/repos/dotnet/roslyn/statuses/6b49fdcd3577acb43b07dbe1cff2ea902d374126"}}}}