Skip to content

Commit 715c158

Browse files
joyeecheungBethGriggs
authored andcommitted
src: port --bash-completion to C++
So that it gets handle earlier and faster during the bootstrap process. Drive-by fixes: - Remove `[has_eval_string]` and `[ssl_openssl_cert_store]` from the completion output - Set `kProfProcess` execution mode for `--prof-process` instead of `kPrintBashProcess` which is removed in this patch. - Append new line to the end of the output of --bash-completion PR-URL: #25901 Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 4f95213 commit 715c158

File tree

6 files changed

+69
-39
lines changed

6 files changed

+69
-39
lines changed

lib/internal/main/print_bash_completion.js

Lines changed: 0 additions & 29 deletions
This file was deleted.

node.gyp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,6 @@
139139
'lib/internal/main/eval_string.js',
140140
'lib/internal/main/eval_stdin.js',
141141
'lib/internal/main/inspect.js',
142-
'lib/internal/main/print_bash_completion.js',
143142
'lib/internal/main/print_help.js',
144143
'lib/internal/main/prof_process.js',
145144
'lib/internal/main/repl.js',

src/node.cc

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -400,9 +400,6 @@ MaybeLocal<Value> StartMainThreadExecution(Environment* env) {
400400
return StartExecution(env, "internal/main/print_help");
401401
}
402402

403-
if (per_process::cli_options->print_bash_completion) {
404-
return StartExecution(env, "internal/main/print_bash_completion");
405-
}
406403

407404
if (env->options()->prof_process) {
408405
return StartExecution(env, "internal/main/prof_process");
@@ -875,6 +872,12 @@ void Init(int* argc,
875872
exit(0);
876873
}
877874

875+
if (per_process::cli_options->print_bash_completion) {
876+
std::string completion = options_parser::GetBashCompletion();
877+
printf("%s\n", completion.c_str());
878+
exit(0);
879+
}
880+
878881
if (per_process::cli_options->print_v8_help) {
879882
V8::SetFlagsFromString("--help", 6); // Doesn't return.
880883
UNREACHABLE();
@@ -944,6 +947,12 @@ InitializationResult InitializeOncePerProcess(int argc, char** argv) {
944947
return result;
945948
}
946949

950+
if (per_process::cli_options->print_bash_completion) {
951+
std::string completion = options_parser::GetBashCompletion();
952+
printf("%s\n", completion.c_str());
953+
exit(0);
954+
}
955+
947956
if (per_process::cli_options->print_v8_help) {
948957
V8::SetFlagsFromString("--help", 6); // Doesn't return.
949958
UNREACHABLE();

src/node_options.cc

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#include "env-inl.h"
55
#include "node_binding.h"
66

7+
#include <errno.h>
8+
#include <sstream>
79
#include <cstdlib> // strtoul, errno
810

911
using v8::Boolean;
@@ -847,6 +849,43 @@ HostPort SplitHostPort(const std::string& arg,
847849
ParseAndValidatePort(arg.substr(colon + 1), errors) };
848850
}
849851

852+
std::string GetBashCompletion() {
853+
Mutex::ScopedLock lock(per_process::cli_options_mutex);
854+
const auto& parser = _ppop_instance;
855+
856+
std::ostringstream out;
857+
858+
out << "_node_complete() {\n"
859+
" local cur_word options\n"
860+
" cur_word=\"${COMP_WORDS[COMP_CWORD]}\"\n"
861+
" if [[ \"${cur_word}\" == -* ]] ; then\n"
862+
" COMPREPLY=( $(compgen -W '";
863+
864+
for (const auto& item : parser.options_) {
865+
if (item.first[0] != '[') {
866+
out << item.first << " ";
867+
}
868+
}
869+
for (const auto& item : parser.aliases_) {
870+
if (item.first[0] != '[') {
871+
out << item.first << " ";
872+
}
873+
}
874+
if (parser.aliases_.size() > 0) {
875+
out.seekp(-1, out.cur); // Strip the trailing space
876+
}
877+
878+
out << "' -- \"${cur_word}\") )\n"
879+
" return 0\n"
880+
" else\n"
881+
" COMPREPLY=( $(compgen -f \"${cur_word}\") )\n"
882+
" return 0\n"
883+
" fi\n"
884+
"}\n"
885+
"complete -F _node_complete node node_g";
886+
return out.str();
887+
}
888+
850889
// Return a map containing all the options and their metadata as well
851890
// as the aliases
852891
void GetOptions(const FunctionCallbackInfo<Value>& args) {

src/node_options.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ namespace options_parser {
255255
HostPort SplitHostPort(const std::string& arg,
256256
std::vector<std::string>* errors);
257257
void GetOptions(const v8::FunctionCallbackInfo<v8::Value>& args);
258+
std::string GetBashCompletion();
258259

259260
enum OptionType {
260261
kNoOp,
@@ -438,6 +439,7 @@ class OptionsParser {
438439
friend class OptionsParser;
439440

440441
friend void GetOptions(const v8::FunctionCallbackInfo<v8::Value>& args);
442+
friend std::string GetBashCompletion();
441443
};
442444

443445
using StringVector = std::vector<std::string>;

test/parallel/test-bash-completion.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,32 @@
22
require('../common');
33
const assert = require('assert');
44
const child_process = require('child_process');
5+
const { inspect } = require('util');
56

67
const p = child_process.spawnSync(
78
process.execPath, [ '--completion-bash' ]);
89
assert.ifError(p.error);
9-
assert.ok(p.stdout.toString().includes(
10-
`_node_complete() {
10+
11+
const output = p.stdout.toString().trim().replace(/\r/g, '');
12+
console.log(output);
13+
14+
const prefix = `_node_complete() {
1115
local cur_word options
1216
cur_word="\${COMP_WORDS[COMP_CWORD]}"
1317
if [[ "\${cur_word}" == -* ]] ; then
14-
COMPREPLY=( $(compgen -W '`));
15-
assert.ok(p.stdout.toString().includes(
16-
`' -- "\${cur_word}") )
18+
COMPREPLY=( $(compgen -W '`.replace(/\r/g, '');
19+
const suffix = `' -- "\${cur_word}") )
1720
return 0
1821
else
1922
COMPREPLY=( $(compgen -f "\${cur_word}") )
2023
return 0
2124
fi
2225
}
23-
complete -F _node_complete node node_g`));
26+
complete -F _node_complete node node_g`.replace(/\r/g, '');
27+
28+
assert.ok(
29+
output.includes(prefix),
30+
`Expect\n\n ${inspect(output)}\n\nto include\n\n${inspect(prefix)}`);
31+
assert.ok(
32+
output.includes(suffix),
33+
`Expect\n\n ${inspect(output)}\n\nto include\n\n${inspect(suffix)}`);

0 commit comments

Comments
 (0)