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/with
some/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 break
There 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
⚠️ It looks like this solution only works inside scripts, not in interactive shells. I haven’t pushed investigations further.
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 @args
Node.js:
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
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.
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_argvand_es_get_command_argvwill 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
argvfrom 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
1.5.0.1404a1.1.0.36Reproduction
Example given for PowerShell, in a temporary, isolated directory:
There 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
$PSNativeCommandArgumentPassing = 'Legacy', but don’t forget to revert itNode.js:
windowsVerbatimArguments: trueoptionPython
Popen, instead of an array of strings. On Windows this would pass it as the whole command line, verbatimMy 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.