Skip to content

add support to ignore ansi sequences when formatting usage display. Fixes #879#942

Open
timmaffett wants to merge 20 commits intodart-lang:mainfrom
timmaffett:length_ignore_ansi
Open

add support to ignore ansi sequences when formatting usage display. Fixes #879#942
timmaffett wants to merge 20 commits intodart-lang:mainfrom
timmaffett:length_ignore_ansi

Conversation

@timmaffett
Copy link
Copy Markdown

This is a RE-push of the #880 PR - the bot closed it and now the code does not update/so I made this PR so that the new changes can be seen. If the #880 PR got re-opened it would probably update and this could be closed...?

---From ORIGINAL #880 PR ----------------
This PR adds logic to exclude hidden ANSI escape sequences when formatting the Usage display.
The ANSI escape sequences are excluded when calculating the lengths of help strings used in the Usage display by using a string extension lengthWithoutAnsi which removes any hidden ANSI escape sequences present before calculating the string length.

It includes tests of the lengthWithoutAnsi getter to ensure that it returns correct length values when no ANSI escape sequences are present as well as when a variety of ANSI escape sequences are present.

(The regex that i am using here is well exercised, as it is the same reg ex that I use within VS Code when parsing and formatting ANSI sequences within the debug console)

@timmaffett timmaffett requested a review from a team as a code owner February 13, 2026 04:51
Comment thread pkgs/args/lib/src/utils.dart Outdated
Comment on lines +10 to +20
/// Matches the Control Sequence Introducer (CSI) ANSI escape sequences.
///
/// Anatomy:
/// \x1b : The literal ESC character (ASCII 27).
/// \[ : The literal '[' character (together with ESC, this forms the CSI).
/// [0-9;?]* : Zero or more parameter bytes:
/// - 0-9 : Numeric parameters (e.g., color codes).
/// - ; : Parameter separators.
/// - ? : Private mode indicators (e.g., cursor toggles).
/// [a-zA-Z] : The 'Final Byte' that determines the command (e.g., 'm' for color).
static final RegExp _ansiRegex = RegExp(r'\x1b\[[0-9;?]*[a-zA-Z]');
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This covers the full set I've seen used in Dart, but I think we may as well expand the regex to include the other parameter bytes and intermediate bytes allowed.

Suggested change
/// Matches the Control Sequence Introducer (CSI) ANSI escape sequences.
///
/// Anatomy:
/// \x1b : The literal ESC character (ASCII 27).
/// \[ : The literal '[' character (together with ESC, this forms the CSI).
/// [0-9;?]* : Zero or more parameter bytes:
/// - 0-9 : Numeric parameters (e.g., color codes).
/// - ; : Parameter separators.
/// - ? : Private mode indicators (e.g., cursor toggles).
/// [a-zA-Z] : The 'Final Byte' that determines the command (e.g., 'm' for color).
static final RegExp _ansiRegex = RegExp(r'\x1b\[[0-9;?]*[a-zA-Z]');
/// Matches the Control Sequence Introducer (CSI) ANSI escape sequences.
///
/// Anatomy based on ECMA-48:
/// \x1b : The literal ESC character (ASCII 27).
/// \[ : The literal '[' character (together with ESC, this forms the CSI).
/// [\x30-\x3f]* : Parameter Bytes (0-9:;<=>?).
/// [\x20-\x2f]* : Intermediate Bytes ( !"#$%&'()*+,-./).
/// [\x40-\x7e] : Final Byte (@A-Z[\]^_`a-z{|}~).
static final RegExp _ansiRegex = RegExp(r'\x1b\[[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]');

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I have change it to now use your more complete regex. I also expanded the tests to exercise a wider range of ECMA-48 ANSI sequences.

Comment thread pkgs/args/pubspec.yaml Outdated
Comment thread pkgs/args/CHANGELOG.md Outdated
@timmaffett
Copy link
Copy Markdown
Author

Thanks for the quick feedback @natebosch
It's always nicer to get it when the PR is fresh in your mind.

In my first attempt at the simpler regex I was just thinking about catching ANSI text styling codes that would typically be used in a usage message, but this one is not that much more complex and it will now catch everything.

Comment thread pkgs/args/lib/src/utils.dart Outdated
Comment thread pkgs/args/lib/src/utils.dart Outdated
Comment thread pkgs/args/lib/src/utils.dart Outdated
Comment thread pkgs/args/lib/src/utils.dart Outdated
Comment thread pkgs/args/lib/src/utils.dart Outdated
Comment thread pkgs/args/lib/src/utils.dart Outdated
String stripAnsi() => replaceAll(_ansiRegex, '');

/// Returns `true` if the string contains any ANSI escape sequences.
bool hasAnsi() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be getter.
Document as

/// Whether this string contains any ANSI escape sequences.

Comment thread pkgs/args/test/utils_test.dart Outdated
Comment thread pkgs/args/test/utils_test.dart
Comment thread pkgs/args/test/utils_test.dart Outdated
Comment thread pkgs/args/test/utils_test.dart Outdated
Comment thread pkgs/args/lib/src/utils.dart Outdated
Comment thread pkgs/args/test/utils_test.dart Outdated
Comment thread pkgs/args/lib/src/utils.dart Outdated
Comment thread pkgs/args/lib/src/utils.dart Outdated

group('ANSI RegEx Systematic Tests', () {

test('Identifies standard SGR (Select Graphic Rendition) codes', () {
Copy link
Copy Markdown
Member

@lrhn lrhn Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider some more negative edge-case test (if they aren't already here and I just missed them):

  • Character between ESC and [: '\x1b${char}[m' where char is some char other [ or ESC, including fx r'\'. (Or where it is ESC, just to be sure it doesn't count the first one.)
  • Non-valid character instead of terminator: '\x1b[${char} where char is 0x7f or a control character like 0x00-0x1F. Or a non-ASCII character (fx a valid character + 0x80, +0x100, +0xD800, and +0x10000).
  • Or in general, try off-by-0x80/0x100/0x1000/0xd800/0x10000 characters in the parameters and intermediate bytes too. Or even ESC and [: ${String.fromCharCode(0x1b + offset)}[0m, \x1b${String.fromCharCode(0x5b + offset)}0m, \x1b[${String.fromCharCode(0x30 + offset)}m, \x1b[0${String.fromCharCode(0x20 + offset)}m, \x1b[0${String.fromCharCode(0x6d + offset)}, with offset being one on of those numbers.

and check that nothing is matched.

(At least this is UTF-16 strings, not UTF-8, no overlong encodings to worry about 😅 .)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, i added test for all of these edge cases.

Comment thread pkgs/args/lib/src/utils.dart Outdated
}

/// Pads [source] to [length] by adding spaces at the end.
String padRight(String source, int length) =>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Could be extension member too, but would be named padRightIgnoreAnsi.)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

padRightIgnoreAscii extension now

Comment thread pkgs/args/lib/src/utils.dart Outdated
@timmaffett
Copy link
Copy Markdown
Author

OK @irhn I have address all of your comments - Thank you for taking the time for a thorough and the great feedback!

I also included a modified example of the ArgParser example that uses extensive ANSI sequences just so I could verify it in action. I am happy to remove this if needed.

Avoid third_party dependencies from core Dart team repos.
@github-actions
Copy link
Copy Markdown

Package publishing

Package Version Status Publish tag (post-merge)
package:args 2.8.1 ready to publish args-v2.8.1
package:async 2.13.1-wip WIP (no publish necessary)
package:characters 1.4.1 already published at pub.dev
package:collection 1.20.0-wip WIP (no publish necessary)
package:convert 3.1.3-wip WIP (no publish necessary)
package:crypto 3.0.8-wip WIP (no publish necessary)
package:fixnum 1.2.0-wip WIP (no publish necessary)
package:lints 6.1.1-wip (error) pubspec version (6.1.1-wip) and changelog (6.1.0) don't agree
package:logging 1.3.1-wip WIP (no publish necessary)
package:os_detect 2.0.4-wip WIP (no publish necessary)
package:path 1.9.2-wip WIP (no publish necessary)
package:platform 3.1.7-wip WIP (no publish necessary)
package:typed_data 1.4.1-wip WIP (no publish necessary)

Documentation at https://github.com/dart-lang/ecosystem/wiki/Publishing-automation.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 24, 2026

PR Health

Coverage ⚠️
File Coverage
pkgs/args/example/arg_parser/ansi_example.dart 💔 Not covered
pkgs/args/lib/command_runner.dart 💔 Not covered
pkgs/args/lib/src/usage.dart 💔 Not covered
pkgs/args/lib/src/utils.dart 💔 Not covered

This check for test coverage is informational (issues shown here will not fail the PR).

This check can be disabled by tagging the PR with skip-coverage-check.

Breaking changes ✔️
Package Change Current Version New Version Needed Version Looking good?
args Breaking 2.7.0 2.8.0-wip 2.8.0-wip ✔️

This check can be disabled by tagging the PR with skip-breaking-check.

Unused Dependencies ⚠️
Package Status
args
❗ Show Issues
These packages are used outside lib/ but are not dev_dependencies:
* io

For details on how to fix these, see dependency_validator.

This check can be disabled by tagging the PR with skip-unused-dependencies-check.

Changelog Entry ✔️
Package Changed Files

Changes to files need to be accounted for in their respective changelogs.

This check can be disabled by tagging the PR with skip-changelog-check.

License Headers ⚠️
""
Files
pkgs/args/lib/src/usage.dart
pkgs/args/lib/src/utils.dart
pkgs/args/test/utils_test.dart

All source files should start with a license header.

Unrelated files missing license headers
Files
pkgs/args/example/command_runner/draw.dart
pkgs/args/lib/args.dart
pkgs/args/lib/src/allow_anything_parser.dart
pkgs/args/lib/src/arg_parser.dart
pkgs/args/lib/src/arg_parser_exception.dart
pkgs/args/lib/src/arg_results.dart
pkgs/args/lib/src/help_command.dart
pkgs/args/lib/src/option.dart
pkgs/args/lib/src/parser.dart
pkgs/args/lib/src/usage_exception.dart
pkgs/args/test/allow_anything_test.dart
pkgs/args/test/args_test.dart
pkgs/args/test/command_parse_test.dart
pkgs/args/test/command_runner_test.dart
pkgs/args/test/command_test.dart
pkgs/args/test/parse_performance_test.dart
pkgs/args/test/parse_test.dart
pkgs/args/test/test_utils.dart
pkgs/args/test/trailing_options_test.dart
pkgs/args/test/usage_test.dart
pkgs/async/lib/async.dart
pkgs/async/lib/src/async_cache.dart
pkgs/async/lib/src/async_memoizer.dart
pkgs/async/lib/src/byte_collector.dart
pkgs/async/lib/src/cancelable_operation.dart
pkgs/async/lib/src/chunked_stream_reader.dart
pkgs/async/lib/src/delegate/event_sink.dart
pkgs/async/lib/src/delegate/future.dart
pkgs/async/lib/src/delegate/sink.dart
pkgs/async/lib/src/delegate/stream.dart
pkgs/async/lib/src/delegate/stream_consumer.dart
pkgs/async/lib/src/delegate/stream_sink.dart
pkgs/async/lib/src/delegate/stream_subscription.dart
pkgs/async/lib/src/future_group.dart
pkgs/async/lib/src/lazy_stream.dart
pkgs/async/lib/src/null_stream_sink.dart
pkgs/async/lib/src/restartable_timer.dart
pkgs/async/lib/src/result/capture_sink.dart
pkgs/async/lib/src/result/capture_transformer.dart
pkgs/async/lib/src/result/error.dart
pkgs/async/lib/src/result/future.dart
pkgs/async/lib/src/result/release_sink.dart
pkgs/async/lib/src/result/release_transformer.dart
pkgs/async/lib/src/result/result.dart
pkgs/async/lib/src/result/value.dart
pkgs/async/lib/src/single_subscription_transformer.dart
pkgs/async/lib/src/sink_base.dart
pkgs/async/lib/src/stream_closer.dart
pkgs/async/lib/src/stream_completer.dart
pkgs/async/lib/src/stream_extensions.dart
pkgs/async/lib/src/stream_group.dart
pkgs/async/lib/src/stream_queue.dart
pkgs/async/lib/src/stream_sink_completer.dart
pkgs/async/lib/src/stream_sink_extensions.dart
pkgs/async/lib/src/stream_sink_transformer.dart
pkgs/async/lib/src/stream_sink_transformer/handler_transformer.dart
pkgs/async/lib/src/stream_sink_transformer/reject_errors.dart
pkgs/async/lib/src/stream_sink_transformer/stream_transformer_wrapper.dart
pkgs/async/lib/src/stream_sink_transformer/typed.dart
pkgs/async/lib/src/stream_splitter.dart
pkgs/async/lib/src/stream_subscription_transformer.dart
pkgs/async/lib/src/stream_zip.dart
pkgs/async/lib/src/subscription_stream.dart
pkgs/async/lib/src/typed/stream_subscription.dart
pkgs/async/lib/src/typed_stream_transformer.dart
pkgs/async/test/async_cache_test.dart
pkgs/async/test/async_memoizer_test.dart
pkgs/async/test/byte_collection_test.dart
pkgs/async/test/cancelable_operation_test.dart
pkgs/async/test/chunked_stream_reader.dart
pkgs/async/test/future_group_test.dart
pkgs/async/test/io_sink_impl.dart
pkgs/async/test/lazy_stream_test.dart
pkgs/async/test/null_stream_sink_test.dart
pkgs/async/test/reject_errors_test.dart
pkgs/async/test/restartable_timer_test.dart
pkgs/async/test/result/result_captureAll_test.dart
pkgs/async/test/result/result_flattenAll_test.dart
pkgs/async/test/result/result_future_test.dart
pkgs/async/test/result/result_test.dart
pkgs/async/test/single_subscription_transformer_test.dart
pkgs/async/test/sink_base_test.dart
pkgs/async/test/stream_closer_test.dart
pkgs/async/test/stream_completer_test.dart
pkgs/async/test/stream_extensions_test.dart
pkgs/async/test/stream_group_test.dart
pkgs/async/test/stream_queue_test.dart
pkgs/async/test/stream_sink_completer_test.dart
pkgs/async/test/stream_sink_transformer_test.dart
pkgs/async/test/stream_splitter_test.dart
pkgs/async/test/stream_zip_test.dart
pkgs/async/test/stream_zip_zone_test.dart
pkgs/async/test/subscription_stream_test.dart
pkgs/async/test/subscription_transformer_test.dart
pkgs/async/test/typed_wrapper/stream_subscription_test.dart
pkgs/async/test/utils.dart
pkgs/characters/benchmark/benchmark.dart
pkgs/characters/example/main.dart
pkgs/characters/lib/characters.dart
pkgs/characters/lib/src/characters.dart
pkgs/characters/lib/src/characters_impl.dart
pkgs/characters/lib/src/extensions.dart
pkgs/characters/test/characters_test.dart
pkgs/characters/test/src/equiv.dart
pkgs/characters/test/src/text_samples.dart
pkgs/characters/test/src/unicode_tests.dart
pkgs/characters/test/src/various_tests.dart
pkgs/characters/tool/benchmark.dart
pkgs/characters/tool/bin/generate_tables.dart
pkgs/characters/tool/bin/generate_tests.dart
pkgs/characters/tool/generate.dart
pkgs/characters/tool/src/atsp.dart
pkgs/characters/tool/src/data_files.dart
pkgs/characters/tool/src/debug_names.dart
pkgs/characters/tool/src/graph.dart
pkgs/characters/tool/src/indirect_table.dart
pkgs/characters/tool/src/list_overlap.dart
pkgs/characters/tool/src/shared.dart
pkgs/characters/tool/src/string_literal_writer.dart
pkgs/characters/tool/src/table_builder.dart
pkgs/collection/benchmark/benchmark_utils.dart
pkgs/collection/benchmark/deep_collection_equality.dart
pkgs/collection/benchmark/legacy_quicksort.dart
pkgs/collection/benchmark/sort_benchmark.dart
pkgs/collection/lib/algorithms.dart
pkgs/collection/lib/collection.dart
pkgs/collection/lib/equality.dart
pkgs/collection/lib/iterable_zip.dart
pkgs/collection/lib/priority_queue.dart
pkgs/collection/lib/src/algorithms.dart
pkgs/collection/lib/src/boollist.dart
pkgs/collection/lib/src/canonicalized_map.dart
pkgs/collection/lib/src/combined_wrappers/combined_iterable.dart
pkgs/collection/lib/src/combined_wrappers/combined_iterator.dart
pkgs/collection/lib/src/combined_wrappers/combined_list.dart
pkgs/collection/lib/src/combined_wrappers/combined_map.dart
pkgs/collection/lib/src/comparators.dart
pkgs/collection/lib/src/empty_unmodifiable_set.dart
pkgs/collection/lib/src/equality.dart
pkgs/collection/lib/src/equality_map.dart
pkgs/collection/lib/src/equality_set.dart
pkgs/collection/lib/src/functions.dart
pkgs/collection/lib/src/iterable_extensions.dart
pkgs/collection/lib/src/iterable_zip.dart
pkgs/collection/lib/src/list_extensions.dart
pkgs/collection/lib/src/priority_queue.dart
pkgs/collection/lib/src/queue_list.dart
pkgs/collection/lib/src/union_set.dart
pkgs/collection/lib/src/union_set_controller.dart
pkgs/collection/lib/src/unmodifiable_wrappers.dart
pkgs/collection/lib/src/utils.dart
pkgs/collection/lib/src/wrappers.dart
pkgs/collection/lib/wrappers.dart
pkgs/collection/test/algorithms_test.dart
pkgs/collection/test/boollist_test.dart
pkgs/collection/test/canonicalized_map_test.dart
pkgs/collection/test/combined_wrapper/iterable_test.dart
pkgs/collection/test/combined_wrapper/list_test.dart
pkgs/collection/test/combined_wrapper/map_test.dart
pkgs/collection/test/comparators_test.dart
pkgs/collection/test/equality_map_test.dart
pkgs/collection/test/equality_set_test.dart
pkgs/collection/test/equality_test.dart
pkgs/collection/test/extensions_test.dart
pkgs/collection/test/functions_test.dart
pkgs/collection/test/ignore_ascii_case_test.dart
pkgs/collection/test/iterable_zip_test.dart
pkgs/collection/test/priority_queue_test.dart
pkgs/collection/test/queue_list_test.dart
pkgs/collection/test/separate_extensions_test.dart
pkgs/collection/test/union_set_controller_test.dart
pkgs/collection/test/union_set_test.dart
pkgs/collection/test/unmodifiable_collection_test.dart
pkgs/collection/test/wrapper_test.dart
pkgs/convert/benchmark/fixed_datetime_formatter_benchmark.dart
pkgs/convert/example/example.dart
pkgs/convert/lib/convert.dart
pkgs/convert/lib/src/accumulator_sink.dart
pkgs/convert/lib/src/byte_accumulator_sink.dart
pkgs/convert/lib/src/charcodes.dart
pkgs/convert/lib/src/fixed_datetime_formatter.dart
pkgs/convert/lib/src/hex.dart
pkgs/convert/lib/src/hex/decoder.dart
pkgs/convert/lib/src/identity_codec.dart
pkgs/convert/lib/src/percent.dart
pkgs/convert/lib/src/percent/decoder.dart
pkgs/convert/lib/src/string_accumulator_sink.dart
pkgs/convert/lib/src/utils.dart
pkgs/convert/test/accumulator_sink_test.dart
pkgs/convert/test/byte_accumulator_sink_test.dart
pkgs/convert/test/codepage_test.dart
pkgs/convert/test/fixed_datetime_formatter_test.dart
pkgs/convert/test/hex_test.dart
pkgs/convert/test/identity_codec_test.dart
pkgs/convert/test/percent_test.dart
pkgs/convert/test/string_accumulator_sink_test.dart
pkgs/crypto/benchmark/benchmark.dart
pkgs/crypto/example/example.dart
pkgs/crypto/lib/crypto.dart
pkgs/crypto/lib/src/digest.dart
pkgs/crypto/lib/src/digest_sink.dart
pkgs/crypto/lib/src/hash.dart
pkgs/crypto/lib/src/hash_sink.dart
pkgs/crypto/lib/src/hmac.dart
pkgs/crypto/lib/src/md5.dart
pkgs/crypto/lib/src/sha1.dart
pkgs/crypto/lib/src/sha256.dart
pkgs/crypto/lib/src/sha512.dart
pkgs/crypto/lib/src/sha512_fastsinks.dart
pkgs/crypto/lib/src/sha512_slowsinks.dart
pkgs/crypto/lib/src/utils.dart
pkgs/crypto/test/hmac_md5_test.dart
pkgs/crypto/test/hmac_sha1_test.dart
pkgs/crypto/test/hmac_sha256_test.dart
pkgs/crypto/test/hmac_sha2_test.dart
pkgs/crypto/test/sha1_test.dart
pkgs/crypto/test/sha256_test.dart
pkgs/crypto/test/sha512_test.dart
pkgs/crypto/test/sha_monte_test.dart
pkgs/crypto/test/utils.dart
pkgs/crypto/tool/md5sum.dart
pkgs/fixnum/lib/fixnum.dart
pkgs/fixnum/lib/src/int32.dart
pkgs/fixnum/lib/src/int64.dart
pkgs/fixnum/lib/src/int64_emulated.dart
pkgs/fixnum/lib/src/int64_native.dart
pkgs/fixnum/lib/src/intx.dart
pkgs/fixnum/lib/src/utilities.dart
pkgs/fixnum/test/all_tests.dart
pkgs/fixnum/test/int32_test.dart
pkgs/fixnum/test/int64_test.dart
pkgs/fixnum/test/int_64_vm_test.dart
pkgs/lints/tool/gen_docs.dart
pkgs/lints/tool/validate_lib.dart
pkgs/logging/example/main.dart
pkgs/logging/lib/logging.dart
pkgs/logging/lib/src/level.dart
pkgs/logging/lib/src/log_record.dart
pkgs/logging/lib/src/logger.dart
pkgs/logging/test/logging_test.dart
pkgs/os_detect/bin/os_detect.dart
pkgs/os_detect/example/example.dart
pkgs/os_detect/example/tree_shaking.dart
pkgs/os_detect/lib/os_detect.dart
pkgs/os_detect/lib/override.dart
pkgs/os_detect/lib/src/os_kind.dart
pkgs/os_detect/lib/src/os_override.dart
pkgs/os_detect/lib/src/osid_html.dart
pkgs/os_detect/lib/src/osid_io.dart
pkgs/os_detect/lib/src/osid_unknown.dart
pkgs/os_detect/test/osid_test.dart
pkgs/path/benchmark/benchmark.dart
pkgs/path/example/example.dart
pkgs/path/lib/path.dart
pkgs/path/lib/src/characters.dart
pkgs/path/lib/src/context.dart
pkgs/path/lib/src/internal_style.dart
pkgs/path/lib/src/path_exception.dart
pkgs/path/lib/src/path_map.dart
pkgs/path/lib/src/path_set.dart
pkgs/path/lib/src/style.dart
pkgs/path/lib/src/style/posix.dart
pkgs/path/lib/src/style/url.dart
pkgs/path/lib/src/style/windows.dart
pkgs/path/lib/src/utils.dart
pkgs/path/test/browser_test.dart
pkgs/path/test/io_test.dart
pkgs/path/test/path_map_test.dart
pkgs/path/test/path_set_test.dart
pkgs/path/test/path_test.dart
pkgs/path/test/posix_test.dart
pkgs/path/test/relative_test.dart
pkgs/path/test/url_test.dart
pkgs/path/test/utils.dart
pkgs/path/test/windows_test.dart
pkgs/typed_data/lib/src/typed_buffer.dart
pkgs/typed_data/lib/src/typed_queue.dart
pkgs/typed_data/lib/typed_buffers.dart
pkgs/typed_data/lib/typed_data.dart
pkgs/typed_data/test/queue_test.dart
pkgs/typed_data/test/typed_buffers_test.dart
pkgs/typed_data/test/typed_buffers_vm_test.dart

This check can be disabled by tagging the PR with skip-license-check.

API leaks ✔️

The following packages contain symbols visible in the public API, but not exported by the library. Export these symbols or remove them from your publicly visible API.

Package Leaked API symbol Leaking sources

This check can be disabled by tagging the PR with skip-leaking-check.

@natebosch
Copy link
Copy Markdown
Member

We avoid dependencies to third party packages from these repos so I've gone ahead and rewritten the example to use a different ansi library - it's not quite as full featured in terms of colors covered, but it shows the intent just as well.

Comment thread pkgs/args/test/utils_test.dart Outdated
});

group('lengthWithoutAnsi is correct with no ANSI sequences', () {
test('lengthWithoutAnsi returns correct length on lines without ansi', () {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of these tests appear to be duplicates. Were they copy/pasted?

Copy link
Copy Markdown
Author

@timmaffett timmaffett Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is quite possible while I was implementing @lrhn 's suggestions i inadvertently pasted or created a duplicate. Thanks for cleaning it up.

Copy link
Copy Markdown
Member

@natebosch natebosch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Took a closer look at the tests and I think we may be over-testing.

RegExp(r'\x1b\[[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]');

/// Combined length of all ANSI escape sequences in the string.
int get ansiLength {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lrhn - I'm inclined to make more of these implementation details private and remove the tests of the individual APIs, leaving only the tests for lengthWithoutAnsi and padWithoutAnsi. Do you have any concerns?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants