diff --git a/tabby-core/package.json b/tabby-core/package.json index a420ff80..9a57fc13 100644 --- a/tabby-core/package.json +++ b/tabby-core/package.json @@ -20,6 +20,7 @@ "@ngx-translate/core": "^14.0.0", "bootstrap": "^4.1.3", "deepmerge": "^4.1.1", + "fuzzy-search": "^3.2.1", "js-yaml": "^4.0.0", "messageformat": "^2.3.0", "mixpanel": "^0.13.0", diff --git a/tabby-core/src/components/selectorModal.component.ts b/tabby-core/src/components/selectorModal.component.ts index f00f34a3..0bffd3ca 100644 --- a/tabby-core/src/components/selectorModal.component.ts +++ b/tabby-core/src/components/selectorModal.component.ts @@ -1,6 +1,7 @@ import { firstBy } from 'thenby' import { Component, Input, HostListener, ViewChildren, QueryList, ElementRef } from '@angular/core' // eslint-disable-line @typescript-eslint/no-unused-vars import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap' +import FuzzySearch from 'fuzzy-search' import { SelectorOption } from '../api/selector' /** @hidden */ @@ -28,18 +29,21 @@ export class SelectorModalComponent { } @HostListener('keydown', ['$event']) onKeyUp (event: KeyboardEvent): void { - if (event.key === 'ArrowUp') { + if (event.key === 'PageUp' || event.key === 'ArrowUp' && event.metaKey) { + this.selectedIndex -= 10 + event.preventDefault() + } else if (event.key === 'PageDown' || event.key === 'ArrowDown' && event.metaKey) { + this.selectedIndex += 10 + event.preventDefault() + } else if (event.key === 'ArrowUp') { this.selectedIndex-- event.preventDefault() - } - if (event.key === 'ArrowDown') { + } else if (event.key === 'ArrowDown') { this.selectedIndex++ event.preventDefault() - } - if (event.key === 'Enter') { + } else if (event.key === 'Enter') { this.selectOption(this.filteredOptions[this.selectedIndex]) - } - if (event.key === 'Escape') { + } else if (event.key === 'Escape') { this.close() } if (event.key === 'Backspace' && this.canEditSelected()) { @@ -64,9 +68,17 @@ export class SelectorModalComponent { ) .filter(x => !x.freeInputPattern) } else { - const terms = f.split(' ') // eslint-disable-next-line @typescript-eslint/restrict-plus-operands - this.filteredOptions = this.options.filter(x => x.freeInputPattern ?? this.filterMatches(x, terms)) + this.filteredOptions = new FuzzySearch( + this.options, + ['name', 'group', 'description'], + { sort: true }, + ).search(f) + + const freeOption = this.options.find(x => x.freeInputPattern) + if (freeOption && !this.filteredOptions.includes(freeOption)) { + this.filteredOptions.push(freeOption) + } } this.selectedIndex = Math.max(0, this.selectedIndex) this.selectedIndex = Math.min(this.filteredOptions.length - 1, this.selectedIndex) diff --git a/tabby-core/yarn.lock b/tabby-core/yarn.lock index 43d3d3da..7c95c69d 100644 --- a/tabby-core/yarn.lock +++ b/tabby-core/yarn.lock @@ -43,6 +43,11 @@ deepmerge@^4.1.1: resolved "https://registry.yarnpkg.com/filesize/-/filesize-6.3.0.tgz#dff53cfb3f104c9e422f346d53be8dbcc971bf11" integrity sha512-ytx0ruGpDHKWVoiui6+BY/QMNngtDQ/pJaFwfBpQif0J63+E8DLdFyqS3NkKQn7vIruUEpoGD9JUJSg7Kp+I0g== +fuzzy-search@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/fuzzy-search/-/fuzzy-search-3.2.1.tgz#65d5faad6bc633aee86f1898b7788dfe312ac6c9" + integrity sha512-vAcPiyomt1ioKAsAL2uxSABHJ4Ju/e4UeDM+g1OlR0vV4YhLGMNsdLNvZTpEDY4JCSt0E4hASCNM5t2ETtsbyg== + https-proxy-agent@5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2"