-
Notifications
You must be signed in to change notification settings - Fork 11
Description
While using the Everything CLI from both PowerShell and Node.js, I noticed a strange behavior: when starting to include spaces in some paths prefixed with a function, things would break.
Example: es folder:"folder/with some/spaces".
Turns out, by default, PowerShell or Node.js would quote and escape the argument to make sure it’s received as a single one, as long as the target application uses “standard” command line parsing to grab the arguments. This is not the case in Everything CLI.
So it receives "folder:\"folder/with some/spaces\"" (I omitted the beginning which contains the executable path). In the source code, _es_get_argv and _es_get_command_argv will not take into account the \" escape sequences and therefore count the second quote as a closing quote, ending up with two, weird arguments instead of one:
"folder:\"folder/withsome/spaces\""
I did some tests, changing the source code, and using argv from C instead seems to be working perfectly fine, at least for my simple use cases. CommandLineToArgv would probably work equally.
So the big question is: besides unfortunate backwards-compability requirements, what are the reasons Everything CLI is doing custom parsing? Could it be possible to use standard runtime behavior instead, in a future major version for instance? Or maybe an alternate build?
Context
- Everything version:
1.5.0.1404a - Everything CLI version:
1.1.0.36
Reproduction
Example given for PowerShell, in a temporary, isolated directory:
mkdir 'folder/with some/spaces' # create a hierarchy with some spaces
es folder:"folder/with some/spaces" # search for it and see it breakThere may be other use cases where it breaks, I haven’t taken the time to investigate more.
Workarounds
For those who are facing the same issue as me.
The list is not exhaustive, and solutions should be adapted to your context.
PowerShell
- use
$PSNativeCommandArgumentPassing = 'Legacy', but don’t forget to revert it - about_Preference_Variables - PowerShell | Microsoft Learn
function es {
try {
$previous = $PSNativeCommandArgumentPassing
$PSNativeCommandArgumentPassing = 'Legacy'
$output = es.exe @args # don't forget the extension to avoid infinite recursion
} finally {
$PSNativeCommandArgumentPassing = $previous
}
$output
}
# instead of:
# es @argsNode.js:
- use
windowsVerbatimArguments: trueoption - Child process | Node.js v25.4.0 Documentation
import process from 'node:process';
import {spawn} from 'node:child_process';
const exe = 'es';
const args = process.argv.slice(2);
const proc = spawn(exe, args, {stdio: 'inherit', windowsVerbatimArguments: true});
// instead of:
// const proc = spawn(exe, args, {stdio: 'inherit'});Python
- use a single string input in
Popen, instead of an array of strings. On Windows this would pass it as the whole command line, verbatim - subprocess — Subprocess management — Python 3.14.2 documentation
import shutil
import sys
from subprocess import Popen
exe = shutil.which('es')
args = sys.argv[1:]
proc = Popen(' '.join([exe] + args))
# instead of:
# proc = Popen([exe] + args)
proc.wait()My workaround
What I actually did on my side is to use the Python wrapper (slightly improved compared to the snippet above), and bundle it with PyInstaller, then publish it as a release asset in my fork. That was also the perfect opportunity to use a more “standard” naming scheme for the asset, so that tools like mise-en-place would be able to find it more easily.