summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2025-11-20 12:29:42 +0800
committerGitHub <[email protected]>2025-11-20 12:29:42 +0800
commit6046c050650e63b430777dda1c6ce497ac43917e (patch)
treec87babf08377b31f2ddf87b4e79cb34312927b83
parent867cac26f83933451ab21ea94c6d2ddded373992 (diff)
parent800e4177ac9584c30a56bf1c3ce356b76b6653e8 (diff)
Merge pull request #7040 from xmake-io/progress
Improve multi-row progress
-rw-r--r--xmake/modules/async/runjobs.lua12
-rw-r--r--xmake/modules/private/action/build/target.lua39
-rw-r--r--xmake/modules/private/check/checkers/clang/tidy.lua19
-rw-r--r--xmake/modules/utils/progress.lua53
-rw-r--r--xmake/plugins/format/main.lua17
5 files changed, 124 insertions, 16 deletions
diff --git a/xmake/modules/async/runjobs.lua b/xmake/modules/async/runjobs.lua
index 286047199..e08acc908 100644
--- a/xmake/modules/async/runjobs.lua
+++ b/xmake/modules/async/runjobs.lua
@@ -49,11 +49,11 @@ function _init_progress(state, opt)
end
-- init progress wrapper
- state.finished_count = 0
+ state.progress_finished_count = 0
state.progress_factor = opt.progress_factor or 1.0
local progress_wrapper = {}
progress_wrapper.current = function ()
- return state.finished_count
+ return state.progress_finished_count
end
progress_wrapper.total = function ()
return state.total
@@ -61,7 +61,7 @@ function _init_progress(state, opt)
progress_wrapper.percent = function ()
local total = state.total
if total and total > 0 then
- return math.floor((state.finished_count * state.progress_factor * 100) / total)
+ return math.floor((state.progress_finished_count * state.progress_factor * 100) / total)
else
return 0
end
@@ -203,8 +203,14 @@ function _consume_jobs_loop(state, run_in_remote)
if curdir then
os.cd(curdir)
end
+
+ -- to avoid running the same task repeatedly,
+ -- we need to update the completion count in advance.
state.finished_count = state.finished_count + 1
job_func(job_index, total, {progress = state.progress_wrapper})
+
+ -- update progress
+ state.progress_finished_count = state.progress_finished_count + 1
end
state.running_jobs_indices[job_index] = nil
co_running:data_set("runjobs.running", false)
diff --git a/xmake/modules/private/action/build/target.lua b/xmake/modules/private/action/build/target.lua
index c88d7b830..c3d21f399 100644
--- a/xmake/modules/private/action/build/target.lua
+++ b/xmake/modules/private/action/build/target.lua
@@ -28,6 +28,7 @@ import("async.runjobs", {alias = "async_runjobs"})
import("async.jobgraph", {alias = "async_jobgraph"})
import("private.utils.batchcmds")
import("private.utils.rule", {alias = "rule_utils"})
+import("utils.progress", {alias = "progress_utils"})
-- clean target for rebuilding
function _clean_target(target)
@@ -791,9 +792,22 @@ function run_targetjobs(targets_root, opt)
local jobgraph = get_targetjobs(targets_root, opt)
if jobgraph and not jobgraph:empty() then
local curdir = os.curdir()
- async_runjobs(job_kind, jobgraph, {
- comax = opt.jobs or option.get("jobs") or 1, curdir = curdir,
- distcc = opt.distcc, remote_only = opt.remote_only, progress_factor = opt.progress_factor})
+ local runjobs_opt = {
+ comax = opt.jobs or option.get("jobs") or 1,
+ curdir = curdir,
+ distcc = opt.distcc,
+ remote_only = opt.remote_only,
+ progress_factor = opt.progress_factor
+ }
+ -- Only set timer for multirow progress mode
+ if progress_utils.is_multirow() then
+ runjobs_opt.timeout = 1000
+ runjobs_opt.on_timer = function (running_indices)
+ -- Periodically refresh multirow progress to update elapsed time
+ progress_utils.refresh()
+ end
+ end
+ async_runjobs(job_kind, jobgraph, runjobs_opt)
os.cd(curdir)
return true
end
@@ -806,9 +820,22 @@ function run_filejobs(targets_root, opt)
local jobgraph = get_filejobs(targets_root, opt)
if jobgraph and not jobgraph:empty() then
local curdir = os.curdir()
- async_runjobs(job_kind, jobgraph, {
- comax = opt.jobs or option.get("jobs") or 1, curdir = curdir,
- distcc = opt.distcc, remote_only = opt.remote_only, progress_factor = opt.progress_factor})
+ local runjobs_opt = {
+ comax = opt.jobs or option.get("jobs") or 1,
+ curdir = curdir,
+ distcc = opt.distcc,
+ remote_only = opt.remote_only,
+ progress_factor = opt.progress_factor
+ }
+ -- Only set timer for multirow progress mode
+ if progress_utils.is_multirow() then
+ runjobs_opt.timeout = 1000
+ runjobs_opt.on_timer = function (running_indices)
+ -- Periodically refresh multirow progress to update elapsed time
+ progress_utils.refresh()
+ end
+ end
+ async_runjobs(job_kind, jobgraph, runjobs_opt)
os.cd(curdir)
return true
end
diff --git a/xmake/modules/private/check/checkers/clang/tidy.lua b/xmake/modules/private/check/checkers/clang/tidy.lua
index fc42a77cc..03568eb6e 100644
--- a/xmake/modules/private/check/checkers/clang/tidy.lua
+++ b/xmake/modules/private/check/checkers/clang/tidy.lua
@@ -85,7 +85,7 @@ end
-- check a single sourcefile
function _check_sourcefile(clang_tidy, sourcefile, opt)
- progress.show(opt.progress_percent, "clang-tidy.analyzing %s", sourcefile)
+ progress.show(opt.progress, "clang-tidy.analyzing %s", sourcefile)
try
{
function ()
@@ -155,15 +155,28 @@ function _check_sourcefiles(clang_tidy, sourcefiles, opt)
-- run clang-tidy
local analyze_time = os.mclock()
+ local runjobs_opt = {
+ total = #sourcefiles,
+ comax = opt.jobs or os.default_njob(),
+ showtips = false
+ }
+ -- Only set timer for multirow progress mode
+ if progress.is_multirow() then
+ runjobs_opt.timeout = 1000
+ runjobs_opt.on_timer = function (running_indices)
+ -- Periodically refresh multirow progress to update elapsed time
+ progress.refresh()
+ end
+ end
runjobs("checker.tidy", function (index, total, job_opt)
local sourcefile = sourcefiles[index]
local tidy_argv = table.join(argv, {sourcefile})
_check_sourcefile(clang_tidy, sourcefile, {
tidy_argv = tidy_argv,
projectdir = projectdir,
- progress_percent = index * 100 / total
+ progress = job_opt.progress
})
- end, {total = #sourcefiles, comax = opt.jobs or os.default_njob()})
+ end, runjobs_opt)
analyze_time = os.mclock() - analyze_time
progress.show(100, "${color.success}clang-tidy analyzed %d files, spent %.3fs", #sourcefiles, analyze_time / 1000)
end
diff --git a/xmake/modules/utils/progress.lua b/xmake/modules/utils/progress.lua
index 4778c073c..60066ddc5 100644
--- a/xmake/modules/utils/progress.lua
+++ b/xmake/modules/utils/progress.lua
@@ -202,11 +202,22 @@ function _display_subprocess_lines(order_lineinfos)
linecount = linecount + 1
end
end
+ -- clear the left lines
+ local left_linecount = #order_lineinfos - linecount
+ if left_linecount > 0 then
+ for i = 1, left_linecount do
+ tty.erase_line().cr()
+ print("")
+ end
+ tty.cursor_move_up(left_linecount)
+ end
_g.linecount = linecount
end
-- redraw the multirow progress area (internal helper)
-function _redraw_multirow_progress(maxwidth)
+-- @param maxwidth: window width
+-- @param current_time: optional current time (to avoid repeated os.mclock() calls)
+function _redraw_multirow_progress(maxwidth, current_time)
local last_total_progress = _g.last_total_progress
if not last_total_progress then
return
@@ -217,7 +228,9 @@ function _redraw_multirow_progress(maxwidth)
cprint(last_total_progress)
-- build and display the subprocess lines
- local current_time = os.mclock()
+ if not current_time then
+ current_time = os.mclock()
+ end
local order_lineinfos = _build_ordered_subprocess_lineinfos(maxwidth, current_time)
_display_subprocess_lines(order_lineinfos)
io.flush()
@@ -266,6 +279,7 @@ function _show_progress_with_multirow_refresh(progress, format, ...)
-- save the total progress line and progress value for potential redraw in show_output
_g.last_total_progress = progress_line
_g.last_total_progress_value = progress
+ _g.last_show_time = current_time
-- update the current progress info
local current_lineinfo = progress_lineinfos[running]
@@ -382,6 +396,41 @@ function show_output(format, ...)
end
end
+-- check if multirow refresh mode is enabled
+function is_multirow()
+ return _is_multirow_refresh()
+end
+
+-- refresh the multirow progress display to update elapsed time
+-- this is useful for long-running tasks to keep the elapsed time updated
+function refresh()
+ local refresh_mode = _g.refresh_mode
+ if refresh_mode == "multirow" then
+ -- get current time once and reuse it
+ local current_time = os.mclock()
+
+ -- only refresh if more than 500ms has passed since last show
+ -- this avoids too frequent refreshes
+ local last_show_time = _g.last_show_time
+ if last_show_time then
+ local elapsed = current_time - last_show_time
+ if elapsed <= 500 then
+ return
+ end
+ end
+
+ -- move cursor back to the top of progress area to avoid scrolling
+ local linecount = _g.linecount or 0
+ if linecount > 0 then
+ tty.cursor_move_up(linecount + 1)
+ end
+
+ -- redraw the progress area immediately, passing current_time to avoid repeated calls
+ local maxwidth = os.getwinsize().width
+ _redraw_multirow_progress(maxwidth, current_time)
+ end
+end
+
-- abort the progress display mode, used for error exit or early termination
-- this function cleans up the progress display area and restores the terminal state
function show_abort()
diff --git a/xmake/plugins/format/main.lua b/xmake/plugins/format/main.lua
index aa2814af8..7a4c53394 100644
--- a/xmake/plugins/format/main.lua
+++ b/xmake/plugins/format/main.lua
@@ -216,12 +216,25 @@ function main()
jobs = os.default_njob()
end
local format_time = os.mclock()
+ local runjobs_opt = {
+ total = #sourcefiles,
+ comax = jobs,
+ showtips = false
+ }
+ -- Only set timer for multirow progress mode
+ if progress.is_multirow() then
+ runjobs_opt.timeout = 1000
+ runjobs_opt.on_timer = function (running_indices)
+ -- Periodically refresh multirow progress to update elapsed time
+ progress.refresh()
+ end
+ end
runjobs("clang-format", function (index, total, opt)
local sourcefile = sourcefiles[index]
local format_argv = table.join(argv, {sourcefile})
- progress.show(index * 100 / total, "clang-format.formatting %s", sourcefile)
+ progress.show(opt.progress, "clang-format.formatting %s", sourcefile)
os.execv(clang_format.program, format_argv, {curdir = projectdir})
- end, {total = #sourcefiles, comax = jobs})
+ end, runjobs_opt)
format_time = os.mclock() - format_time
progress.show(100, "${color.success}clang-format formatted %d files, spent %.3fs", #sourcefiles, format_time / 1000)
end