From 1c8327bc210756b10bb0ad4e8de5b4da9d786409 Mon Sep 17 00:00:00 2001 From: Ido Frenkel Date: Thu, 29 Aug 2024 17:16:21 +0300 Subject: [PATCH] Add the option to search with regex --- src/components/LazyLog/index.tsx | 14 ++++++++-- src/components/Utils/search.ts | 45 +++++++++++++++++++++++++++++--- src/stories/LazyLog.stories.tsx | 1 + 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/src/components/LazyLog/index.tsx b/src/components/LazyLog/index.tsx index 81b3e00..d06a853 100644 --- a/src/components/LazyLog/index.tsx +++ b/src/components/LazyLog/index.tsx @@ -218,6 +218,10 @@ export interface LazyLogProps { * certain browsers/devices. Defaults to `100`. */ overscanRowCount?: number; + /** + * Use Regex for search + */ + regexSearch?: boolean; /** * A fixed row height in pixels. Controls how tall a line is, * as well as the `lineHeight` style of the line's text. @@ -304,6 +308,7 @@ export default class LazyLog extends Component { overflow: "initial", }, caseInsensitive: false, + regexSearch: false, enableGutters: false, enableHotKeys: false, enableLineNumbers: true, @@ -732,11 +737,16 @@ export default class LazyLog extends Component { handleSearch = (keywords: string | undefined) => { const { resultLines, searchKeywords } = this.state; - const { caseInsensitive, stream, websocket } = this.props; + const { caseInsensitive, stream, websocket, regexSearch } = this.props; const currentResultLines = !stream && !websocket && keywords === searchKeywords ? resultLines - : searchLines(keywords, this.encodedLog!, caseInsensitive!); + : searchLines( + keywords, + this.encodedLog!, + caseInsensitive!, + regexSearch! + ); this.setState( { diff --git a/src/components/Utils/search.ts b/src/components/Utils/search.ts index d076eb0..525577b 100644 --- a/src/components/Utils/search.ts +++ b/src/components/Utils/search.ts @@ -65,18 +65,56 @@ export const searchIndexes = ( return results; }; +/** + * Search for a given pattern in the text + * + * @param rawKeywords - The Regex pattern to search. + * @param {Uint8Array} rawLog - The log data to search within. + * @returns {number[]} An array of indices where the keyword is found in the log. + */ +export const searchIndexesRegex = ( + rawKeywords: string | undefined, + rawLog: Uint8Array, + isCaseInsensitive: boolean +) => { + if (!rawKeywords) return []; + + const decodedLog = new TextDecoder("utf-8").decode(rawLog); + const indexes: number[] = []; + + let flags = "g"; + if (isCaseInsensitive) { + flags += "i"; + } + + try { + const regex = new RegExp(rawKeywords, flags); + let match; + + while ((match = regex.exec(decodedLog)) !== null) { + indexes.push(match.index); + } + } catch (e) { + return []; + } + + return indexes; +}; + /** * Searches for keywords within log lines, handling case sensitivity. * * @param {string | undefined} rawKeywords - The search term to look for. * @param {Uint8Array} rawLog - The log data to search within. * @param {boolean} isCaseInsensitive - Whether the search should be case-insensitive. + * @param {boolean} regexSearch - Search with regex. * @returns {number[]} An array of line numbers where the keyword is found. */ export const searchLines = ( rawKeywords: string | undefined, rawLog: Uint8Array, - isCaseInsensitive: boolean + isCaseInsensitive: boolean, + regexSearch: boolean ) => { let keywords = rawKeywords; let log = rawLog; @@ -91,8 +129,9 @@ export const searchLines = ( decodedLog = decodedLog.endsWith("\n") ? decodedLog : decodedLog + "\n"; log = encode(decodedLog); - // Perform the search - const results = searchIndexes(keywords, log); + const results = regexSearch + ? searchIndexesRegex(keywords, log, isCaseInsensitive) + : searchIndexes(keywords, log); const linesRanges = getLinesLengthRanges(log); const maxLineRangeIndex = linesRanges.length; const maxResultIndex = results.length; diff --git a/src/stories/LazyLog.stories.tsx b/src/stories/LazyLog.stories.tsx index 8e0441b..d145bfe 100644 --- a/src/stories/LazyLog.stories.tsx +++ b/src/stories/LazyLog.stories.tsx @@ -12,6 +12,7 @@ type Story = StoryObj; const BaseStory = { caseInsensitive: true, + regexSearch: false, enableGutters: false, enableHotKeys: true, enableLineNumbers: true,