Skip to content

Commit b65fe82

Browse files
committed
fix: require line-start anchor in thinking section title pattern to prevent ghost sections
1 parent 11f342d commit b65fe82

2 files changed

Lines changed: 45 additions & 1 deletion

File tree

com.microsoft.copilot.eclipse.ui.test/src/com/microsoft/copilot/eclipse/ui/chat/ThinkingBlockParseTest.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,49 @@ void parseSections_handlesLfOnlyTitleBoundary() throws Exception {
6262
assertEquals("plan body", body(sections.get(1)));
6363
}
6464

65+
@Test
66+
void parseSections_inlineBoldNotTreatedAsTitle() throws Exception {
67+
// Inline bold at end of string should NOT be parsed as a section title.
68+
String raw = "combined with **The Ship of Theseus**";
69+
List<?> sections = invokeParseSections(raw);
70+
assertEquals(1, sections.size());
71+
assertNull(title(sections.get(0)));
72+
assertEquals("combined with **The Ship of Theseus**", body(sections.get(0)));
73+
}
74+
75+
@Test
76+
void parseSections_inlineBoldFollowedByText() throws Exception {
77+
// Inline bold mid-line should remain as body text.
78+
String raw = "text with **bold** and more text";
79+
List<?> sections = invokeParseSections(raw);
80+
assertEquals(1, sections.size());
81+
assertNull(title(sections.get(0)));
82+
assertEquals("text with **bold** and more text", body(sections.get(0)));
83+
}
84+
85+
@Test
86+
void parseSections_mixOfInlineBoldAndStandaloneTitle() throws Exception {
87+
// Inline bold on one line, standalone title on next line.
88+
String raw = "text with **inline bold** here\n**Standalone Title**\nbody after title";
89+
List<?> sections = invokeParseSections(raw);
90+
assertEquals(2, sections.size());
91+
assertNull(title(sections.get(0)));
92+
assertEquals("text with **inline bold** here", body(sections.get(0)));
93+
assertEquals("Standalone Title", title(sections.get(1)));
94+
assertEquals("body after title", body(sections.get(1)));
95+
}
96+
97+
@Test
98+
void parseSections_titleAtStartOfText() throws Exception {
99+
String raw = "**First**\nbody one\n**Second**\nbody two";
100+
List<?> sections = invokeParseSections(raw);
101+
assertEquals(2, sections.size());
102+
assertEquals("First", title(sections.get(0)));
103+
assertEquals("body one", body(sections.get(0)));
104+
assertEquals("Second", title(sections.get(1)));
105+
assertEquals("body two", body(sections.get(1)));
106+
}
107+
65108
private static String invokeStripTrailingNewlines(String input) throws Exception {
66109
Method m = ThinkingBlock.class.getDeclaredMethod("stripTrailingNewlines", String.class);
67110
m.setAccessible(true);

com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/chat/ThinkingBlock.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@
3434
*/
3535
public class ThinkingBlock extends Composite {
3636
private static final String SECONDARY_TEXT_CSS_CLASS = "text-secondary";
37-
private static final Pattern TITLE_PATTERN = Pattern.compile("\\*\\*([^*\\r\\n]+?)\\*\\*(?=\\r?\\n|$)");
37+
private static final Pattern TITLE_PATTERN =
38+
Pattern.compile("(?:^|\\n)\\*\\*([^*\\r\\n]+?)\\*\\*(?=\\r?\\n|$)");
3839

3940
private Composite header;
4041
private Label iconLabel;

0 commit comments

Comments
 (0)