• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17import {FilterFlag} from 'common/filter_flag';
18import {StringUtils} from 'common/string_utils';
19import {StringFilterPredicate} from 'viewers/common/string_filter_predicate';
20
21export class TextFilter {
22  constructor(
23    public filterString: string = '',
24    public flags: FilterFlag[] = [],
25  ) {}
26
27  getFilterPredicate(): StringFilterPredicate {
28    const matchCase = this.flags.includes(FilterFlag.MATCH_CASE);
29    const matchWord = this.flags.includes(FilterFlag.MATCH_WORD);
30    const useRegex = this.flags.includes(FilterFlag.USE_REGEX);
31
32    if (useRegex) {
33      const regexFlags = useRegex && !matchCase ? 'i' : '';
34      const regexString = matchWord
35        ? '\\b(?:' + this.filterString + ')\\b'
36        : this.filterString;
37      try {
38        const regex = new RegExp(regexString, regexFlags);
39        return (entryString: string) => {
40          if (this.filterString.length === 0) return true;
41          return regex.test(entryString);
42        };
43      } catch (e) {
44        return (entryString: string) => false;
45      }
46    } else {
47      const testString = matchCase
48        ? this.filterString
49        : this.filterString.toLowerCase();
50      return (entryString: string) => {
51        if (this.filterString.length === 0) return true;
52
53        let entrySubstring = matchCase
54          ? entryString
55          : entryString.toLowerCase();
56        let testStringIndex = entrySubstring.indexOf(testString);
57
58        while (testStringIndex !== -1) {
59          if (!matchWord) return true;
60
61          const nextChar = entrySubstring.at(
62            testStringIndex + testString.length,
63          );
64          if (
65            nextChar === undefined ||
66            !(StringUtils.isAlpha(nextChar) || StringUtils.isDigit(nextChar))
67          ) {
68            return true;
69          }
70
71          entrySubstring = entrySubstring.slice(
72            testStringIndex + testString.length,
73          );
74          testStringIndex = entrySubstring.indexOf(testString);
75        }
76        return false;
77      };
78    }
79  }
80}
81