{"action":"created","comment":{"url":"https://api.github.com/repos/dotnet/roslyn/pulls/comments/37324512","id":37324512,"diff_hunk":"@@ -1447,88 +1461,126 @@ private void MeasurePrompts(int startLine, int endLine, out int minPromptLength,\n         {\n             Debug.Assert(endLine > startLine);\n \n-            var promptSpanIndex = GetProjectionSpanIndexFromEditableBufferPosition(_projectionBuffer.CurrentSnapshot, _projectionSpans.Count, startLine) - 1;\n-            Debug.Assert(_projectionSpans[promptSpanIndex].Kind.IsPrompt());\n+            var projectionSnapshot = _projectionBuffer.CurrentSnapshot;\n+            var sourceSpans = projectionSnapshot.GetSourceSpans();\n+            var promptSpanIndex = GetProjectionSpanIndexFromEditableBufferPosition(projectionSnapshot, sourceSpans.Count, startLine) - 1;\n+            var promptSpan = sourceSpans[promptSpanIndex];\n+            Debug.Assert(IsPrompt(promptSpan.Snapshot));\n \n-            var promptSpan = _projectionSpans[promptSpanIndex];\n             minPromptLength = maxPromptLength = promptSpan.Length;\n         }\n \n-        private int GetPromptIndexForPoint(SnapshotPoint point)\n+        private ReplSpanKind GetSpanKind(ITextSnapshot snapshot)\n+        {\n+            var textBuffer = snapshot.TextBuffer;\n+            if ((textBuffer == _outputBuffer) || (textBuffer == _outputLineBreakBuffer))\n+            {\n+                return ReplSpanKind.Output;\n+            }\n+            if (textBuffer == _standardInputBuffer)\n+            {\n+                return ReplSpanKind.StandardInput;\n+            }\n+            if (textBuffer == _promptBuffer)\n+            {\n+                return ReplSpanKind.Prompt;\n+            }\n+            if (textBuffer == _secondaryPromptBuffer)\n+            {\n+                return ReplSpanKind.SecondaryPrompt;\n+            }\n+            if (textBuffer == _standardInputPromptBuffer)\n+            {\n+                return ReplSpanKind.StandardInputPrompt;\n+            }\n+            return ReplSpanKind.Language;\n+        }\n+\n+        private bool IsPrompt(ITextSnapshot snapshot)\n         {\n-            int lineNumber = point.GetContainingLine().LineNumber;\n-            return _projectionSpans.BinarySearch(new ReplSpan(\"\", ReplSpanKind.Prompt, lineNumber), ReplSpanComparer.Instance);\n+            var kind = GetSpanKind(snapshot);\n+            return (kind == ReplSpanKind.Prompt) || (kind == ReplSpanKind.SecondaryPrompt);\n         }\n \n-        private class ReplSpanComparer : IComparer<ReplSpan>\n+        private bool IsLanguage(ITextSnapshot snapshot)\n         {\n-            public static readonly IComparer<ReplSpan> Instance = new ReplSpanComparer();\n+            return GetSpanKind(snapshot) == ReplSpanKind.Language;\n+        }\n \n-            private ReplSpanComparer()\n-            {\n-            }\n+        private static ReadOnlyCollection<SnapshotSpan> GetSourceSpans(ITextSnapshot snapshot)\n+        {\n+            return ((IProjectionSnapshot)snapshot).GetSourceSpans();\n+        }\n \n-            int IComparer<ReplSpan>.Compare(ReplSpan x, ReplSpan y)\n+        private int GetPromptIndexForPoint(ReadOnlyCollection<SnapshotSpan> sourceSpans, SnapshotPoint point)\n+        {\n+            int index = BinarySearch(\n+                sourceSpans,\n+                sourceSpan =>\n+                {\n+                    var start = _textView.BufferGraph.MapUpToBuffer(sourceSpan.Start, PointTrackingMode.Positive, PositionAffinity.Successor, _projectionBuffer);\n+                    Debug.Assert(start != null);\n+                    if (point < start.Value)\n+                    {\n+                        return -1;\n+                    }\n+                    var end = _textView.BufferGraph.MapUpToBuffer(sourceSpan.End, PointTrackingMode.Positive, PositionAffinity.Successor, _projectionBuffer);\n+                    Debug.Assert(end != null);\n+                    return (point < end.Value) ? 0 : 1;\n+                });\n+\n+            if (index < 0)\n             {\n-                int comp = x.LineNumber - y.LineNumber;\n-                return comp != 0\n-                    ? comp\n-                    : GetKindOrdinal(x) - GetKindOrdinal(y);\n+                Debug.Assert(~index == sourceSpans.Count);\n+                Debug.Assert(point.Position == point.Snapshot.Length);\n+                index = ~index - 1;\n             }\n \n-            /// <summary>\n-            /// Within a given line, the order is Output &lt; Prompt &lt; Language/StdIn.\n-            /// </summary>\n-            /// <remarks>\n-            /// While, visually, it appears that every line begins with a prompt, a line\n-            /// may actually begin with an empty output prompt, because at any given time\n-            /// there must be a writable output buffer for <see cref=\"AppendOutput\"/>.\n-            /// Generally, this occurs when a submission has no output.\n-            /// </remarks>\n-            private static int GetKindOrdinal(ReplSpan span)\n+            Debug.Assert(index >= 0);\n+            Debug.Assert(index < sourceSpans.Count);\n+\n+            // Find the nearest preceding prompt.\n+            while (!IsPrompt(sourceSpans[index].Snapshot))","path":"src/InteractiveWindow/Editor/InteractiveWindow.cs","position":333,"original_position":333,"commit_id":"1404f022ccf9792fc7a98a3199740dc73cf645ce","original_commit_id":"1404f022ccf9792fc7a98a3199740dc73cf645ce","user":{"login":"amcasey","id":10508071,"avatar_url":"https://avatars.githubusercontent.com/u/10508071?v=3","gravatar_id":"","url":"https://api.github.com/users/amcasey","html_url":"https://github.com/amcasey","followers_url":"https://api.github.com/users/amcasey/followers","following_url":"https://api.github.com/users/amcasey/following{/other_user}","gists_url":"https://api.github.com/users/amcasey/gists{/gist_id}","starred_url":"https://api.github.com/users/amcasey/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/amcasey/subscriptions","organizations_url":"https://api.github.com/users/amcasey/orgs","repos_url":"https://api.github.com/users/amcasey/repos","events_url":"https://api.github.com/users/amcasey/events{/privacy}","received_events_url":"https://api.github.com/users/amcasey/received_events","type":"User","site_admin":false},"body":"It's okay to finish with a linear search because we expect the number of iterations to be small?","created_at":"2015-08-18T17:05:20Z","updated_at":"2015-08-18T17:05:20Z","html_url":"https://github.com/dotnet/roslyn/pull/4596#discussion_r37324512","pull_request_url":"https://api.github.com/repos/dotnet/roslyn/pulls/4596","_links":{"self":{"href":"https://api.github.com/repos/dotnet/roslyn/pulls/comments/37324512"},"html":{"href":"https://github.com/dotnet/roslyn/pull/4596#discussion_r37324512"},"pull_request":{"href":"https://api.github.com/repos/dotnet/roslyn/pulls/4596"}}},"pull_request":{"url":"https://api.github.com/repos/dotnet/roslyn/pulls/4596","id":42627914,"html_url":"https://github.com/dotnet/roslyn/pull/4596","diff_url":"https://github.com/dotnet/roslyn/pull/4596.diff","patch_url":"https://github.com/dotnet/roslyn/pull/4596.patch","issue_url":"https://api.github.com/repos/dotnet/roslyn/issues/4596","number":4596,"state":"open","locked":false,"title":"Remove InteractiveWindow._projectionSpans","user":{"login":"cston","id":10732005,"avatar_url":"https://avatars.githubusercontent.com/u/10732005?v=3","gravatar_id":"","url":"https://api.github.com/users/cston","html_url":"https://github.com/cston","followers_url":"https://api.github.com/users/cston/followers","following_url":"https://api.github.com/users/cston/following{/other_user}","gists_url":"https://api.github.com/users/cston/gists{/gist_id}","starred_url":"https://api.github.com/users/cston/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cston/subscriptions","organizations_url":"https://api.github.com/users/cston/orgs","repos_url":"https://api.github.com/users/cston/repos","events_url":"https://api.github.com/users/cston/events{/privacy}","received_events_url":"https://api.github.com/users/cston/received_events","type":"User","site_admin":false},"body":"Remove InteractiveWindow._projectionSpans\r\n\r\nThe spans were tracked in _projectionBuffer.CurrentSnapshot and ReplSpan.LineNumber might get out of sync if preceding buffers change size.","created_at":"2015-08-17T20:02:37Z","updated_at":"2015-08-18T17:05:20Z","closed_at":null,"merged_at":null,"merge_commit_sha":"54a138bc25df4cbfb9a4264f4dc800a7e3e0b97f","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/dotnet/roslyn/pulls/4596/commits","review_comments_url":"https://api.github.com/repos/dotnet/roslyn/pulls/4596/comments","review_comment_url":"https://api.github.com/repos/dotnet/roslyn/pulls/comments{/number}","comments_url":"https://api.github.com/repos/dotnet/roslyn/issues/4596/comments","statuses_url":"https://api.github.com/repos/dotnet/roslyn/statuses/1404f022ccf9792fc7a98a3199740dc73cf645ce","head":{"label":"cston:4546","ref":"4546","sha":"1404f022ccf9792fc7a98a3199740dc73cf645ce","user":{"login":"cston","id":10732005,"avatar_url":"https://avatars.githubusercontent.com/u/10732005?v=3","gravatar_id":"","url":"https://api.github.com/users/cston","html_url":"https://github.com/cston","followers_url":"https://api.github.com/users/cston/followers","following_url":"https://api.github.com/users/cston/following{/other_user}","gists_url":"https://api.github.com/users/cston/gists{/gist_id}","starred_url":"https://api.github.com/users/cston/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cston/subscriptions","organizations_url":"https://api.github.com/users/cston/orgs","repos_url":"https://api.github.com/users/cston/repos","events_url":"https://api.github.com/users/cston/events{/privacy}","received_events_url":"https://api.github.com/users/cston/received_events","type":"User","site_admin":false},"repo":{"id":30556803,"name":"roslyn","full_name":"cston/roslyn","owner":{"login":"cston","id":10732005,"avatar_url":"https://avatars.githubusercontent.com/u/10732005?v=3","gravatar_id":"","url":"https://api.github.com/users/cston","html_url":"https://github.com/cston","followers_url":"https://api.github.com/users/cston/followers","following_url":"https://api.github.com/users/cston/following{/other_user}","gists_url":"https://api.github.com/users/cston/gists{/gist_id}","starred_url":"https://api.github.com/users/cston/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cston/subscriptions","organizations_url":"https://api.github.com/users/cston/orgs","repos_url":"https://api.github.com/users/cston/repos","events_url":"https://api.github.com/users/cston/events{/privacy}","received_events_url":"https://api.github.com/users/cston/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/cston/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/cston/roslyn","forks_url":"https://api.github.com/repos/cston/roslyn/forks","keys_url":"https://api.github.com/repos/cston/roslyn/keys{/key_id}","collaborators_url":"https://api.github.com/repos/cston/roslyn/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/cston/roslyn/teams","hooks_url":"https://api.github.com/repos/cston/roslyn/hooks","issue_events_url":"https://api.github.com/repos/cston/roslyn/issues/events{/number}","events_url":"https://api.github.com/repos/cston/roslyn/events","assignees_url":"https://api.github.com/repos/cston/roslyn/assignees{/user}","branches_url":"https://api.github.com/repos/cston/roslyn/branches{/branch}","tags_url":"https://api.github.com/repos/cston/roslyn/tags","blobs_url":"https://api.github.com/repos/cston/roslyn/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/cston/roslyn/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/cston/roslyn/git/refs{/sha}","trees_url":"https://api.github.com/repos/cston/roslyn/git/trees{/sha}","statuses_url":"https://api.github.com/repos/cston/roslyn/statuses/{sha}","languages_url":"https://api.github.com/repos/cston/roslyn/languages","stargazers_url":"https://api.github.com/repos/cston/roslyn/stargazers","contributors_url":"https://api.github.com/repos/cston/roslyn/contributors","subscribers_url":"https://api.github.com/repos/cston/roslyn/subscribers","subscription_url":"https://api.github.com/repos/cston/roslyn/subscription","commits_url":"https://api.github.com/repos/cston/roslyn/commits{/sha}","git_commits_url":"https://api.github.com/repos/cston/roslyn/git/commits{/sha}","comments_url":"https://api.github.com/repos/cston/roslyn/comments{/number}","issue_comment_url":"https://api.github.com/repos/cston/roslyn/issues/comments{/number}","contents_url":"https://api.github.com/repos/cston/roslyn/contents/{+path}","compare_url":"https://api.github.com/repos/cston/roslyn/compare/{base}...{head}","merges_url":"https://api.github.com/repos/cston/roslyn/merges","archive_url":"https://api.github.com/repos/cston/roslyn/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/cston/roslyn/downloads","issues_url":"https://api.github.com/repos/cston/roslyn/issues{/number}","pulls_url":"https://api.github.com/repos/cston/roslyn/pulls{/number}","milestones_url":"https://api.github.com/repos/cston/roslyn/milestones{/number}","notifications_url":"https://api.github.com/repos/cston/roslyn/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/cston/roslyn/labels{/name}","releases_url":"https://api.github.com/repos/cston/roslyn/releases{/id}","created_at":"2015-02-09T20:26:55Z","updated_at":"2015-02-11T03:04:47Z","pushed_at":"2015-08-18T01:46:01Z","git_url":"git://github.com/cston/roslyn.git","ssh_url":"git@github.com:cston/roslyn.git","clone_url":"https://github.com/cston/roslyn.git","svn_url":"https://github.com/cston/roslyn","homepage":"","size":90232,"stargazers_count":0,"watchers_count":0,"language":"C#","has_issues":false,"has_downloads":true,"has_wiki":true,"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":"15c1320f433fdb95a8b0ec584a17dfd0c34bf76f","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}","created_at":"2015-01-11T02:39:03Z","updated_at":"2015-08-18T16:58:05Z","pushed_at":"2015-08-18T15:53:35Z","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":167791,"stargazers_count":3031,"watchers_count":3031,"language":"C#","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":686,"mirror_url":null,"open_issues_count":1355,"forks":686,"open_issues":1355,"watchers":3031,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/dotnet/roslyn/pulls/4596"},"html":{"href":"https://github.com/dotnet/roslyn/pull/4596"},"issue":{"href":"https://api.github.com/repos/dotnet/roslyn/issues/4596"},"comments":{"href":"https://api.github.com/repos/dotnet/roslyn/issues/4596/comments"},"review_comments":{"href":"https://api.github.com/repos/dotnet/roslyn/pulls/4596/comments"},"review_comment":{"href":"https://api.github.com/repos/dotnet/roslyn/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/dotnet/roslyn/pulls/4596/commits"},"statuses":{"href":"https://api.github.com/repos/dotnet/roslyn/statuses/1404f022ccf9792fc7a98a3199740dc73cf645ce"}}}}