/** @license * fzf v0.5.2 * Copyright (c) 2021 Ajit * Licensed under BSD 3-Clause */ const normalized = { 216: "O", 223: "s", 248: "o", 273: "d", 295: "h", 305: "i", 320: "l", 322: "l", 359: "t", 383: "s", 384: "b", 385: "B", 387: "b", 390: "O", 392: "c", 393: "D", 394: "D", 396: "d", 398: "E", 400: "E", 402: "f", 403: "G", 407: "I", 409: "k", 410: "l", 412: "M", 413: "N", 414: "n", 415: "O", 421: "p", 427: "t", 429: "t", 430: "T", 434: "V", 436: "y", 438: "z", 477: "e", 485: "g", 544: "N", 545: "d", 549: "z", 564: "l", 565: "n", 566: "t", 567: "j", 570: "A", 571: "C", 572: "c", 573: "L", 574: "T", 575: "s", 576: "z", 579: "B", 580: "U", 581: "V", 582: "E", 583: "e", 584: "J", 585: "j", 586: "Q", 587: "q", 588: "R", 589: "r", 590: "Y", 591: "y", 592: "a", 593: "a", 595: "b", 596: "o", 597: "c", 598: "d", 599: "d", 600: "e", 603: "e", 604: "e", 605: "e", 606: "e", 607: "j", 608: "g", 609: "g", 610: "G", 613: "h", 614: "h", 616: "i", 618: "I", 619: "l", 620: "l", 621: "l", 623: "m", 624: "m", 625: "m", 626: "n", 627: "n", 628: "N", 629: "o", 633: "r", 634: "r", 635: "r", 636: "r", 637: "r", 638: "r", 639: "r", 640: "R", 641: "R", 642: "s", 647: "t", 648: "t", 649: "u", 651: "v", 652: "v", 653: "w", 654: "y", 655: "Y", 656: "z", 657: "z", 663: "c", 665: "B", 666: "e", 667: "G", 668: "H", 669: "j", 670: "k", 671: "L", 672: "q", 686: "h", 867: "a", 868: "e", 869: "i", 870: "o", 871: "u", 872: "c", 873: "d", 874: "h", 875: "m", 876: "r", 877: "t", 878: "v", 879: "x", 7424: "A", 7427: "B", 7428: "C", 7429: "D", 7431: "E", 7432: "e", 7433: "i", 7434: "J", 7435: "K", 7436: "L", 7437: "M", 7438: "N", 7439: "O", 7440: "O", 7441: "o", 7442: "o", 7443: "o", 7446: "o", 7447: "o", 7448: "P", 7449: "R", 7450: "R", 7451: "T", 7452: "U", 7453: "u", 7454: "u", 7455: "m", 7456: "V", 7457: "W", 7458: "Z", 7522: "i", 7523: "r", 7524: "u", 7525: "v", 7834: "a", 7835: "s", 8305: "i", 8341: "h", 8342: "k", 8343: "l", 8344: "m", 8345: "n", 8346: "p", 8347: "s", 8348: "t", 8580: "c" }; for (let i = "\u0300".codePointAt(0); i <= "\u036F".codePointAt(0); ++i) { const diacritic = String.fromCodePoint(i); for (const asciiChar of "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz") { const withDiacritic = (asciiChar + diacritic).normalize(); const withDiacriticCodePoint = withDiacritic.codePointAt(0); if (withDiacriticCodePoint > 126) { normalized[withDiacriticCodePoint] = asciiChar; } } } const ranges = { a: [7844, 7863], e: [7870, 7879], o: [7888, 7907], u: [7912, 7921] }; for (const lowerChar of Object.keys(ranges)) { const upperChar = lowerChar.toUpperCase(); for (let i = ranges[lowerChar][0]; i <= ranges[lowerChar][1]; ++i) { normalized[i] = i % 2 === 0 ? upperChar : lowerChar; } } function normalizeRune(rune) { if (rune < 192 || rune > 8580) { return rune; } const normalizedChar = normalized[rune]; if (normalizedChar !== void 0) return normalizedChar.codePointAt(0); return rune; } function toShort(number) { return number; } function toInt(number) { return number; } function maxInt16(num1, num2) { return num1 > num2 ? num1 : num2; } const strToRunes = (str) => str.split("").map((s) => s.codePointAt(0)); const runesToStr = (runes) => runes.map((r) => String.fromCodePoint(r)).join(""); const whitespaceRunes = new Set( " \f\n\r \v\xA0\u1680\u2028\u2029\u202F\u205F\u3000\uFEFF".split("").map((v) => v.codePointAt(0)) ); for (let codePoint = "\u2000".codePointAt(0); codePoint <= "\u200A".codePointAt(0); codePoint++) { whitespaceRunes.add(codePoint); } const isWhitespace = (rune) => whitespaceRunes.has(rune); const whitespacesAtStart = (runes) => { let whitespaces = 0; for (const rune of runes) { if (isWhitespace(rune)) whitespaces++; else break; } return whitespaces; }; const whitespacesAtEnd = (runes) => { let whitespaces = 0; for (let i = runes.length - 1; i >= 0; i--) { if (isWhitespace(runes[i])) whitespaces++; else break; } return whitespaces; }; const MAX_ASCII = "\x7F".codePointAt(0); const CAPITAL_A_RUNE = "A".codePointAt(0); const CAPITAL_Z_RUNE = "Z".codePointAt(0); const SMALL_A_RUNE = "a".codePointAt(0); const SMALL_Z_RUNE = "z".codePointAt(0); const NUMERAL_ZERO_RUNE = "0".codePointAt(0); const NUMERAL_NINE_RUNE = "9".codePointAt(0); function indexAt(index, max, forward) { if (forward) { return index; } return max - index - 1; } const SCORE_MATCH = 16, SCORE_GAP_START = -3, SCORE_GAP_EXTENTION = -1, BONUS_BOUNDARY = SCORE_MATCH / 2, BONUS_NON_WORD = SCORE_MATCH / 2, BONUS_CAMEL_123 = BONUS_BOUNDARY + SCORE_GAP_EXTENTION, BONUS_CONSECUTIVE = -(SCORE_GAP_START + SCORE_GAP_EXTENTION), BONUS_FIRST_CHAR_MULTIPLIER = 2; function createPosSet(withPos) { if (withPos) { return /* @__PURE__ */ new Set(); } return null; } function alloc16(offset, slab2, size) { if (slab2 !== null && slab2.i16.length > offset + size) { const subarray = slab2.i16.subarray(offset, offset + size); return [offset + size, subarray]; } return [offset, new Int16Array(size)]; } function alloc32(offset, slab2, size) { if (slab2 !== null && slab2.i32.length > offset + size) { const subarray = slab2.i32.subarray(offset, offset + size); return [offset + size, subarray]; } return [offset, new Int32Array(size)]; } function charClassOfAscii(rune) { if (rune >= SMALL_A_RUNE && rune <= SMALL_Z_RUNE) { return 1; } else if (rune >= CAPITAL_A_RUNE && rune <= CAPITAL_Z_RUNE) { return 2; } else if (rune >= NUMERAL_ZERO_RUNE && rune <= NUMERAL_NINE_RUNE) { return 4; } else { return 0; } } function charClassOfNonAscii(rune) { const char = String.fromCodePoint(rune); if (char !== char.toUpperCase()) { return 1; } else if (char !== char.toLowerCase()) { return 2; } else if (char.match(/\p{Number}/gu) !== null) { return 4; } else if (char.match(/\p{Letter}/gu) !== null) { return 3; } return 0; } function charClassOf(rune) { if (rune <= MAX_ASCII) { return charClassOfAscii(rune); } return charClassOfNonAscii(rune); } function bonusFor(prevClass, currClass) { if (prevClass === 0 && currClass !== 0) { return BONUS_BOUNDARY; } else if (prevClass === 1 && currClass === 2 || prevClass !== 4 && currClass === 4) { return BONUS_CAMEL_123; } else if (currClass === 0) { return BONUS_NON_WORD; } return 0; } function bonusAt(input, idx) { if (idx === 0) { return BONUS_BOUNDARY; } return bonusFor(charClassOf(input[idx - 1]), charClassOf(input[idx])); } function trySkip(input, caseSensitive, char, from) { let rest = input.slice(from); let idx = rest.indexOf(char); if (idx === 0) { return from; } if (!caseSensitive && char >= SMALL_A_RUNE && char <= SMALL_Z_RUNE) { if (idx > 0) { rest = rest.slice(0, idx); } const uidx = rest.indexOf(char - 32); if (uidx >= 0) { idx = uidx; } } if (idx < 0) { return -1; } return from + idx; } function isAscii(runes) { for (const rune of runes) { if (rune >= 128) { return false; } } return true; } function asciiFuzzyIndex(input, pattern, caseSensitive) { if (!isAscii(input)) { return 0; } if (!isAscii(pattern)) { return -1; } let firstIdx = 0, idx = 0; for (let pidx = 0; pidx < pattern.length; pidx++) { idx = trySkip(input, caseSensitive, pattern[pidx], idx); if (idx < 0) { return -1; } if (pidx === 0 && idx > 0) { firstIdx = idx - 1; } idx++; } return firstIdx; } const fuzzyMatchV2 = (caseSensitive, normalize, forward, input, pattern, withPos, slab2) => { const M = pattern.length; if (M === 0) { return [{ start: 0, end: 0, score: 0 }, createPosSet(withPos)]; } const N = input.length; if (slab2 !== null && N * M > slab2.i16.length) { return fuzzyMatchV1(caseSensitive, normalize, forward, input, pattern, withPos); } const idx = asciiFuzzyIndex(input, pattern, caseSensitive); if (idx < 0) { return [{ start: -1, end: -1, score: 0 }, null]; } let offset16 = 0, offset32 = 0, H0 = null, C0 = null, B = null, F = null; [offset16, H0] = alloc16(offset16, slab2, N); [offset16, C0] = alloc16(offset16, slab2, N); [offset16, B] = alloc16(offset16, slab2, N); [offset32, F] = alloc32(offset32, slab2, M); const [, T] = alloc32(offset32, slab2, N); for (let i = 0; i < T.length; i++) { T[i] = input[i]; } let maxScore = toShort(0), maxScorePos = 0; let pidx = 0, lastIdx = 0; const pchar0 = pattern[0]; let pchar = pattern[0], prevH0 = toShort(0), prevCharClass = 0, inGap = false; let Tsub = T.subarray(idx); let H0sub = H0.subarray(idx).subarray(0, Tsub.length), C0sub = C0.subarray(idx).subarray(0, Tsub.length), Bsub = B.subarray(idx).subarray(0, Tsub.length); for (let [off, char] of Tsub.entries()) { let charClass = null; if (char <= MAX_ASCII) { charClass = charClassOfAscii(char); if (!caseSensitive && charClass === 2) { char += 32; } } else { charClass = charClassOfNonAscii(char); if (!caseSensitive && charClass === 2) { char = String.fromCodePoint(char).toLowerCase().codePointAt(0); } if (normalize) { char = normalizeRune(char); } } Tsub[off] = char; const bonus = bonusFor(prevCharClass, charClass); Bsub[off] = bonus; prevCharClass = charClass; if (char === pchar) { if (pidx < M) { F[pidx] = toInt(idx + off); pidx++; pchar = pattern[Math.min(pidx, M - 1)]; } lastIdx = idx + off; } if (char === pchar0) { const score = SCORE_MATCH + bonus * BONUS_FIRST_CHAR_MULTIPLIER; H0sub[off] = score; C0sub[off] = 1; if (M === 1 && (forward && score > maxScore || !forward && score >= maxScore)) { maxScore = score; maxScorePos = idx + off; if (forward && bonus === BONUS_BOUNDARY) { break; } } inGap = false; } else { if (inGap) { H0sub[off] = maxInt16(prevH0 + SCORE_GAP_EXTENTION, 0); } else { H0sub[off] = maxInt16(prevH0 + SCORE_GAP_START, 0); } C0sub[off] = 0; inGap = true; } prevH0 = H0sub[off]; } if (pidx !== M) { return [{ start: -1, end: -1, score: 0 }, null]; } if (M === 1) { const result = { start: maxScorePos, end: maxScorePos + 1, score: maxScore }; if (!withPos) { return [result, null]; } const pos2 = /* @__PURE__ */ new Set(); pos2.add(maxScorePos); return [result, pos2]; } const f0 = F[0]; const width = lastIdx - f0 + 1; let H = null; [offset16, H] = alloc16(offset16, slab2, width * M); { const toCopy = H0.subarray(f0, lastIdx + 1); for (const [i, v] of toCopy.entries()) { H[i] = v; } } let [, C] = alloc16(offset16, slab2, width * M); { const toCopy = C0.subarray(f0, lastIdx + 1); for (const [i, v] of toCopy.entries()) { C[i] = v; } } const Fsub = F.subarray(1); const Psub = pattern.slice(1).slice(0, Fsub.length); for (const [off, f] of Fsub.entries()) { let inGap2 = false; const pchar2 = Psub[off], pidx2 = off + 1, row = pidx2 * width, Tsub2 = T.subarray(f, lastIdx + 1), Bsub2 = B.subarray(f).subarray(0, Tsub2.length), Csub = C.subarray(row + f - f0).subarray(0, Tsub2.length), Cdiag = C.subarray(row + f - f0 - 1 - width).subarray(0, Tsub2.length), Hsub = H.subarray(row + f - f0).subarray(0, Tsub2.length), Hdiag = H.subarray(row + f - f0 - 1 - width).subarray(0, Tsub2.length), Hleft = H.subarray(row + f - f0 - 1).subarray(0, Tsub2.length); Hleft[0] = 0; for (const [off2, char] of Tsub2.entries()) { const col = off2 + f; let s1 = 0, s2 = 0, consecutive = 0; if (inGap2) { s2 = Hleft[off2] + SCORE_GAP_EXTENTION; } else { s2 = Hleft[off2] + SCORE_GAP_START; } if (pchar2 === char) { s1 = Hdiag[off2] + SCORE_MATCH; let b = Bsub2[off2]; consecutive = Cdiag[off2] + 1; if (b === BONUS_BOUNDARY) { consecutive = 1; } else if (consecutive > 1) { b = maxInt16(b, maxInt16(BONUS_CONSECUTIVE, B[col - consecutive + 1])); } if (s1 + b < s2) { s1 += Bsub2[off2]; consecutive = 0; } else { s1 += b; } } Csub[off2] = consecutive; inGap2 = s1 < s2; const score = maxInt16(maxInt16(s1, s2), 0); if (pidx2 === M - 1 && (forward && score > maxScore || !forward && score >= maxScore)) { maxScore = score; maxScorePos = col; } Hsub[off2] = score; } } const pos = createPosSet(withPos); let j = f0; if (withPos && pos !== null) { let i = M - 1; j = maxScorePos; let preferMatch = true; while (true) { const I = i * width, j0 = j - f0, s = H[I + j0]; let s1 = 0, s2 = 0; if (i > 0 && j >= F[i]) { s1 = H[I - width + j0 - 1]; } if (j > F[i]) { s2 = H[I + j0 - 1]; } if (s > s1 && (s > s2 || s === s2 && preferMatch)) { pos.add(j); if (i === 0) { break; } i--; } preferMatch = C[I + j0] > 1 || I + width + j0 + 1 < C.length && C[I + width + j0 + 1] > 0; j--; } } return [{ start: j, end: maxScorePos + 1, score: maxScore }, pos]; }; function calculateScore(caseSensitive, normalize, text, pattern, sidx, eidx, withPos) { let pidx = 0, score = 0, inGap = false, consecutive = 0, firstBonus = toShort(0); const pos = createPosSet(withPos); let prevCharClass = 0; if (sidx > 0) { prevCharClass = charClassOf(text[sidx - 1]); } for (let idx = sidx; idx < eidx; idx++) { let rune = text[idx]; const charClass = charClassOf(rune); if (!caseSensitive) { if (rune >= CAPITAL_A_RUNE && rune <= CAPITAL_Z_RUNE) { rune += 32; } else if (rune > MAX_ASCII) { rune = String.fromCodePoint(rune).toLowerCase().codePointAt(0); } } if (normalize) { rune = normalizeRune(rune); } if (rune === pattern[pidx]) { if (withPos && pos !== null) { pos.add(idx); } score += SCORE_MATCH; let bonus = bonusFor(prevCharClass, charClass); if (consecutive === 0) { firstBonus = bonus; } else { if (bonus === BONUS_BOUNDARY) { firstBonus = bonus; } bonus = maxInt16(maxInt16(bonus, firstBonus), BONUS_CONSECUTIVE); } if (pidx === 0) { score += bonus * BONUS_FIRST_CHAR_MULTIPLIER; } else { score += bonus; } inGap = false; consecutive++; pidx++; } else { if (inGap) { score += SCORE_GAP_EXTENTION; } else { score += SCORE_GAP_START; } inGap = true; consecutive = 0; firstBonus = 0; } prevCharClass = charClass; } return [score, pos]; } const fuzzyMatchV1 = (caseSensitive, normalize, forward, text, pattern, withPos, slab2) => { if (pattern.length === 0) { return [{ start: 0, end: 0, score: 0 }, null]; } if (asciiFuzzyIndex(text, pattern, caseSensitive) < 0) { return [{ start: -1, end: -1, score: 0 }, null]; } let pidx = 0, sidx = -1, eidx = -1; const lenRunes = text.length; const lenPattern = pattern.length; for (let index = 0; index < lenRunes; index++) { let rune = text[indexAt(index, lenRunes, forward)]; if (!caseSensitive) { if (rune >= CAPITAL_A_RUNE && rune <= CAPITAL_Z_RUNE) { rune += 32; } else if (rune > MAX_ASCII) { rune = String.fromCodePoint(rune).toLowerCase().codePointAt(0); } } if (normalize) { rune = normalizeRune(rune); } const pchar = pattern[indexAt(pidx, lenPattern, forward)]; if (rune === pchar) { if (sidx < 0) { sidx = index; } pidx++; if (pidx === lenPattern) { eidx = index + 1; break; } } } if (sidx >= 0 && eidx >= 0) { pidx--; for (let index = eidx - 1; index >= sidx; index--) { const tidx = indexAt(index, lenRunes, forward); let rune = text[tidx]; if (!caseSensitive) { if (rune >= CAPITAL_A_RUNE && rune <= CAPITAL_Z_RUNE) { rune += 32; } else if (rune > MAX_ASCII) { rune = String.fromCodePoint(rune).toLowerCase().codePointAt(0); } } const pidx_ = indexAt(pidx, lenPattern, forward); const pchar = pattern[pidx_]; if (rune === pchar) { pidx--; if (pidx < 0) { sidx = index; break; } } } if (!forward) { const sidxTemp = sidx; sidx = lenRunes - eidx; eidx = lenRunes - sidxTemp; } const [score, pos] = calculateScore( caseSensitive, normalize, text, pattern, sidx, eidx, withPos ); return [{ start: sidx, end: eidx, score }, pos]; } return [{ start: -1, end: -1, score: 0 }, null]; }; const exactMatchNaive = (caseSensitive, normalize, forward, text, pattern, withPos, slab2) => { if (pattern.length === 0) { return [{ start: 0, end: 0, score: 0 }, null]; } const lenRunes = text.length; const lenPattern = pattern.length; if (lenRunes < lenPattern) { return [{ start: -1, end: -1, score: 0 }, null]; } if (asciiFuzzyIndex(text, pattern, caseSensitive) < 0) { return [{ start: -1, end: -1, score: 0 }, null]; } let pidx = 0; let bestPos = -1, bonus = toShort(0), bestBonus = toShort(-1); for (let index = 0; index < lenRunes; index++) { const index_ = indexAt(index, lenRunes, forward); let rune = text[index_]; if (!caseSensitive) { if (rune >= CAPITAL_A_RUNE && rune <= CAPITAL_Z_RUNE) { rune += 32; } else if (rune > MAX_ASCII) { rune = String.fromCodePoint(rune).toLowerCase().codePointAt(0); } } if (normalize) { rune = normalizeRune(rune); } const pidx_ = indexAt(pidx, lenPattern, forward); const pchar = pattern[pidx_]; if (pchar === rune) { if (pidx_ === 0) { bonus = bonusAt(text, index_); } pidx++; if (pidx === lenPattern) { if (bonus > bestBonus) { bestPos = index; bestBonus = bonus; } if (bonus === BONUS_BOUNDARY) { break; } index -= pidx - 1; pidx = 0; bonus = 0; } } else { index -= pidx; pidx = 0; bonus = 0; } } if (bestPos >= 0) { let sidx = 0, eidx = 0; if (forward) { sidx = bestPos - lenPattern + 1; eidx = bestPos + 1; } else { sidx = lenRunes - (bestPos + 1); eidx = lenRunes - (bestPos - lenPattern + 1); } const [score] = calculateScore(caseSensitive, normalize, text, pattern, sidx, eidx, false); return [{ start: sidx, end: eidx, score }, null]; } return [{ start: -1, end: -1, score: 0 }, null]; }; const prefixMatch = (caseSensitive, normalize, forward, text, pattern, withPos, slab2) => { if (pattern.length === 0) { return [{ start: 0, end: 0, score: 0 }, null]; } let trimmedLen = 0; if (!isWhitespace(pattern[0])) { trimmedLen = whitespacesAtStart(text); } if (text.length - trimmedLen < pattern.length) { return [{ start: -1, end: -1, score: 0 }, null]; } for (const [index, r] of pattern.entries()) { let rune = text[trimmedLen + index]; if (!caseSensitive) { rune = String.fromCodePoint(rune).toLowerCase().codePointAt(0); } if (normalize) { rune = normalizeRune(rune); } if (rune !== r) { return [{ start: -1, end: -1, score: 0 }, null]; } } const lenPattern = pattern.length; const [score] = calculateScore( caseSensitive, normalize, text, pattern, trimmedLen, trimmedLen + lenPattern, false ); return [{ start: trimmedLen, end: trimmedLen + lenPattern, score }, null]; }; const suffixMatch = (caseSensitive, normalize, forward, text, pattern, withPos, slab2) => { const lenRunes = text.length; let trimmedLen = lenRunes; if (pattern.length === 0 || !isWhitespace(pattern[pattern.length - 1])) { trimmedLen -= whitespacesAtEnd(text); } if (pattern.length === 0) { return [{ start: trimmedLen, end: trimmedLen, score: 0 }, null]; } const diff = trimmedLen - pattern.length; if (diff < 0) { return [{ start: -1, end: -1, score: 0 }, null]; } for (const [index, r] of pattern.entries()) { let rune = text[index + diff]; if (!caseSensitive) { rune = String.fromCodePoint(rune).toLowerCase().codePointAt(0); } if (normalize) { rune = normalizeRune(rune); } if (rune !== r) { return [{ start: -1, end: -1, score: 0 }, null]; } } const lenPattern = pattern.length; const sidx = trimmedLen - lenPattern; const eidx = trimmedLen; const [score] = calculateScore(caseSensitive, normalize, text, pattern, sidx, eidx, false); return [{ start: sidx, end: eidx, score }, null]; }; const equalMatch = (caseSensitive, normalize, forward, text, pattern, withPos, slab2) => { const lenPattern = pattern.length; if (lenPattern === 0) { return [{ start: -1, end: -1, score: 0 }, null]; } let trimmedLen = 0; if (!isWhitespace(pattern[0])) { trimmedLen = whitespacesAtStart(text); } let trimmedEndLen = 0; if (!isWhitespace(pattern[lenPattern - 1])) { trimmedEndLen = whitespacesAtEnd(text); } if (text.length - trimmedLen - trimmedEndLen != lenPattern) { return [{ start: -1, end: -1, score: 0 }, null]; } let match = true; if (normalize) { const runes = text; for (const [idx, pchar] of pattern.entries()) { let rune = runes[trimmedLen + idx]; if (!caseSensitive) { rune = String.fromCodePoint(rune).toLowerCase().codePointAt(0); } if (normalizeRune(pchar) !== normalizeRune(rune)) { match = false; break; } } } else { let runesStr = runesToStr(text).substring(trimmedLen, text.length - trimmedEndLen); if (!caseSensitive) { runesStr = runesStr.toLowerCase(); } match = runesStr === runesToStr(pattern); } if (match) { return [ { start: trimmedLen, end: trimmedLen + lenPattern, score: (SCORE_MATCH + BONUS_BOUNDARY) * lenPattern + (BONUS_FIRST_CHAR_MULTIPLIER - 1) * BONUS_BOUNDARY }, null ]; } return [{ start: -1, end: -1, score: 0 }, null]; }; const SLAB_16_SIZE = 100 * 1024; const SLAB_32_SIZE = 2048; function makeSlab(size16, size32) { return { i16: new Int16Array(size16), i32: new Int32Array(size32) }; } const slab = makeSlab(SLAB_16_SIZE, SLAB_32_SIZE); var TermType = /* @__PURE__ */ ((TermType2) => { TermType2[TermType2["Fuzzy"] = 0] = "Fuzzy"; TermType2[TermType2["Exact"] = 1] = "Exact"; TermType2[TermType2["Prefix"] = 2] = "Prefix"; TermType2[TermType2["Suffix"] = 3] = "Suffix"; TermType2[TermType2["Equal"] = 4] = "Equal"; return TermType2; })(TermType || {}); const termTypeMap = { [0]: fuzzyMatchV2, [1]: exactMatchNaive, [2]: prefixMatch, [3]: suffixMatch, [4]: equalMatch }; function buildPatternForExtendedMatch(fuzzy, caseMode, normalize, str) { let cacheable = true; str = str.trimLeft(); { const trimmedAtRightStr = str.trimRight(); if (trimmedAtRightStr.endsWith("\\") && str[trimmedAtRightStr.length] === " ") { str = trimmedAtRightStr + " "; } else { str = trimmedAtRightStr; } } let sortable = false; let termSets = []; termSets = parseTerms(fuzzy, caseMode, normalize, str); Loop: for (const termSet of termSets) { for (const [idx, term] of termSet.entries()) { if (!term.inv) { sortable = true; } if (!cacheable || idx > 0 || term.inv || fuzzy && term.typ !== 0 || !fuzzy && term.typ !== 1) { cacheable = false; if (sortable) { break Loop; } } } } return { str, termSets, sortable, cacheable, fuzzy }; } function parseTerms(fuzzy, caseMode, normalize, str) { str = str.replace(/\\ /g, " "); const tokens = str.split(/ +/); const sets = []; let set = []; let switchSet = false; let afterBar = false; for (const token of tokens) { let typ = 0, inv = false, text = token.replace(/\t/g, " "); const lowerText = text.toLowerCase(); const caseSensitive = caseMode === "case-sensitive" || caseMode === "smart-case" && text !== lowerText; const normalizeTerm = normalize && lowerText === runesToStr(strToRunes(lowerText).map(normalizeRune)); if (!caseSensitive) { text = lowerText; } if (!fuzzy) { typ = 1; } if (set.length > 0 && !afterBar && text === "|") { switchSet = false; afterBar = true; continue; } afterBar = false; if (text.startsWith("!")) { inv = true; typ = 1; text = text.substring(1); } if (text !== "$" && text.endsWith("$")) { typ = 3; text = text.substring(0, text.length - 1); } if (text.startsWith("'")) { if (fuzzy && !inv) { typ = 1; } else { typ = 0; } text = text.substring(1); } else if (text.startsWith("^")) { if (typ === 3) { typ = 4; } else { typ = 2; } text = text.substring(1); } if (text.length > 0) { if (switchSet) { sets.push(set); set = []; } let textRunes = strToRunes(text); if (normalizeTerm) { textRunes = textRunes.map(normalizeRune); } set.push({ typ, inv, text: textRunes, caseSensitive, normalize: normalizeTerm }); switchSet = true; } } if (set.length > 0) { sets.push(set); } return sets; } const buildPatternForBasicMatch = (query, casing, normalize) => { let caseSensitive = false; switch (casing) { case "smart-case": if (query.toLowerCase() !== query) { caseSensitive = true; } break; case "case-sensitive": caseSensitive = true; break; case "case-insensitive": query = query.toLowerCase(); caseSensitive = false; break; } let queryRunes = strToRunes(query); if (normalize) { queryRunes = queryRunes.map(normalizeRune); } return { queryRunes, caseSensitive }; }; function iter(algoFn, tokens, caseSensitive, normalize, forward, pattern, slab2) { for (const part of tokens) { const [res, pos] = algoFn(caseSensitive, normalize, forward, part.text, pattern, true, slab2); if (res.start >= 0) { const sidx = res.start + part.prefixLength; const eidx = res.end + part.prefixLength; if (pos !== null) { const newPos = /* @__PURE__ */ new Set(); pos.forEach((v) => newPos.add(part.prefixLength + v)); return [[sidx, eidx], res.score, newPos]; } return [[sidx, eidx], res.score, pos]; } } return [[-1, -1], 0, null]; } function computeExtendedMatch(text, pattern, fuzzyAlgo, forward) { const input = [ { text, prefixLength: 0 } ]; const offsets = []; let totalScore = 0; const allPos = /* @__PURE__ */ new Set(); for (const termSet of pattern.termSets) { let offset = [0, 0]; let currentScore = 0; let matched = false; for (const term of termSet) { let algoFn = termTypeMap[term.typ]; if (term.typ === TermType.Fuzzy) { algoFn = fuzzyAlgo; } const [off, score, pos] = iter( algoFn, input, term.caseSensitive, term.normalize, forward, term.text, slab ); const sidx = off[0]; if (sidx >= 0) { if (term.inv) { continue; } offset = off; currentScore = score; matched = true; if (pos !== null) { pos.forEach((v) => allPos.add(v)); } else { for (let idx = off[0]; idx < off[1]; ++idx) { allPos.add(idx); } } break; } else if (term.inv) { offset = [0, 0]; currentScore = 0; matched = true; continue; } } if (matched) { offsets.push(offset); totalScore += currentScore; } } return { offsets, totalScore, allPos }; } function getResultFromScoreMap(scoreMap, limit) { const scoresInDesc = Object.keys(scoreMap).map((v) => parseInt(v, 10)).sort((a, b) => b - a); let result = []; for (const score of scoresInDesc) { result = result.concat(scoreMap[score]); if (result.length >= limit) { break; } } return result; } function getBasicMatchIter(scoreMap, queryRunes, caseSensitive) { return (idx) => { const itemRunes = this.runesList[idx]; if (queryRunes.length > itemRunes.length) return; let [match, positions] = this.algoFn( caseSensitive, this.opts.normalize, this.opts.forward, itemRunes, queryRunes, true, slab ); if (match.start === -1) return; if (this.opts.fuzzy === false) { positions = /* @__PURE__ */ new Set(); for (let position = match.start; position < match.end; ++position) { positions.add(position); } } const scoreKey = this.opts.sort ? match.score : 0; if (scoreMap[scoreKey] === void 0) { scoreMap[scoreKey] = []; } scoreMap[scoreKey].push({ item: this.items[idx], ...match, positions: positions != null ? positions : /* @__PURE__ */ new Set() }); }; } function getExtendedMatchIter(scoreMap, pattern) { return (idx) => { const runes = this.runesList[idx]; const match = computeExtendedMatch(runes, pattern, this.algoFn, this.opts.forward); if (match.offsets.length !== pattern.termSets.length) return; let sidx = -1, eidx = -1; if (match.allPos.size > 0) { sidx = Math.min(...match.allPos); eidx = Math.max(...match.allPos) + 1; } const scoreKey = this.opts.sort ? match.totalScore : 0; if (scoreMap[scoreKey] === void 0) { scoreMap[scoreKey] = []; } scoreMap[scoreKey].push({ score: match.totalScore, item: this.items[idx], positions: match.allPos, start: sidx, end: eidx }); }; } function basicMatch(query) { const { queryRunes, caseSensitive } = buildPatternForBasicMatch( query, this.opts.casing, this.opts.normalize ); const scoreMap = {}; const iter2 = getBasicMatchIter.bind(this)( scoreMap, queryRunes, caseSensitive ); for (let i = 0, len = this.runesList.length; i < len; ++i) { iter2(i); } return getResultFromScoreMap(scoreMap, this.opts.limit); } function extendedMatch(query) { const pattern = buildPatternForExtendedMatch( Boolean(this.opts.fuzzy), this.opts.casing, this.opts.normalize, query ); const scoreMap = {}; const iter2 = getExtendedMatchIter.bind(this)(scoreMap, pattern); for (let i = 0, len = this.runesList.length; i < len; ++i) { iter2(i); } return getResultFromScoreMap(scoreMap, this.opts.limit); } const isNode = typeof require !== "undefined" && typeof window === "undefined"; function asyncMatcher(token, len, iter2, onFinish) { return new Promise((resolve, reject) => { const INCREMENT = 1e3; let i = 0, end = Math.min(INCREMENT, len); const step = () => { if (token.cancelled) return reject("search cancelled"); for (; i < end; ++i) { iter2(i); } if (end < len) { end = Math.min(end + INCREMENT, len); isNode ? setImmediate(step) : setTimeout(step); } else { resolve(onFinish()); } }; step(); }); } function asyncBasicMatch(query, token) { const { queryRunes, caseSensitive } = buildPatternForBasicMatch( query, this.opts.casing, this.opts.normalize ); const scoreMap = {}; return asyncMatcher( token, this.runesList.length, getBasicMatchIter.bind(this)(scoreMap, queryRunes, caseSensitive), () => getResultFromScoreMap(scoreMap, this.opts.limit) ); } function asyncExtendedMatch(query, token) { const pattern = buildPatternForExtendedMatch( Boolean(this.opts.fuzzy), this.opts.casing, this.opts.normalize, query ); const scoreMap = {}; return asyncMatcher( token, this.runesList.length, getExtendedMatchIter.bind(this)(scoreMap, pattern), () => getResultFromScoreMap(scoreMap, this.opts.limit) ); } const defaultOpts = { limit: Infinity, selector: (v) => v, casing: "smart-case", normalize: true, fuzzy: "v2", tiebreakers: [], sort: true, forward: true }; class BaseFinder { constructor(list, ...optionsTuple) { this.opts = { ...defaultOpts, ...optionsTuple[0] }; this.items = list; this.runesList = list.map((item) => strToRunes(this.opts.selector(item).normalize())); this.algoFn = exactMatchNaive; switch (this.opts.fuzzy) { case "v2": this.algoFn = fuzzyMatchV2; break; case "v1": this.algoFn = fuzzyMatchV1; break; } } } const syncDefaultOpts = { ...defaultOpts, match: basicMatch }; class SyncFinder extends BaseFinder { constructor(list, ...optionsTuple) { super(list, ...optionsTuple); this.opts = { ...syncDefaultOpts, ...optionsTuple[0] }; } find(query) { if (query.length === 0 || this.items.length === 0) return this.items.slice(0, this.opts.limit).map(createResultItemWithEmptyPos); query = query.normalize(); let result = this.opts.match.bind(this)(query); return postProcessResultItems(result, this.opts); } } const asyncDefaultOpts = { ...defaultOpts, match: asyncBasicMatch }; class AsyncFinder extends BaseFinder { constructor(list, ...optionsTuple) { super(list, ...optionsTuple); this.opts = { ...asyncDefaultOpts, ...optionsTuple[0] }; this.token = { cancelled: false }; } async find(query) { this.token.cancelled = true; this.token = { cancelled: false }; if (query.length === 0 || this.items.length === 0) return this.items.slice(0, this.opts.limit).map(createResultItemWithEmptyPos); query = query.normalize(); let result = await this.opts.match.bind(this)(query, this.token); return postProcessResultItems(result, this.opts); } } const createResultItemWithEmptyPos = (item) => ({ item, start: -1, end: -1, score: 0, positions: /* @__PURE__ */ new Set() }); function postProcessResultItems(result, opts) { if (opts.sort) { const { selector } = opts; result.sort((a, b) => { if (a.score === b.score) { for (const tiebreaker of opts.tiebreakers) { const diff = tiebreaker(a, b, selector); if (diff !== 0) { return diff; } } } return 0; }); } if (Number.isFinite(opts.limit)) { result.splice(opts.limit); } return result; } function byLengthAsc(a, b, selector) { return selector(a.item).length - selector(b.item).length; } function byStartAsc(a, b) { return a.start - b.start; } class Fzf { constructor(list, ...optionsTuple) { this.finder = new SyncFinder(list, ...optionsTuple); this.find = this.finder.find.bind(this.finder); } } class AsyncFzf { constructor(list, ...optionsTuple) { this.finder = new AsyncFinder(list, ...optionsTuple); this.find = this.finder.find.bind(this.finder); } } export { AsyncFzf, Fzf, asyncBasicMatch, asyncExtendedMatch, basicMatch, byLengthAsc, byStartAsc, extendedMatch };