From 91efb6d9972185495d4ecc7f2ef1568b4bcb5f55 Mon Sep 17 00:00:00 2001 From: Gyubong Date: Sat, 12 Feb 2022 22:26:40 +0900 Subject: [PATCH] Support fuzzy search (#82) Co-authored-by: Sindre Sorhus --- cli.js | 1 + interactive.js | 29 +++++++++++------------------ package.json | 1 + readme.md | 1 + test.js | 10 ++++++++++ 5 files changed, 24 insertions(+), 18 deletions(-) diff --git a/cli.js b/cli.js index ba24612..b92e469 100755 --- a/cli.js +++ b/cli.js @@ -24,6 +24,7 @@ const cli = meow(` Run without arguments to use the interactive mode. In interactive mode, 🚦n% indicates high CPU usage and 🐏n% indicates high memory usage. + Supports fuzzy search in the interactive mode. The process name is case insensitive. `, { diff --git a/interactive.js b/interactive.js index e7dd9cb..772dd5d 100644 --- a/interactive.js +++ b/interactive.js @@ -9,6 +9,7 @@ import cliTruncate from 'cli-truncate'; import {allPortsWithPid} from 'pid-port'; import fkill from 'fkill'; import processExists from 'process-exists'; +import FuzzySearch from 'fuzzy-search'; const isWindows = process.platform === 'win32'; const commandLineMargins = 4; @@ -43,16 +44,6 @@ const processExited = async (pid, timeout) => { return !exists; }; -const nameFilter = (input, process_) => { - const isPort = input[0] === ':'; - - if (isPort) { - return process_.ports.find(port => port.startsWith(input.slice(1))); - } - - return process_.name.toLowerCase().includes(input.toLowerCase()); -}; - const preferNotMatching = matches => (a, b) => { const aMatches = matches(a); return matches(b) === aMatches ? 0 : (aMatches ? 1 : -1); @@ -99,22 +90,24 @@ const preferHeurisicallyInterestingProcesses = (a, b) => { }; const filterProcesses = (input, processes, flags) => { - const filters = { - name: process_ => input ? nameFilter(input, process_) : true, - verbose: process_ => input ? (isWindows ? process_.name : process_.cmd).toLowerCase().includes(input.toLowerCase()) : true, - }; - const memoryThreshold = flags.verbose ? 0 : 1; const cpuThreshold = flags.verbose ? 0 : 3; - return processes + const filteredProcesses = new FuzzySearch( + processes, + [flags.verbose && !isWindows ? 'cmd' : 'name'], + { + caseSensitive: false, + }, + ) + .search(input); + + return filteredProcesses .filter(process_ => !( process_.name.endsWith('-helper') || process_.name.endsWith('Helper') || process_.name.endsWith('HelperApp') )) - // eslint-disable-next-line unicorn/no-array-callback-reference - .filter(flags.verbose ? filters.verbose : filters.name) .sort(preferHeurisicallyInterestingProcesses) .map(process_ => { const renderPercentage = percents => { diff --git a/package.json b/package.json index fe2c43c..9a76dde 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "cli-truncate": "^3.1.0", "esc-exit": "^3.0.0", "fkill": "^8.0.0", + "fuzzy-search": "^3.2.1", "inquirer": "^8.2.0", "inquirer-autocomplete-prompt": "^1.4.0", "meow": "^10.1.1", diff --git a/readme.md b/readme.md index 47e56a5..3ccf8b1 100644 --- a/readme.md +++ b/readme.md @@ -71,6 +71,7 @@ $ fkill --help Run without arguments to use the interactive interface. In interactive mode, 🚦n% indicates high CPU usage and 🐏n% indicates high memory usage. + Supports fuzzy search in the interactive mode. The process name is case insensitive. ``` diff --git a/test.js b/test.js index 274843c..91a46d9 100644 --- a/test.js +++ b/test.js @@ -1,3 +1,4 @@ +import process from 'node:process'; import childProcess from 'node:child_process'; import test from 'ava'; import execa from 'execa'; @@ -23,6 +24,15 @@ test('pid', async t => { await noopProcessKilled(t, pid); }); +// TODO: Remove the if-statement when https://github.com/nodejs/node/issues/35503 is fixed. +if (process.platform === 'darwin') { + test('fuzzy search', async t => { + const pid = await noopProcess({title: '!noo00oop@'}); + await execa('./cli.js', ['o00oop@']); + await noopProcessKilled(t, pid); + }); +} + test('kill from port', async t => { const port = await getPort(); const {pid} = childProcess.spawn('node', ['fixture.js', port]);