| 41 | } |
| 42 | |
| 43 | async searchFiles (args, data) { |
| 44 | const results = [] |
| 45 | for (const [file, content] of Object.entries(data)) { |
| 46 | const lowerCase = content.toLowerCase() |
| 47 | // skip if no matches at all |
| 48 | if (!args.some(a => lowerCase.includes(a.toLowerCase()))) { |
| 49 | continue |
| 50 | } |
| 51 | |
| 52 | const lines = content.split(/\n+/) |
| 53 | |
| 54 | // if a line has a search term, then skip it and the next line. |
| 55 | // if the next line has a search term, then skip all 3 |
| 56 | // otherwise, set the line to null |
| 57 | // finally, remove the nulls |
| 58 | for (let i = 0; i < lines.length; i++) { |
| 59 | const line = lines[i] |
| 60 | const nextLine = lines[i + 1] |
| 61 | let match = false |
| 62 | if (nextLine) { |
| 63 | match = args.some(a => |
| 64 | nextLine.toLowerCase().includes(a.toLowerCase())) |
| 65 | if (match) { |
| 66 | // skip over the next line, and the line after it. |
| 67 | i += 2 |
| 68 | continue |
| 69 | } |
| 70 | } |
| 71 | |
| 72 | match = args.some(a => line.toLowerCase().includes(a.toLowerCase())) |
| 73 | |
| 74 | if (match) { |
| 75 | // skip over the next line |
| 76 | i++ |
| 77 | continue |
| 78 | } |
| 79 | |
| 80 | lines[i] = null |
| 81 | } |
| 82 | |
| 83 | // now squish any string of nulls into a single null |
| 84 | const pruned = lines.reduce((l, r) => { |
| 85 | if (!(r === null && l[l.length - 1] === null)) { |
| 86 | l.push(r) |
| 87 | } |
| 88 | |
| 89 | return l |
| 90 | }, []) |
| 91 | |
| 92 | if (pruned[pruned.length - 1] === null) { |
| 93 | pruned.pop() |
| 94 | } |
| 95 | |
| 96 | if (pruned[0] === null) { |
| 97 | pruned.shift() |
| 98 | } |
| 99 | |
| 100 | // now count how many args were found |