Instead of making static buffers configurable, let's pick strong
defaults and then use the update thread's stack memory to store the
preallocations. The thread uses a fairly shallow stack so this memory is
otherwise unused. This also makes the data section of the executable
smaller since it runtime allocates the memory when a `std.Progress`
instance is allocated, and in the case that the process is not connected
to a terminal, it never allocates the memory.
It stored some metadata into the canonical node storage data but that is
a race condition because another thread recycles those nodes.
Also, keep the parent name for empty child root node names.
* bump default statically allocated resources
* debug help when multiple instances of std.Progress are initialized
* only handle sigwinch on supported operating systems
* handle when reading from the pipe returns 0 bytes
* avoid printing more lines than rows
This time, we preallocate a fixed set of nodes and have the user-visible
Node only be an index into them. This allows for lock-free management of
the node storage.
Only the parent indexes are stored, and the update thread makes a
serialized copy of the state before trying to compute children lists.
The update thread then walks the tree and outputs an entire tree of
progress rather than only one line.
There is a problem with clearing from the cursor to the end of the
screen when the cursor is at the bottom of the terminal.
New design ideas:
* One global instance, don't try to play nicely with other instances
except via IPC.
* One process owns the terminal and the other processes communicate via
IPC.
* Clear the whole terminal and use multiple lines.
What's implemented so far:
* Query the terminal for size.
* Register a SIGWINCH handler.
* Use a thread for redraws.
To be done:
* IPC
* Handling single threaded targets
* Porting to Windows
* More intelligent display of the progress tree rather than only using
one line.
Most of this migration was performed automatically with `zig fmt`. There
were a few exceptions which I had to manually fix:
* `@alignCast` and `@addrSpaceCast` cannot be automatically rewritten
* `@truncate`'s fixup is incorrect for vectors
* Test cases are not formatted, and their error locations change
API users can take advantage of these to freely write to the terminal
which has an ongoing progress display, similar to what Ninja does when
compiling C/C++ objects and a warning or error message is printed.
I have noticed this causing my terminal to stop accepting input
sometimes. The previous implementation with all of its flaws was better
in the sense that it never caused this to happen.
This commit has multiple reverts in it:
Revert "Merge pull request #13148 from r00ster91/progressfollowup"
This reverts commit cb257d59f9, reversing
changes made to f5f28e0d2c.
Revert "`std.Progress`: fix inaccurate line truncation and use optimal
max terminal width (#12079)"
This reverts commit cd3d8f3a4e.
I think this may be helpful in the future when we might want to calculate this again at some other point.
It also makes it more clear that the other two functions below it are only required for this calculation.
* prep: output_buffer -> output_buffer_slice
* fix: truncate lines accurately
Currently, the code assumes a terminal width of 100.
If we look at what's printed for the last test:
```
Test [1/1] test "basic functionality"... [101/100] this is a really long name designed to activate the truncation code. let's fi...
```
No, it does not really work because the relevant part here is `"[101/100] this is a really long name designed to activate the truncation code. let's fi... "`,
which is 90 characters, but we expect 100 because that's the width that is assumed.
The reason is that it also measures **unprintable characters** (escape sequences) at least non-Windows systems.
With this commit the output is now:
```
Test [1/1] test "basic functionality"... [101/100] this is a really long name designed to activate the truncation code. let's find out if...
```
Of which `"[101/100] this is a really long name designed to activate the truncation code. let's find out if... "`
is the actual output of *our* `std.Progress` (remember that `zig test` has an `std.Progress` and our test itself does).
The length of that string is 100. Now the length is consistent with Windows where we don't use escape sequences. This issue was only present on non-Windows systems.
* feat: decide optimal maximum width
This is done by 1. getting the current terminal width and 2. subtracting that by the current cursor column. This accounts for previous output from someone else.
* test: add more tests
They make it easier to see how the progress line is printed in different cases.
* style: fix typo and improve docs
It also expands an acronym used as a variable name. It confused me.
* cleanup: import std.time
* test: add test
* fix: limit termios usage to Linux only for now
* fix: missing cast on Windows
* test: try to debug failure
* fix: fix off-by-one and disable tests
* docs: make comment clearer
* fix: more durability
* fix(getTerminalWidth): change order
Previously, `suffix` was copied to `output_buffer` at position
`max_end`, thereby writing into reserved space after `max_end`.
This only worked because `suffix` was not larger than
`bytes_needed_for_esc_codes_at_end` (otherwise there'd be a potential
buffer overrun) and no escape codes at end are actually written.
Since 2d5b2bf1c9, escape codes are no
longer written to the end of the buffer. They are now written
exclusively to the front of the buffer.
This allows removing `bytes_needed_for_esc_codes_at_end` and
simplifying the suffix printing logic.
This also fixes the bug that the ellipse suffix was not printed in
Windows terminals because `end.* > max_end` was never true.
Previously the progress displayed the first item as [0/x]. This was
misleading when x is the number of items. The first item should be
displayed as [1/x]
The console test# label [test#/#tests] was being generated inside
refreshWithHeldLock (in lib/std/Progress.zig), using the number of
completed items. This was being incremented by 1 when displayed,
which is not required.
This is a breaking change. Before, usage looked like this:
```zig
const held = mutex.acquire();
defer held.release();
```
Now it looks like this:
```zig
mutex.lock();
defer mutex.unlock();
```
The `Held` type was an idea to make mutexes slightly safer by making it
more difficult to forget to release an aquired lock. However, this
ultimately caused more problems than it solved, when any data structures
needed to store a held mutex. Simplify everything by reducing the API
down to the primitives: lock() and unlock().
Closes#8051Closes#8246Closes#10105
We already have a LICENSE file that covers the Zig Standard Library. We
no longer need to remind everyone that the license is MIT in every single
file.
Previously this was introduced to clarify the situation for a fork of
Zig that made Zig's LICENSE file harder to find, and replaced it with
their own license that required annual payments to their company.
However that fork now appears to be dead. So there is no need to
reinforce the copyright notice in every single file.
This reverts the most recent big changes to `std.Progress` changing the
strategy for printing. Before the changes, it would leave the cursor after
the progress line, having better behavior when a stray print happened,
and supporting sub-process progress without any coordination.
After the changes, the cursor was left at the beginning of the line,
making any prints print garbage and often interfering with stack traces
or other debug information.
This commit reverts to before the changes.
Revert "std: Use more common escape sequences in Progress"
This reverts commit 8ebb18d9da.
Revert "Handle some weird edge cases of Win32 API"
This reverts commit b0724a350f.
Revert "Fix many thinkos"
This reverts commit b5a50a26eb.
Revert "Fix Progress printing on Windows systems"
This reverts commit 3010bfb08a.
Revert "std: Better handling of line-wrapping in Progress"
This reverts commit 4fc2e92876.