diff options
| author | ruki <[email protected]> | 2025-11-20 12:29:42 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-11-20 12:29:42 +0800 |
| commit | 6046c050650e63b430777dda1c6ce497ac43917e (patch) | |
| tree | c87babf08377b31f2ddf87b4e79cb34312927b83 | |
| parent | 867cac26f83933451ab21ea94c6d2ddded373992 (diff) | |
| parent | 800e4177ac9584c30a56bf1c3ce356b76b6653e8 (diff) | |
Merge pull request #7040 from xmake-io/progress
Improve multi-row progress
| -rw-r--r-- | xmake/modules/async/runjobs.lua | 12 | ||||
| -rw-r--r-- | xmake/modules/private/action/build/target.lua | 39 | ||||
| -rw-r--r-- | xmake/modules/private/check/checkers/clang/tidy.lua | 19 | ||||
| -rw-r--r-- | xmake/modules/utils/progress.lua | 53 | ||||
| -rw-r--r-- | xmake/plugins/format/main.lua | 17 |
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 |
