* 在单个页面的消息中搜索,返回按消息分组的结果
( messages: ChatMessage[], pattern: RegExp, pageId: string, options: GlobalSearchOptions )
| 143 | * 在单个页面的消息中搜索,返回按消息分组的结果 |
| 144 | */ |
| 145 | function searchInMessages( |
| 146 | messages: ChatMessage[], |
| 147 | pattern: RegExp, |
| 148 | pageId: string, |
| 149 | options: GlobalSearchOptions |
| 150 | ): GlobalSearchMessageGroup[] { |
| 151 | const messageGroups: GlobalSearchMessageGroup[] = [] |
| 152 | let totalMatchCount = 0 |
| 153 | |
| 154 | for (const message of messages) { |
| 155 | // 角色筛选 |
| 156 | if (options.roleFilter !== 'all' && message.role !== options.roleFilter) { |
| 157 | continue |
| 158 | } |
| 159 | |
| 160 | // 时间筛选 |
| 161 | if (!isInTimeRange(message.createdAt, options.timeRange)) { |
| 162 | continue |
| 163 | } |
| 164 | |
| 165 | const content = message.content |
| 166 | if (!content) continue |
| 167 | |
| 168 | // 重置正则表达式的 lastIndex |
| 169 | pattern.lastIndex = 0 |
| 170 | |
| 171 | const matches: GlobalSearchMatch[] = [] |
| 172 | let match: RegExpExecArray | null |
| 173 | |
| 174 | while ((match = pattern.exec(content)) !== null && totalMatchCount < MAX_MATCHES_PER_PAGE) { |
| 175 | const matchText = match[0] |
| 176 | const { snippet, matchStart, matchEnd } = extractSnippet( |
| 177 | content, |
| 178 | match.index, |
| 179 | matchText.length |
| 180 | ) |
| 181 | |
| 182 | matches.push({ |
| 183 | messageId: message.id, |
| 184 | pageId, |
| 185 | role: message.role, |
| 186 | snippet, |
| 187 | matchStart, |
| 188 | matchEnd, |
| 189 | contentStart: match.index, |
| 190 | contentEnd: match.index + matchText.length, |
| 191 | occurrenceIndexInMessage: countOccurrencesBefore(content, matchText, match.index), |
| 192 | createdAt: message.createdAt |
| 193 | }) |
| 194 | |
| 195 | totalMatchCount++ |
| 196 | |
| 197 | // 防止零长度匹配导致无限循环 |
| 198 | if (match[0].length === 0) { |
| 199 | pattern.lastIndex++ |
| 200 | } |
| 201 | } |
| 202 |
no test coverage detected