Skip to content

Commit 41c55f8

Browse files
committed
refactor(cli): unify new command output and add registry init
1 parent 9c75350 commit 41c55f8

2 files changed

Lines changed: 198 additions & 61 deletions

File tree

src/commands/NewCommand.cpp

Lines changed: 100 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -867,10 +867,12 @@ int main()
867867
};
868868

869869
int cursorIndex = 0;
870+
int selectedIndex = 0;
871+
res.selected[selectedIndex] = true;
870872

871873
auto render_item = [&](const Item &item, bool active) -> std::string
872874
{
873-
const bool on = static_cast<bool>(res.selected[item.index]);
875+
const bool selected = (selectedIndex == static_cast<int>(item.index));
874876

875877
std::string line = PAD;
876878
line += " ";
@@ -880,7 +882,10 @@ int main()
880882
else
881883
line += " ";
882884

883-
line += on ? "" : "";
885+
if (selected)
886+
line += std::string(CYAN) + "" + RESET;
887+
else
888+
line += std::string(GRAY) + "" + RESET;
884889

885890
if (active)
886891
line += std::string(CYAN) + BOLD + item.label + RESET;
@@ -893,18 +898,19 @@ int main()
893898
auto build_lines = [&](int activeIdx) -> std::vector<std::string>
894899
{
895900
std::vector<std::string> out;
896-
out.reserve(9);
897901

898902
out.push_back(std::string(PAD) + BOLD + CYAN + "Core" + RESET);
899903

900904
for (int i = 0; i < 3; ++i)
901-
out.push_back(render_item(items[static_cast<std::size_t>(i)], i == activeIdx));
905+
out.push_back(render_item(items[i], i == activeIdx));
906+
907+
out.push_back("");
902908

903-
out.push_back(std::string(PAD));
904909
out.push_back(std::string(PAD) + BOLD + CYAN + "Advanced" + RESET);
905910
out.push_back(render_item(items[3], activeIdx == 3));
906911

907-
out.push_back(std::string(PAD) + ui::dim("" + items[static_cast<std::size_t>(activeIdx)].tip));
912+
out.push_back("");
913+
out.push_back(std::string(PAD) + ui::dim(items[activeIdx].tip));
908914

909915
return out;
910916
};
@@ -935,41 +941,45 @@ int main()
935941

936942
if (k == Key::Up)
937943
{
938-
cursorIndex -= 1;
939-
if (cursorIndex < 0)
940-
cursorIndex = 3;
944+
cursorIndex = (cursorIndex - 1 + 4) % 4;
945+
selectedIndex = cursorIndex;
946+
947+
std::fill(res.selected.begin(), res.selected.end(), false);
948+
res.selected[static_cast<std::size_t>(selectedIndex)] = true;
949+
941950
render_lines(build_lines(cursorIndex), firstDraw);
942951
continue;
943952
}
944953

945954
if (k == Key::Down)
946955
{
947956
cursorIndex = (cursorIndex + 1) % 4;
948-
render_lines(build_lines(cursorIndex), firstDraw);
949-
continue;
950-
}
957+
selectedIndex = cursorIndex;
958+
959+
std::fill(res.selected.begin(), res.selected.end(), false);
960+
res.selected[static_cast<std::size_t>(selectedIndex)] = true;
951961

952-
if (k == Key::Space)
953-
{
954-
const std::size_t idx = items[static_cast<std::size_t>(cursorIndex)].index;
955-
res.selected[idx] = !static_cast<bool>(res.selected[idx]);
956962
render_lines(build_lines(cursorIndex), firstDraw);
957963
continue;
958964
}
959965

960-
if (k == Key::ToggleAll)
966+
if (k == Key::Space || k == Key::Enter)
961967
{
962-
toggle_all(res.selected);
968+
selectedIndex = cursorIndex;
969+
970+
std::fill(res.selected.begin(), res.selected.end(), false);
971+
res.selected[selectedIndex] = true;
972+
973+
if (k == Key::Enter)
974+
{
975+
res.cancelled = false;
976+
return res;
977+
}
978+
963979
render_lines(build_lines(cursorIndex), firstDraw);
964980
continue;
965981
}
966982

967-
if (k == Key::Enter)
968-
{
969-
res.cancelled = false;
970-
return res;
971-
}
972-
973983
if (k == Key::Escape || k == Key::Quit)
974984
{
975985
std::cout << "\n";
@@ -980,11 +990,10 @@ int main()
980990
}
981991
}
982992

983-
// Project generation (strict: no unselected feature appears)
984993
static std::string make_readme_app(const std::string &projectName)
985994
{
986995
std::string readme;
987-
readme.reserve(6200);
996+
readme.reserve(7200);
988997

989998
readme += "# " + projectName + "\n\n";
990999
readme += "Minimal Vix.cpp application.\n\n";
@@ -1013,6 +1022,7 @@ int main()
10131022

10141023
readme += "## Tasks\n\n";
10151024
readme += "This template also defines default tasks in `vix.json`.\n\n";
1025+
10161026
readme += "Run them with:\n\n";
10171027
readme += "```bash\n";
10181028
readme += "vix task <name>\n";
@@ -1039,34 +1049,46 @@ int main()
10391049
readme += "You can edit `vix.json` to customize commands, variables, environments, and task pipelines.\n\n";
10401050

10411051
readme += "## Configuration\n\n";
1042-
readme += "Vix applications do not auto-load project configuration by default.\n";
1043-
readme += "If you want to use a project-level configuration, for example to configure the server port,\n";
1044-
readme += "you must explicitly initialize and read it in your application.\n\n";
1052+
readme += "Vix applications use `.env` files for project configuration.\n";
1053+
readme += "This lets you configure ports, database settings, logging, WebSocket options, and other runtime values without changing your C++ code.\n\n";
10451054

1046-
readme += "### Project config file\n\n";
1047-
readme += "Create a configuration file at:\n\n";
1055+
readme += "### Project env file\n\n";
1056+
readme += "Create a file at the project root:\n\n";
10481057
readme += "```\n";
1049-
readme += "config/config.json\n";
1058+
readme += ".env\n";
10501059
readme += "```\n\n";
10511060

10521061
readme += "Example:\n\n";
1053-
readme += "```json\n";
1054-
readme += "{\n";
1055-
readme += " \"server\": {\n";
1056-
readme += " \"port\": 8081\n";
1057-
readme += " }\n";
1058-
readme += "}\n";
1062+
readme += "```env\n";
1063+
readme += "SERVER_PORT=8081\n";
1064+
readme += "DATABASE_ENGINE=mysql\n";
1065+
readme += "DATABASE_DEFAULT_HOST=127.0.0.1\n";
1066+
readme += "DATABASE_DEFAULT_PORT=3306\n";
1067+
readme += "DATABASE_DEFAULT_USER=root\n";
1068+
readme += "DATABASE_DEFAULT_PASSWORD=\n";
1069+
readme += "DATABASE_DEFAULT_NAME=appdb\n";
1070+
readme += "LOGGING_ASYNC=true\n";
1071+
readme += "WAF_MODE=basic\n";
10591072
readme += "```\n\n";
10601073

1061-
readme += "### Using the config in code\n\n";
1074+
readme += "### Layered env files\n\n";
1075+
readme += "Vix supports layered env files.\n";
1076+
readme += "Depending on your environment, you can use files such as:\n\n";
1077+
readme += "- `.env`\n";
1078+
readme += "- `.env.local`\n";
1079+
readme += "- `.env.production`\n";
1080+
readme += "- `.env.production.local`\n\n";
1081+
1082+
readme += "This makes it easy to separate local development and production configuration.\n\n";
1083+
1084+
readme += "### Using config in code\n\n";
10621085
readme += "To use the project configuration, initialize and read it explicitly:\n\n";
10631086
readme += "```cpp\n";
10641087
readme += "#include <vix.hpp>\n";
10651088
readme += "using namespace vix;\n\n";
10661089
readme += "int main()\n";
10671090
readme += "{\n";
1068-
readme += " // Load project config (project config overrides Vix install config)\n";
1069-
readme += " auto &cfg = vix::config::Config::getInstance();\n\n";
1091+
readme += " auto &cfg = vix::config::Config::getInstance(\".env\");\n\n";
10701092
readme += " App app;\n";
10711093
readme += " app.get(\"/\", [](Request&, Response& res) {\n";
10721094
readme += " res.send(\"Hello world\");\n";
@@ -1075,10 +1097,26 @@ int main()
10751097
readme += "}\n";
10761098
readme += "```\n\n";
10771099

1078-
readme += "> The project `config/config.json` always takes precedence over the global Vix installation config.\n";
1100+
readme += "### Environment variable mapping\n\n";
1101+
readme += "Internally, Vix uses logical config keys such as:\n\n";
1102+
readme += "- `server.port`\n";
1103+
readme += "- `database.default.host`\n";
1104+
readme += "- `database.default.name`\n";
1105+
readme += "- `websocket.max_message_size`\n\n";
1106+
1107+
readme += "These are mapped automatically to environment variables such as:\n\n";
1108+
readme += "- `SERVER_PORT`\n";
1109+
readme += "- `DATABASE_DEFAULT_HOST`\n";
1110+
readme += "- `DATABASE_DEFAULT_NAME`\n";
1111+
readme += "- `WEBSOCKET_MAX_MESSAGE_SIZE`\n\n";
1112+
1113+
readme += "This keeps the C++ API clean while staying friendly to `.env` workflows.\n\n";
1114+
1115+
readme += "> Recommended: keep `.env` for development and use environment-specific files such as `.env.production` for deployment.\n";
10791116

10801117
return readme;
10811118
}
1119+
10821120
static std::string make_readme_lib(const std::string &name)
10831121
{
10841122
std::string readme;
@@ -1843,27 +1881,31 @@ int main()
18431881

18441882
static void print_next_steps_app(const fs::path &, const std::string &projName)
18451883
{
1884+
namespace ui = vix::cli::util;
1885+
18461886
const std::string manifest = projName + ".vix";
18471887

18481888
std::cout << "\n";
1849-
info("Next steps");
1850-
step("cd " + projName + "/");
1851-
step("vix build");
1852-
step("vix run");
1889+
ui::info_line(std::cout, "Next steps");
1890+
std::cout << " " << ui::dim("cd " + projName + "/") << "\n";
1891+
std::cout << " " << ui::dim("vix build") << "\n";
1892+
std::cout << " " << ui::dim("vix run") << "\n";
18531893
std::cout << "\n";
1854-
hint("vix task dev");
1855-
hint("vix dev " + manifest);
1894+
std::cout << " " << ui::dim("vix task dev") << "\n";
1895+
std::cout << " " << ui::dim("vix dev " + manifest) << "\n";
18561896
}
18571897

18581898
static void print_next_steps_lib(const fs::path &, const std::string &projName)
18591899
{
18601900
namespace ui = vix::cli::util;
18611901

1902+
std::cout << "\n";
18621903
ui::info_line(std::cout, "Next steps");
18631904
std::cout << " " << ui::dim("cd " + projName + "/") << "\n";
18641905
std::cout << " " << ui::dim("vix build") << "\n";
18651906
std::cout << " " << ui::dim("vix tests") << "\n";
1866-
ui::tip_line(std::cout, "tag + publish when ready");
1907+
std::cout << "\n";
1908+
std::cout << " " << ui::dim("TIP: tag + publish when ready") << "\n";
18671909
}
18681910
} // namespace
18691911

@@ -2102,28 +2144,29 @@ namespace vix::commands::NewCommand
21022144
{
21032145
if (!generate_app_project(projectDir, projName, features, genErr))
21042146
{
2105-
error("Failed to create project files.");
2106-
hint(genErr);
2147+
vix::cli::util::err_line(std::cerr, "Failed to create project files.");
2148+
vix::cli::util::warn_line(std::cerr, genErr);
21072149
return 1;
21082150
}
21092151

2110-
success("Project created.");
2111-
info("Location: " + projectDir.string());
2152+
vix::cli::util::ok_line(std::cout, "Project created.");
2153+
vix::cli::util::kv(std::cout, "Location", projectDir.string());
21122154
print_next_steps_app(projectDir, projName);
21132155
return 0;
21142156
}
21152157

21162158
if (!generate_lib_project(projectDir, projName, genErr))
21172159
{
2118-
error("Failed to create project files.");
2119-
hint(genErr);
2160+
vix::cli::util::err_line(std::cerr, "Failed to create project files.");
2161+
vix::cli::util::warn_line(std::cerr, genErr);
21202162
return 1;
21212163
}
21222164

2123-
success("Project created.");
2124-
info("Location: " + projectDir.string());
2165+
vix::cli::util::ok_line(std::cout, "Project created.");
2166+
vix::cli::util::kv(std::cout, "Location", projectDir.string());
21252167
print_next_steps_lib(projectDir, projName);
21262168
return 0;
2169+
return 0;
21272170
}
21282171
catch (const std::exception &ex)
21292172
{

0 commit comments

Comments
 (0)