Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion vkconfig_core/executable_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,10 +195,14 @@ bool ExecutableManager::Load(const QJsonObject& json_root_object, ConfiguratorMo
executable_options.label = json_options_object.value("label").toString().toStdString();
executable_options.working_folder = json_options_object.value("working_folder").toString().toStdString();

std::vector<std::string> args;
const QJsonArray& json_command_lines_array = json_options_object.value("arguments").toArray();
for (int k = 0, p = json_command_lines_array.size(); k < p; ++k) {
executable_options.args.push_back(json_command_lines_array[k].toString().toStdString());
args.push_back(json_command_lines_array[k].toString().toStdString());
}
// Workaround to resolved badly stored arguments when we were using SplitSpace instead of SplitArgs to fill the
// executable arguments option in the UI
executable_options.args = SplitArgs(Merge(args, " "));

const QJsonArray& json_environment_variables_array = json_options_object.value("environment_variables").toArray();
for (int k = 0, p = json_environment_variables_array.size(); k < p; ++k) {
Expand Down
25 changes: 25 additions & 0 deletions vkconfig_core/test/test_command_line.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,31 @@ TEST(test_command_line, usage_mode_settings_html_default_implicit_and_output) {
EXPECT_EQ(HELP_DEFAULT, command_line.help);
}

TEST(test_command_line, usage_mode_settings_html_default_implicit_and_output_whitespace) {
static char* argv[] = {(char*)"vkconfig", (char*)"settings", // settings
(char*)"--generate", (char*)"html", // generate
(char*)"--output", (char*)"\"./my directory/my settings.html\""};
int argc = static_cast<int>(std::size(argv));

CommandLine command_line(argc, argv);

EXPECT_EQ(COMMAND_SETTINGS, command_line.command);
EXPECT_EQ(COMMAND_RESET_SOFT, command_line.command_reset_arg);
EXPECT_EQ(COMMAND_LAYERS_NONE, command_line.command_layers_arg);
EXPECT_EQ(COMMAND_LOADER_NONE, command_line.command_loader_arg);
EXPECT_EQ(COMMAND_DOC_NONE, command_line.command_doc_arg);
EXPECT_EQ(GENERATE_SETTINGS_HTML, command_line.generate_settings_mode);
EXPECT_TRUE(command_line.selected_layers_name.empty());
EXPECT_STREQ("default", command_line.selected_configuration_name.c_str());
EXPECT_TRUE(command_line.GetInputPath().Empty());
EXPECT_STREQ("\"./my directory/my settings.html\"",
ConvertStandardSeparators(command_line.GetOutputPath().RelativePath()).c_str());
EXPECT_EQ(false, command_line.dry_run);
EXPECT_EQ(ERROR_NONE, command_line.error);
EXPECT_TRUE(command_line.error_args.empty());
EXPECT_EQ(HELP_DEFAULT, command_line.help);
}

TEST(test_command_line, usage_mode_settings_html_default_explicit_and_output) {
static char* argv[] = {(char*)"vkconfig", (char*)"settings", // settings
(char*)"--generate", (char*)"html", // generate
Expand Down
90 changes: 89 additions & 1 deletion vkconfig_core/test/test_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ TEST(test_util, trim_surrounding_whitepace) {
std::vector<std::string> strings;
strings.push_back("-o profile.json");
strings.push_back(" -o profile.json ");
strings.push_back("\"-o profile.json\"");
strings.push_back("\t-o profile.json\n");

for (std::size_t i = 0, n = strings.size(); i < n; ++i) {
std::string trimed_string = TrimSurroundingWhitespace(strings[i]);
Expand All @@ -144,6 +144,94 @@ TEST(test_util, trim_surrounding_whitepace) {
}
}

TEST(test_util, split_args_single) {
const std::string source_arg = "--argA";
const std::vector<std::string> split_arg = SplitArgs(source_arg);
EXPECT_EQ(1, split_arg.size());
EXPECT_STREQ("--argA", split_arg[0].c_str());
}

TEST(test_util, split_args_single_with_parem) {
const std::string source_arg = "--argA value-A";
const std::vector<std::string> split_arg = SplitArgs(source_arg);
EXPECT_EQ(1, split_arg.size());
EXPECT_STREQ("--argA value-A", split_arg[0].c_str());
}

TEST(test_util, split_args_single_no_quote) {
const std::string source_arg = "--argA value A";
const std::vector<std::string> split_arg = SplitArgs(source_arg);
EXPECT_EQ(1, split_arg.size());
EXPECT_STREQ("--argA value A", split_arg[0].c_str());
}

TEST(test_util, split_args_multiple_no_quote) {
const std::string source_arg = "--argA value A --argB";
const std::vector<std::string> split_arg = SplitArgs(source_arg);
EXPECT_EQ(2, split_arg.size());
EXPECT_STREQ("--argA value A", split_arg[0].c_str());
EXPECT_STREQ("--argB", split_arg[1].c_str());
}

TEST(test_util, split_args_single_with_quote_with_space) {
const std::string source_arg = "--argA \"value A\"";
const std::vector<std::string> split_arg = SplitArgs(source_arg);
EXPECT_EQ(1, split_arg.size());
EXPECT_STREQ("--argA \"value A\"", split_arg[0].c_str());
}

TEST(test_util, split_args_single_with_quote_without_space) {
const std::string source_arg = "--argA \"value-A\"";
const std::vector<std::string> split_arg = SplitArgs(source_arg);
EXPECT_EQ(1, split_arg.size());
EXPECT_STREQ("--argA \"value-A\"", split_arg[0].c_str());
}

TEST(test_util, split_args_single_with_quote_and_extra) {
const std::string source_arg = "--argA \"value-A\" --argB";
const std::vector<std::string> split_arg = SplitArgs(source_arg);
EXPECT_EQ(2, split_arg.size());
EXPECT_STREQ("--argA \"value-A\"", split_arg[0].c_str());
EXPECT_STREQ("--argB", split_arg[1].c_str());
}

TEST(test_util, split_args_single_with_command_quote_without_space) {
const std::string source_arg = "command --argA \"value-A\"";
const std::vector<std::string> split_arg = SplitArgs(source_arg);
EXPECT_EQ(2, split_arg.size());
EXPECT_STREQ("command", split_arg[0].c_str());
EXPECT_STREQ("--argA \"value-A\"", split_arg[1].c_str());
}

TEST(test_util, split_args_single_with_command_double_quote_without_space) {
const std::string source_arg = "command area --argA \"value-A\"";
const std::vector<std::string> split_arg = SplitArgs(source_arg);
EXPECT_EQ(3, split_arg.size());
EXPECT_STREQ("command", split_arg[0].c_str());
EXPECT_STREQ("area", split_arg[1].c_str());
EXPECT_STREQ("--argA \"value-A\"", split_arg[2].c_str());
}

TEST(test_util, split_args_multiple) {
const std::string source_arg = "--argA --argB valueB --argC \"value C\" --argD value D";
const std::vector<std::string> split_arg = SplitArgs(source_arg);
EXPECT_EQ(4, split_arg.size());
EXPECT_STREQ("--argA", split_arg[0].c_str());
EXPECT_STREQ("--argB valueB", split_arg[1].c_str());
EXPECT_STREQ("--argC \"value C\"", split_arg[2].c_str());
EXPECT_STREQ("--argD value D", split_arg[3].c_str());
}

TEST(test_util, split_args_multiple_mix) {
const std::string source_arg = "cargo run --example solari --features=\"bevy_solari https free_camera\"";
const std::vector<std::string> split_arg = SplitArgs(source_arg);
EXPECT_EQ(4, split_arg.size());
EXPECT_STREQ("cargo", split_arg[0].c_str());
EXPECT_STREQ("run", split_arg[1].c_str());
EXPECT_STREQ("--example solari", split_arg[2].c_str());
EXPECT_STREQ("--features=\"bevy_solari https free_camera\"", split_arg[3].c_str());
}

TEST(test_util, split_arg_default) {
const std::string source_arg = "--argA --argB=valueB \"--argC=value C\" --argD=\"value D\"";
const std::vector<std::string> split_arg = SplitSpace(source_arg);
Expand Down
29 changes: 29 additions & 0 deletions vkconfig_core/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,35 @@ std::vector<std::string> SplitSpace(const std::string& parse) {
return split_result;
}

std::vector<std::string> SplitArgs(const std::string& value) {
std::vector<std::string> space_splitted = SplitSpace(value);

std::vector<std::string> split_result;

bool previous_value_had_dash = false;
for (std::size_t i = 0, n = space_splitted.size(); i < n; ++i) {
std::string value = space_splitted[i];
if (value.empty()) {
continue;
}

if (split_result.empty()) {
split_result.push_back(value);
previous_value_had_dash = value[0] == '-';
continue;
}

if (previous_value_had_dash && value[0] != '-') {
split_result[split_result.size() - 1] += " " + value;
} else {
split_result.push_back(value);
previous_value_had_dash = value[0] == '-';
}
}

return split_result;
}

std::string Merge(const std::vector<std::string>& value, const std::string& delimiter) {
std::string result;

Expand Down
4 changes: 3 additions & 1 deletion vkconfig_core/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,14 @@ bool IsStringFound(const std::vector<std::string>& list, const std::string& valu

std::string TrimString(const std::string& str, const std::string& whitespaces = " \t");

std::string TrimSurroundingWhitespace(const std::string& str, const std::string& whitespaces = " \"\t\n\r");
std::string TrimSurroundingWhitespace(const std::string& str, const std::string& whitespaces = " \t\n\r");

std::vector<std::string> Split(const std::string& value, const std::string& delimiter);

std::vector<std::string> SplitSpace(const std::string& value);

std::vector<std::string> SplitArgs(const std::string& value);

std::string Merge(const std::vector<std::string>& value, const std::string& delimiter);

std::vector<std::string> ConvertString(const QStringList& string_list);
Expand Down
5 changes: 4 additions & 1 deletion vkconfig_gui/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
- Improve generated layer settings C++ library to output to code for `vulkan.hpp`
- Clean up generated layer settings C++ library for less friction on use

### Fixes:
- Fix command line whitespace decoding #2625

## Vulkan Configurator 3.4.2 - Febuary 2026
[Vulkan SDK 1.4.341.0](https://github.com/LunarG/VulkanTools/tree/vulkan-sdk-1.4.341)

Expand All @@ -25,7 +28,7 @@
- Add `settings --layers` command lines option to list multiple layer names when generating files
- Add Validation and API Dump default configuration for interleaved log in stdout
- Add diagnostic log refresh button
- Add layer settings reset to default values button
- Add layer settings reset to default values button #2573
- Improved UI to set an external `vk_layer_settings.txt` file
- Improved "View Enabled Layers" and "Configure All Layers" UI
- Add buttons to open Vulkan SDK directories in diagnostics tab #2585
Expand Down
2 changes: 1 addition & 1 deletion vkconfig_gui/tab_applications.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ void TabApplications::on_launch_options_args_textEdited(const QString &text) {
Executable *executable = configurator.executables.GetActiveExecutable();
ExecutableOptions *options = executable->GetActiveOptions();

options->args = SplitSpace(text.toStdString());
options->args = SplitArgs(text.toStdString());
}

void TabApplications::on_launch_options_envs_textEdited(const QString &text) {
Expand Down