Skip to content

Commit d0f82c2

Browse files
committed
feat(cli): show rebuild timing in dev mode
1 parent 3447aba commit d0f82c2

5 files changed

Lines changed: 103 additions & 28 deletions

File tree

include/vix/cli/build/BuildStyle.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,14 @@ namespace vix::cli::build
177177
const std::string &message,
178178
long long milliseconds);
179179

180+
/** Format a build duration using the build/watch convention. */
181+
std::string format_build_duration(long long milliseconds);
182+
183+
/** Write only a duration, colored when the destination is a TTY. */
184+
void write_build_duration(
185+
std::ostream &out,
186+
long long milliseconds);
187+
180188
void print_task_header_full(
181189
std::ostream &out,
182190
const std::string &action,

include/vix/cli/commands/run/dev/DevSession.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,8 @@ namespace vix::commands::RunCommand::dev
126126
vix::async::core::task<DevChildRunResult> run_child_once_async(
127127
vix::async::core::io_context &ctx,
128128
const fs::path &exePath,
129-
vix::async::core::cancel_token ct);
129+
vix::async::core::cancel_token ct,
130+
std::optional<long long> rebuildDurationMs = std::nullopt);
130131

131132
[[noreturn]] void exec_child_process(const fs::path &exePath) const;
132133

src/build/BuildStyle.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,41 @@
2626
#include <iomanip>
2727

2828
#include <vix/cli/Style.hpp>
29+
#include <vix/cli/util/Strings.hpp>
30+
31+
#ifdef _WIN32
32+
#include <io.h>
33+
#else
34+
#include <unistd.h>
35+
#endif
2936

3037
namespace vix::cli::build
3138
{
3239
namespace style = vix::cli::style;
3340

41+
namespace
42+
{
43+
bool output_is_tty(std::ostream &out) noexcept
44+
{
45+
if (&out != &std::cout)
46+
return false;
47+
#ifdef _WIN32
48+
return _isatty(_fileno(stdout)) != 0;
49+
#else
50+
return ::isatty(STDOUT_FILENO) != 0;
51+
#endif
52+
}
53+
54+
const char *duration_color(long long milliseconds) noexcept
55+
{
56+
if (milliseconds >= 10000)
57+
return style::RED;
58+
if (milliseconds >= 3000)
59+
return style::YELLOW;
60+
return style::GREEN;
61+
}
62+
} // namespace
63+
3464
static std::string colorize(
3565
const char *color,
3666
const std::string &value)
@@ -320,6 +350,26 @@ namespace vix::cli::build
320350
out << "\n";
321351
}
322352

353+
std::string format_build_duration(long long milliseconds)
354+
{
355+
if (milliseconds > 0 && milliseconds < 1000)
356+
return std::to_string(milliseconds) + "ms";
357+
358+
return util::format_seconds(milliseconds);
359+
}
360+
361+
void write_build_duration(
362+
std::ostream &out,
363+
long long milliseconds)
364+
{
365+
const std::string duration = format_build_duration(milliseconds);
366+
if (output_is_tty(out))
367+
out << duration_color(milliseconds) << style::BOLD
368+
<< duration << style::RESET;
369+
else
370+
out << duration;
371+
}
372+
323373
bool BuildLocation::valid() const
324374
{
325375
return !file.empty();

src/commands/run/RunScript.cpp

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <vix/cli/commands/replay/ReplayCapture.hpp>
2323
#include <vix/cli/commands/replay/ReplayRecorder.hpp>
2424
#include <vix/cli/errors/RawLogDetectors.hpp>
25+
#include <vix/cli/build/BuildStyle.hpp>
2526
#include <vix/cli/Style.hpp>
2627
#include <vix/cli/util/Ui.hpp>
2728
#include <vix/utils/Env.hpp>
@@ -37,7 +38,6 @@
3738
#include <cstring>
3839
#include <filesystem>
3940
#include <fstream>
40-
#include <iomanip>
4141
#include <iostream>
4242
#include <mutex>
4343
#include <nlohmann/json.hpp>
@@ -173,21 +173,6 @@ namespace vix::commands::RunCommand::detail
173173
std::thread worker_;
174174
};
175175

176-
std::string format_single_file_build_duration(std::chrono::milliseconds duration)
177-
{
178-
const long long milliseconds = duration.count();
179-
if (milliseconds < 1000)
180-
return std::to_string(milliseconds) + "ms";
181-
182-
std::ostringstream out;
183-
out << std::fixed << std::setprecision(1)
184-
<< static_cast<double>(milliseconds) / 1000.0;
185-
std::string seconds = out.str();
186-
if (seconds.size() >= 2 &&
187-
seconds.compare(seconds.size() - 2, 2, ".0") == 0)
188-
seconds.resize(seconds.size() - 2);
189-
return seconds + "s";
190-
}
191176
#endif
192177

193178
void print_double_dash_warning_if_needed(const Options &opt);
@@ -2342,8 +2327,11 @@ namespace vix::commands::RunCommand::detail
23422327
if (isRebuild)
23432328
{
23442329
std::cout << "Rebuilt " << script.filename().string()
2345-
<< " in " << format_single_file_build_duration(buildDuration)
2346-
<< "\n" << std::flush;
2330+
<< " in ";
2331+
vix::cli::build::write_build_duration(
2332+
std::cout,
2333+
buildDuration.count());
2334+
std::cout << "\n" << std::flush;
23472335
}
23482336

23492337
const auto childStart = Clock::now();

src/commands/run/dev/DevSession.cpp

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616

1717
#include <vix/cli/commands/run/dev/DevSession.hpp>
18+
#include <vix/cli/build/BuildStyle.hpp>
1819
#include <vix/cli/Style.hpp>
1920
#include <vix/cli/commands/run/RunScriptHelpers.hpp>
2021
#include <vix/cli/errors/RawLogDetectors.hpp>
@@ -112,13 +113,21 @@ namespace vix::commands::RunCommand::dev
112113
<< "\n\n";
113114
}
114115

115-
void print_dev_started(int pid)
116+
void print_dev_started(
117+
int pid,
118+
std::optional<long long> rebuildDurationMs)
116119
{
117120
std::cout << " "
118-
<< GREEN << "" << RESET
119-
<< " Started"
120-
<< GRAY << " pid=" << pid << RESET
121-
<< "\n";
121+
<< GREEN << "" << RESET << " ";
122+
if (rebuildDurationMs)
123+
{
124+
std::cout << "Rebuilt in ";
125+
vix::cli::build::write_build_duration(
126+
std::cout,
127+
*rebuildDurationMs);
128+
std::cout << GRAY << " · " << RESET;
129+
}
130+
std::cout << "Started" << GRAY << " pid=" << pid << RESET << "\n";
122131
}
123132

124133
void print_dev_app_exited_cleanly()
@@ -284,9 +293,18 @@ namespace vix::commands::RunCommand::dev
284293
<< GRAY << " (dev)" << RESET
285294
<< "\n";
286295

296+
fs::path changedPath = change.path;
297+
if (!dev_verbose_ui(options_))
298+
{
299+
std::error_code ec;
300+
const fs::path relative = fs::relative(change.path, options_.projectDir, ec);
301+
if (!ec && !relative.empty())
302+
changedPath = relative;
303+
}
304+
287305
std::cout << " "
288306
<< GRAY << "changed: " << RESET
289-
<< change.path.string()
307+
<< changedPath.generic_string()
290308
<< "\n";
291309
}
292310

@@ -378,10 +396,19 @@ namespace vix::commands::RunCommand::dev
378396
{
379397
const DevChangeKind rebuildKind = pendingChangeKind_;
380398
pendingChangeKind_ = DevChangeKind::Ignore;
399+
const bool isRebuild = rebuildKind != DevChangeKind::Ignore;
400+
const auto rebuildStart = std::chrono::steady_clock::now();
381401

382402
DevRebuilderResult rebuildResult =
383403
co_await rebuild_async(ctx, rebuildKind, ct);
384404

405+
const std::optional<long long> rebuildDurationMs = isRebuild && rebuildResult.ok
406+
? std::optional<long long>(
407+
std::chrono::duration_cast<std::chrono::milliseconds>(
408+
std::chrono::steady_clock::now() - rebuildStart)
409+
.count())
410+
: std::nullopt;
411+
385412
if (ct.is_cancelled())
386413
{
387414
result.exitCode = 130;
@@ -448,7 +475,7 @@ namespace vix::commands::RunCommand::dev
448475
}
449476

450477
const DevChildRunResult childResult =
451-
co_await run_child_once_async(ctx, *exePath, ct);
478+
co_await run_child_once_async(ctx, *exePath, ct, rebuildDurationMs);
452479

453480
if (childResult.reason == DevChildExitReason::RestartRequested)
454481
continue;
@@ -859,7 +886,8 @@ namespace vix::commands::RunCommand::dev
859886
vix::async::core::task<DevChildRunResult> DevSession::run_child_once_async(
860887
vix::async::core::io_context &ctx,
861888
const fs::path &exePath,
862-
vix::async::core::cancel_token ct)
889+
vix::async::core::cancel_token ct,
890+
std::optional<long long> rebuildDurationMs)
863891
{
864892
using Clock = std::chrono::steady_clock;
865893

@@ -907,7 +935,7 @@ namespace vix::commands::RunCommand::dev
907935
std::string runtimeLog;
908936

909937
if (!options_.quiet)
910-
print_dev_started(static_cast<int>(pid));
938+
print_dev_started(static_cast<int>(pid), rebuildDurationMs);
911939

912940
// Do not make the first observable child output wait for a complete file
913941
// polling period. File indexing remains at pollInterval; this short,

0 commit comments

Comments
 (0)