Skip to content
This repository has been archived by the owner on Jul 11, 2022. It is now read-only.

Replace lib fuzzy by fuse.js #20

Closed
Nexucis opened this issue Aug 8, 2020 · 5 comments · Fixed by #26
Closed

Replace lib fuzzy by fuse.js #20

Nexucis opened this issue Aug 8, 2020 · 5 comments · Fixed by #26
Labels
enhancement New feature or request

Comments

@Nexucis
Copy link
Member

Nexucis commented Aug 8, 2020

  • fuzzy looks like it's abandoned and doesn't support ES5
  • fuse.js can return the indices of matched characters. Useful for enhance the highlight and the escape of the HTML characters.
@Nexucis Nexucis added enhancement New feature or request good first issue Good for newcomers labels Aug 8, 2020
@Nexucis
Copy link
Member Author

Nexucis commented Aug 8, 2020

should fix the issue raised in the PR #18 regarding the problem of escaping the html characters.

@Nexucis
Copy link
Member Author

Nexucis commented Aug 9, 2020

fuse.js is a bit weird of how it is matching the element. From my test, the string su is matching group .
It's not really a big issue, this lib is a bit more permissive than the other one.

@Nexucis
Copy link
Member Author

Nexucis commented Aug 9, 2020

image

Looks like the algo is testing every possible combination.

Another example:
image

Not sure we want that after all. Or maybe there is an option to avoid that, but so far I didn't find it. Any thoughts on this @juliusv ?

In case someone find how to do a better matching and want to fix the issue, here is the filter method I coded for this purpose:

const fuzzyOption = {
  includeScore: true,
  includeMatches: true,
  findAllMatches: false,
};

export class HybridComplete implements CompleteStrategy {
  private filter(
    label: string,
    text: string,
    apply: string | ((view: EditorView, result: CompletionResult, completion: Completion) => void),
    context: AutocompleteContext,
    type?: string
  ): Completion | null {
    if (context.filterType !== FilterType.Fuzzy) {
      // in case the fuzzy filtering is not used, then use the filter method coming from CMN
      let score: number | null;
      if ((score = context.filter(label, text, false))) {
        return { label: escape(label), apply: apply, type: type, score: score };
      }
    }

    const fuse = new Fuse([label], fuzzyOption);
    const result = fuse.search(text);
    if (!result || result.length === 0) {
      return null;
    }

    const matches = result[0].matches;
    if (!matches) {
      // weird case, shouldn't happen regarding the fuzzy option set
      return null;
    }
    // in case fuzzyPre and fuzzyPost option are not set, then there is nothing to do to highlight the string matched
    if (this.fuzzyPre.length === 0 || this.fuzzyPost.length === 0) {
      return { label: escape(label), apply: apply, type: type, score: result[0].score || 0 };
    }
    // otherwise we have to loop other the different match item and replace it one by one
    if (matches.length > 1) {
      // for the moment no idea what do to when there is multiple matches
      // so far, when playing with the lib, it always returns one result for an array of string
      return null;
    }

    let finalLabel = label;
    let shift = 0;
    let startIndex = 0;
    let endIndex = 0;
    for (const idx of matches[0].indices) {
      // move to the next substring matched
      startIndex = shift + idx[0];
      endIndex = startIndex + idx[1] - idx[0];

      let sub = label.substr(idx[0], idx[1] - idx[0] + 1);
      sub = this.fuzzyPre + escape(sub) + this.fuzzyPost;
      finalLabel = finalLabel.substring(0, startIndex) + sub + finalLabel.substring(endIndex + 1);

      shift = shift + sub.length - label.substr(idx[0], idx[1] - idx[0] + 1).length;
    }
    return { label: finalLabel, apply: apply, type: type, score: result[0].score ? 1 - result[0].score : 0 };
  }
}

Note: it's not finished. The only thing remains is to escape the substring between two substring that should be highlighted

@Nexucis Nexucis removed the good first issue Good for newcomers label Aug 9, 2020
@juliusv
Copy link
Member

juliusv commented Aug 11, 2020

Hm yeah, I didn't find an option (immediately) to turn off that over-zealous matching either. We definitely don't want that, I think. Otherwise an approach like this could be interesting.

@Nexucis
Copy link
Member Author

Nexucis commented Aug 13, 2020

lib will be replaced by https://github.com/Nexucis/fuzzy instead

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request
Projects
None yet
2 participants