@theia/ai-chat-ui 1.76.0-next.6 → 1.76.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/lib/browser/ai-chat-ui-frontend-module.d.ts.map +1 -1
  2. package/lib/browser/ai-chat-ui-frontend-module.js +6 -0
  3. package/lib/browser/ai-chat-ui-frontend-module.js.map +1 -1
  4. package/lib/browser/chat-find/chat-find-contribution.d.ts +18 -0
  5. package/lib/browser/chat-find/chat-find-contribution.d.ts.map +1 -0
  6. package/lib/browser/chat-find/chat-find-contribution.js +76 -0
  7. package/lib/browser/chat-find/chat-find-contribution.js.map +1 -0
  8. package/lib/browser/chat-find/chat-find-highlighter.d.ts +114 -0
  9. package/lib/browser/chat-find/chat-find-highlighter.d.ts.map +1 -0
  10. package/lib/browser/chat-find/chat-find-highlighter.js +353 -0
  11. package/lib/browser/chat-find/chat-find-highlighter.js.map +1 -0
  12. package/lib/browser/chat-find/chat-find-highlighter.spec.d.ts +2 -0
  13. package/lib/browser/chat-find/chat-find-highlighter.spec.d.ts.map +1 -0
  14. package/lib/browser/chat-find/chat-find-highlighter.spec.js +283 -0
  15. package/lib/browser/chat-find/chat-find-highlighter.spec.js.map +1 -0
  16. package/lib/browser/chat-find/chat-find-matcher.d.ts +72 -0
  17. package/lib/browser/chat-find/chat-find-matcher.d.ts.map +1 -0
  18. package/lib/browser/chat-find/chat-find-matcher.js +168 -0
  19. package/lib/browser/chat-find/chat-find-matcher.js.map +1 -0
  20. package/lib/browser/chat-find/chat-find-matcher.spec.d.ts +2 -0
  21. package/lib/browser/chat-find/chat-find-matcher.spec.d.ts.map +1 -0
  22. package/lib/browser/chat-find/chat-find-matcher.spec.js +145 -0
  23. package/lib/browser/chat-find/chat-find-matcher.spec.js.map +1 -0
  24. package/lib/browser/chat-find/chat-find-text.d.ts +20 -0
  25. package/lib/browser/chat-find/chat-find-text.d.ts.map +1 -0
  26. package/lib/browser/chat-find/chat-find-text.js +56 -0
  27. package/lib/browser/chat-find/chat-find-text.js.map +1 -0
  28. package/lib/browser/chat-find/chat-find-widget.d.ts +96 -0
  29. package/lib/browser/chat-find/chat-find-widget.d.ts.map +1 -0
  30. package/lib/browser/chat-find/chat-find-widget.js +332 -0
  31. package/lib/browser/chat-find/chat-find-widget.js.map +1 -0
  32. package/lib/browser/chat-find/chat-find-widget.spec.d.ts +2 -0
  33. package/lib/browser/chat-find/chat-find-widget.spec.d.ts.map +1 -0
  34. package/lib/browser/chat-find/chat-find-widget.spec.js +236 -0
  35. package/lib/browser/chat-find/chat-find-widget.spec.js.map +1 -0
  36. package/lib/browser/chat-input-scroll-util.d.ts +7 -0
  37. package/lib/browser/chat-input-scroll-util.d.ts.map +1 -0
  38. package/lib/browser/chat-input-scroll-util.js +33 -0
  39. package/lib/browser/chat-input-scroll-util.js.map +1 -0
  40. package/lib/browser/chat-input-scroll-util.spec.d.ts +2 -0
  41. package/lib/browser/chat-input-scroll-util.spec.d.ts.map +1 -0
  42. package/lib/browser/chat-input-scroll-util.spec.js +38 -0
  43. package/lib/browser/chat-input-scroll-util.spec.js.map +1 -0
  44. package/lib/browser/chat-input-widget.d.ts +21 -3
  45. package/lib/browser/chat-input-widget.d.ts.map +1 -1
  46. package/lib/browser/chat-input-widget.js +109 -50
  47. package/lib/browser/chat-input-widget.js.map +1 -1
  48. package/lib/browser/chat-input-widget.spec.js +21 -0
  49. package/lib/browser/chat-input-widget.spec.js.map +1 -1
  50. package/lib/browser/chat-response-renderer/code-part-renderer.d.ts.map +1 -1
  51. package/lib/browser/chat-response-renderer/code-part-renderer.js +9 -1
  52. package/lib/browser/chat-response-renderer/code-part-renderer.js.map +1 -1
  53. package/lib/browser/chat-response-renderer/code-wrapper-editors.d.ts +13 -0
  54. package/lib/browser/chat-response-renderer/code-wrapper-editors.d.ts.map +1 -0
  55. package/lib/browser/chat-response-renderer/code-wrapper-editors.js +41 -0
  56. package/lib/browser/chat-response-renderer/code-wrapper-editors.js.map +1 -0
  57. package/lib/browser/chat-response-renderer/delegation-tool-renderer.js +74 -43
  58. package/lib/browser/chat-response-renderer/delegation-tool-renderer.js.map +1 -1
  59. package/lib/browser/chat-response-renderer/index.d.ts +1 -0
  60. package/lib/browser/chat-response-renderer/index.d.ts.map +1 -1
  61. package/lib/browser/chat-response-renderer/index.js +1 -0
  62. package/lib/browser/chat-response-renderer/index.js.map +1 -1
  63. package/lib/browser/chat-response-renderer/markdown-part-renderer.d.ts +9 -0
  64. package/lib/browser/chat-response-renderer/markdown-part-renderer.d.ts.map +1 -1
  65. package/lib/browser/chat-response-renderer/markdown-part-renderer.js +34 -16
  66. package/lib/browser/chat-response-renderer/markdown-part-renderer.js.map +1 -1
  67. package/lib/browser/chat-response-renderer/server-toolcall-part-renderer.d.ts.map +1 -1
  68. package/lib/browser/chat-response-renderer/server-toolcall-part-renderer.js +2 -2
  69. package/lib/browser/chat-response-renderer/server-toolcall-part-renderer.js.map +1 -1
  70. package/lib/browser/chat-response-renderer/spinner.d.ts +3 -0
  71. package/lib/browser/chat-response-renderer/spinner.d.ts.map +1 -0
  72. package/lib/browser/chat-response-renderer/spinner.js +24 -0
  73. package/lib/browser/chat-response-renderer/spinner.js.map +1 -0
  74. package/lib/browser/chat-response-renderer/thinking-part-renderer.d.ts +9 -1
  75. package/lib/browser/chat-response-renderer/thinking-part-renderer.d.ts.map +1 -1
  76. package/lib/browser/chat-response-renderer/thinking-part-renderer.js +93 -2
  77. package/lib/browser/chat-response-renderer/thinking-part-renderer.js.map +1 -1
  78. package/lib/browser/chat-response-renderer/thinking-part-renderer.spec.d.ts +2 -0
  79. package/lib/browser/chat-response-renderer/thinking-part-renderer.spec.d.ts.map +1 -0
  80. package/lib/browser/chat-response-renderer/thinking-part-renderer.spec.js +84 -0
  81. package/lib/browser/chat-response-renderer/thinking-part-renderer.spec.js.map +1 -0
  82. package/lib/browser/chat-response-renderer/toolcall-part-renderer.d.ts.map +1 -1
  83. package/lib/browser/chat-response-renderer/toolcall-part-renderer.js +2 -2
  84. package/lib/browser/chat-response-renderer/toolcall-part-renderer.js.map +1 -1
  85. package/lib/browser/chat-response-renderer/toolcall-part-renderer.spec.js +16 -0
  86. package/lib/browser/chat-response-renderer/toolcall-part-renderer.spec.js.map +1 -1
  87. package/lib/browser/chat-response-renderer/toolcall-utils.d.ts.map +1 -1
  88. package/lib/browser/chat-response-renderer/toolcall-utils.js +7 -2
  89. package/lib/browser/chat-response-renderer/toolcall-utils.js.map +1 -1
  90. package/lib/browser/chat-tree-view/chat-view-tree-container.d.ts.map +1 -1
  91. package/lib/browser/chat-tree-view/chat-view-tree-container.js +4 -0
  92. package/lib/browser/chat-tree-view/chat-view-tree-container.js.map +1 -1
  93. package/lib/browser/chat-tree-view/chat-view-tree-widget.d.ts +20 -1
  94. package/lib/browser/chat-tree-view/chat-view-tree-widget.d.ts.map +1 -1
  95. package/lib/browser/chat-tree-view/chat-view-tree-widget.js +88 -7
  96. package/lib/browser/chat-tree-view/chat-view-tree-widget.js.map +1 -1
  97. package/lib/common/toolcall-utils.d.ts +11 -1
  98. package/lib/common/toolcall-utils.d.ts.map +1 -1
  99. package/lib/common/toolcall-utils.js +191 -9
  100. package/lib/common/toolcall-utils.js.map +1 -1
  101. package/lib/common/toolcall-utils.spec.js +92 -4
  102. package/lib/common/toolcall-utils.spec.js.map +1 -1
  103. package/package.json +13 -13
  104. package/src/browser/ai-chat-ui-frontend-module.ts +7 -0
  105. package/src/browser/chat-find/chat-find-contribution.ts +74 -0
  106. package/src/browser/chat-find/chat-find-highlighter.spec.ts +313 -0
  107. package/src/browser/chat-find/chat-find-highlighter.ts +385 -0
  108. package/src/browser/chat-find/chat-find-matcher.spec.ts +173 -0
  109. package/src/browser/chat-find/chat-find-matcher.ts +197 -0
  110. package/src/browser/chat-find/chat-find-text.ts +65 -0
  111. package/src/browser/chat-find/chat-find-widget.spec.tsx +261 -0
  112. package/src/browser/chat-find/chat-find-widget.tsx +418 -0
  113. package/src/browser/chat-input-scroll-util.spec.ts +42 -0
  114. package/src/browser/chat-input-scroll-util.ts +30 -0
  115. package/src/browser/chat-input-widget.spec.ts +29 -0
  116. package/src/browser/chat-input-widget.tsx +118 -56
  117. package/src/browser/chat-response-renderer/code-part-renderer.tsx +9 -1
  118. package/src/browser/chat-response-renderer/code-wrapper-editors.ts +41 -0
  119. package/src/browser/chat-response-renderer/delegation-tool-renderer.tsx +88 -62
  120. package/src/browser/chat-response-renderer/index.ts +1 -0
  121. package/src/browser/chat-response-renderer/markdown-part-renderer.tsx +34 -17
  122. package/src/browser/chat-response-renderer/server-toolcall-part-renderer.tsx +2 -5
  123. package/src/browser/chat-response-renderer/spinner.tsx +22 -0
  124. package/src/browser/chat-response-renderer/thinking-part-renderer.spec.tsx +104 -0
  125. package/src/browser/chat-response-renderer/thinking-part-renderer.tsx +129 -9
  126. package/src/browser/chat-response-renderer/toolcall-part-renderer.spec.ts +16 -0
  127. package/src/browser/chat-response-renderer/toolcall-part-renderer.tsx +1 -4
  128. package/src/browser/chat-response-renderer/toolcall-utils.ts +5 -0
  129. package/src/browser/chat-tree-view/chat-view-tree-container.ts +4 -0
  130. package/src/browser/chat-tree-view/chat-view-tree-widget.tsx +99 -6
  131. package/src/browser/style/chat-find.css +107 -0
  132. package/src/browser/style/index.css +75 -8
  133. package/src/common/toolcall-utils.spec.ts +113 -4
  134. package/src/common/toolcall-utils.ts +207 -9
@@ -0,0 +1,283 @@
1
+ "use strict";
2
+ // *****************************************************************************
3
+ // Copyright (C) 2026 Safi Seid-Ahmad, K2view and others.
4
+ //
5
+ // This program and the accompanying materials are made available under the
6
+ // terms of the Eclipse Public License v. 2.0 which is available at
7
+ // http://www.eclipse.org/legal/epl-2.0.
8
+ //
9
+ // This Source Code may also be made available under the following Secondary
10
+ // Licenses when the conditions for such availability set forth in the Eclipse
11
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
12
+ // with the GNU Classpath Exception which is available at
13
+ // https://www.gnu.org/software/classpath/license.html.
14
+ //
15
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
16
+ // *****************************************************************************
17
+ var TestHighlighter_1;
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ const tslib_1 = require("tslib");
20
+ const jsdom_1 = require("@theia/core/lib/browser/test/jsdom");
21
+ let disableJSDOM = (0, jsdom_1.enableJSDOM)();
22
+ const chai_1 = require("chai");
23
+ const inversify_1 = require("@theia/core/shared/inversify");
24
+ const code_wrapper_editors_1 = require("../chat-response-renderer/code-wrapper-editors");
25
+ const chat_find_highlighter_1 = require("./chat-find-highlighter");
26
+ const chat_find_matcher_1 = require("./chat-find-matcher");
27
+ disableJSDOM();
28
+ class FakeRegistry {
29
+ constructor() {
30
+ this.highlights = new Map();
31
+ }
32
+ set(name, ranges) {
33
+ this.highlights.set(name, ranges);
34
+ }
35
+ delete(name) {
36
+ this.highlights.delete(name);
37
+ }
38
+ texts(name) {
39
+ return (this.highlights.get(name) ?? []).map(range => range.toString());
40
+ }
41
+ }
42
+ let TestHighlighter = class TestHighlighter extends chat_find_highlighter_1.ChatFindHighlighter {
43
+ static { TestHighlighter_1 = this; }
44
+ createRegistry() {
45
+ return TestHighlighter_1.registry;
46
+ }
47
+ };
48
+ TestHighlighter = TestHighlighter_1 = tslib_1.__decorate([
49
+ (0, inversify_1.injectable)()
50
+ ], TestHighlighter);
51
+ function createHighlighter(registry) {
52
+ TestHighlighter.registry = registry;
53
+ const container = new inversify_1.Container();
54
+ container.bind(chat_find_matcher_1.ChatFindMatcher).toSelf().inSingletonScope();
55
+ container.bind(TestHighlighter).toSelf();
56
+ return container.get(TestHighlighter);
57
+ }
58
+ /** A stand-in for the editor of a code part: offsets are used as columns of a single line. */
59
+ function fakeEditor() {
60
+ let decorations = [];
61
+ let sets = 0;
62
+ const collection = {
63
+ set: (items) => {
64
+ sets++;
65
+ decorations = items.map(item => ({ start: item.range.startColumn - 1, end: item.range.endColumn - 1, className: item.options.className }));
66
+ },
67
+ clear: () => { decorations = []; }
68
+ };
69
+ const editor = {
70
+ document: { textEditorModel: { getPositionAt: (offset) => ({ lineNumber: 1, column: offset + 1 }), getVersionId: () => 1 } },
71
+ getControl: () => ({ createDecorationsCollection: () => collection })
72
+ };
73
+ return { editor, decorations: () => decorations, setCount: () => sets };
74
+ }
75
+ /** Gives an element the layout jsdom does not compute. */
76
+ function layout(element, rect) {
77
+ element.getBoundingClientRect = () => ({
78
+ top: rect.top, bottom: rect.top + rect.height, height: rect.height,
79
+ left: 0, right: 0, width: 0, x: 0, y: rect.top, toJSON: () => ({})
80
+ });
81
+ }
82
+ function scrollable(element, scrollHeight, clientHeight) {
83
+ element.style.overflowY = 'auto';
84
+ Object.defineProperty(element, 'scrollHeight', { value: scrollHeight, configurable: true });
85
+ Object.defineProperty(element, 'clientHeight', { value: clientHeight, configurable: true });
86
+ }
87
+ describe('ChatFindHighlighter', () => {
88
+ let root;
89
+ let registry;
90
+ let highlighter;
91
+ const requestMatch = (occurrence) => ({ nodeId: 'r1', kind: chat_find_matcher_1.ChatFindMatch.REQUEST_KIND, occurrence, start: 0, end: 7 });
92
+ // Offsets of 'find me and find me', the text of content 1.
93
+ const contentMatch = (contentIndex, occurrence, kind = 'markdownContent') => ({ nodeId: 'r1-response', kind, contentIndex, occurrence, start: occurrence * 12, end: occurrence * 12 + 7 });
94
+ before(() => disableJSDOM = (0, jsdom_1.enableJSDOM)());
95
+ after(() => disableJSDOM());
96
+ beforeEach(() => {
97
+ root = document.createElement('div');
98
+ document.body.appendChild(root);
99
+ root.innerHTML = `
100
+ <div data-node-id="r1"><div class="theia-RequestNode"><p><span>find </span><span>me</span></p></div></div>
101
+ <div data-node-id="r1-response"><div class="theia-ResponseNode">
102
+ <div class="theia-ResponseNode-Content"><p>a tool call that would find me too</p></div>
103
+ <div class="theia-ResponseNode-Content"><p>find <strong>me</strong> and find me</p></div>
104
+ </div></div>`;
105
+ registry = new FakeRegistry();
106
+ highlighter = createHighlighter(registry);
107
+ });
108
+ afterEach(() => {
109
+ highlighter.dispose();
110
+ document.body.removeChild(root);
111
+ });
112
+ it('highlights only the content the matcher searched, never unsearched parts', () => {
113
+ // The matcher skips tool calls, reasoning and delegated sub-chats, so content 0 has no matches.
114
+ highlighter.update(root, /find me/gi, [contentMatch(1, 0), contentMatch(1, 1)], undefined);
115
+ const ranges = registry.highlights.get(chat_find_highlighter_1.ChatFindHighlighter.MATCH_HIGHLIGHT);
116
+ const contents = root.querySelectorAll('.theia-ResponseNode-Content');
117
+ (0, chai_1.expect)(ranges).to.have.length(2);
118
+ (0, chai_1.expect)(ranges.every(r => contents[1].contains(r.startContainer))).to.be.true;
119
+ (0, chai_1.expect)(ranges.some(r => contents[0].contains(r.startContainer))).to.be.false;
120
+ });
121
+ it('resolves content parts among the row\'s own nodes, not those of a delegated sub-chat inside a part', () => {
122
+ // A delegation renders the sub-chat's response node inline (collapsed) inside the outer content element.
123
+ root.querySelectorAll('.theia-ResponseNode-Content')[0].innerHTML = '<details><div class="theia-ResponseNode">' +
124
+ '<div class="theia-ResponseNode-Content"><p>find me in the sub-chat</p></div></div></details>';
125
+ const match = contentMatch(1, 0);
126
+ highlighter.update(root, /find me/gi, [match], match);
127
+ const inSubChat = (range) => !!range.startContainer.parentElement.closest('details');
128
+ const ranges = registry.highlights.get(chat_find_highlighter_1.ChatFindHighlighter.MATCH_HIGHLIGHT);
129
+ (0, chai_1.expect)(ranges).to.have.length(2);
130
+ (0, chai_1.expect)(ranges.some(inSubChat)).to.be.false;
131
+ const current = registry.highlights.get(chat_find_highlighter_1.ChatFindHighlighter.CURRENT_HIGHLIGHT);
132
+ (0, chai_1.expect)(current.map(range => range.toString())).to.deep.equal(['find me']);
133
+ (0, chai_1.expect)(current.some(inSubChat)).to.be.false;
134
+ });
135
+ it('does not highlight text inside <style> or <script>, e.g. a diagram stylesheet', () => {
136
+ root.querySelectorAll('.theia-ResponseNode-Content')[1].innerHTML =
137
+ '<svg><style>.find-me-node{fill:#fff}</style>' +
138
+ '<foreignObject><div><span>find me</span></div></foreignObject></svg>' +
139
+ '<script>const findMe = "find me";</script>';
140
+ highlighter.update(root, /find me/gi, [contentMatch(1, 0)], undefined);
141
+ const ranges = registry.highlights.get(chat_find_highlighter_1.ChatFindHighlighter.MATCH_HIGHLIGHT);
142
+ (0, chai_1.expect)(ranges).to.have.length(1);
143
+ (0, chai_1.expect)(ranges[0].startContainer.parentElement.nodeName.toLowerCase()).to.equal('span');
144
+ });
145
+ it('highlights request text when the match belongs to a request row', () => {
146
+ highlighter.update(root, /find me/gi, [requestMatch(0)], undefined);
147
+ (0, chai_1.expect)(registry.texts(chat_find_highlighter_1.ChatFindHighlighter.MATCH_HIGHLIGHT)).to.deep.equal(['find me']);
148
+ });
149
+ it('marks the current match by content index and occurrence', () => {
150
+ highlighter.update(root, /find me/gi, [contentMatch(1, 0), contentMatch(1, 1)], contentMatch(1, 1));
151
+ const current = registry.highlights.get(chat_find_highlighter_1.ChatFindHighlighter.CURRENT_HIGHLIGHT);
152
+ (0, chai_1.expect)(current).to.have.length(1);
153
+ (0, chai_1.expect)(current[0].toString()).to.equal('find me');
154
+ // the second occurrence lives in the trailing text node ' and find me'
155
+ (0, chai_1.expect)(current[0].startOffset).to.equal(5);
156
+ });
157
+ it('marks the current match by its offsets, not by counting occurrences in the DOM', () => {
158
+ // The DOM holds an occurrence the match list does not (e.g. still being streamed): offsets still pick the right one.
159
+ root.querySelectorAll('.theia-ResponseNode-Content')[1].innerHTML = '<p>find me <em>and</em> find me</p>';
160
+ const second = { ...contentMatch(1, 0), start: 12, end: 19 };
161
+ highlighter.update(root, /find me/gi, [second], second);
162
+ const current = registry.highlights.get(chat_find_highlighter_1.ChatFindHighlighter.CURRENT_HIGHLIGHT);
163
+ (0, chai_1.expect)(current).to.have.length(1);
164
+ (0, chai_1.expect)(current[0].startContainer.textContent).to.equal(' find me');
165
+ });
166
+ it('marks nothing as current when the DOM has no such occurrence', () => {
167
+ highlighter.update(root, /find me/gi, [contentMatch(1, 5)], contentMatch(1, 5));
168
+ (0, chai_1.expect)(registry.highlights.get(chat_find_highlighter_1.ChatFindHighlighter.CURRENT_HIGHLIGHT)).to.deep.equal([]);
169
+ });
170
+ it('searches only the message of an error part', () => {
171
+ root.querySelectorAll('.theia-ResponseNode-Content')[1].innerHTML = '<div class="theia-ChatPart-Error">' +
172
+ '<div class="theia-ChatPart-Error-headline"><div class="theia-ChatPart-Error-prefix">Error find me:</div>' +
173
+ '<div class="theia-ChatPart-Error-message">find me</div></div><details><pre>find me</pre></details></div>';
174
+ const match = contentMatch(1, 0, 'error');
175
+ highlighter.update(root, /find me/gi, [match], match);
176
+ const ranges = registry.highlights.get(chat_find_highlighter_1.ChatFindHighlighter.MATCH_HIGHLIGHT);
177
+ (0, chai_1.expect)(ranges).to.have.length(1);
178
+ (0, chai_1.expect)(ranges[0].startContainer.parentElement.className).to.equal('theia-ChatPart-Error-message');
179
+ });
180
+ it('skips blocked-resource placeholders and treats non-breaking spaces as spaces', () => {
181
+ root.querySelectorAll('.theia-ResponseNode-Content')[1].innerHTML =
182
+ '<p><span class="theia-blocked-resource">find me</span>find\u00a0me</p>';
183
+ highlighter.update(root, /find me/gi, [contentMatch(1, 0)], contentMatch(1, 0));
184
+ const ranges = registry.highlights.get(chat_find_highlighter_1.ChatFindHighlighter.MATCH_HIGHLIGHT);
185
+ (0, chai_1.expect)(ranges).to.have.length(1);
186
+ (0, chai_1.expect)(ranges[0].startContainer.parentElement.nodeName.toLowerCase()).to.equal('p');
187
+ (0, chai_1.expect)(registry.highlights.get(chat_find_highlighter_1.ChatFindHighlighter.CURRENT_HIGHLIGHT)).to.have.length(1);
188
+ });
189
+ describe('code parts', () => {
190
+ let wrapper;
191
+ let fake;
192
+ beforeEach(() => {
193
+ root.querySelectorAll('.theia-ResponseNode-Content')[1].innerHTML =
194
+ `<div class="theia-CodePartRenderer-root"><div class="${code_wrapper_editors_1.CodeWrapperEditors.CLASS}"><span>find\u00a0me</span></div></div>`;
195
+ wrapper = root.querySelector(`.${code_wrapper_editors_1.CodeWrapperEditors.CLASS}`);
196
+ fake = fakeEditor();
197
+ code_wrapper_editors_1.CodeWrapperEditors.set(wrapper, fake.editor);
198
+ });
199
+ it('decorates matches in the editor instead of highlighting its DOM', () => {
200
+ const first = contentMatch(1, 0, 'code');
201
+ const second = contentMatch(1, 1, 'code');
202
+ highlighter.update(root, /find me/gi, [first, second], second);
203
+ (0, chai_1.expect)(fake.decorations()).to.deep.equal([
204
+ { start: 0, end: 7, className: 'findMatch' },
205
+ { start: 12, end: 19, className: 'currentFindMatch' }
206
+ ]);
207
+ (0, chai_1.expect)(registry.highlights.get(chat_find_highlighter_1.ChatFindHighlighter.MATCH_HIGHLIGHT)).to.deep.equal([]);
208
+ (0, chai_1.expect)(registry.highlights.get(chat_find_highlighter_1.ChatFindHighlighter.CURRENT_HIGHLIGHT)).to.deep.equal([]);
209
+ });
210
+ it('does not set unchanged decorations again, so decorating does not loop through the mutation observer', () => {
211
+ const match = contentMatch(1, 0, 'code');
212
+ highlighter.update(root, /find me/gi, [match], match);
213
+ highlighter.refresh();
214
+ (0, chai_1.expect)(fake.setCount()).to.equal(1);
215
+ });
216
+ it('clears the decorations when the find is cleared', () => {
217
+ highlighter.update(root, /find me/gi, [contentMatch(1, 0, 'code')], undefined);
218
+ highlighter.update(root, undefined, [], undefined);
219
+ (0, chai_1.expect)(fake.decorations()).to.deep.equal([]);
220
+ });
221
+ });
222
+ it('clears both highlights when the regexp is removed', () => {
223
+ highlighter.update(root, /find/gi, [contentMatch(1, 0)], undefined);
224
+ highlighter.update(root, undefined, [], undefined);
225
+ (0, chai_1.expect)(registry.highlights.has(chat_find_highlighter_1.ChatFindHighlighter.MATCH_HIGHLIGHT)).to.be.false;
226
+ (0, chai_1.expect)(registry.highlights.has(chat_find_highlighter_1.ChatFindHighlighter.CURRENT_HIGHLIGHT)).to.be.false;
227
+ });
228
+ it('does nothing without a registry', () => {
229
+ const noop = createHighlighter(undefined);
230
+ noop.update(root, /find/gi, [contentMatch(1, 0)], undefined);
231
+ noop.dispose();
232
+ (0, chai_1.expect)(registry.highlights.size).to.equal(0);
233
+ });
234
+ it('re-applies after DOM mutations', async () => {
235
+ highlighter.update(root, /find/gi, [contentMatch(1, 0), contentMatch(1, 1)], undefined);
236
+ const before = registry.texts(chat_find_highlighter_1.ChatFindHighlighter.MATCH_HIGHLIGHT).length;
237
+ root.querySelectorAll('.theia-ResponseNode-Content')[1].insertAdjacentHTML('beforeend', '<p>find again</p>');
238
+ await new Promise(resolve => setTimeout(resolve, 50));
239
+ (0, chai_1.expect)(registry.texts(chat_find_highlighter_1.ChatFindHighlighter.MATCH_HIGHLIGHT).length).to.equal(before + 1);
240
+ });
241
+ describe('scrollCurrentIntoView', () => {
242
+ let outer;
243
+ let scroller;
244
+ let scrollIntoViewCalls;
245
+ beforeEach(() => {
246
+ scrollIntoViewCalls = 0;
247
+ Element.prototype.scrollIntoView = function () { scrollIntoViewCalls++; };
248
+ // An element outside the root that must never be scrolled (stands in for the Theia shell).
249
+ outer = document.createElement('div');
250
+ scrollable(outer, 2000, 400);
251
+ document.body.appendChild(outer);
252
+ outer.appendChild(root);
253
+ // The tree's own scroll container, inside the root.
254
+ scroller = document.createElement('div');
255
+ scrollable(scroller, 1000, 200);
256
+ layout(scroller, { top: 0, height: 200 });
257
+ root.insertBefore(scroller, root.firstChild);
258
+ scroller.innerHTML = '<div data-node-id="r9"><div class="theia-ResponseNode">' +
259
+ '<div class="theia-ResponseNode-Content"><p>find me</p></div></div></div>';
260
+ });
261
+ afterEach(() => {
262
+ document.body.removeChild(outer);
263
+ document.body.appendChild(root);
264
+ });
265
+ const match = () => ({ nodeId: 'r9', kind: 'markdownContent', contentIndex: 0, occurrence: 0, start: 0, end: 7 });
266
+ it('scrolls the tree scroll container and never an ancestor outside the root', () => {
267
+ layout(scroller.querySelector('p'), { top: 500, height: 20 });
268
+ highlighter.update(root, /find me/gi, [match()], match());
269
+ highlighter.scrollCurrentIntoView(root);
270
+ (0, chai_1.expect)(scroller.scrollTop).to.equal(410); // 500 - (200 - 20) / 2
271
+ (0, chai_1.expect)(outer.scrollTop).to.equal(0);
272
+ (0, chai_1.expect)(scrollIntoViewCalls).to.equal(0);
273
+ });
274
+ it('leaves the scroll position alone when the match is already visible', () => {
275
+ layout(scroller.querySelector('p'), { top: 50, height: 20 });
276
+ scroller.scrollTop = 120;
277
+ highlighter.update(root, /find me/gi, [match()], match());
278
+ highlighter.scrollCurrentIntoView(root);
279
+ (0, chai_1.expect)(scroller.scrollTop).to.equal(120);
280
+ });
281
+ });
282
+ });
283
+ //# sourceMappingURL=chat-find-highlighter.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-find-highlighter.spec.js","sourceRoot":"","sources":["../../../src/browser/chat-find/chat-find-highlighter.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,72 @@
1
+ import { ChatModel, ChatRequestModel, ChatResponseContent } from '@theia/ai-chat/lib/common';
2
+ export interface ChatFindOptions {
3
+ matchCase: boolean;
4
+ wholeWord: boolean;
5
+ useRegex: boolean;
6
+ }
7
+ export interface ChatFindTextRange {
8
+ start: number;
9
+ end: number;
10
+ }
11
+ /**
12
+ * A match of the find query inside a chat session, located by the tree node that renders it.
13
+ */
14
+ export interface ChatFindMatch extends ChatFindTextRange {
15
+ /** Id of the tree node rendering the matched text: the request id or the response id. */
16
+ nodeId: string;
17
+ /** The `kind` of the matched response part, or {@link ChatFindMatch.REQUEST_KIND} for request text. */
18
+ kind: string;
19
+ /** Index into `response.response.content`; `undefined` for request text. */
20
+ contentIndex?: number;
21
+ /** 0-based index of this match among all matches inside the same text. */
22
+ occurrence: number;
23
+ }
24
+ export declare namespace ChatFindMatch {
25
+ const REQUEST_KIND = "request";
26
+ /** Stable identity of a match across recomputations of the match list. */
27
+ function key(match: ChatFindMatch): string;
28
+ }
29
+ /**
30
+ * Computes find matches over a chat session model. Only the displayed branch (`model.getRequests()`) is searched.
31
+ *
32
+ * Text is searched as it is rendered, not as it is stored: markdown is rendered the way the chat renders it and
33
+ * its text read with {@link ChatFindText}, the same way the highlighter reads the mounted DOM, so match offsets
34
+ * are valid in both. Subclass and override {@link getSearchableText} to search additional content kinds.
35
+ */
36
+ export declare class ChatFindMatcher {
37
+ /** VS Code's default `editor.wordSeparators`; whitespace separates words as well. */
38
+ protected static readonly WORD_SEPARATORS = "`~!@#$%^&*()-=+[{]}\\|;:'\",.<>/?";
39
+ /** Rendered text by the object it was rendered for, reused while its source text is unchanged. */
40
+ protected readonly renderedTextCache: WeakMap<object, {
41
+ source: string;
42
+ text: string;
43
+ }>;
44
+ /**
45
+ * Builds the regular expression shared by model matching and DOM highlighting.
46
+ * @returns `undefined` for an empty query or an invalid regular expression.
47
+ */
48
+ createRegExp(query: string, options: ChatFindOptions): RegExp | undefined;
49
+ /** All matches in tree order: request row, then response row, content parts in order, offsets ascending. */
50
+ findMatches(model: ChatModel, regexp: RegExp): ChatFindMatch[];
51
+ /** All non-empty occurrences of `regexp` in `text`, in order. */
52
+ findInText(text: string, regexp: RegExp): ChatFindTextRange[];
53
+ /**
54
+ * Restricts `source` to whole words the way VS Code does: each end of a match must be the end of the text, next
55
+ * to a word separator, or itself a word separator. Unlike `\b`, this also works for queries such as `C++` or `foo()`.
56
+ */
57
+ protected wrapWholeWord(source: string): string;
58
+ protected collect(matches: ChatFindMatch[], regexp: RegExp, text: string, nodeId: string, kind: string, contentIndex: number | undefined): void;
59
+ /**
60
+ * The request text as rendered by `ChatRequestRender`: agent, variable and function mentions as labels,
61
+ * text parts as inline markdown, inline image parts skipped.
62
+ */
63
+ protected getRequestText(request: ChatRequestModel): string;
64
+ /**
65
+ * The searchable text of a response part as it is rendered, or `undefined` for kinds that are not searched
66
+ * (tool calls, reasoning, progress, informational content, which the chat does not render, ...).
67
+ */
68
+ protected getSearchableText(content: ChatResponseContent): string | undefined;
69
+ /** The text of `markdown` rendered the way `useMarkdownRendering` renders it, cached per `owner`. */
70
+ protected getRenderedMarkdownText(owner: object, markdown: string, skipSurroundingParagraph: boolean, blockExternalResourceLoading: boolean): string;
71
+ }
72
+ //# sourceMappingURL=chat-find-matcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-find-matcher.d.ts","sourceRoot":"","sources":["../../../src/browser/chat-find/chat-find-matcher.ts"],"names":[],"mappings":"AAgBA,OAAO,EACH,SAAS,EAAE,gBAAgB,EAAE,mBAAmB,EAEnD,MAAM,2BAA2B,CAAC;AAUnC,MAAM,WAAW,eAAe;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,aAAc,SAAQ,iBAAiB;IACpD,yFAAyF;IACzF,MAAM,EAAE,MAAM,CAAC;IACf,uGAAuG;IACvG,IAAI,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0EAA0E;IAC1E,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,yBAAiB,aAAa,CAAC;IACpB,MAAM,YAAY,YAAY,CAAC;IAEtC,0EAA0E;IAC1E,SAAgB,GAAG,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAEhD;CACJ;AAED;;;;;;GAMG;AACH,qBACa,eAAe;IAExB,qFAAqF;IACrF,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,uCAAuC;IAEhF,kGAAkG;IAClG,SAAS,CAAC,QAAQ,CAAC,iBAAiB;gBAAiC,MAAM;cAAQ,MAAM;OAAM;IAE/F;;;OAGG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,MAAM,GAAG,SAAS;IAezE,4GAA4G;IAC5G,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,EAAE;IAc9D,iEAAiE;IACjE,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,iBAAiB,EAAE;IAe7D;;;OAGG;IACH,SAAS,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAK/C,SAAS,CAAC,OAAO,CACb,OAAO,EAAE,aAAa,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,SAAS,GACvH,IAAI;IAMP;;;OAGG;IACH,SAAS,CAAC,cAAc,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM;IAW3D;;;OAGG;IACH,SAAS,CAAC,iBAAiB,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM,GAAG,SAAS;IAoB7E,qGAAqG;IACrG,SAAS,CAAC,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,wBAAwB,EAAE,OAAO,EAAE,4BAA4B,EAAE,OAAO,GAAG,MAAM;CAUvJ"}
@@ -0,0 +1,168 @@
1
+ "use strict";
2
+ // *****************************************************************************
3
+ // Copyright (C) 2026 Safi Seid-Ahmad, K2view and others.
4
+ //
5
+ // This program and the accompanying materials are made available under the
6
+ // terms of the Eclipse Public License v. 2.0 which is available at
7
+ // http://www.eclipse.org/legal/epl-2.0.
8
+ //
9
+ // This Source Code may also be made available under the following Secondary
10
+ // Licenses when the conditions for such availability set forth in the Eclipse
11
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
12
+ // with the GNU Classpath Exception which is available at
13
+ // https://www.gnu.org/software/classpath/license.html.
14
+ //
15
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
16
+ // *****************************************************************************
17
+ var ChatFindMatcher_1;
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.ChatFindMatcher = exports.ChatFindMatch = void 0;
20
+ const tslib_1 = require("tslib");
21
+ const common_1 = require("@theia/ai-chat/lib/common");
22
+ const image_context_variable_1 = require("@theia/ai-chat/lib/common/image-context-variable");
23
+ const strings_1 = require("@theia/core/lib/common/strings");
24
+ const inversify_1 = require("@theia/core/shared/inversify");
25
+ const markdown_part_renderer_1 = require("../chat-response-renderer/markdown-part-renderer");
26
+ const chat_find_text_1 = require("./chat-find-text");
27
+ /** Language id of code parts that are rendered as a diagram instead of as source. */
28
+ const MERMAID_LANGUAGE_ID = 'mermaid';
29
+ var ChatFindMatch;
30
+ (function (ChatFindMatch) {
31
+ ChatFindMatch.REQUEST_KIND = 'request';
32
+ /** Stable identity of a match across recomputations of the match list. */
33
+ function key(match) {
34
+ return `${match.nodeId}/${match.contentIndex ?? 'request'}/${match.occurrence}`;
35
+ }
36
+ ChatFindMatch.key = key;
37
+ })(ChatFindMatch || (exports.ChatFindMatch = ChatFindMatch = {}));
38
+ /**
39
+ * Computes find matches over a chat session model. Only the displayed branch (`model.getRequests()`) is searched.
40
+ *
41
+ * Text is searched as it is rendered, not as it is stored: markdown is rendered the way the chat renders it and
42
+ * its text read with {@link ChatFindText}, the same way the highlighter reads the mounted DOM, so match offsets
43
+ * are valid in both. Subclass and override {@link getSearchableText} to search additional content kinds.
44
+ */
45
+ let ChatFindMatcher = class ChatFindMatcher {
46
+ constructor() {
47
+ /** Rendered text by the object it was rendered for, reused while its source text is unchanged. */
48
+ this.renderedTextCache = new WeakMap();
49
+ }
50
+ static { ChatFindMatcher_1 = this; }
51
+ /** VS Code's default `editor.wordSeparators`; whitespace separates words as well. */
52
+ static { this.WORD_SEPARATORS = '`~!@#$%^&*()-=+[{]}\\|;:\'",.<>/?'; }
53
+ /**
54
+ * Builds the regular expression shared by model matching and DOM highlighting.
55
+ * @returns `undefined` for an empty query or an invalid regular expression.
56
+ */
57
+ createRegExp(query, options) {
58
+ if (!query) {
59
+ return undefined;
60
+ }
61
+ let source = options.useRegex ? query : (0, strings_1.escapeRegExpCharacters)(query);
62
+ if (options.wholeWord) {
63
+ source = this.wrapWholeWord(source);
64
+ }
65
+ try {
66
+ return new RegExp(source, options.matchCase ? 'g' : 'gi');
67
+ }
68
+ catch {
69
+ return undefined;
70
+ }
71
+ }
72
+ /** All matches in tree order: request row, then response row, content parts in order, offsets ascending. */
73
+ findMatches(model, regexp) {
74
+ const matches = [];
75
+ for (const request of model.getRequests()) {
76
+ this.collect(matches, regexp, this.getRequestText(request), request.id, ChatFindMatch.REQUEST_KIND, undefined);
77
+ request.response.response.content.forEach((content, contentIndex) => {
78
+ const text = this.getSearchableText(content);
79
+ if (text) {
80
+ this.collect(matches, regexp, text, request.response.id, content.kind, contentIndex);
81
+ }
82
+ });
83
+ }
84
+ return matches;
85
+ }
86
+ /** All non-empty occurrences of `regexp` in `text`, in order. */
87
+ findInText(text, regexp) {
88
+ const ranges = [];
89
+ regexp.lastIndex = 0;
90
+ let result = regexp.exec(text);
91
+ while (result) {
92
+ if (result[0].length === 0) {
93
+ regexp.lastIndex++;
94
+ }
95
+ else {
96
+ ranges.push({ start: result.index, end: result.index + result[0].length });
97
+ }
98
+ result = regexp.exec(text);
99
+ }
100
+ return ranges;
101
+ }
102
+ /**
103
+ * Restricts `source` to whole words the way VS Code does: each end of a match must be the end of the text, next
104
+ * to a word separator, or itself a word separator. Unlike `\b`, this also works for queries such as `C++` or `foo()`.
105
+ */
106
+ wrapWholeWord(source) {
107
+ const separator = `[\\s${(0, strings_1.escapeRegExpCharacters)(ChatFindMatcher_1.WORD_SEPARATORS)}]`;
108
+ return `(?:(?<=^|${separator})|(?=${separator}))(?:${source})(?:(?=${separator}|$)|(?<=${separator}))`;
109
+ }
110
+ collect(matches, regexp, text, nodeId, kind, contentIndex) {
111
+ this.findInText(text, regexp).forEach((range, occurrence) => {
112
+ matches.push({ nodeId, kind, contentIndex, occurrence, start: range.start, end: range.end });
113
+ });
114
+ }
115
+ /**
116
+ * The request text as rendered by `ChatRequestRender`: agent, variable and function mentions as labels,
117
+ * text parts as inline markdown, inline image parts skipped.
118
+ */
119
+ getRequestText(request) {
120
+ const parts = request.message.parts;
121
+ const inlineImages = image_context_variable_1.ImageContextVariable.extractInlineImagesWithIndices(parts);
122
+ return parts
123
+ .filter((_, index) => !inlineImages.has(index))
124
+ .map(part => part.kind === 'agent' || part.kind === 'var' || part.kind === 'function'
125
+ ? chat_find_text_1.ChatFindText.normalize(part.text)
126
+ : this.getRenderedMarkdownText(part, markdown_part_renderer_1.MarkdownRendering.prepareRequestText(part.text), true, false))
127
+ .join('');
128
+ }
129
+ /**
130
+ * The searchable text of a response part as it is rendered, or `undefined` for kinds that are not searched
131
+ * (tool calls, reasoning, progress, informational content, which the chat does not render, ...).
132
+ */
133
+ getSearchableText(content) {
134
+ if (common_1.TextChatResponseContent.is(content)) {
135
+ return chat_find_text_1.ChatFindText.normalize(content.asString?.() ?? content.content);
136
+ }
137
+ if (common_1.MarkdownChatResponseContent.is(content)) {
138
+ return this.getRenderedMarkdownText(content, content.content.value, false, true);
139
+ }
140
+ if (common_1.CodeChatResponseContent.is(content)) {
141
+ // A mermaid block is rendered as a diagram rather than as its source (see MermaidPartRenderer), so its
142
+ // source text is nowhere on screen: matches in it could be counted but never highlighted or revealed.
143
+ // Other code parts are highlighted in their editor, by offsets into the code.
144
+ return content.language?.toLowerCase() === MERMAID_LANGUAGE_ID ? undefined : content.code;
145
+ }
146
+ if (common_1.ErrorChatResponseContent.is(content)) {
147
+ // Only the message of the headline; the highlighter scopes an error part to the same element.
148
+ return chat_find_text_1.ChatFindText.normalize((0, common_1.formatProviderError)(content.error.message).message);
149
+ }
150
+ return undefined;
151
+ }
152
+ /** The text of `markdown` rendered the way `useMarkdownRendering` renders it, cached per `owner`. */
153
+ getRenderedMarkdownText(owner, markdown, skipSurroundingParagraph, blockExternalResourceLoading) {
154
+ const cached = this.renderedTextCache.get(owner);
155
+ if (cached?.source === markdown) {
156
+ return cached.text;
157
+ }
158
+ const fragment = markdown_part_renderer_1.MarkdownRendering.renderToFragment(markdown, skipSurroundingParagraph, blockExternalResourceLoading);
159
+ const text = chat_find_text_1.ChatFindText.collect(fragment).text;
160
+ this.renderedTextCache.set(owner, { source: markdown, text });
161
+ return text;
162
+ }
163
+ };
164
+ exports.ChatFindMatcher = ChatFindMatcher;
165
+ exports.ChatFindMatcher = ChatFindMatcher = ChatFindMatcher_1 = tslib_1.__decorate([
166
+ (0, inversify_1.injectable)()
167
+ ], ChatFindMatcher);
168
+ //# sourceMappingURL=chat-find-matcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-find-matcher.js","sourceRoot":"","sources":["../../../src/browser/chat-find/chat-find-matcher.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,yDAAyD;AACzD,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;;;;;AAEhF,sDAGmC;AACnC,6FAAwF;AACxF,4DAAwE;AACxE,4DAA0D;AAC1D,6FAAqF;AACrF,qDAAgD;AAEhD,qFAAqF;AACrF,MAAM,mBAAmB,GAAG,SAAS,CAAC;AA2BtC,IAAiB,aAAa,CAO7B;AAPD,WAAiB,aAAa;IACb,0BAAY,GAAG,SAAS,CAAC;IAEtC,0EAA0E;IAC1E,SAAgB,GAAG,CAAC,KAAoB;QACpC,OAAO,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,YAAY,IAAI,SAAS,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;IACpF,CAAC;IAFe,iBAAG,MAElB,CAAA;AACL,CAAC,EAPgB,aAAa,6BAAb,aAAa,QAO7B;AAED;;;;;;GAMG;AAEI,IAAM,eAAe,GAArB,MAAM,eAAe;IAArB;QAKH,kGAAkG;QAC/E,sBAAiB,GAAG,IAAI,OAAO,EAA4C,CAAC;IAuHnG,CAAC;;IA3HG,qFAAqF;aAC3D,oBAAe,GAAG,mCAAmC,AAAtC,CAAuC;IAKhF;;;OAGG;IACH,YAAY,CAAC,KAAa,EAAE,OAAwB;QAChD,IAAI,CAAC,KAAK,EAAE,CAAC;YACT,OAAO,SAAS,CAAC;QACrB,CAAC;QACD,IAAI,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAA,gCAAsB,EAAC,KAAK,CAAC,CAAC;QACtE,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;YACpB,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;QACxC,CAAC;QACD,IAAI,CAAC;YACD,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC9D,CAAC;QAAC,MAAM,CAAC;YACL,OAAO,SAAS,CAAC;QACrB,CAAC;IACL,CAAC;IAED,4GAA4G;IAC5G,WAAW,CAAC,KAAgB,EAAE,MAAc;QACxC,MAAM,OAAO,GAAoB,EAAE,CAAC;QACpC,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,EAAE,aAAa,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;YAC/G,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE;gBAChE,MAAM,IAAI,GAAG,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;gBAC7C,IAAI,IAAI,EAAE,CAAC;oBACP,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;gBACzF,CAAC;YACL,CAAC,CAAC,CAAC;QACP,CAAC;QACD,OAAO,OAAO,CAAC;IACnB,CAAC;IAED,iEAAiE;IACjE,UAAU,CAAC,IAAY,EAAE,MAAc;QACnC,MAAM,MAAM,GAAwB,EAAE,CAAC;QACvC,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC;QACrB,IAAI,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,OAAO,MAAM,EAAE,CAAC;YACZ,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACzB,MAAM,CAAC,SAAS,EAAE,CAAC;YACvB,CAAC;iBAAM,CAAC;gBACJ,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;YAC/E,CAAC;YACD,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;QACD,OAAO,MAAM,CAAC;IAClB,CAAC;IAED;;;OAGG;IACO,aAAa,CAAC,MAAc;QAClC,MAAM,SAAS,GAAG,OAAO,IAAA,gCAAsB,EAAC,iBAAe,CAAC,eAAe,CAAC,GAAG,CAAC;QACpF,OAAO,YAAY,SAAS,QAAQ,SAAS,QAAQ,MAAM,UAAU,SAAS,WAAW,SAAS,IAAI,CAAC;IAC3G,CAAC;IAES,OAAO,CACb,OAAwB,EAAE,MAAc,EAAE,IAAY,EAAE,MAAc,EAAE,IAAY,EAAE,YAAgC;QAEtH,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE;YACxD,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;QACjG,CAAC,CAAC,CAAC;IACP,CAAC;IAED;;;OAGG;IACO,cAAc,CAAC,OAAyB;QAC9C,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC;QACpC,MAAM,YAAY,GAAG,6CAAoB,CAAC,8BAA8B,CAAC,KAAK,CAAC,CAAC;QAChF,OAAO,KAAK;aACP,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;aAC9C,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU;YACjF,CAAC,CAAC,6BAAY,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;YACnC,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,IAAI,EAAE,0CAAiB,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;aACtG,IAAI,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC;IAED;;;OAGG;IACO,iBAAiB,CAAC,OAA4B;QACpD,IAAI,gCAAuB,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;YACtC,OAAO,6BAAY,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;QAC3E,CAAC;QACD,IAAI,oCAA2B,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;YAC1C,OAAO,IAAI,CAAC,uBAAuB,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QACrF,CAAC;QACD,IAAI,gCAAuB,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;YACtC,uGAAuG;YACvG,sGAAsG;YACtG,8EAA8E;YAC9E,OAAO,OAAO,CAAC,QAAQ,EAAE,WAAW,EAAE,KAAK,mBAAmB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;QAC9F,CAAC;QACD,IAAI,iCAAwB,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;YACvC,8FAA8F;YAC9F,OAAO,6BAAY,CAAC,SAAS,CAAC,IAAA,4BAAmB,EAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC;QACtF,CAAC;QACD,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,qGAAqG;IAC3F,uBAAuB,CAAC,KAAa,EAAE,QAAgB,EAAE,wBAAiC,EAAE,4BAAqC;QACvI,MAAM,MAAM,GAAG,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACjD,IAAI,MAAM,EAAE,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC9B,OAAO,MAAM,CAAC,IAAI,CAAC;QACvB,CAAC;QACD,MAAM,QAAQ,GAAG,0CAAiB,CAAC,gBAAgB,CAAC,QAAQ,EAAE,wBAAwB,EAAE,4BAA4B,CAAC,CAAC;QACtH,MAAM,IAAI,GAAG,6BAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC;QACjD,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9D,OAAO,IAAI,CAAC;IAChB,CAAC;;AA5HQ,0CAAe;0BAAf,eAAe;IAD3B,IAAA,sBAAU,GAAE;GACA,eAAe,CA6H3B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=chat-find-matcher.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-find-matcher.spec.d.ts","sourceRoot":"","sources":["../../../src/browser/chat-find/chat-find-matcher.spec.ts"],"names":[],"mappings":""}