From e7b7555d1516d0b274e7269961fce9ec9b30bc98 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 29 Mar 2023 14:33:22 -0500 Subject: [PATCH 001/293] chore: First step --- .cargo/config | 5 + .clippy.toml | 12 ++ .github/renovate.json5 | 71 +++++++++++ .github/settings.yml | 52 ++++++++ .github/workflows/audit.yml | 49 ++++++++ .github/workflows/ci.yml | 128 ++++++++++++++++++++ .github/workflows/committed.yml | 24 ++++ .github/workflows/pre-commit.yml | 23 ++++ .github/workflows/rust-next.yml | 88 ++++++++++++++ .github/workflows/spelling.yml | 21 ++++ .gitignore | 1 + .pre-commit-config.yaml | 26 ++++ CHANGELOG.md | 11 ++ CONTRIBUTING.md | 70 +++++++++++ Cargo.lock | 7 ++ Cargo.toml | 38 ++++++ LICENSE-APACHE | 202 +++++++++++++++++++++++++++++++ LICENSE-MIT | 19 +++ README.md | 26 ++++ committed.toml | 3 + deny.toml | 135 +++++++++++++++++++++ release.toml | 6 + src/lib.rs | 2 + 23 files changed, 1019 insertions(+) create mode 100644 .cargo/config create mode 100644 .clippy.toml create mode 100644 .github/renovate.json5 create mode 100644 .github/settings.yml create mode 100644 .github/workflows/audit.yml create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/committed.yml create mode 100644 .github/workflows/pre-commit.yml create mode 100644 .github/workflows/rust-next.yml create mode 100644 .github/workflows/spelling.yml create mode 100644 .gitignore create mode 100644 .pre-commit-config.yaml create mode 100644 CHANGELOG.md create mode 100644 CONTRIBUTING.md create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 LICENSE-APACHE create mode 100644 LICENSE-MIT create mode 100644 README.md create mode 100644 committed.toml create mode 100644 deny.toml create mode 100644 release.toml create mode 100644 src/lib.rs diff --git a/.cargo/config b/.cargo/config new file mode 100644 index 00000000..ba321231 --- /dev/null +++ b/.cargo/config @@ -0,0 +1,5 @@ +[target.x86_64-pc-windows-msvc] +rustflags = ["-Ctarget-feature=+crt-static"] + +[target.i686-pc-windows-msvc] +rustflags = ["-Ctarget-feature=+crt-static"] diff --git a/.clippy.toml b/.clippy.toml new file mode 100644 index 00000000..16749abd --- /dev/null +++ b/.clippy.toml @@ -0,0 +1,12 @@ +msrv = "1.64.0" # MSRV +warn-on-all-wildcard-imports = true +allow-expect-in-tests = true +allow-unwrap-in-tests = true +allow-dbg-in-tests = true +allow-print-in-tests = true +disallowed-methods = [ + { path = "std::option::Option::map_or", reason = "use `map(..).unwrap_or(..)`" }, + { path = "std::option::Option::map_or_else", reason = "use `map(..).unwrap_or_else(..)`" }, + { path = "std::result::Result::map_or", reason = "use `map(..).unwrap_or(..)`" }, + { path = "std::result::Result::map_or_else", reason = "use `map(..).unwrap_or_else(..)`" }, +] diff --git a/.github/renovate.json5 b/.github/renovate.json5 new file mode 100644 index 00000000..51faa753 --- /dev/null +++ b/.github/renovate.json5 @@ -0,0 +1,71 @@ +{ + "schedule": [ + "before 3am on the first day of the month" + ], + "semanticCommits": "enabled", + "configMigration": true, + "dependencyDashboard": true, + "regexManagers": [ + { + "fileMatch": [ + "^rust-toolchain\\.toml$", + "Cargo.toml$", + "clippy.toml$", + "\.clippy.toml$", + "^\.github/workflows/ci.yml$", + "^\.github/workflows/rust-next.yml$", + ], + "matchStrings": [ + "MSRV.*?(?\\d+\\.\\d+(\\.\\d+)?)", + "(?\\d+\\.\\d+(\\.\\d+)?).*?MSRV", + ], + "depNameTemplate": "rust", + "packageNameTemplate": "rust-lang/rust", + "datasourceTemplate": "github-releases", + } + ], + "packageRules": [ + { + "commitMessageTopic": "MSRV", + "matchManagers": ["regex"], + "matchPackageNames": ["rust"], + "stabilityDays": 126, // 3 releases * 6 weeks per release * 7 days per week + }, + // Goals: + // - Keep version reqs low, ignoring compatible normal/build dependencies + // - Take advantage of latest dev-dependencies + // - Rollup safe upgrades to reduce CI runner load + // - Help keep number of versions down by always using latest breaking change + // - Have lockfile and manifest in-sync + { + "matchManagers": ["cargo"], + "matchDepTypes": ["build-dependencies", "dependencies"], + "matchCurrentVersion": ">=0.1.0", + "matchUpdateTypes": ["patch"], + "enabled": false, + }, + { + "matchManagers": ["cargo"], + "matchDepTypes": ["build-dependencies", "dependencies"], + "matchCurrentVersion": ">=1.0.0", + "matchUpdateTypes": ["minor"], + "enabled": false, + }, + { + "matchManagers": ["cargo"], + "matchDepTypes": ["dev-dependencies"], + "matchCurrentVersion": ">=0.1.0", + "matchUpdateTypes": ["patch"], + "automerge": true, + "groupName": "compatible (dev)", + }, + { + "matchManagers": ["cargo"], + "matchDepTypes": ["dev-dependencies"], + "matchCurrentVersion": ">=1.0.0", + "matchUpdateTypes": ["minor"], + "automerge": true, + "groupName": "compatible (dev)", + }, + ], +} diff --git a/.github/settings.yml b/.github/settings.yml new file mode 100644 index 00000000..0469378d --- /dev/null +++ b/.github/settings.yml @@ -0,0 +1,52 @@ +# These settings are synced to GitHub by https://probot.github.io/apps/settings/ + +repository: + description: "DESCRIPTION" + homepage: "https://docs.rs/PROJECT" + topics: "" + has_issues: true + has_projects: false + has_wiki: false + has_downloads: true + default_branch: main + + allow_squash_merge: true + allow_merge_commit: true + allow_rebase_merge: true + + allow_auto_merge: true + delete_branch_on_merge: true + + squash_merge_commit_title: "PR_TITLE" + squash_merge_commit_message: "PR_BODY" + merge_commit_message: "PR_BODY" + +labels: + # Type + - name: bug + color: '#b60205' + description: Not as expected + - name: enhancement + color: '#1d76db' + description: Improve the expected + # Flavor + - name: question + color: "#cc317c" + description: Uncertainty is involved + - name: breaking-change + color: "#e99695" + - name: good first issue + color: '#c2e0c6' + description: Help wanted! + +branches: + - name: main + protection: + required_pull_request_reviews: null + required_conversation_resolution: true + required_status_checks: + # Required. Require branches to be up to date before merging. + strict: false + contexts: ["CI", "Lint Commits", "Spell Check with Typos"] + enforce_admins: false + restrictions: null diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml new file mode 100644 index 00000000..5b7e83ac --- /dev/null +++ b/.github/workflows/audit.yml @@ -0,0 +1,49 @@ +name: Security audit + +permissions: + contents: read + +on: + pull_request: + paths: + - '**/Cargo.toml' + - '**/Cargo.lock' + push: + branches: + - main + +env: + RUST_BACKTRACE: 1 + CARGO_TERM_COLOR: always + CLICOLOR: 1 + +jobs: + security_audit: + permissions: + issues: write # to create issues (actions-rs/audit-check) + checks: write # to create check (actions-rs/audit-check) + runs-on: ubuntu-latest + # Prevent sudden announcement of a new advisory from failing ci: + continue-on-error: true + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - uses: actions-rs/audit-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + cargo_deny: + permissions: + issues: write # to create issues (actions-rs/audit-check) + checks: write # to create check (actions-rs/audit-check) + runs-on: ubuntu-latest + strategy: + matrix: + checks: + - bans licenses sources + steps: + - uses: actions/checkout@v3 + - uses: EmbarkStudios/cargo-deny-action@v1 + with: + command: check ${{ matrix.checks }} + rust-version: stable diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..783247cb --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,128 @@ +name: CI + +permissions: + contents: read + +on: + pull_request: + push: + branches: + - main + +env: + RUST_BACKTRACE: 1 + CARGO_TERM_COLOR: always + CLICOLOR: 1 + +jobs: + ci: + permissions: + contents: none + name: CI + needs: [test, msrv, docs, rustfmt, clippy] + runs-on: ubuntu-latest + steps: + - name: Done + run: exit 0 + test: + name: Test + strategy: + matrix: + os: ["ubuntu-latest", "windows-latest", "macos-latest"] + rust: ["stable"] + continue-on-error: ${{ matrix.rust != 'stable' }} + runs-on: ${{ matrix.os }} + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + toolchain: ${{ matrix.rust }} + - uses: Swatinem/rust-cache@v2 + - name: Build + run: cargo test --no-run --workspace --all-features + - name: Default features + run: cargo test --workspace + - name: All features + run: cargo test --workspace --all-features + - name: No-default features + run: cargo test --workspace --no-default-features + msrv: + name: "Check MSRV: 1.64.0" + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + toolchain: 1.64.0 # MSRV + - uses: Swatinem/rust-cache@v2 + - name: Default features + run: cargo check --workspace --all-targets + - name: All features + run: cargo check --workspace --all-targets --all-features + - name: No-default features + run: cargo check --workspace --all-targets --no-default-features + docs: + name: Docs + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + - uses: Swatinem/rust-cache@v2 + - name: Check documentation + env: + RUSTDOCFLAGS: -D warnings + run: cargo doc --workspace --all-features --no-deps --document-private-items + rustfmt: + name: rustfmt + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + # Not MSRV because its harder to jump between versions and people are + # more likely to have stable + toolchain: stable + components: rustfmt + - uses: Swatinem/rust-cache@v2 + - name: Check formatting + run: cargo fmt --all -- --check + clippy: + name: clippy + runs-on: ubuntu-latest + permissions: + security-events: write # to upload sarif results + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + toolchain: 1.64.0 # MSRV + components: clippy + - uses: Swatinem/rust-cache@v2 + - name: Install SARIF tools + run: cargo install clippy-sarif --version 0.3.4 --locked # Held back due to msrv + - name: Install SARIF tools + run: cargo install sarif-fmt --version 0.3.4 --locked # Held back due to msrv + - name: Check + run: > + cargo clippy --workspace --all-features --all-targets --message-format=json -- -D warnings --allow deprecated + | clippy-sarif + | tee clippy-results.sarif + | sarif-fmt + continue-on-error: true + - name: Upload + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: clippy-results.sarif + wait-for-processing: true diff --git a/.github/workflows/committed.yml b/.github/workflows/committed.yml new file mode 100644 index 00000000..509be080 --- /dev/null +++ b/.github/workflows/committed.yml @@ -0,0 +1,24 @@ +# Not run as part of pre-commit checks because they don't handle sending the correct commit +# range to `committed` +name: Lint Commits +on: [pull_request] + +permissions: + contents: read + +env: + RUST_BACKTRACE: 1 + CARGO_TERM_COLOR: always + CLICOLOR: 1 + +jobs: + committed: + name: Lint Commits + runs-on: ubuntu-latest + steps: + - name: Checkout Actions Repository + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Lint Commits + uses: crate-ci/committed@master diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml new file mode 100644 index 00000000..d4b0f84a --- /dev/null +++ b/.github/workflows/pre-commit.yml @@ -0,0 +1,23 @@ +name: pre-commit + +permissions: {} # none + +on: + pull_request: + push: + branches: [main] + +env: + RUST_BACKTRACE: 1 + CARGO_TERM_COLOR: always + CLICOLOR: 1 + +jobs: + pre-commit: + permissions: + contents: read + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + - uses: pre-commit/action@v3.0.0 diff --git a/.github/workflows/rust-next.yml b/.github/workflows/rust-next.yml new file mode 100644 index 00000000..8faba304 --- /dev/null +++ b/.github/workflows/rust-next.yml @@ -0,0 +1,88 @@ +name: rust-next + +permissions: + contents: read + +on: + schedule: + - cron: '1 1 1 * *' + +env: + RUST_BACKTRACE: 1 + CARGO_TERM_COLOR: always + CLICOLOR: 1 + +jobs: + test: + name: Test + strategy: + matrix: + os: ["ubuntu-latest", "windows-latest", "macos-latest"] + rust: ["stable", "beta"] + include: + - os: ubuntu-latest + rust: "nightly" + continue-on-error: ${{ matrix.rust != 'stable' }} + runs-on: ${{ matrix.os }} + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + toolchain: ${{ matrix.rust }} + - uses: Swatinem/rust-cache@v2 + - name: Default features + run: cargo test --workspace + - name: All features + run: cargo test --workspace --all-features + - name: No-default features + run: cargo test --workspace --no-default-features + rustfmt: + name: rustfmt + strategy: + matrix: + rust: + - stable + - beta + continue-on-error: ${{ matrix.rust != 'stable' }} + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + toolchain: ${{ matrix.rust }} + components: rustfmt + - uses: Swatinem/rust-cache@v2 + - name: Check formatting + run: cargo fmt --all -- --check + clippy: + name: clippy + runs-on: ubuntu-latest + permissions: + security-events: write # to upload sarif results + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + components: clippy + - uses: Swatinem/rust-cache@v2 + - name: Install SARIF tools + run: cargo install clippy-sarif sarif-fmt + - name: Check + run: > + cargo clippy --workspace --all-features --all-targets --message-format=json -- -D warnings --allow deprecated + | clippy-sarif + | tee clippy-results.sarif + | sarif-fmt + continue-on-error: true + - name: Upload + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: clippy-results.sarif + wait-for-processing: true diff --git a/.github/workflows/spelling.yml b/.github/workflows/spelling.yml new file mode 100644 index 00000000..f31c7ed8 --- /dev/null +++ b/.github/workflows/spelling.yml @@ -0,0 +1,21 @@ +name: Spelling + +permissions: + contents: read + +on: [pull_request] + +env: + RUST_BACKTRACE: 1 + CARGO_TERM_COLOR: always + CLICOLOR: 1 + +jobs: + spelling: + name: Spell Check with Typos + runs-on: ubuntu-latest + steps: + - name: Checkout Actions Repository + uses: actions/checkout@v3 + - name: Spell Check Repo + uses: crate-ci/typos@master diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..eb5a316c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +target diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..f751dec5 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,26 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.3.0 + hooks: + - id: check-yaml + stages: [commit] + - id: check-json + stages: [commit] + - id: check-toml + stages: [commit] + - id: check-merge-conflict + stages: [commit] + - id: check-case-conflict + stages: [commit] + - id: detect-private-key + stages: [commit] + - repo: https://github.com/crate-ci/typos + rev: v1.11.1 + hooks: + - id: typos + stages: [commit] + - repo: https://github.com/crate-ci/committed + rev: v1.0.4 + hooks: + - id: committed + stages: [commit-msg] diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..23a247b5 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,11 @@ +# Change Log +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + + +## [Unreleased] - ReleaseDate + + +[Unreleased]: https://github.com/rust-cli/argfile/compare/v0.1.5...HEAD diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..ce840a94 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,70 @@ +# Contributing to PROJECT + +Thanks for wanting to contribute! There are many ways to contribute and we +appreciate any level you're willing to do. + +## Feature Requests + +Need some new functionality to help? You can let us know by opening an +[issue][new issue]. It's helpful to look through [all issues][all issues] in +case its already being talked about. + +## Bug Reports + +Please let us know about what problems you run into, whether in behavior or +ergonomics of API. You can do this by opening an [issue][new issue]. It's +helpful to look through [all issues][all issues] in case its already being +talked about. + +## Pull Requests + +Looking for an idea? Check our [issues][issues]. If it's look more open ended, +it is probably best to post on the issue how you are thinking of resolving the +issue so you can get feedback early in the process. We want you to be +successful and it can be discouraging to find out a lot of re-work is needed. + +Already have an idea? It might be good to first [create an issue][new issue] +to propose it so we can make sure we are aligned and lower the risk of having +to re-work some of it and the discouragement that goes along with that. + +### Process + +Before posting a PR, we request that the commit history get cleaned up. +However, we recommend avoiding this during the review to make it easier to +check how feedback was handled. Once the PR is ready, we'll ask you to clean up +the commit history from the review. Once you let us know this is done, we can +move forward with merging! If you are uncomfortable with these parts of git, +let us know and we can help. + +For commit messages, we use [Conventional](https://www.conventionalcommits.org) +style. If you already wrote your commits and don't feel comfortable changing +them, don't worry and go ahead and create your PR. We'll work with you on the +best route forward. You can check your branch locally with +[`committed`](https://github.com/crate-ci/committed). + +As a heads up, we'll be running your PR through the following gauntlet: +- warnings turned to compile errors +- `cargo test` +- `rustfmt` +- `clippy` +- `rustdoc` +- [`committed`](https://github.com/crate-ci/committed) +- [`typos`](https://github.com/crate-ci/typos) + +## Releasing + +Pre-requisites +- Running `cargo login` +- A member of `ORG:Maintainers` +- Push permission to the repo +- [`cargo-release`](https://github.com/crate-ci/cargo-release/) + +When we're ready to release, a project owner should do the following +1. Update the changelog (see `cargo release changes` for ideas) +2. Determine what the next version is, according to semver +3. Run [`cargo release -x `](https://github.com/crate-ci/cargo-release) + +[issues]: https://github.com/ORG/PROJECT/issues +[new issue]: https://github.com/ORG/PROJECT/issues/new +[all issues]: https://github.com/ORG/PROJECT/issues?utf8=%E2%9C%93&q=is%3Aissue +[travis]: https://github.com/ORG/PROJECT/blob/master/.travis.yml diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..49c1f2dc --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "PROJECT" +version = "0.0.1" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..55dc8553 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "PROJECT" +version = "0.0.1" +description = "DESCRIPTION" +license = "MIT OR Apache-2.0" +categories = [] +keywords = [] +edition = "2021" +rust-version = "1.64.0" # MSRV +include = [ + "build.rs", + "src/**/*", + "Cargo.toml", + "LICENSE*", + "README.md", + "benches/**/*", + "examples/**/*" +] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[package.metadata.release] +pre-release-replacements = [ + {file="CHANGELOG.md", search="Unreleased", replace="{{version}}", min=1}, + {file="CHANGELOG.md", search="\\.\\.\\.HEAD", replace="...{{tag_name}}", exactly=1}, + {file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}", min=1}, + {file="CHANGELOG.md", search="", replace="\n## [Unreleased] - ReleaseDate\n", exactly=1}, + {file="CHANGELOG.md", search="", replace="\n[Unreleased]: https://github.com/ORG/PROJECT/compare/{{tag_name}}...HEAD", exactly=1}, +] + +[features] +default = [] + +[dependencies] + +[dev-dependencies] diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 00000000..8f71f43f --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 00000000..a2d01088 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright (c) Individual contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 00000000..41d5a974 --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +# PROJECT + +> DESCRIPTION + +[![Documentation](https://img.shields.io/badge/docs-master-blue.svg)][Documentation] +![License](https://img.shields.io/crates/l/PROJECT.svg) +[![Crates Status](https://img.shields.io/crates/v/PROJECT.svg)](https://crates.io/crates/PROJECT) + +## License + +Licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual licensed as above, without any additional terms or +conditions. + +[Crates.io]: https://crates.io/crates/PROJECT +[Documentation]: https://docs.rs/PROJECT diff --git a/committed.toml b/committed.toml new file mode 100644 index 00000000..4211ae38 --- /dev/null +++ b/committed.toml @@ -0,0 +1,3 @@ +style="conventional" +ignore_author_re="(dependabot|renovate)" +merge_commit = false diff --git a/deny.toml b/deny.toml new file mode 100644 index 00000000..ad23fbb3 --- /dev/null +++ b/deny.toml @@ -0,0 +1,135 @@ +# Note that all fields that take a lint level have these possible values: +# * deny - An error will be produced and the check will fail +# * warn - A warning will be produced, but the check will not fail +# * allow - No warning or error will be produced, though in some cases a note +# will be + +# This section is considered when running `cargo deny check advisories` +# More documentation for the advisories section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html +[advisories] +# The lint level for security vulnerabilities +vulnerability = "deny" +# The lint level for unmaintained crates +unmaintained = "warn" +# The lint level for crates that have been yanked from their source registry +yanked = "warn" +# The lint level for crates with security notices. Note that as of +# 2019-12-17 there are no security notice advisories in +# https://github.com/rustsec/advisory-db +notice = "warn" +# A list of advisory IDs to ignore. Note that ignored advisories will still +# output a note when they are encountered. +# +# e.g. "RUSTSEC-0000-0000", +ignore = [ +] + +# This section is considered when running `cargo deny check licenses` +# More documentation for the licenses section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html +[licenses] +unlicensed = "deny" +# List of explicitly allowed licenses +# See https://spdx.org/licenses/ for list of possible licenses +# [possible values: any SPDX 3.11 short identifier (+ optional exception)]. +allow = [ + "MIT", + "Apache-2.0", + #"Apache-2.0 WITH LLVM-exception", +] +# List of explicitly disallowed licenses +# See https://spdx.org/licenses/ for list of possible licenses +# [possible values: any SPDX 3.11 short identifier (+ optional exception)]. +deny = [ +] +# Lint level for licenses considered copyleft +copyleft = "deny" +# Blanket approval or denial for OSI-approved or FSF Free/Libre licenses +# * both - The license will be approved if it is both OSI-approved *AND* FSF +# * either - The license will be approved if it is either OSI-approved *OR* FSF +# * osi-only - The license will be approved if is OSI-approved *AND NOT* FSF +# * fsf-only - The license will be approved if is FSF *AND NOT* OSI-approved +# * neither - This predicate is ignored and the default lint level is used +allow-osi-fsf-free = "neither" +# Lint level used when no other predicates are matched +# 1. License isn't in the allow or deny lists +# 2. License isn't copyleft +# 3. License isn't OSI/FSF, or allow-osi-fsf-free = "neither" +default = "deny" +# The confidence threshold for detecting a license from license text. +# The higher the value, the more closely the license text must be to the +# canonical license text of a valid SPDX license file. +# [possible values: any between 0.0 and 1.0]. +confidence-threshold = 0.8 +# Allow 1 or more licenses on a per-crate basis, so that particular licenses +# aren't accepted for every possible crate as with the normal allow list +exceptions = [ + # Each entry is the crate and version constraint, and its specific allow + # list + #{ allow = ["Zlib"], name = "adler32", version = "*" }, +] + +[licenses.private] +# If true, ignores workspace crates that aren't published, or are only +# published to private registries. +# To see how to mark a crate as unpublished (to the official registry), +# visit https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field. +ignore = true + +# This section is considered when running `cargo deny check bans`. +# More documentation about the 'bans' section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html +[bans] +# Lint level for when multiple versions of the same crate are detected +multiple-versions = "warn" +# Lint level for when a crate version requirement is `*` +wildcards = "deny" +# The graph highlighting used when creating dotgraphs for crates +# with multiple versions +# * lowest-version - The path to the lowest versioned duplicate is highlighted +# * simplest-path - The path to the version with the fewest edges is highlighted +# * all - Both lowest-version and simplest-path are used +highlight = "all" +# The default lint level for `default` features for crates that are members of +# the workspace that is being checked. This can be overridden by allowing/denying +# `default` on a crate-by-crate basis if desired. +workspace-default-features = "allow" +# The default lint level for `default` features for external crates that are not +# members of the workspace. This can be overridden by allowing/denying `default` +# on a crate-by-crate basis if desired. +external-default-features = "allow" +# List of crates that are allowed. Use with care! +allow = [ + #{ name = "ansi_term", version = "=0.11.0" }, +] +# List of crates to deny +deny = [ + # Each entry the name of a crate and a version range. If version is + # not specified, all versions will be matched. + #{ name = "ansi_term", version = "=0.11.0" }, + # + # Wrapper crates can optionally be specified to allow the crate when it + # is a direct dependency of the otherwise banned crate + #{ name = "ansi_term", version = "=0.11.0", wrappers = [] }, +] + +# This section is considered when running `cargo deny check sources`. +# More documentation about the 'sources' section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html +[sources] +# Lint level for what to happen when a crate from a crate registry that is not +# in the allow list is encountered +unknown-registry = "deny" +# Lint level for what to happen when a crate from a git repository that is not +# in the allow list is encountered +unknown-git = "deny" +# List of URLs for allowed crate registries. Defaults to the crates.io index +# if not specified. If it is specified but empty, no registries are allowed. +allow-registry = ["https://github.com/rust-lang/crates.io-index"] +# List of URLs for allowed Git repositories +allow-git = [] + +[sources.allow-org] +# 1 or more github.com organizations to allow git sources for +github = [] diff --git a/release.toml b/release.toml new file mode 100644 index 00000000..16df989c --- /dev/null +++ b/release.toml @@ -0,0 +1,6 @@ +pre-release-commit-message = "chore: Release" +tag-message = "{{tag_name}}" +tag-name = "{{prefix}}v{{version}}" +consolidate-commits = true +consolidate-pushes = true +allow-branch = ["main"] diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 00000000..45bf577c --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,2 @@ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![allow(non_snake_case)] // TODO: Delete me From d6b4446cd761d82313a0e69cf0da82ebfc4084cb Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 29 Mar 2023 14:33:42 -0500 Subject: [PATCH 002/293] docs: Set changelog base --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23a247b5..e378dd7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,4 +8,4 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] - ReleaseDate -[Unreleased]: https://github.com/rust-cli/argfile/compare/v0.1.5...HEAD +[Unreleased]: https://github.com/rust-cli/argfile/compare/e7b7555...HEAD From fbaab420b9e4e01e60522f87e89e2e0a28250c73 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 1 Apr 2023 00:32:08 +0000 Subject: [PATCH 003/293] chore(deps): update msrv to v1.65.0 --- .clippy.toml | 2 +- .github/workflows/ci.yml | 6 +++--- Cargo.toml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.clippy.toml b/.clippy.toml index 16749abd..5c6f9841 100644 --- a/.clippy.toml +++ b/.clippy.toml @@ -1,4 +1,4 @@ -msrv = "1.64.0" # MSRV +msrv = "1.65.0" # MSRV warn-on-all-wildcard-imports = true allow-expect-in-tests = true allow-unwrap-in-tests = true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 783247cb..017d45ec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,7 +49,7 @@ jobs: - name: No-default features run: cargo test --workspace --no-default-features msrv: - name: "Check MSRV: 1.64.0" + name: "Check MSRV: 1.65.0" runs-on: ubuntu-latest steps: - name: Checkout repository @@ -57,7 +57,7 @@ jobs: - name: Install Rust uses: dtolnay/rust-toolchain@stable with: - toolchain: 1.64.0 # MSRV + toolchain: 1.65.0 # MSRV - uses: Swatinem/rust-cache@v2 - name: Default features run: cargo check --workspace --all-targets @@ -107,7 +107,7 @@ jobs: - name: Install Rust uses: dtolnay/rust-toolchain@stable with: - toolchain: 1.64.0 # MSRV + toolchain: 1.65.0 # MSRV components: clippy - uses: Swatinem/rust-cache@v2 - name: Install SARIF tools diff --git a/Cargo.toml b/Cargo.toml index 55dc8553..1c84a5ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" categories = [] keywords = [] edition = "2021" -rust-version = "1.64.0" # MSRV +rust-version = "1.65.0" # MSRV include = [ "build.rs", "src/**/*", From 614b0a2376b9ae6d95a1b768b93d06057f4b82d6 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 29 Mar 2023 14:40:57 -0500 Subject: [PATCH 004/293] docs(contrib): Remove reference to travis --- CONTRIBUTING.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ce840a94..e9d70793 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -67,4 +67,3 @@ When we're ready to release, a project owner should do the following [issues]: https://github.com/ORG/PROJECT/issues [new issue]: https://github.com/ORG/PROJECT/issues/new [all issues]: https://github.com/ORG/PROJECT/issues?utf8=%E2%9C%93&q=is%3Aissue -[travis]: https://github.com/ORG/PROJECT/blob/master/.travis.yml From afeff23549a05cd0e5997f129e5d7a564ec41866 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 29 Mar 2023 14:41:29 -0500 Subject: [PATCH 005/293] chore(ci): Quote strings in yaml --- .github/settings.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/settings.yml b/.github/settings.yml index 0469378d..8ead1bac 100644 --- a/.github/settings.yml +++ b/.github/settings.yml @@ -25,19 +25,19 @@ labels: # Type - name: bug color: '#b60205' - description: Not as expected + description: "Not as expected" - name: enhancement color: '#1d76db' - description: Improve the expected + description: "Improve the expected" # Flavor - name: question color: "#cc317c" - description: Uncertainty is involved + description: "Uncertainty is involved" - name: breaking-change color: "#e99695" - name: good first issue color: '#c2e0c6' - description: Help wanted! + description: "Help wanted!" branches: - name: main From 2768727452315929d88dda7d0686440d8e668736 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 29 Mar 2023 14:46:23 -0500 Subject: [PATCH 006/293] chore: Don't set rustflags by default Doing so can cause unnecessary recompilation --- .cargo/config | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .cargo/config diff --git a/.cargo/config b/.cargo/config deleted file mode 100644 index ba321231..00000000 --- a/.cargo/config +++ /dev/null @@ -1,5 +0,0 @@ -[target.x86_64-pc-windows-msvc] -rustflags = ["-Ctarget-feature=+crt-static"] - -[target.i686-pc-windows-msvc] -rustflags = ["-Ctarget-feature=+crt-static"] From 083884043cc08394c6f91df81e6407721b2dc19e Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 29 Mar 2023 14:51:13 -0500 Subject: [PATCH 007/293] chore: Update release process --- release.toml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/release.toml b/release.toml index 16df989c..160b061b 100644 --- a/release.toml +++ b/release.toml @@ -1,6 +1,2 @@ -pre-release-commit-message = "chore: Release" -tag-message = "{{tag_name}}" -tag-name = "{{prefix}}v{{version}}" -consolidate-commits = true -consolidate-pushes = true +dependent-version = "fix" allow-branch = ["main"] From afd6a45ef73201bf5d5f3d4f0317f432b17c60d0 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 29 Mar 2023 14:53:08 -0500 Subject: [PATCH 008/293] chore: Use workspace inheritance --- Cargo.toml | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1c84a5ee..6e698fb3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,8 @@ -[package] -name = "PROJECT" -version = "0.0.1" -description = "DESCRIPTION" +[workspace] +resolver = "2" + +[workspace.package] license = "MIT OR Apache-2.0" -categories = [] -keywords = [] edition = "2021" rust-version = "1.65.0" # MSRV include = [ @@ -17,6 +15,17 @@ include = [ "examples/**/*" ] +[package] +name = "PROJECT" +version = "0.0.1" +description = "DESCRIPTION" +categories = [] +keywords = [] +license.workspace = true +edition.workspace = true +rust-version.workspace = true +include.workspace = true + [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] From 037f37906dad6d39f9fad371bc9a8ab76e8bd5c4 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 29 Mar 2023 15:07:09 -0500 Subject: [PATCH 009/293] chore(ci): Remove rustfmt/clippy next jobs --- .github/workflows/rust-next.yml | 48 --------------------------------- 1 file changed, 48 deletions(-) diff --git a/.github/workflows/rust-next.yml b/.github/workflows/rust-next.yml index 8faba304..e90121bc 100644 --- a/.github/workflows/rust-next.yml +++ b/.github/workflows/rust-next.yml @@ -38,51 +38,3 @@ jobs: run: cargo test --workspace --all-features - name: No-default features run: cargo test --workspace --no-default-features - rustfmt: - name: rustfmt - strategy: - matrix: - rust: - - stable - - beta - continue-on-error: ${{ matrix.rust != 'stable' }} - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - name: Install Rust - uses: dtolnay/rust-toolchain@stable - with: - toolchain: ${{ matrix.rust }} - components: rustfmt - - uses: Swatinem/rust-cache@v2 - - name: Check formatting - run: cargo fmt --all -- --check - clippy: - name: clippy - runs-on: ubuntu-latest - permissions: - security-events: write # to upload sarif results - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - name: Install Rust - uses: dtolnay/rust-toolchain@stable - with: - toolchain: stable - components: clippy - - uses: Swatinem/rust-cache@v2 - - name: Install SARIF tools - run: cargo install clippy-sarif sarif-fmt - - name: Check - run: > - cargo clippy --workspace --all-features --all-targets --message-format=json -- -D warnings --allow deprecated - | clippy-sarif - | tee clippy-results.sarif - | sarif-fmt - continue-on-error: true - - name: Upload - uses: github/codeql-action/upload-sarif@v2 - with: - sarif_file: clippy-results.sarif - wait-for-processing: true From d1dd4ae94067be2f3158fa46b0e78504705dfb26 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 29 Mar 2023 15:28:54 -0500 Subject: [PATCH 010/293] chore(ci): Expand approved licenses --- deny.toml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/deny.toml b/deny.toml index ad23fbb3..942e08db 100644 --- a/deny.toml +++ b/deny.toml @@ -35,8 +35,12 @@ unlicensed = "deny" # [possible values: any SPDX 3.11 short identifier (+ optional exception)]. allow = [ "MIT", + "MIT-0", "Apache-2.0", - #"Apache-2.0 WITH LLVM-exception", + "BSD-3-Clause", + "MPL-2.0", + "Unicode-DFS-2016", + "CC0-1.0", ] # List of explicitly disallowed licenses # See https://spdx.org/licenses/ for list of possible licenses From 6c8df60dc4015279cef303cab8f4760efb5ebea8 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 29 Mar 2023 22:38:45 -0500 Subject: [PATCH 011/293] chore: Include Cargo.lock --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 6e698fb3..b8ecde11 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ include = [ "build.rs", "src/**/*", "Cargo.toml", + "Cargo.lock", "LICENSE*", "README.md", "benches/**/*", From f7b990b803a4aa448e81a323df3a54e66d2d8df4 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 17 Apr 2023 08:50:19 -0500 Subject: [PATCH 012/293] fix(ci): Fix Renovate regexes --- .github/renovate.json5 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 51faa753..5e8e7e24 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -11,9 +11,9 @@ "^rust-toolchain\\.toml$", "Cargo.toml$", "clippy.toml$", - "\.clippy.toml$", - "^\.github/workflows/ci.yml$", - "^\.github/workflows/rust-next.yml$", + "\\.clippy.toml$", + "^\\.github/workflows/ci.yml$", + "^\\.github/workflows/rust-next.yml$", ], "matchStrings": [ "MSRV.*?(?\\d+\\.\\d+(\\.\\d+)?)", From 4163ad78c72df3a993bea6084fc05c6a2a44b9c2 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 17 Apr 2023 08:51:48 -0500 Subject: [PATCH 013/293] style(ci): Match auto-generated style This will make reviewing auto-update PRs easier --- .github/renovate.json5 | 126 +++++++++++++++++++++++++---------------- 1 file changed, 78 insertions(+), 48 deletions(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 5e8e7e24..0393074e 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -1,35 +1,39 @@ { - "schedule": [ - "before 3am on the first day of the month" + schedule: [ + 'before 3am on the first day of the month' ], - "semanticCommits": "enabled", - "configMigration": true, - "dependencyDashboard": true, - "regexManagers": [ + semanticCommits: 'enabled', + configMigration: true, + dependencyDashboard: true, + regexManagers: [ { - "fileMatch": [ - "^rust-toolchain\\.toml$", - "Cargo.toml$", - "clippy.toml$", - "\\.clippy.toml$", - "^\\.github/workflows/ci.yml$", - "^\\.github/workflows/rust-next.yml$", - ], - "matchStrings": [ - "MSRV.*?(?\\d+\\.\\d+(\\.\\d+)?)", - "(?\\d+\\.\\d+(\\.\\d+)?).*?MSRV", - ], - "depNameTemplate": "rust", - "packageNameTemplate": "rust-lang/rust", - "datasourceTemplate": "github-releases", + fileMatch: [ + '^rust-toolchain\\.toml$', + 'Cargo.toml$', + 'clippy.toml$', + '\\.clippy.toml$', + '^\\.github/workflows/ci.yml$', + '^\\.github/workflows/rust-next.yml$', + ], + matchStrings: [ + 'MSRV.*?(?\\d+\\.\\d+(\\.\\d+)?)', + '(?\\d+\\.\\d+(\\.\\d+)?).*?MSRV', + ], + depNameTemplate: 'rust', + packageNameTemplate: 'rust-lang/rust', + datasourceTemplate: 'github-releases', } ], - "packageRules": [ + packageRules: [ { - "commitMessageTopic": "MSRV", - "matchManagers": ["regex"], - "matchPackageNames": ["rust"], - "stabilityDays": 126, // 3 releases * 6 weeks per release * 7 days per week + commitMessageTopic: 'MSRV', + matchManagers: [ + 'regex', + ], + matchPackageNames: [ + 'rust', + ], + stabilityDays: 126, // 3 releases * 6 weeks per release * 7 days per week }, // Goals: // - Keep version reqs low, ignoring compatible normal/build dependencies @@ -38,34 +42,60 @@ // - Help keep number of versions down by always using latest breaking change // - Have lockfile and manifest in-sync { - "matchManagers": ["cargo"], - "matchDepTypes": ["build-dependencies", "dependencies"], - "matchCurrentVersion": ">=0.1.0", - "matchUpdateTypes": ["patch"], - "enabled": false, + matchManagers: [ + 'cargo', + ], + matchDepTypes: [ + 'build-dependencies', + 'dependencies', + ], + matchCurrentVersion: '>=0.1.0', + matchUpdateTypes: [ + 'patch', + ], + enabled: false, }, { - "matchManagers": ["cargo"], - "matchDepTypes": ["build-dependencies", "dependencies"], - "matchCurrentVersion": ">=1.0.0", - "matchUpdateTypes": ["minor"], - "enabled": false, + matchManagers: [ + 'cargo', + ], + matchDepTypes: [ + 'build-dependencies', + 'dependencies', + ], + matchCurrentVersion: '>=1.0.0', + matchUpdateTypes: [ + 'minor', + ], + enabled: false, }, { - "matchManagers": ["cargo"], - "matchDepTypes": ["dev-dependencies"], - "matchCurrentVersion": ">=0.1.0", - "matchUpdateTypes": ["patch"], - "automerge": true, - "groupName": "compatible (dev)", + matchManagers: [ + 'cargo', + ], + matchDepTypes: [ + 'dev-dependencies', + ], + matchCurrentVersion: '>=0.1.0', + matchUpdateTypes: [ + 'patch', + ], + automerge: true, + groupName: 'compatible (dev)', }, { - "matchManagers": ["cargo"], - "matchDepTypes": ["dev-dependencies"], - "matchCurrentVersion": ">=1.0.0", - "matchUpdateTypes": ["minor"], - "automerge": true, - "groupName": "compatible (dev)", + matchManagers: [ + 'cargo', + ], + matchDepTypes: [ + 'dev-dependencies', + ], + matchCurrentVersion: '>=1.0.0', + matchUpdateTypes: [ + 'minor', + ], + automerge: true, + groupName: 'compatible (dev)', }, ], } From 563de12d25e777e7244a73308090adcfb8b90014 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 17 Apr 2023 09:01:54 -0500 Subject: [PATCH 014/293] chore(ci): Update stabilidyDays to new syntax --- .github/renovate.json5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 0393074e..d5485d2c 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -33,7 +33,7 @@ matchPackageNames: [ 'rust', ], - stabilityDays: 126, // 3 releases * 6 weeks per release * 7 days per week + stabilityDays: "126 days", // 3 releases * 6 weeks per release * 7 days per week }, // Goals: // - Keep version reqs low, ignoring compatible normal/build dependencies From 2c4a7f574f6fed6655e8b2f25916c22d7bf08ad1 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 17 Apr 2023 09:02:40 -0500 Subject: [PATCH 015/293] chore(ci): Delay Renovate PRs until ready --- .github/renovate.json5 | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index d5485d2c..0e8f1d62 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -34,6 +34,7 @@ 'rust', ], stabilityDays: "126 days", // 3 releases * 6 weeks per release * 7 days per week + internalChecksFilter: "strict", }, // Goals: // - Keep version reqs low, ignoring compatible normal/build dependencies From 62401b8eafb71d8a928137f6f8dfc25340e39bbf Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 17 Apr 2023 09:05:31 -0500 Subject: [PATCH 016/293] chore(ci): Lower the MSRV churn for template --- .github/renovate.json5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 0e8f1d62..900feaf9 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -33,7 +33,7 @@ matchPackageNames: [ 'rust', ], - stabilityDays: "126 days", // 3 releases * 6 weeks per release * 7 days per week + stabilityDays: "336 days", // 8 releases * 6 weeks per release * 7 days per week internalChecksFilter: "strict", }, // Goals: From d99db2e632b25a8b020491c3e1d40bf2efd3472a Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 17 Apr 2023 09:54:05 -0500 Subject: [PATCH 017/293] style(ci): Match auto-generated style --- .github/renovate.json5 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 900feaf9..54bc5935 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -1,6 +1,6 @@ { schedule: [ - 'before 3am on the first day of the month' + 'before 3am on the first day of the month', ], semanticCommits: 'enabled', configMigration: true, @@ -22,7 +22,7 @@ depNameTemplate: 'rust', packageNameTemplate: 'rust-lang/rust', datasourceTemplate: 'github-releases', - } + }, ], packageRules: [ { From afaba35d39c75d13138e2928cddeb0b93601cee3 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 17 Apr 2023 09:54:21 -0500 Subject: [PATCH 018/293] chore(ci): Use new minimumReleaseAge field --- .github/renovate.json5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 54bc5935..79e5152c 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -33,7 +33,7 @@ matchPackageNames: [ 'rust', ], - stabilityDays: "336 days", // 8 releases * 6 weeks per release * 7 days per week + minimumReleaseAge: "336 days", // 8 releases * 6 weeks per release * 7 days per week internalChecksFilter: "strict", }, // Goals: From 60a8ec89e3f97baad0dbe097e03dc0cd30899e02 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 17 Apr 2023 20:03:56 -0500 Subject: [PATCH 019/293] chore(ci): Ban for_each --- .clippy.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.clippy.toml b/.clippy.toml index 5c6f9841..56d269a8 100644 --- a/.clippy.toml +++ b/.clippy.toml @@ -9,4 +9,6 @@ disallowed-methods = [ { path = "std::option::Option::map_or_else", reason = "use `map(..).unwrap_or_else(..)`" }, { path = "std::result::Result::map_or", reason = "use `map(..).unwrap_or(..)`" }, { path = "std::result::Result::map_or_else", reason = "use `map(..).unwrap_or_else(..)`" }, + { path = "std::iter::Iterator::for_each", reason = "prefer `for` for side-effects" }, + { path = "std::iter::Iterator::try_for_each", reason = "prefer `for` for side-effects" }, ] From 96297f038d8d931bb9d5ba4dfcdced18d7c81061 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 17 Apr 2023 20:04:56 -0500 Subject: [PATCH 020/293] chore(ci): Clarify why map_or is banned --- .clippy.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.clippy.toml b/.clippy.toml index 56d269a8..22fe10b7 100644 --- a/.clippy.toml +++ b/.clippy.toml @@ -5,10 +5,10 @@ allow-unwrap-in-tests = true allow-dbg-in-tests = true allow-print-in-tests = true disallowed-methods = [ - { path = "std::option::Option::map_or", reason = "use `map(..).unwrap_or(..)`" }, - { path = "std::option::Option::map_or_else", reason = "use `map(..).unwrap_or_else(..)`" }, - { path = "std::result::Result::map_or", reason = "use `map(..).unwrap_or(..)`" }, - { path = "std::result::Result::map_or_else", reason = "use `map(..).unwrap_or_else(..)`" }, + { path = "std::option::Option::map_or", reason = "prefer `map(..).unwrap_or(..)` for legibility" }, + { path = "std::option::Option::map_or_else", reason = "prefer `map(..).unwrap_or_else(..)` for legibility" }, + { path = "std::result::Result::map_or", reason = "prefer `map(..).unwrap_or(..)` for legibility" }, + { path = "std::result::Result::map_or_else", reason = "prefer `map(..).unwrap_or_else(..)` for legibility" }, { path = "std::iter::Iterator::for_each", reason = "prefer `for` for side-effects" }, { path = "std::iter::Iterator::try_for_each", reason = "prefer `for` for side-effects" }, ] From 716170eaa853ddf3032baa9b107eb3e44d6a4124 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 17 Apr 2023 20:13:36 -0500 Subject: [PATCH 021/293] chore(gh): Ban rebase merges --- .github/settings.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/settings.yml b/.github/settings.yml index 8ead1bac..7d5e4fce 100644 --- a/.github/settings.yml +++ b/.github/settings.yml @@ -10,9 +10,12 @@ repository: has_downloads: true default_branch: main - allow_squash_merge: true + # Preference: people do clean commits allow_merge_commit: true - allow_rebase_merge: true + # Backup in case we need to clean up commits + allow_squash_merge: true + # Not really needed + allow_rebase_merge: false allow_auto_merge: true delete_branch_on_merge: true From 80d4cdd688e88b897f384b770f9c13268ecb3793 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 18 May 2023 14:57:02 -0500 Subject: [PATCH 022/293] chore: Remove clippy lint past MSRV (needs 1.67) --- .clippy.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/.clippy.toml b/.clippy.toml index 22fe10b7..090e2bec 100644 --- a/.clippy.toml +++ b/.clippy.toml @@ -3,7 +3,6 @@ warn-on-all-wildcard-imports = true allow-expect-in-tests = true allow-unwrap-in-tests = true allow-dbg-in-tests = true -allow-print-in-tests = true disallowed-methods = [ { path = "std::option::Option::map_or", reason = "prefer `map(..).unwrap_or(..)` for legibility" }, { path = "std::option::Option::map_or_else", reason = "prefer `map(..).unwrap_or_else(..)` for legibility" }, From 2b6bb28cd18916a6244a2632a6abcba9362b9fd0 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 18 May 2023 14:58:59 -0500 Subject: [PATCH 023/293] chore(ci): Catch clippy config failures --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 017d45ec..a7bb3256 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -126,3 +126,5 @@ jobs: with: sarif_file: clippy-results.sarif wait-for-processing: true + - name: Report status + run: cargo clippy --workspace --all-features --all-targets -- -D warnings --allow deprecated From 4d44cd7ca51f05fb06185677642d73c0ff0da079 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 19 May 2023 13:12:26 -0500 Subject: [PATCH 024/293] chore: Update precommit hooks --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f751dec5..fd77abba 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.3.0 + rev: v4.4.0 hooks: - id: check-yaml stages: [commit] @@ -15,12 +15,12 @@ repos: - id: detect-private-key stages: [commit] - repo: https://github.com/crate-ci/typos - rev: v1.11.1 + rev: v1.14.10 hooks: - id: typos stages: [commit] - repo: https://github.com/crate-ci/committed - rev: v1.0.4 + rev: v1.0.17 hooks: - id: committed stages: [commit-msg] From d6075a44bff9073c811510e86d73216baa844a69 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 2 Aug 2023 11:11:52 -0500 Subject: [PATCH 025/293] chore: Expand update window so more likely to be hit --- .github/renovate.json5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 79e5152c..e5733ed2 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -1,6 +1,6 @@ { schedule: [ - 'before 3am on the first day of the month', + 'before 5am on the first day of the month', ], semanticCommits: 'enabled', configMigration: true, From 67eb1d9e3d396cc7f786d767e287d7e946ed3118 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 7 Aug 2023 16:16:17 -0500 Subject: [PATCH 026/293] chore(ci): Ensure lockfile isn't stale --- .github/workflows/ci.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a7bb3256..26c9b0f4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,6 +65,18 @@ jobs: run: cargo check --workspace --all-targets --all-features - name: No-default features run: cargo check --workspace --all-targets --no-default-features + lockfile: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + - uses: Swatinem/rust-cache@v2 + - name: "Is lockfile updated?" + run: cargo fetch --locked docs: name: Docs runs-on: ubuntu-latest From ba76b8bd911b98ab78fec3cf6c8e7ee679721a6f Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 11 Aug 2023 13:29:06 -0500 Subject: [PATCH 027/293] chore(ci): Ensure latest deps are good --- .github/workflows/rust-next.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/workflows/rust-next.yml b/.github/workflows/rust-next.yml index e90121bc..a540ba58 100644 --- a/.github/workflows/rust-next.yml +++ b/.github/workflows/rust-next.yml @@ -38,3 +38,22 @@ jobs: run: cargo test --workspace --all-features - name: No-default features run: cargo test --workspace --no-default-features + latest: + name: "Check latest dependencies" + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + - uses: Swatinem/rust-cache@v2 + - name: Update dependencues + run: cargo update + - name: Default features + run: cargo test --workspace --all-targets + - name: All features + run: cargo test --workspace --all-targets --all-features + - name: No-default features + run: cargo test --workspace --all-targets --no-default-features From 528638729492300730aebee283d2a837325b4a62 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 11 Aug 2023 16:04:07 -0500 Subject: [PATCH 028/293] chore: Update pre-commit hooks --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fd77abba..3d9e40fd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,12 +15,12 @@ repos: - id: detect-private-key stages: [commit] - repo: https://github.com/crate-ci/typos - rev: v1.14.10 + rev: v1.16.3 hooks: - id: typos stages: [commit] - repo: https://github.com/crate-ci/committed - rev: v1.0.17 + rev: v1.0.20 hooks: - id: committed stages: [commit-msg] From efe14d60899ec75c901c88b46174ccd3fc5e14d8 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 22 Aug 2023 11:06:55 -0500 Subject: [PATCH 029/293] chore(renovate): Make style consistent --- .github/renovate.json5 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index e5733ed2..8e31ad0f 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -33,8 +33,8 @@ matchPackageNames: [ 'rust', ], - minimumReleaseAge: "336 days", // 8 releases * 6 weeks per release * 7 days per week - internalChecksFilter: "strict", + minimumReleaseAge: '336 days', // 8 releases * 6 weeks per release * 7 days per week + internalChecksFilter: 'strict', }, // Goals: // - Keep version reqs low, ignoring compatible normal/build dependencies From a6ecf92327e4c75e6545cdd238cc40171337c403 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 22 Aug 2023 11:07:34 -0500 Subject: [PATCH 030/293] chore(renovate): Update config --- .github/renovate.json5 | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 8e31ad0f..7b75c589 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -7,6 +7,7 @@ dependencyDashboard: true, regexManagers: [ { + customType: 'regex', fileMatch: [ '^rust-toolchain\\.toml$', 'Cargo.toml$', From c8624f0538c30bb5498db489f456af6012988bdb Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 23 Aug 2023 09:24:15 -0500 Subject: [PATCH 031/293] chore(renovate): Update MSRV on release --- .github/renovate.json5 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 7b75c589..a367a473 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -36,6 +36,9 @@ ], minimumReleaseAge: '336 days', // 8 releases * 6 weeks per release * 7 days per week internalChecksFilter: 'strict', + schedule: [ + 'every day', + ], }, // Goals: // - Keep version reqs low, ignoring compatible normal/build dependencies From 44604fc1d369e255c7edd0954979310131e24fa4 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 23 Aug 2023 09:35:47 -0500 Subject: [PATCH 032/293] chore(renovate): Try to fix schedule --- .github/renovate.json5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index a367a473..28e23ee1 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -37,7 +37,7 @@ minimumReleaseAge: '336 days', // 8 releases * 6 weeks per release * 7 days per week internalChecksFilter: 'strict', schedule: [ - 'every day', + '* * * * *', ], }, // Goals: From ff82d6960a9903e3c62414cdacc9b2fa0a7ce2cb Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 23 Aug 2023 10:43:57 -0500 Subject: [PATCH 033/293] chore(ci): Don't fail on wildcards See EmbarkStudios/cargo-deny#241 --- deny.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deny.toml b/deny.toml index 942e08db..58cc98d5 100644 --- a/deny.toml +++ b/deny.toml @@ -88,7 +88,7 @@ ignore = true # Lint level for when multiple versions of the same crate are detected multiple-versions = "warn" # Lint level for when a crate version requirement is `*` -wildcards = "deny" +wildcards = "warn" # The graph highlighting used when creating dotgraphs for crates # with multiple versions # * lowest-version - The path to the lowest versioned duplicate is highlighted From 5749aa0932d42cd0ee484b6cb9fcf6f6dd026749 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 7 Sep 2023 09:33:44 -0500 Subject: [PATCH 034/293] chore: Approve ISC --- deny.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/deny.toml b/deny.toml index 58cc98d5..21fa937f 100644 --- a/deny.toml +++ b/deny.toml @@ -41,6 +41,7 @@ allow = [ "MPL-2.0", "Unicode-DFS-2016", "CC0-1.0", + "ISC", ] # List of explicitly disallowed licenses # See https://spdx.org/licenses/ for list of possible licenses From 4173c8f4767296f76a6eb96d70b7ca6c13bb38bd Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 20 Sep 2023 09:05:41 -0500 Subject: [PATCH 035/293] chore(ci): Don't set patch for MSRV --- .github/renovate.json5 | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 28e23ee1..56cf1e33 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -36,6 +36,7 @@ ], minimumReleaseAge: '336 days', // 8 releases * 6 weeks per release * 7 days per week internalChecksFilter: 'strict', + "extractVersion": "^(?\\d+\\.\\d+)", // Drop the patch version schedule: [ '* * * * *', ], From 86c29dea384c7392a2b682fa0150f52c0f4c7f00 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 26 Sep 2023 08:16:33 -0500 Subject: [PATCH 036/293] chore(ci): Updaet Renovate schema --- .github/renovate.json5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 56cf1e33..4eaf67fb 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -5,7 +5,7 @@ semanticCommits: 'enabled', configMigration: true, dependencyDashboard: true, - regexManagers: [ + customManagers: [ { customType: 'regex', fileMatch: [ From ac51f0925003597dec21529538597dbd7872d1ac Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 26 Sep 2023 08:16:47 -0500 Subject: [PATCH 037/293] chore(ci): Normalize json5 syntax --- .github/renovate.json5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 4eaf67fb..72d05795 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -36,7 +36,7 @@ ], minimumReleaseAge: '336 days', // 8 releases * 6 weeks per release * 7 days per week internalChecksFilter: 'strict', - "extractVersion": "^(?\\d+\\.\\d+)", // Drop the patch version + extractVersion: '^(?\\d+\\.\\d+)', // Drop the patch version schedule: [ '* * * * *', ], From 305798083f34bb57951fb6351aa6b897790907eb Mon Sep 17 00:00:00 2001 From: Peter Kehl Date: Fri, 29 Sep 2023 22:59:44 -0700 Subject: [PATCH 038/293] README.md 'Crates Status' icon link now uses the Markdown placeholder/substitution name 'Crates.io' --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 41d5a974..6958ee06 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![Documentation](https://img.shields.io/badge/docs-master-blue.svg)][Documentation] ![License](https://img.shields.io/crates/l/PROJECT.svg) -[![Crates Status](https://img.shields.io/crates/v/PROJECT.svg)](https://crates.io/crates/PROJECT) +[![Crates Status](https://img.shields.io/crates/v/PROJECT.svg)][Crates.io] ## License From cad9b4717162cc4dbd4253227fc9c5705a302758 Mon Sep 17 00:00:00 2001 From: Peter Kehl Date: Fri, 29 Sep 2023 23:04:45 -0700 Subject: [PATCH 039/293] README.md list indentation and no bare URLs, as per Markdown Lint VS Code extension. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 41d5a974..6f307686 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ Licensed under either of - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) +* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) +* MIT license ([LICENSE-MIT](LICENSE-MIT) or ) at your option. From 6d3f888975aedf79e10336c8090d6aab20751b10 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 1 Oct 2023 01:37:07 +0000 Subject: [PATCH 040/293] chore(deps): update actions/checkout action to v4 --- .github/workflows/audit.yml | 4 ++-- .github/workflows/ci.yml | 12 ++++++------ .github/workflows/committed.yml | 2 +- .github/workflows/pre-commit.yml | 2 +- .github/workflows/rust-next.yml | 4 ++-- .github/workflows/spelling.yml | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index 5b7e83ac..ccee1fef 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -27,7 +27,7 @@ jobs: continue-on-error: true steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - uses: actions-rs/audit-check@v1 with: token: ${{ secrets.GITHUB_TOKEN }} @@ -42,7 +42,7 @@ jobs: checks: - bans licenses sources steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: EmbarkStudios/cargo-deny-action@v1 with: command: check ${{ matrix.checks }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 26c9b0f4..1a703726 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install Rust uses: dtolnay/rust-toolchain@stable with: @@ -53,7 +53,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install Rust uses: dtolnay/rust-toolchain@stable with: @@ -69,7 +69,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install Rust uses: dtolnay/rust-toolchain@stable with: @@ -82,7 +82,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install Rust uses: dtolnay/rust-toolchain@stable with: @@ -97,7 +97,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install Rust uses: dtolnay/rust-toolchain@stable with: @@ -115,7 +115,7 @@ jobs: security-events: write # to upload sarif results steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install Rust uses: dtolnay/rust-toolchain@stable with: diff --git a/.github/workflows/committed.yml b/.github/workflows/committed.yml index 509be080..04625584 100644 --- a/.github/workflows/committed.yml +++ b/.github/workflows/committed.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Actions Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Lint Commits diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index d4b0f84a..80447507 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -18,6 +18,6 @@ jobs: contents: read runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 - uses: pre-commit/action@v3.0.0 diff --git a/.github/workflows/rust-next.yml b/.github/workflows/rust-next.yml index a540ba58..d8c2d257 100644 --- a/.github/workflows/rust-next.yml +++ b/.github/workflows/rust-next.yml @@ -26,7 +26,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install Rust uses: dtolnay/rust-toolchain@stable with: @@ -43,7 +43,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install Rust uses: dtolnay/rust-toolchain@stable with: diff --git a/.github/workflows/spelling.yml b/.github/workflows/spelling.yml index f31c7ed8..12f75859 100644 --- a/.github/workflows/spelling.yml +++ b/.github/workflows/spelling.yml @@ -16,6 +16,6 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Actions Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Spell Check Repo uses: crate-ci/typos@master From 5e3b324b5e6488667be2f00a424781030e37a277 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 5 Oct 2023 14:41:40 -0500 Subject: [PATCH 041/293] chore(ci): Ensure MSRV is quoted Switching from specifying patch to not, with a minor version with a trailing zero, is causing YAML to convert `1.70` to `1.7`. --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a703726..19efcf9f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,7 +57,7 @@ jobs: - name: Install Rust uses: dtolnay/rust-toolchain@stable with: - toolchain: 1.65.0 # MSRV + toolchain: "1.65.0" # MSRV - uses: Swatinem/rust-cache@v2 - name: Default features run: cargo check --workspace --all-targets @@ -119,7 +119,7 @@ jobs: - name: Install Rust uses: dtolnay/rust-toolchain@stable with: - toolchain: 1.65.0 # MSRV + toolchain: "1.65.0" # MSRV components: clippy - uses: Swatinem/rust-cache@v2 - name: Install SARIF tools From 5ebe30b9722ac700d414043ff099bad7f3978582 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 26 Oct 2023 09:14:51 -0500 Subject: [PATCH 042/293] chore(ci): Update pre-commit hooks --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3d9e40fd..68db968e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: check-yaml stages: [commit] @@ -15,7 +15,7 @@ repos: - id: detect-private-key stages: [commit] - repo: https://github.com/crate-ci/typos - rev: v1.16.3 + rev: v1.16.20 hooks: - id: typos stages: [commit] From 598c6244983fb392457f3fbec9badf25fab6d051 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 3 Dec 2023 09:19:35 +0000 Subject: [PATCH 043/293] chore(config): migrate config .github/renovate.json5 --- .github/renovate.json5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 72d05795..3119c425 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -29,7 +29,7 @@ { commitMessageTopic: 'MSRV', matchManagers: [ - 'regex', + 'custom.regex', ], matchPackageNames: [ 'rust', From 69fa0268a44a9859c4db98a6692369c0e8719146 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 1 Jan 2024 00:59:55 +0000 Subject: [PATCH 044/293] chore(deps): update actions/setup-python action to v5 --- .github/workflows/pre-commit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 80447507..95514075 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -19,5 +19,5 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 - uses: pre-commit/action@v3.0.0 From 82c9aa7bddef20e9705d3d404403e59b2cd7e8e1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 1 Jan 2024 00:59:58 +0000 Subject: [PATCH 045/293] chore(deps): update github/codeql-action action to v3 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 19efcf9f..1b09d217 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -134,7 +134,7 @@ jobs: | sarif-fmt continue-on-error: true - name: Upload - uses: github/codeql-action/upload-sarif@v2 + uses: github/codeql-action/upload-sarif@v3 with: sarif_file: clippy-results.sarif wait-for-processing: true From a4c062667d3b0c94928d285052795637de0a7227 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 2 Jan 2024 09:56:35 -0600 Subject: [PATCH 046/293] chore: Make renovate commits to match --- .github/renovate.json5 | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 3119c425..e5a5de0f 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -3,6 +3,7 @@ 'before 5am on the first day of the month', ], semanticCommits: 'enabled', + commitMessageLowerCase: 'never', configMigration: true, dependencyDashboard: true, customManagers: [ From 61250a36135d0032ceda4316b43d3a62d8b07643 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 3 Jan 2024 08:27:59 -0600 Subject: [PATCH 047/293] chore(ci): Optimize CI runs --- .github/workflows/ci.yml | 2 +- .github/workflows/rust-next.yml | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1b09d217..943becfb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,7 +41,7 @@ jobs: toolchain: ${{ matrix.rust }} - uses: Swatinem/rust-cache@v2 - name: Build - run: cargo test --no-run --workspace --all-features + run: cargo test --workspace --no-run - name: Default features run: cargo test --workspace - name: All features diff --git a/.github/workflows/rust-next.yml b/.github/workflows/rust-next.yml index d8c2d257..43b4ec8f 100644 --- a/.github/workflows/rust-next.yml +++ b/.github/workflows/rust-next.yml @@ -32,6 +32,8 @@ jobs: with: toolchain: ${{ matrix.rust }} - uses: Swatinem/rust-cache@v2 + - name: Build + run: cargo test --workspace --no-run - name: Default features run: cargo test --workspace - name: All features @@ -51,9 +53,11 @@ jobs: - uses: Swatinem/rust-cache@v2 - name: Update dependencues run: cargo update + - name: Build + run: cargo test --workspace --no-run - name: Default features - run: cargo test --workspace --all-targets + run: cargo test --workspace - name: All features - run: cargo test --workspace --all-targets --all-features + run: cargo test --workspace --all-features - name: No-default features - run: cargo test --workspace --all-targets --no-default-features + run: cargo test --workspace --no-default-features From e819db4af62e231bcedd976faa488b4e6f46f312 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 18 Jan 2024 09:22:25 -0600 Subject: [PATCH 048/293] chore(ci): Cancel prior CI runs --- .github/workflows/audit.yml | 4 ++++ .github/workflows/ci.yml | 4 ++++ .github/workflows/committed.yml | 4 ++++ .github/workflows/pre-commit.yml | 4 ++++ .github/workflows/rust-next.yml | 4 ++++ .github/workflows/spelling.yml | 4 ++++ 6 files changed, 24 insertions(+) diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index ccee1fef..07c70eeb 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -17,6 +17,10 @@ env: CARGO_TERM_COLOR: always CLICOLOR: 1 +concurrency: + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + jobs: security_audit: permissions: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 943becfb..2bbd5a57 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,6 +14,10 @@ env: CARGO_TERM_COLOR: always CLICOLOR: 1 +concurrency: + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + jobs: ci: permissions: diff --git a/.github/workflows/committed.yml b/.github/workflows/committed.yml index 04625584..e7a50fbb 100644 --- a/.github/workflows/committed.yml +++ b/.github/workflows/committed.yml @@ -11,6 +11,10 @@ env: CARGO_TERM_COLOR: always CLICOLOR: 1 +concurrency: + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + jobs: committed: name: Lint Commits diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 95514075..7d773285 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -12,6 +12,10 @@ env: CARGO_TERM_COLOR: always CLICOLOR: 1 +concurrency: + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + jobs: pre-commit: permissions: diff --git a/.github/workflows/rust-next.yml b/.github/workflows/rust-next.yml index 43b4ec8f..f0febc9f 100644 --- a/.github/workflows/rust-next.yml +++ b/.github/workflows/rust-next.yml @@ -12,6 +12,10 @@ env: CARGO_TERM_COLOR: always CLICOLOR: 1 +concurrency: + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + jobs: test: name: Test diff --git a/.github/workflows/spelling.yml b/.github/workflows/spelling.yml index 12f75859..8e58d9ec 100644 --- a/.github/workflows/spelling.yml +++ b/.github/workflows/spelling.yml @@ -10,6 +10,10 @@ env: CARGO_TERM_COLOR: always CLICOLOR: 1 +concurrency: + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + jobs: spelling: name: Spell Check with Typos From 0b029063fe83d818e3a79819b88bee8b8314f752 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 24 Jan 2024 08:40:56 -0600 Subject: [PATCH 049/293] chore(ci): Be explicit in renovate updates --- .github/renovate.json5 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index e5a5de0f..32d3628d 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -73,6 +73,7 @@ matchCurrentVersion: '>=1.0.0', matchUpdateTypes: [ 'minor', + 'patch', ], enabled: false, }, @@ -100,6 +101,7 @@ matchCurrentVersion: '>=1.0.0', matchUpdateTypes: [ 'minor', + 'patch', ], automerge: true, groupName: 'compatible (dev)', From 131de55d50284af7a54287d34699347b74d75709 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 31 Jan 2024 12:07:12 -0600 Subject: [PATCH 050/293] chore(ci): Add m1 runners See https://github.blog/changelog/2024-01-30-github-actions-introducing-the-new-m1-macos-runner-available-to-open-source/ --- .github/workflows/ci.yml | 2 +- .github/workflows/rust-next.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2bbd5a57..a8826b05 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: name: Test strategy: matrix: - os: ["ubuntu-latest", "windows-latest", "macos-latest"] + os: ["ubuntu-latest", "windows-latest", "macos-latest", "macos-14"] rust: ["stable"] continue-on-error: ${{ matrix.rust != 'stable' }} runs-on: ${{ matrix.os }} diff --git a/.github/workflows/rust-next.yml b/.github/workflows/rust-next.yml index f0febc9f..49e5d8c3 100644 --- a/.github/workflows/rust-next.yml +++ b/.github/workflows/rust-next.yml @@ -21,7 +21,7 @@ jobs: name: Test strategy: matrix: - os: ["ubuntu-latest", "windows-latest", "macos-latest"] + os: ["ubuntu-latest", "windows-latest", "macos-latest", "macos-14"] rust: ["stable", "beta"] include: - os: ubuntu-latest From 9a5af5c8d21d549a7eb785343ae055d931952075 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 8 Feb 2024 07:45:48 -0600 Subject: [PATCH 051/293] chore(ci): Only check intel mac on schedule --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a8826b05..af065d56 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: name: Test strategy: matrix: - os: ["ubuntu-latest", "windows-latest", "macos-latest", "macos-14"] + os: ["ubuntu-latest", "windows-latest", "macos-14"] rust: ["stable"] continue-on-error: ${{ matrix.rust != 'stable' }} runs-on: ${{ matrix.os }} From da56001fd6cabdb744f25b021c9efd230472f671 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 8 Feb 2024 07:48:29 -0600 Subject: [PATCH 052/293] chore(ci): Gather coverage --- .github/workflows/ci.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index af065d56..7849a735 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -144,3 +144,22 @@ jobs: wait-for-processing: true - name: Report status run: cargo clippy --workspace --all-features --all-targets -- -D warnings --allow deprecated + coverage: + name: Coverage + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + toolchain: "1.75" # STABLE + - uses: Swatinem/rust-cache@v2 + - name: Install cargo-tarpaulin + run: cargo install cargo-tarpaulin + - name: Gather coverage + run: cargo tarpaulin --output-dir coverage --out lcov + - name: Publish to Coveralls + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} From 1313256db3e9a31a3e0647abaacc9a8e4edb51b1 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 8 Feb 2024 09:07:52 -0600 Subject: [PATCH 053/293] chore(ci): Use latest for coverage --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7849a735..2e6597e9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -153,7 +153,7 @@ jobs: - name: Install Rust uses: dtolnay/rust-toolchain@stable with: - toolchain: "1.75" # STABLE + toolchain: stable - uses: Swatinem/rust-cache@v2 - name: Install cargo-tarpaulin run: cargo install cargo-tarpaulin From 51a98a25b6c30dd2fbdd74795432006525d1d84a Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 15 Feb 2024 09:57:26 -0600 Subject: [PATCH 054/293] chore(ci): Defer to package.rust-version for clippy --- .clippy.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/.clippy.toml b/.clippy.toml index 090e2bec..293c14f3 100644 --- a/.clippy.toml +++ b/.clippy.toml @@ -1,4 +1,3 @@ -msrv = "1.65.0" # MSRV warn-on-all-wildcard-imports = true allow-expect-in-tests = true allow-unwrap-in-tests = true From 4db293d99b81e9c7da8fb030b1471e4e96dc91ef Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 15 Feb 2024 09:58:01 -0600 Subject: [PATCH 055/293] chore(ci): Only verify MSRV for published packages --- .github/workflows/ci.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2e6597e9..03a4fc0b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -53,7 +53,7 @@ jobs: - name: No-default features run: cargo test --workspace --no-default-features msrv: - name: "Check MSRV: 1.65.0" + name: "Check MSRV" runs-on: ubuntu-latest steps: - name: Checkout repository @@ -61,14 +61,15 @@ jobs: - name: Install Rust uses: dtolnay/rust-toolchain@stable with: - toolchain: "1.65.0" # MSRV + toolchain: stable - uses: Swatinem/rust-cache@v2 + - uses: taiki-e/install-action@cargo-hack - name: Default features - run: cargo check --workspace --all-targets + run: cargo hack check --rust-version --ignore-private --workspace --all-targets - name: All features - run: cargo check --workspace --all-targets --all-features + run: cargo hack check --rust-version --ignore-private --workspace --all-targets --all-features - name: No-default features - run: cargo check --workspace --all-targets --no-default-features + run: cargo hack check --rust-version --ignore-private --workspace --all-targets --no-default-features lockfile: runs-on: ubuntu-latest steps: From 779496bb002837bf4e115ae3a33e7c819abdf293 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 15 Feb 2024 10:03:14 -0600 Subject: [PATCH 056/293] chore(ci): Run the latest clippy --- .github/renovate.json5 | 37 +++++++++++++++++++++++++++++++++++-- .github/workflows/ci.yml | 2 +- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 32d3628d..06c1d639 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -21,7 +21,25 @@ 'MSRV.*?(?\\d+\\.\\d+(\\.\\d+)?)', '(?\\d+\\.\\d+(\\.\\d+)?).*?MSRV', ], - depNameTemplate: 'rust', + depNameTemplate: 'MSRV', + packageNameTemplate: 'rust-lang/rust', + datasourceTemplate: 'github-releases', + }, + { + customType: 'regex', + fileMatch: [ + '^rust-toolchain\\.toml$', + 'Cargo.toml$', + 'clippy.toml$', + '\\.clippy.toml$', + '^\\.github/workflows/ci.yml$', + '^\\.github/workflows/rust-next.yml$', + ], + matchStrings: [ + 'STABLE.*?(?\\d+\\.\\d+(\\.\\d+)?)', + '(?\\d+\\.\\d+(\\.\\d+)?).*?STABLE', + ], + depNameTemplate: 'STABLE', packageNameTemplate: 'rust-lang/rust', datasourceTemplate: 'github-releases', }, @@ -33,7 +51,7 @@ 'custom.regex', ], matchPackageNames: [ - 'rust', + 'MSRV', ], minimumReleaseAge: '336 days', // 8 releases * 6 weeks per release * 7 days per week internalChecksFilter: 'strict', @@ -41,6 +59,21 @@ schedule: [ '* * * * *', ], + groupName: 'rust-version', + }, + { + commitMessageTopic: 'STABLE', + matchManagers: [ + 'custom.regex', + ], + matchPackageNames: [ + 'STABLE', + ], + extractVersion: '^(?\\d+\\.\\d+)', // Drop the patch version + schedule: [ + '* * * * *', + ], + groupName: 'rust-version', }, // Goals: // - Keep version reqs low, ignoring compatible normal/build dependencies diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 03a4fc0b..1c18ca65 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -124,7 +124,7 @@ jobs: - name: Install Rust uses: dtolnay/rust-toolchain@stable with: - toolchain: "1.65.0" # MSRV + toolchain: "1.76" # STABLE components: clippy - uses: Swatinem/rust-cache@v2 - name: Install SARIF tools From c977df514987a625772ca04df9fc100ba8b7576f Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 20 Feb 2024 20:22:05 -0600 Subject: [PATCH 057/293] chore(ci): Prevent cargo-hack from blowing away our lockfile See taiki-e/cargo-hack#234 --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1c18ca65..12d398cd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,11 +65,11 @@ jobs: - uses: Swatinem/rust-cache@v2 - uses: taiki-e/install-action@cargo-hack - name: Default features - run: cargo hack check --rust-version --ignore-private --workspace --all-targets + run: cargo hack check --locked --rust-version --ignore-private --workspace --all-targets - name: All features - run: cargo hack check --rust-version --ignore-private --workspace --all-targets --all-features + run: cargo hack check --locked --rust-version --ignore-private --workspace --all-targets --all-features - name: No-default features - run: cargo hack check --rust-version --ignore-private --workspace --all-targets --no-default-features + run: cargo hack check --locked --rust-version --ignore-private --workspace --all-targets --no-default-features lockfile: runs-on: ubuntu-latest steps: From 7846c5130e5459ce452bd4fdb17373d83f45dff3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 1 Mar 2024 00:30:14 +0000 Subject: [PATCH 058/293] chore(deps): Update pre-commit/action action to v3.0.1 --- .github/workflows/pre-commit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 7d773285..1b000abf 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -24,4 +24,4 @@ jobs: steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 - - uses: pre-commit/action@v3.0.0 + - uses: pre-commit/action@v3.0.1 From 3d5ead81cf3962997045915cd9b137086d35d1a9 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 21 Mar 2024 10:46:56 -0500 Subject: [PATCH 059/293] chore(ci): Configure standard lints --- Cargo.toml | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 ++ 2 files changed, 86 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index b8ecde11..e51c5ddd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,87 @@ include = [ "examples/**/*" ] +[workspace.lints.rust] +missing_docs = "warn" +rust_2018_idioms = "warn" +unreachable_pub = "warn" +unsafe-op-in-unsafe-fn = "warn" +unsafe_code = "warn" +unused-crate-dependencies = "warn" +unused-lifetimes = "warn" +unused-macro-rules = "warn" +unused-qualifications = "warn" + +[workspace.lints.clippy] +bool_assert_comparison = "allow" +branches_sharing_code = "allow" +checked_conversions = "warn" +collapsible_else_if = "allow" +create_dir = "warn" +dbg_macro = "warn" +debug_assert_with_mut_call = "warn" +doc_markdown = "warn" +empty_enum = "warn" +enum_glob_use = "warn" +exhaustive_enums = "warn" +exhaustive_structs = "warn" +exit = "warn" +expl_impl_clone_on_copy = "warn" +explicit_deref_methods = "warn" +explicit_into_iter_loop = "warn" +fallible_impl_from = "warn" +filter_map_next = "warn" +flat_map_option = "warn" +float_cmp_const = "warn" +fn_params_excessive_bools = "warn" +from_iter_instead_of_collect = "warn" +if_same_then_else = "allow" +implicit_clone = "warn" +imprecise_flops = "warn" +inconsistent_struct_constructor = "warn" +inefficient_to_string = "warn" +infinite_loop = "warn" +invalid_upcast_comparisons = "warn" +items_after_statements = "warn" +large_digit_groups = "warn" +large_stack_arrays = "warn" +large_types_passed_by_value = "warn" +let_and_return = "allow" # sometimes good to name what you are returning +linkedlist = "warn" +lossy_float_literal = "warn" +macro_use_imports = "warn" +match_wildcard_for_single_variants = "warn" +mem_forget = "warn" +mutex_integer = "warn" +needless_continue = "warn" +needless_for_each = "warn" +negative_feature_names = "warn" +path_buf_push_overwrite = "warn" +print_stderr = "warn" +print_stdout = "warn" +ptr_as_ptr = "warn" +rc_mutex = "warn" +redundant_feature_names = "warn" +ref_option_ref = "warn" +rest_pat_in_fully_bound_structs = "warn" +return_self_not_must_use = "warn" +same_functions_in_if_condition = "warn" +self_named_module_files = "warn" +semicolon_if_nothing_returned = "warn" +single_match_else = "warn" +str_to_string = "warn" +string_add = "warn" +string_add_assign = "warn" +string_lit_as_bytes = "warn" +string_to_string = "warn" +tests_outside_test_module = "warn" +todo = "warn" +trait_duplication_in_bounds = "warn" +unwrap_used = "warn" +verbose_file_reads = "warn" +wildcard_imports = "warn" +zero_sized_map_values = "warn" + [package] name = "PROJECT" version = "0.0.1" @@ -46,3 +127,6 @@ default = [] [dependencies] [dev-dependencies] + +[lints] +workspace = true diff --git a/src/lib.rs b/src/lib.rs index 45bf577c..8ce46b57 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,4 @@ +//! > DESCRIPTION + #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![allow(non_snake_case)] // TODO: Delete me From ace6e07683db64f05a237d8c833e2320a951b5d4 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 21 Mar 2024 12:20:47 -0500 Subject: [PATCH 060/293] chore(ci): Don't update stable and MSRV together We might want to hold one or the other back --- .github/renovate.json5 | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 06c1d639..373fc0e5 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -59,10 +59,9 @@ schedule: [ '* * * * *', ], - groupName: 'rust-version', }, { - commitMessageTopic: 'STABLE', + commitMessageTopic: 'Rust Stable', matchManagers: [ 'custom.regex', ], @@ -73,7 +72,6 @@ schedule: [ '* * * * *', ], - groupName: 'rust-version', }, // Goals: // - Keep version reqs low, ignoring compatible normal/build dependencies From 8ec86ab9a22aa7333af26113d8b725333966635f Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 25 Mar 2024 12:33:58 -0500 Subject: [PATCH 061/293] chore: Normalize clippy lint names --- Cargo.toml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e51c5ddd..d03936f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,12 +20,12 @@ include = [ missing_docs = "warn" rust_2018_idioms = "warn" unreachable_pub = "warn" -unsafe-op-in-unsafe-fn = "warn" +unsafe_op_in_unsafe_fn = "warn" unsafe_code = "warn" -unused-crate-dependencies = "warn" -unused-lifetimes = "warn" -unused-macro-rules = "warn" -unused-qualifications = "warn" +unused_crate_dependencies = "warn" +unused_lifetimes = "warn" +unused_macro_rules = "warn" +unused_qualifications = "warn" [workspace.lints.clippy] bool_assert_comparison = "allow" From 8e647d9cd40a6891d524737d97d93a43a9e7b965 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 28 Mar 2024 09:35:59 -0500 Subject: [PATCH 062/293] chore: Encourage use of workspace.dependencies --- Cargo.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index d03936f4..e07a4738 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,8 @@ include = [ "examples/**/*" ] +[workspace.dependencies] + [workspace.lints.rust] missing_docs = "warn" rust_2018_idioms = "warn" From 126eb3d4dc4f59bcbee11d9d55545f01f75fb734 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 28 Mar 2024 09:48:35 -0500 Subject: [PATCH 063/293] chore: Encourage a single test binary --- Cargo.lock | 49 ++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 ++ tests/testsuite/delete_me.rs | 0 tests/testsuite/main.rs | 1 + 4 files changed, 52 insertions(+) create mode 100644 tests/testsuite/delete_me.rs create mode 100644 tests/testsuite/main.rs diff --git a/Cargo.lock b/Cargo.lock index 49c1f2dc..e50f2865 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,3 +5,52 @@ version = 3 [[package]] name = "PROJECT" version = "0.0.1" +dependencies = [ + "automod", +] + +[[package]] +name = "automod" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edf3ee19dbc0a46d740f6f0926bde8c50f02bdbc7b536842da28f6ac56513a8b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "2.0.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" diff --git a/Cargo.toml b/Cargo.toml index e07a4738..d5e3b014 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ include = [ ] [workspace.dependencies] +automod = "1.0.14" [workspace.lints.rust] missing_docs = "warn" @@ -129,6 +130,7 @@ default = [] [dependencies] [dev-dependencies] +automod.workspace = true [lints] workspace = true diff --git a/tests/testsuite/delete_me.rs b/tests/testsuite/delete_me.rs new file mode 100644 index 00000000..e69de29b diff --git a/tests/testsuite/main.rs b/tests/testsuite/main.rs new file mode 100644 index 00000000..44413747 --- /dev/null +++ b/tests/testsuite/main.rs @@ -0,0 +1 @@ +automod::dir!("tests/testsuite"); From c8b190be3a7397d63ffb175f8387ef98e7896b5a Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 28 Mar 2024 09:50:22 -0500 Subject: [PATCH 064/293] chore(ci): Use latest SARIF Now that we run clippy on stable, we can do this --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 12d398cd..52ce7f22 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -128,9 +128,9 @@ jobs: components: clippy - uses: Swatinem/rust-cache@v2 - name: Install SARIF tools - run: cargo install clippy-sarif --version 0.3.4 --locked # Held back due to msrv + run: cargo install clippy-sarif --locked - name: Install SARIF tools - run: cargo install sarif-fmt --version 0.3.4 --locked # Held back due to msrv + run: cargo install sarif-fmt --locked - name: Check run: > cargo clippy --workspace --all-features --all-targets --message-format=json -- -D warnings --allow deprecated From 9b1b56620156971664aaf0f7a693bf3bc72ca0cb Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 28 Mar 2024 09:51:51 -0500 Subject: [PATCH 065/293] chore(ci): Fix all rust-version-specific checks to stable --- .github/workflows/ci.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 52ce7f22..42c6be7e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,7 +91,7 @@ jobs: - name: Install Rust uses: dtolnay/rust-toolchain@stable with: - toolchain: stable + toolchain: "1.76" # STABLE - uses: Swatinem/rust-cache@v2 - name: Check documentation env: @@ -106,9 +106,7 @@ jobs: - name: Install Rust uses: dtolnay/rust-toolchain@stable with: - # Not MSRV because its harder to jump between versions and people are - # more likely to have stable - toolchain: stable + toolchain: "1.76" # STABLE components: rustfmt - uses: Swatinem/rust-cache@v2 - name: Check formatting From 92d486c4b03efa984a9d03aa7279a1febe84d816 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 28 Mar 2024 09:53:02 -0500 Subject: [PATCH 066/293] chore(ci): Speed up lockfile check --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 42c6be7e..7a455a4d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -81,7 +81,7 @@ jobs: toolchain: stable - uses: Swatinem/rust-cache@v2 - name: "Is lockfile updated?" - run: cargo fetch --locked + run: cargo update --workspace --locked docs: name: Docs runs-on: ubuntu-latest From 9258d9af7b87bc0394ef09be7e65bf6152d99f4b Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 28 Mar 2024 09:57:23 -0500 Subject: [PATCH 067/293] chore(ci): More exhaustively check features --- .github/workflows/ci.yml | 15 ++++----------- .github/workflows/rust-next.yml | 18 ++++++------------ 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7a455a4d..134c3179 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,14 +44,11 @@ jobs: with: toolchain: ${{ matrix.rust }} - uses: Swatinem/rust-cache@v2 + - uses: taiki-e/install-action@cargo-hack - name: Build run: cargo test --workspace --no-run - - name: Default features - run: cargo test --workspace - - name: All features - run: cargo test --workspace --all-features - - name: No-default features - run: cargo test --workspace --no-default-features + - name: Test + run: cargo hack test --feature-powerset --workspace msrv: name: "Check MSRV" runs-on: ubuntu-latest @@ -65,11 +62,7 @@ jobs: - uses: Swatinem/rust-cache@v2 - uses: taiki-e/install-action@cargo-hack - name: Default features - run: cargo hack check --locked --rust-version --ignore-private --workspace --all-targets - - name: All features - run: cargo hack check --locked --rust-version --ignore-private --workspace --all-targets --all-features - - name: No-default features - run: cargo hack check --locked --rust-version --ignore-private --workspace --all-targets --no-default-features + run: cargo hack check --feature-powerset --locked --rust-version --ignore-private --workspace --all-targets lockfile: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/rust-next.yml b/.github/workflows/rust-next.yml index 49e5d8c3..e673b652 100644 --- a/.github/workflows/rust-next.yml +++ b/.github/workflows/rust-next.yml @@ -36,14 +36,11 @@ jobs: with: toolchain: ${{ matrix.rust }} - uses: Swatinem/rust-cache@v2 + - uses: taiki-e/install-action@cargo-hack - name: Build run: cargo test --workspace --no-run - - name: Default features - run: cargo test --workspace - - name: All features - run: cargo test --workspace --all-features - - name: No-default features - run: cargo test --workspace --no-default-features + - name: Test + run: cargo hack test --feature-powerset --workspace latest: name: "Check latest dependencies" runs-on: ubuntu-latest @@ -55,13 +52,10 @@ jobs: with: toolchain: stable - uses: Swatinem/rust-cache@v2 + - uses: taiki-e/install-action@cargo-hack - name: Update dependencues run: cargo update - name: Build run: cargo test --workspace --no-run - - name: Default features - run: cargo test --workspace - - name: All features - run: cargo test --workspace --all-features - - name: No-default features - run: cargo test --workspace --no-default-features + - name: Test + run: cargo hack test --feature-powerset --workspace From 2714cca7c31a9c73716e88a93693c119c527d7f1 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 28 Mar 2024 09:58:31 -0500 Subject: [PATCH 068/293] chore(ci): Don't check for unused crates --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d5e3b014..4097fef0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,6 @@ rust_2018_idioms = "warn" unreachable_pub = "warn" unsafe_op_in_unsafe_fn = "warn" unsafe_code = "warn" -unused_crate_dependencies = "warn" unused_lifetimes = "warn" unused_macro_rules = "warn" unused_qualifications = "warn" From 314eef7f5fb7e415e8cd92887e5e878e9bfa929b Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 28 Mar 2024 10:38:57 -0500 Subject: [PATCH 069/293] chore: Dont check must_use See https://github.com/rust-lang/rust-clippy/issues/8339 --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4097fef0..666e6e39 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -81,7 +81,6 @@ rc_mutex = "warn" redundant_feature_names = "warn" ref_option_ref = "warn" rest_pat_in_fully_bound_structs = "warn" -return_self_not_must_use = "warn" same_functions_in_if_condition = "warn" self_named_module_files = "warn" semicolon_if_nothing_returned = "warn" From 6a9d2bf50fa78d8f277b77be836b48fad8c7c764 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 28 Mar 2024 12:45:57 -0500 Subject: [PATCH 070/293] chore: Don't warn on unsafe This works well when a package is a safe abstraction but to universally apply in a template to all members of a workspace doesn't make sense. --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 666e6e39..50bfea56 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,6 @@ missing_docs = "warn" rust_2018_idioms = "warn" unreachable_pub = "warn" unsafe_op_in_unsafe_fn = "warn" -unsafe_code = "warn" unused_lifetimes = "warn" unused_macro_rules = "warn" unused_qualifications = "warn" From 8d4b1b6c8daf3c32828bf92725811cf433917081 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 28 Mar 2024 13:24:28 -0500 Subject: [PATCH 071/293] chore: Remove clippy::tests_outside_test_module See https://github.com/rust-lang/rust-clippy/issues/11024 --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 50bfea56..ed593eba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -89,7 +89,6 @@ string_add = "warn" string_add_assign = "warn" string_lit_as_bytes = "warn" string_to_string = "warn" -tests_outside_test_module = "warn" todo = "warn" trait_duplication_in_bounds = "warn" unwrap_used = "warn" From 99e034bbbbae7d60bb68d68c6d0db8338a97b030 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 28 Mar 2024 15:10:58 -0500 Subject: [PATCH 072/293] chore: Move print lints to lib.rs While there is a config for ignoring these in tests, it doesn't help with examples. --- Cargo.toml | 2 -- src/lib.rs | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ed593eba..faf1e63a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,8 +73,6 @@ needless_continue = "warn" needless_for_each = "warn" negative_feature_names = "warn" path_buf_push_overwrite = "warn" -print_stderr = "warn" -print_stdout = "warn" ptr_as_ptr = "warn" rc_mutex = "warn" redundant_feature_names = "warn" diff --git a/src/lib.rs b/src/lib.rs index 8ce46b57..2eabbd09 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,6 @@ //! > DESCRIPTION #![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![warn(clippy::print_stderr)] +#![warn(clippy::print_stdout)] #![allow(non_snake_case)] // TODO: Delete me From a516bda4adb0f367da527488697ea308fbe58b38 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 1 Apr 2024 08:58:36 -0500 Subject: [PATCH 073/293] chore: Drop workspace.dependencies Without automated checks, this will make it harder to track breaking changes. --- Cargo.toml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index faf1e63a..983e0905 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,9 +16,6 @@ include = [ "examples/**/*" ] -[workspace.dependencies] -automod = "1.0.14" - [workspace.lints.rust] missing_docs = "warn" rust_2018_idioms = "warn" @@ -124,7 +121,7 @@ default = [] [dependencies] [dev-dependencies] -automod.workspace = true +automod = "1.0.14" [lints] workspace = true From ebc70d00f9259146592b7987bfcb8a0cb6c16661 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 1 Apr 2024 09:11:24 -0500 Subject: [PATCH 074/293] chore: Only check missing_docs in lib This also fires in examples and other places. While docs in examples would be nice, it isn't universally applicable and `allow`s would undermine the examples. --- Cargo.toml | 1 - src/lib.rs | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 983e0905..715131bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,6 @@ include = [ ] [workspace.lints.rust] -missing_docs = "warn" rust_2018_idioms = "warn" unreachable_pub = "warn" unsafe_op_in_unsafe_fn = "warn" diff --git a/src/lib.rs b/src/lib.rs index 2eabbd09..39877b76 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ //! > DESCRIPTION #![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![warn(missing_docs)] #![warn(clippy::print_stderr)] #![warn(clippy::print_stdout)] #![allow(non_snake_case)] // TODO: Delete me From 3278d49444c33ece610de3fb5547bd885124dfe7 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 1 Apr 2024 10:35:16 -0500 Subject: [PATCH 075/293] chore: Allow print in tests --- .clippy.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/.clippy.toml b/.clippy.toml index 293c14f3..027eef41 100644 --- a/.clippy.toml +++ b/.clippy.toml @@ -1,4 +1,5 @@ warn-on-all-wildcard-imports = true +allow-print-in-tests = true allow-expect-in-tests = true allow-unwrap-in-tests = true allow-dbg-in-tests = true From d634de649f30d5a4deade46333606bc63897d05e Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 1 Apr 2024 11:36:58 -0500 Subject: [PATCH 076/293] chore(ci): Ensure CI job always runs --- .github/workflows/ci.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 134c3179..95b13b4f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,11 +23,13 @@ jobs: permissions: contents: none name: CI - needs: [test, msrv, docs, rustfmt, clippy] + needs: [test, msrv, lockfile, docs, rustfmt, clippy] runs-on: ubuntu-latest + if: "always()" steps: - - name: Done - run: exit 0 + - name: Failed + run: exit 1 + if: "contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped')" test: name: Test strategy: From 2570b58a0feaf355dede9080a9f4c98f8ba5580b Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 1 Apr 2024 12:31:49 -0500 Subject: [PATCH 077/293] chore(ci): Skip branch protections --- .github/settings.yml | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/.github/settings.yml b/.github/settings.yml index 7d5e4fce..08983ae0 100644 --- a/.github/settings.yml +++ b/.github/settings.yml @@ -42,14 +42,18 @@ labels: color: '#c2e0c6' description: "Help wanted!" -branches: - - name: main - protection: - required_pull_request_reviews: null - required_conversation_resolution: true - required_status_checks: - # Required. Require branches to be up to date before merging. - strict: false - contexts: ["CI", "Lint Commits", "Spell Check with Typos"] - enforce_admins: false - restrictions: null +# This serves more as documentation. +# Branch protection API was replaced by rulesets but settings isn't updated. +# See https://github.com/repository-settings/app/issues/825 +# +# branches: +# - name: main +# protection: +# required_pull_request_reviews: null +# required_conversation_resolution: true +# required_status_checks: +# # Required. Require branches to be up to date before merging. +# strict: false +# contexts: ["CI", "Lint Commits", "Spell Check with Typos"] +# enforce_admins: false +# restrictions: null From afd275590c5568e8f7ca60abc1f33b20e3679c03 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 1 Apr 2024 12:36:16 -0500 Subject: [PATCH 078/293] chore(ci): Don't block on Lint Commits --- .github/settings.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/settings.yml b/.github/settings.yml index 08983ae0..457eed62 100644 --- a/.github/settings.yml +++ b/.github/settings.yml @@ -54,6 +54,6 @@ labels: # required_status_checks: # # Required. Require branches to be up to date before merging. # strict: false -# contexts: ["CI", "Lint Commits", "Spell Check with Typos"] +# contexts: ["CI", "Spell Check with Typos"] # enforce_admins: false # restrictions: null From 14225df351a4510a6fad72e716b29173347aac84 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 16 Apr 2024 21:46:56 -0500 Subject: [PATCH 079/293] chore(ci): Auto-merge linter version updates --- .github/renovate.json5 | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 373fc0e5..62ca46b6 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -72,6 +72,7 @@ schedule: [ '* * * * *', ], + automerge: true, }, // Goals: // - Keep version reqs low, ignoring compatible normal/build dependencies From be30b1bba034344c1a7c526b2b1898a8767471c5 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 26 Apr 2024 09:20:18 -0500 Subject: [PATCH 080/293] chore(ci): Try again with not auto-updating MSRV The overhead for MSRV bumping is a lot lower and its annoying merging all of the PRs (and I don't want these auto-merged) --- .github/renovate.json5 | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 62ca46b6..c1844208 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -7,24 +7,6 @@ configMigration: true, dependencyDashboard: true, customManagers: [ - { - customType: 'regex', - fileMatch: [ - '^rust-toolchain\\.toml$', - 'Cargo.toml$', - 'clippy.toml$', - '\\.clippy.toml$', - '^\\.github/workflows/ci.yml$', - '^\\.github/workflows/rust-next.yml$', - ], - matchStrings: [ - 'MSRV.*?(?\\d+\\.\\d+(\\.\\d+)?)', - '(?\\d+\\.\\d+(\\.\\d+)?).*?MSRV', - ], - depNameTemplate: 'MSRV', - packageNameTemplate: 'rust-lang/rust', - datasourceTemplate: 'github-releases', - }, { customType: 'regex', fileMatch: [ @@ -45,21 +27,6 @@ }, ], packageRules: [ - { - commitMessageTopic: 'MSRV', - matchManagers: [ - 'custom.regex', - ], - matchPackageNames: [ - 'MSRV', - ], - minimumReleaseAge: '336 days', // 8 releases * 6 weeks per release * 7 days per week - internalChecksFilter: 'strict', - extractVersion: '^(?\\d+\\.\\d+)', // Drop the patch version - schedule: [ - '* * * * *', - ], - }, { commitMessageTopic: 'Rust Stable', matchManagers: [ From a01f25da96e8bd3e216fbc19ac9883ab3bf969ce Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 26 Apr 2024 09:23:28 -0500 Subject: [PATCH 081/293] chore(ci): Reduce noisy lints Want to add this back in later but this is slowing down migration of my repos. --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 39877b76..2eabbd09 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,6 @@ //! > DESCRIPTION #![cfg_attr(docsrs, feature(doc_auto_cfg))] -#![warn(missing_docs)] #![warn(clippy::print_stderr)] #![warn(clippy::print_stdout)] #![allow(non_snake_case)] // TODO: Delete me From 82cf9a62b027c10c6fafdcaaee24c4e92d7da61d Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 26 Apr 2024 09:35:55 -0500 Subject: [PATCH 082/293] chore(ci): Reduce noisy lints --- Cargo.toml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 715131bb..898251ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,9 +35,6 @@ debug_assert_with_mut_call = "warn" doc_markdown = "warn" empty_enum = "warn" enum_glob_use = "warn" -exhaustive_enums = "warn" -exhaustive_structs = "warn" -exit = "warn" expl_impl_clone_on_copy = "warn" explicit_deref_methods = "warn" explicit_into_iter_loop = "warn" @@ -85,7 +82,6 @@ string_lit_as_bytes = "warn" string_to_string = "warn" todo = "warn" trait_duplication_in_bounds = "warn" -unwrap_used = "warn" verbose_file_reads = "warn" wildcard_imports = "warn" zero_sized_map_values = "warn" From 181a2cf5e673d0f6f42133a5b30ccafd86b0106d Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 26 Apr 2024 11:36:19 -0500 Subject: [PATCH 083/293] chore(ci): Allow prelude wildcard imports --- .clippy.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/.clippy.toml b/.clippy.toml index 027eef41..1d4c5dc6 100644 --- a/.clippy.toml +++ b/.clippy.toml @@ -1,4 +1,3 @@ -warn-on-all-wildcard-imports = true allow-print-in-tests = true allow-expect-in-tests = true allow-unwrap-in-tests = true From 51de731521efb05c5503e05c33036d8fa439bc5a Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 26 Apr 2024 15:59:46 -0500 Subject: [PATCH 084/293] chore(ci): Lint clippy::items_after_statements seems too strict --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 898251ed..5a905800 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,6 @@ inconsistent_struct_constructor = "warn" inefficient_to_string = "warn" infinite_loop = "warn" invalid_upcast_comparisons = "warn" -items_after_statements = "warn" large_digit_groups = "warn" large_stack_arrays = "warn" large_types_passed_by_value = "warn" From 78741e51bbbe6c83aaa98305623a8ffc6226493f Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 27 May 2024 21:45:38 -0500 Subject: [PATCH 085/293] chore: Remove lints that lead to bad code --- Cargo.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5a905800..80906914 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,7 +58,6 @@ let_and_return = "allow" # sometimes good to name what you are returning linkedlist = "warn" lossy_float_literal = "warn" macro_use_imports = "warn" -match_wildcard_for_single_variants = "warn" mem_forget = "warn" mutex_integer = "warn" needless_continue = "warn" @@ -73,7 +72,6 @@ rest_pat_in_fully_bound_structs = "warn" same_functions_in_if_condition = "warn" self_named_module_files = "warn" semicolon_if_nothing_returned = "warn" -single_match_else = "warn" str_to_string = "warn" string_add = "warn" string_add_assign = "warn" From 44916f6d2b8da4d778186083c31ff52a73187edf Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 29 May 2024 16:15:19 -0500 Subject: [PATCH 086/293] chore: Update deny config --- deny.toml | 176 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 136 insertions(+), 40 deletions(-) diff --git a/deny.toml b/deny.toml index 21fa937f..b6ecbe9c 100644 --- a/deny.toml +++ b/deny.toml @@ -4,32 +4,82 @@ # * allow - No warning or error will be produced, though in some cases a note # will be +# Root options + +# The graph table configures how the dependency graph is constructed and thus +# which crates the checks are performed against +[graph] +# If 1 or more target triples (and optionally, target_features) are specified, +# only the specified targets will be checked when running `cargo deny check`. +# This means, if a particular package is only ever used as a target specific +# dependency, such as, for example, the `nix` crate only being used via the +# `target_family = "unix"` configuration, that only having windows targets in +# this list would mean the nix crate, as well as any of its exclusive +# dependencies not shared by any other crates, would be ignored, as the target +# list here is effectively saying which targets you are building for. +targets = [ + # The triple can be any string, but only the target triples built in to + # rustc (as of 1.40) can be checked against actual config expressions + #"x86_64-unknown-linux-musl", + # You can also specify which target_features you promise are enabled for a + # particular target. target_features are currently not validated against + # the actual valid features supported by the target architecture. + #{ triple = "wasm32-unknown-unknown", features = ["atomics"] }, +] +# When creating the dependency graph used as the source of truth when checks are +# executed, this field can be used to prune crates from the graph, removing them +# from the view of cargo-deny. This is an extremely heavy hammer, as if a crate +# is pruned from the graph, all of its dependencies will also be pruned unless +# they are connected to another crate in the graph that hasn't been pruned, +# so it should be used with care. The identifiers are [Package ID Specifications] +# (https://doc.rust-lang.org/cargo/reference/pkgid-spec.html) +#exclude = [] +# If true, metadata will be collected with `--all-features`. Note that this can't +# be toggled off if true, if you want to conditionally enable `--all-features` it +# is recommended to pass `--all-features` on the cmd line instead +all-features = false +# If true, metadata will be collected with `--no-default-features`. The same +# caveat with `all-features` applies +no-default-features = false +# If set, these feature will be enabled when collecting metadata. If `--features` +# is specified on the cmd line they will take precedence over this option. +#features = [] + +# The output table provides options for how/if diagnostics are outputted +[output] +# When outputting inclusion graphs in diagnostics that include features, this +# option can be used to specify the depth at which feature edges will be added. +# This option is included since the graphs can be quite large and the addition +# of features from the crate(s) to all of the graph roots can be far too verbose. +# This option can be overridden via `--feature-depth` on the cmd line +feature-depth = 1 + # This section is considered when running `cargo deny check advisories` # More documentation for the advisories section can be found here: # https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html [advisories] -# The lint level for security vulnerabilities -vulnerability = "deny" -# The lint level for unmaintained crates -unmaintained = "warn" -# The lint level for crates that have been yanked from their source registry -yanked = "warn" -# The lint level for crates with security notices. Note that as of -# 2019-12-17 there are no security notice advisories in -# https://github.com/rustsec/advisory-db -notice = "warn" +# The path where the advisory databases are cloned/fetched into +#db-path = "$CARGO_HOME/advisory-dbs" +# The url(https://github.com/s) of the advisory databases to use +#db-urls = ["https://github.com/rustsec/advisory-db"] # A list of advisory IDs to ignore. Note that ignored advisories will still # output a note when they are encountered. -# -# e.g. "RUSTSEC-0000-0000", ignore = [ + #"RUSTSEC-0000-0000", + #{ id = "RUSTSEC-0000-0000", reason = "you can specify a reason the advisory is ignored" }, + #"a-crate-that-is-yanked@0.1.1", # you can also ignore yanked crate versions if you wish + #{ crate = "a-crate-that-is-yanked@0.1.1", reason = "you can specify why you are ignoring the yanked crate" }, ] +# If this is true, then cargo deny will use the git executable to fetch advisory database. +# If this is false, then it uses a built-in git library. +# Setting this to true can be helpful if you have special authentication requirements that cargo-deny does not support. +# See Git Authentication for more information about setting up git authentication. +#git-fetch-with-cli = true # This section is considered when running `cargo deny check licenses` # More documentation for the licenses section can be found here: # https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html [licenses] -unlicensed = "deny" # List of explicitly allowed licenses # See https://spdx.org/licenses/ for list of possible licenses # [possible values: any SPDX 3.11 short identifier (+ optional exception)]. @@ -42,26 +92,8 @@ allow = [ "Unicode-DFS-2016", "CC0-1.0", "ISC", + "OpenSSL", ] -# List of explicitly disallowed licenses -# See https://spdx.org/licenses/ for list of possible licenses -# [possible values: any SPDX 3.11 short identifier (+ optional exception)]. -deny = [ -] -# Lint level for licenses considered copyleft -copyleft = "deny" -# Blanket approval or denial for OSI-approved or FSF Free/Libre licenses -# * both - The license will be approved if it is both OSI-approved *AND* FSF -# * either - The license will be approved if it is either OSI-approved *OR* FSF -# * osi-only - The license will be approved if is OSI-approved *AND NOT* FSF -# * fsf-only - The license will be approved if is FSF *AND NOT* OSI-approved -# * neither - This predicate is ignored and the default lint level is used -allow-osi-fsf-free = "neither" -# Lint level used when no other predicates are matched -# 1. License isn't in the allow or deny lists -# 2. License isn't copyleft -# 3. License isn't OSI/FSF, or allow-osi-fsf-free = "neither" -default = "deny" # The confidence threshold for detecting a license from license text. # The higher the value, the more closely the license text must be to the # canonical license text of a valid SPDX license file. @@ -72,7 +104,25 @@ confidence-threshold = 0.8 exceptions = [ # Each entry is the crate and version constraint, and its specific allow # list - #{ allow = ["Zlib"], name = "adler32", version = "*" }, + #{ allow = ["Zlib"], crate = "adler32" }, +] + +# Some crates don't have (easily) machine readable licensing information, +# adding a clarification entry for it allows you to manually specify the +# licensing information +[[licenses.clarify]] +# The package spec the clarification applies to +crate = "ring" +# The SPDX expression for the license requirements of the crate +expression = "MIT AND ISC AND OpenSSL" +# One or more files in the crate's source used as the "source of truth" for +# the license expression. If the contents match, the clarification will be used +# when running the license check, otherwise the clarification will be ignored +# and the crate will be checked normally, which may produce warnings or errors +# depending on the rest of your configuration +license-files = [ +# Each entry is a crate relative path, and the (opaque) hash of its contents +{ path = "LICENSE", hash = 0xbd0eed23 } ] [licenses.private] @@ -81,6 +131,12 @@ exceptions = [ # To see how to mark a crate as unpublished (to the official registry), # visit https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field. ignore = true +# One or more private registries that you might publish crates to, if a crate +# is only published to private registries, and ignore is true, the crate will +# not have its license(s) checked +registries = [ + #"https://sekretz.com/registry+]%20%20#%20This%20section%20is%20considered%20when%20running%20%60cargo%20deny%20check%20bans%60.%20#%20More%20documentation%20about%20the'bans' section can be found here: @@ -89,7 +145,7 @@ ignore = true # Lint level for when multiple versions of the same crate are detected multiple-versions = "warn" # Lint level for when a crate version requirement is `*` -wildcards = "warn" +wildcards = "allow" # The graph highlighting used when creating dotgraphs for crates # with multiple versions # * lowest-version - The path to the lowest versioned duplicate is highlighted @@ -106,17 +162,53 @@ workspace-default-features = "allow" external-default-features = "allow" # List of crates that are allowed. Use with care! allow = [ - #{ name = "ansi_term", version = "=0.11.0" }, + #"ansi_term@0.11.0", + #{ crate = "ansi_term@0.11.0", reason = "you can specify a reason it is allowed" }, ] # List of crates to deny deny = [ - # Each entry the name of a crate and a version range. If version is - # not specified, all versions will be matched. - #{ name = "ansi_term", version = "=0.11.0" }, - # + #"ansi_term@0.11.0", + #{ crate = "ansi_term@0.11.0", reason = "you can specify a reason it is banned" }, # Wrapper crates can optionally be specified to allow the crate when it # is a direct dependency of the otherwise banned crate - #{ name = "ansi_term", version = "=0.11.0", wrappers = [] }, + #{ crate = "ansi_term@0.11.0", wrappers = ["this-crate-directly-depends-on-ansi_term"] }, +] + +# List of features to allow/deny +# Each entry the name of a crate and a version range. If version is +# not specified, all versions will be matched. +#[[bans.features]] +#crate = "reqwest" +# Features to not allow +#deny = ["json"] +# Features to allow +#allow = [ +# "rustls", +# "__rustls", +# "__tls", +# "hyper-rustls", +# "rustls", +# "rustls-pemfile", +# "rustls-tls-webpki-roots", +# "tokio-rustls", +# "webpki-roots", +#] +# If true, the allowed features must exactly match the enabled feature set. If +# this is set there is no point setting `deny` +#exact = true + +# Certain crates/versions that will be skipped when doing duplicate detection. +skip = [ + #"ansi_term@0.11.0", + #{ crate = "ansi_term@0.11.0", reason = "you can specify a reason why it can't be updated/removed" }, +] +# Similarly to `skip` allows you to skip certain crates during duplicate +# detection. Unlike skip, it also includes the entire tree of transitive +# dependencies starting at the specified crate, up to a certain depth, which is +# by default infinite. +skip-tree = [ + #"ansi_term@0.11.0", # will be skipped along with _all_ of its direct and transitive dependencies + #{ crate = "ansi_term@0.11.0", depth = 20 }, ] # This section is considered when running `cargo deny check sources`. @@ -138,3 +230,7 @@ allow-git = [] [sources.allow-org] # 1 or more github.com organizations to allow git sources for github = [] +# 1 or more gitlab.com organizations to allow git sources for +gitlab = [] +# 1 or more bitbucket.org organizations to allow git sources for +bitbucket = [] From ce6badcd188650dac4b3c97b69bde86a738917a0 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 3 Jun 2024 10:29:26 -0500 Subject: [PATCH 087/293] chore: Fix typo --- .github/workflows/rust-next.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust-next.yml b/.github/workflows/rust-next.yml index e673b652..ab499633 100644 --- a/.github/workflows/rust-next.yml +++ b/.github/workflows/rust-next.yml @@ -53,7 +53,7 @@ jobs: toolchain: stable - uses: Swatinem/rust-cache@v2 - uses: taiki-e/install-action@cargo-hack - - name: Update dependencues + - name: Update dependencies run: cargo update - name: Build run: cargo test --workspace --no-run From 1353a953a527b7ebc0b0a3f267fc47f56359e886 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 4 Jun 2024 15:33:16 -0500 Subject: [PATCH 088/293] chore: Encourage use of repository --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 80906914..c9695d79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -87,6 +87,7 @@ zero_sized_map_values = "warn" name = "PROJECT" version = "0.0.1" description = "DESCRIPTION" +repository = "REPOSITORY" categories = [] keywords = [] license.workspace = true From 7039c66c7f0a42b84136a2f166ce6446edbb9ce0 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 4 Jun 2024 15:33:50 -0500 Subject: [PATCH 089/293] chore: Encourage cloneable repositories --- Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c9695d79..96cb2348 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ resolver = "2" [workspace.package] +repository = "REPOSITORY" license = "MIT OR Apache-2.0" edition = "2021" rust-version = "1.65.0" # MSRV @@ -87,9 +88,9 @@ zero_sized_map_values = "warn" name = "PROJECT" version = "0.0.1" description = "DESCRIPTION" -repository = "REPOSITORY" categories = [] keywords = [] +repository.workspace = true license.workspace = true edition.workspace = true rust-version.workspace = true From 2a274e149f7f6f7f80f08486bd34c4fc7b8d63c8 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 21 Jun 2024 14:21:41 -0400 Subject: [PATCH 090/293] chore(ci): Auto-update Mac now that latest uses m1 --- .github/workflows/ci.yml | 2 +- .github/workflows/rust-next.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 95b13b4f..6e064993 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,7 @@ jobs: name: Test strategy: matrix: - os: ["ubuntu-latest", "windows-latest", "macos-14"] + os: ["ubuntu-latest", "windows-latest", "macos-latest"] rust: ["stable"] continue-on-error: ${{ matrix.rust != 'stable' }} runs-on: ${{ matrix.os }} diff --git a/.github/workflows/rust-next.yml b/.github/workflows/rust-next.yml index ab499633..e98386c4 100644 --- a/.github/workflows/rust-next.yml +++ b/.github/workflows/rust-next.yml @@ -21,7 +21,7 @@ jobs: name: Test strategy: matrix: - os: ["ubuntu-latest", "windows-latest", "macos-latest", "macos-14"] + os: ["ubuntu-latest", "windows-latest", "macos-latest"] rust: ["stable", "beta"] include: - os: ubuntu-latest From 0547ff2d0f135d541faef3735143b40c174b4c3a Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 4 Jul 2024 12:54:40 -0400 Subject: [PATCH 091/293] docs(contrib): Clarify our policies --- CONTRIBUTING.md | 45 ++++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e9d70793..1a6dd1cd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,27 +29,42 @@ to re-work some of it and the discouragement that goes along with that. ### Process -Before posting a PR, we request that the commit history get cleaned up. -However, we recommend avoiding this during the review to make it easier to -check how feedback was handled. Once the PR is ready, we'll ask you to clean up -the commit history from the review. Once you let us know this is done, we can -move forward with merging! If you are uncomfortable with these parts of git, -let us know and we can help. - -For commit messages, we use [Conventional](https://www.conventionalcommits.org) -style. If you already wrote your commits and don't feel comfortable changing -them, don't worry and go ahead and create your PR. We'll work with you on the -best route forward. You can check your branch locally with -[`committed`](https://github.com/crate-ci/committed). - As a heads up, we'll be running your PR through the following gauntlet: - warnings turned to compile errors - `cargo test` - `rustfmt` - `clippy` - `rustdoc` -- [`committed`](https://github.com/crate-ci/committed) -- [`typos`](https://github.com/crate-ci/typos) +- [`committed`](https://github.com/crate-ci/committed) as we use [Conventional](https://www.conventionalcommits.org) commit styl +- [`typos`](https://github.com/crate-ci/typos) to check spelling + +Not everything can be checked automatically though. + +We request that the commit history get cleaned up. +We ask that commits are atomic, meaning they are complete and have a single responsibility. +PRs shoukd tell a cohesive story, with test and refactor commits that keep the +fix or feature commits simple and clear. + +Specifically, we would encouage +- File renames be isolated into their own commit +- Add tests in a commit before their feature or fix, showing the current behavior. + The diff for the feature/fix commit will then show how the behavior changed, + making it clearer to reviewrs and the community and showing people that the + test is verifying the expected state. + - e.g. [clap#5520](https://github.com/clap-rs/clap/pull/5520) + +Note that we are talking about ideals. +We understand having a clean history requires more advanced git skills; +feel free to ask us for help! +We might even suggest where it would work to be lax. +We also understand that editing some early commits may cause a lot of churn +with merge conflicts which can make it not worth editing all of the history. + +For code organization, we recommend +- Grouping `impl` blocks next to their type (or trait) +- Grouping private items after the `pub` item that uses them. + - The intent is to help people quickly find the "relevant" details, allowing them to "dig deeper" as needed. Or put another way, the `pub` items serve as a table-of-contents. + - The exact order is fuzzy; do what makes sense ## Releasing From eb4e999f1b679936ce1d11aa68b923066aff2ab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jalil=20David=20Salam=C3=A9=20Messina?= <60845989+jalil-salame@users.noreply.github.com> Date: Thu, 4 Jul 2024 19:06:12 +0200 Subject: [PATCH 092/293] Fix typos in CONTRIBUTING.md I found this through [mastodon][1] and found the typos jarring. [1]: https://hachyderm.io/@epage/112729287446906823 --- CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1a6dd1cd..87d9134e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -35,14 +35,14 @@ As a heads up, we'll be running your PR through the following gauntlet: - `rustfmt` - `clippy` - `rustdoc` -- [`committed`](https://github.com/crate-ci/committed) as we use [Conventional](https://www.conventionalcommits.org) commit styl +- [`committed`](https://github.com/crate-ci/committed) as we use [Conventional](https://www.conventionalcommits.org) commit style - [`typos`](https://github.com/crate-ci/typos) to check spelling Not everything can be checked automatically though. -We request that the commit history get cleaned up. +We request that the commit history gets cleaned up. We ask that commits are atomic, meaning they are complete and have a single responsibility. -PRs shoukd tell a cohesive story, with test and refactor commits that keep the +PRs should tell a cohesive story, with test and refactor commits that keep the fix or feature commits simple and clear. Specifically, we would encouage From bdb06a11df6cf4d8b06848520f18609ab07c7b5e Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 9 Jul 2024 11:06:45 -0500 Subject: [PATCH 093/293] chore(ci): Verify version requirements --- .github/workflows/ci.yml | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6e064993..d49017e7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: permissions: contents: none name: CI - needs: [test, msrv, lockfile, docs, rustfmt, clippy] + needs: [test, msrv, lockfile, docs, rustfmt, clippy, minimal-versions] runs-on: ubuntu-latest if: "always()" steps: @@ -65,6 +65,24 @@ jobs: - uses: taiki-e/install-action@cargo-hack - name: Default features run: cargo hack check --feature-powerset --locked --rust-version --ignore-private --workspace --all-targets + minimal-versions: + name: Minimal versions + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Install stable Rust + uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + - name: Install nightly Rust + uses: dtolnay/rust-toolchain@stable + with: + toolchain: nightly + - name: Downgrade dependencies to minimal versions + run: cargo +nightly generate-lockfile -Z minimal-versions + - name: Compile with minimal versions + run: cargo +stable check --workspace --all-features --locked lockfile: runs-on: ubuntu-latest steps: From 87d9ae55c792a4f37b3f989250c1a3512df2926e Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 25 Jul 2024 15:48:09 -0500 Subject: [PATCH 094/293] chore: Fix clippy::lint_groups_priority for 1.80 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 96cb2348..90d89f6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ include = [ ] [workspace.lints.rust] -rust_2018_idioms = "warn" +rust_2018_idioms = { level = "warn", priority = -1 } unreachable_pub = "warn" unsafe_op_in_unsafe_fn = "warn" unused_lifetimes = "warn" From 553258af51034bc84dc9f951201e7b8f2285b57e Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 25 Jul 2024 15:35:58 -0700 Subject: [PATCH 095/293] Have clippy warn about uninlined format arguments This makes clippy warn about `format!("{}", var)`, with a machine-applicable fix converting to `format!("{var}")`. --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 90d89f6e..97c7ed79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -80,6 +80,7 @@ string_lit_as_bytes = "warn" string_to_string = "warn" todo = "warn" trait_duplication_in_bounds = "warn" +uninlined_format_args = "warn" verbose_file_reads = "warn" wildcard_imports = "warn" zero_sized_map_values = "warn" From c5443c45979b52a7ef3790c9604681a171ee76f8 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Wed, 21 Aug 2024 15:01:07 -0600 Subject: [PATCH 096/293] test: Move all fixture tests to color --- tests/fixtures/{no-color => color}/ann_eof.svg | 0 tests/fixtures/{no-color => color}/ann_eof.toml | 0 tests/fixtures/{no-color => color}/ann_insertion.svg | 0 tests/fixtures/{no-color => color}/ann_insertion.toml | 0 tests/fixtures/{no-color => color}/ann_multiline.svg | 0 tests/fixtures/{no-color => color}/ann_multiline.toml | 0 tests/fixtures/{no-color => color}/ann_multiline2.svg | 0 tests/fixtures/{no-color => color}/ann_multiline2.toml | 0 tests/fixtures/{no-color => color}/ann_removed_nl.svg | 0 tests/fixtures/{no-color => color}/ann_removed_nl.toml | 0 .../fixtures/{no-color => color}/ensure-emoji-highlight-width.svg | 0 .../{no-color => color}/ensure-emoji-highlight-width.toml | 0 tests/fixtures/{no-color => color}/fold_ann_multiline.svg | 0 tests/fixtures/{no-color => color}/fold_ann_multiline.toml | 0 tests/fixtures/{no-color => color}/fold_bad_origin_line.svg | 0 tests/fixtures/{no-color => color}/fold_bad_origin_line.toml | 0 tests/fixtures/{no-color => color}/fold_leading.svg | 0 tests/fixtures/{no-color => color}/fold_leading.toml | 0 tests/fixtures/{no-color => color}/fold_trailing.svg | 0 tests/fixtures/{no-color => color}/fold_trailing.toml | 0 tests/fixtures/{no-color => color}/issue_9.svg | 0 tests/fixtures/{no-color => color}/issue_9.toml | 0 tests/fixtures/{no-color => color}/multiple_annotations.svg | 0 tests/fixtures/{no-color => color}/multiple_annotations.toml | 0 tests/fixtures/{no-color => color}/simple.svg | 0 tests/fixtures/{no-color => color}/simple.toml | 0 tests/fixtures/{no-color => color}/strip_line.svg | 0 tests/fixtures/{no-color => color}/strip_line.toml | 0 tests/fixtures/{no-color => color}/strip_line_char.svg | 0 tests/fixtures/{no-color => color}/strip_line_char.toml | 0 tests/fixtures/{no-color => color}/strip_line_non_ws.svg | 0 tests/fixtures/{no-color => color}/strip_line_non_ws.toml | 0 32 files changed, 0 insertions(+), 0 deletions(-) rename tests/fixtures/{no-color => color}/ann_eof.svg (100%) rename tests/fixtures/{no-color => color}/ann_eof.toml (100%) rename tests/fixtures/{no-color => color}/ann_insertion.svg (100%) rename tests/fixtures/{no-color => color}/ann_insertion.toml (100%) rename tests/fixtures/{no-color => color}/ann_multiline.svg (100%) rename tests/fixtures/{no-color => color}/ann_multiline.toml (100%) rename tests/fixtures/{no-color => color}/ann_multiline2.svg (100%) rename tests/fixtures/{no-color => color}/ann_multiline2.toml (100%) rename tests/fixtures/{no-color => color}/ann_removed_nl.svg (100%) rename tests/fixtures/{no-color => color}/ann_removed_nl.toml (100%) rename tests/fixtures/{no-color => color}/ensure-emoji-highlight-width.svg (100%) rename tests/fixtures/{no-color => color}/ensure-emoji-highlight-width.toml (100%) rename tests/fixtures/{no-color => color}/fold_ann_multiline.svg (100%) rename tests/fixtures/{no-color => color}/fold_ann_multiline.toml (100%) rename tests/fixtures/{no-color => color}/fold_bad_origin_line.svg (100%) rename tests/fixtures/{no-color => color}/fold_bad_origin_line.toml (100%) rename tests/fixtures/{no-color => color}/fold_leading.svg (100%) rename tests/fixtures/{no-color => color}/fold_leading.toml (100%) rename tests/fixtures/{no-color => color}/fold_trailing.svg (100%) rename tests/fixtures/{no-color => color}/fold_trailing.toml (100%) rename tests/fixtures/{no-color => color}/issue_9.svg (100%) rename tests/fixtures/{no-color => color}/issue_9.toml (100%) rename tests/fixtures/{no-color => color}/multiple_annotations.svg (100%) rename tests/fixtures/{no-color => color}/multiple_annotations.toml (100%) rename tests/fixtures/{no-color => color}/simple.svg (100%) rename tests/fixtures/{no-color => color}/simple.toml (100%) rename tests/fixtures/{no-color => color}/strip_line.svg (100%) rename tests/fixtures/{no-color => color}/strip_line.toml (100%) rename tests/fixtures/{no-color => color}/strip_line_char.svg (100%) rename tests/fixtures/{no-color => color}/strip_line_char.toml (100%) rename tests/fixtures/{no-color => color}/strip_line_non_ws.svg (100%) rename tests/fixtures/{no-color => color}/strip_line_non_ws.toml (100%) diff --git a/tests/fixtures/no-color/ann_eof.svg b/tests/fixtures/color/ann_eof.svg similarity index 100% rename from tests/fixtures/no-color/ann_eof.svg rename to tests/fixtures/color/ann_eof.svg diff --git a/tests/fixtures/no-color/ann_eof.toml b/tests/fixtures/color/ann_eof.toml similarity index 100% rename from tests/fixtures/no-color/ann_eof.toml rename to tests/fixtures/color/ann_eof.toml diff --git a/tests/fixtures/no-color/ann_insertion.svg b/tests/fixtures/color/ann_insertion.svg similarity index 100% rename from tests/fixtures/no-color/ann_insertion.svg rename to tests/fixtures/color/ann_insertion.svg diff --git a/tests/fixtures/no-color/ann_insertion.toml b/tests/fixtures/color/ann_insertion.toml similarity index 100% rename from tests/fixtures/no-color/ann_insertion.toml rename to tests/fixtures/color/ann_insertion.toml diff --git a/tests/fixtures/no-color/ann_multiline.svg b/tests/fixtures/color/ann_multiline.svg similarity index 100% rename from tests/fixtures/no-color/ann_multiline.svg rename to tests/fixtures/color/ann_multiline.svg diff --git a/tests/fixtures/no-color/ann_multiline.toml b/tests/fixtures/color/ann_multiline.toml similarity index 100% rename from tests/fixtures/no-color/ann_multiline.toml rename to tests/fixtures/color/ann_multiline.toml diff --git a/tests/fixtures/no-color/ann_multiline2.svg b/tests/fixtures/color/ann_multiline2.svg similarity index 100% rename from tests/fixtures/no-color/ann_multiline2.svg rename to tests/fixtures/color/ann_multiline2.svg diff --git a/tests/fixtures/no-color/ann_multiline2.toml b/tests/fixtures/color/ann_multiline2.toml similarity index 100% rename from tests/fixtures/no-color/ann_multiline2.toml rename to tests/fixtures/color/ann_multiline2.toml diff --git a/tests/fixtures/no-color/ann_removed_nl.svg b/tests/fixtures/color/ann_removed_nl.svg similarity index 100% rename from tests/fixtures/no-color/ann_removed_nl.svg rename to tests/fixtures/color/ann_removed_nl.svg diff --git a/tests/fixtures/no-color/ann_removed_nl.toml b/tests/fixtures/color/ann_removed_nl.toml similarity index 100% rename from tests/fixtures/no-color/ann_removed_nl.toml rename to tests/fixtures/color/ann_removed_nl.toml diff --git a/tests/fixtures/no-color/ensure-emoji-highlight-width.svg b/tests/fixtures/color/ensure-emoji-highlight-width.svg similarity index 100% rename from tests/fixtures/no-color/ensure-emoji-highlight-width.svg rename to tests/fixtures/color/ensure-emoji-highlight-width.svg diff --git a/tests/fixtures/no-color/ensure-emoji-highlight-width.toml b/tests/fixtures/color/ensure-emoji-highlight-width.toml similarity index 100% rename from tests/fixtures/no-color/ensure-emoji-highlight-width.toml rename to tests/fixtures/color/ensure-emoji-highlight-width.toml diff --git a/tests/fixtures/no-color/fold_ann_multiline.svg b/tests/fixtures/color/fold_ann_multiline.svg similarity index 100% rename from tests/fixtures/no-color/fold_ann_multiline.svg rename to tests/fixtures/color/fold_ann_multiline.svg diff --git a/tests/fixtures/no-color/fold_ann_multiline.toml b/tests/fixtures/color/fold_ann_multiline.toml similarity index 100% rename from tests/fixtures/no-color/fold_ann_multiline.toml rename to tests/fixtures/color/fold_ann_multiline.toml diff --git a/tests/fixtures/no-color/fold_bad_origin_line.svg b/tests/fixtures/color/fold_bad_origin_line.svg similarity index 100% rename from tests/fixtures/no-color/fold_bad_origin_line.svg rename to tests/fixtures/color/fold_bad_origin_line.svg diff --git a/tests/fixtures/no-color/fold_bad_origin_line.toml b/tests/fixtures/color/fold_bad_origin_line.toml similarity index 100% rename from tests/fixtures/no-color/fold_bad_origin_line.toml rename to tests/fixtures/color/fold_bad_origin_line.toml diff --git a/tests/fixtures/no-color/fold_leading.svg b/tests/fixtures/color/fold_leading.svg similarity index 100% rename from tests/fixtures/no-color/fold_leading.svg rename to tests/fixtures/color/fold_leading.svg diff --git a/tests/fixtures/no-color/fold_leading.toml b/tests/fixtures/color/fold_leading.toml similarity index 100% rename from tests/fixtures/no-color/fold_leading.toml rename to tests/fixtures/color/fold_leading.toml diff --git a/tests/fixtures/no-color/fold_trailing.svg b/tests/fixtures/color/fold_trailing.svg similarity index 100% rename from tests/fixtures/no-color/fold_trailing.svg rename to tests/fixtures/color/fold_trailing.svg diff --git a/tests/fixtures/no-color/fold_trailing.toml b/tests/fixtures/color/fold_trailing.toml similarity index 100% rename from tests/fixtures/no-color/fold_trailing.toml rename to tests/fixtures/color/fold_trailing.toml diff --git a/tests/fixtures/no-color/issue_9.svg b/tests/fixtures/color/issue_9.svg similarity index 100% rename from tests/fixtures/no-color/issue_9.svg rename to tests/fixtures/color/issue_9.svg diff --git a/tests/fixtures/no-color/issue_9.toml b/tests/fixtures/color/issue_9.toml similarity index 100% rename from tests/fixtures/no-color/issue_9.toml rename to tests/fixtures/color/issue_9.toml diff --git a/tests/fixtures/no-color/multiple_annotations.svg b/tests/fixtures/color/multiple_annotations.svg similarity index 100% rename from tests/fixtures/no-color/multiple_annotations.svg rename to tests/fixtures/color/multiple_annotations.svg diff --git a/tests/fixtures/no-color/multiple_annotations.toml b/tests/fixtures/color/multiple_annotations.toml similarity index 100% rename from tests/fixtures/no-color/multiple_annotations.toml rename to tests/fixtures/color/multiple_annotations.toml diff --git a/tests/fixtures/no-color/simple.svg b/tests/fixtures/color/simple.svg similarity index 100% rename from tests/fixtures/no-color/simple.svg rename to tests/fixtures/color/simple.svg diff --git a/tests/fixtures/no-color/simple.toml b/tests/fixtures/color/simple.toml similarity index 100% rename from tests/fixtures/no-color/simple.toml rename to tests/fixtures/color/simple.toml diff --git a/tests/fixtures/no-color/strip_line.svg b/tests/fixtures/color/strip_line.svg similarity index 100% rename from tests/fixtures/no-color/strip_line.svg rename to tests/fixtures/color/strip_line.svg diff --git a/tests/fixtures/no-color/strip_line.toml b/tests/fixtures/color/strip_line.toml similarity index 100% rename from tests/fixtures/no-color/strip_line.toml rename to tests/fixtures/color/strip_line.toml diff --git a/tests/fixtures/no-color/strip_line_char.svg b/tests/fixtures/color/strip_line_char.svg similarity index 100% rename from tests/fixtures/no-color/strip_line_char.svg rename to tests/fixtures/color/strip_line_char.svg diff --git a/tests/fixtures/no-color/strip_line_char.toml b/tests/fixtures/color/strip_line_char.toml similarity index 100% rename from tests/fixtures/no-color/strip_line_char.toml rename to tests/fixtures/color/strip_line_char.toml diff --git a/tests/fixtures/no-color/strip_line_non_ws.svg b/tests/fixtures/color/strip_line_non_ws.svg similarity index 100% rename from tests/fixtures/no-color/strip_line_non_ws.svg rename to tests/fixtures/color/strip_line_non_ws.svg diff --git a/tests/fixtures/no-color/strip_line_non_ws.toml b/tests/fixtures/color/strip_line_non_ws.toml similarity index 100% rename from tests/fixtures/no-color/strip_line_non_ws.toml rename to tests/fixtures/color/strip_line_non_ws.toml From a059969c14e8c10fa1799a9f8e073699cd438ade Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Wed, 21 Aug 2024 15:02:49 -0600 Subject: [PATCH 097/293] test: Make all color tests have color --- tests/fixtures/color/ann_eof.svg | 15 +++++---- tests/fixtures/color/ann_eof.toml | 3 ++ tests/fixtures/color/ann_insertion.svg | 15 +++++---- tests/fixtures/color/ann_insertion.toml | 3 ++ tests/fixtures/color/ann_multiline.svg | 21 +++++++----- tests/fixtures/color/ann_multiline.toml | 3 ++ tests/fixtures/color/ann_multiline2.svg | 19 ++++++----- tests/fixtures/color/ann_multiline2.toml | 3 ++ tests/fixtures/color/ann_removed_nl.svg | 15 +++++---- tests/fixtures/color/ann_removed_nl.toml | 3 ++ .../color/ensure-emoji-highlight-width.svg | 15 +++++---- .../color/ensure-emoji-highlight-width.toml | 3 ++ tests/fixtures/color/fold_ann_multiline.svg | 28 +++++++++------- tests/fixtures/color/fold_ann_multiline.toml | 3 ++ tests/fixtures/color/fold_bad_origin_line.svg | 16 +++++---- .../fixtures/color/fold_bad_origin_line.toml | 3 ++ tests/fixtures/color/fold_leading.svg | 15 +++++---- tests/fixtures/color/fold_leading.toml | 3 ++ tests/fixtures/color/fold_trailing.svg | 15 +++++---- tests/fixtures/color/fold_trailing.toml | 3 ++ tests/fixtures/color/issue_9.svg | 28 +++++++++------- tests/fixtures/color/issue_9.toml | 3 ++ tests/fixtures/color/multiple_annotations.svg | 33 ++++++++++--------- .../fixtures/color/multiple_annotations.toml | 3 ++ tests/fixtures/color/simple.svg | 22 ++++++++----- tests/fixtures/color/simple.toml | 3 ++ tests/fixtures/color/strip_line.svg | 15 +++++---- tests/fixtures/color/strip_line.toml | 2 +- tests/fixtures/color/strip_line_char.svg | 15 +++++---- tests/fixtures/color/strip_line_char.toml | 2 +- tests/fixtures/color/strip_line_non_ws.svg | 19 ++++++----- tests/fixtures/color/strip_line_non_ws.toml | 1 + tests/fixtures/deserialize.rs | 11 ++++++- 33 files changed, 231 insertions(+), 130 deletions(-) diff --git a/tests/fixtures/color/ann_eof.svg b/tests/fixtures/color/ann_eof.svg index c8900d03..bb12aecf 100644 --- a/tests/fixtures/color/ann_eof.svg +++ b/tests/fixtures/color/ann_eof.svg @@ -2,10 +2,13 @@ + + + + + error[E0010]: allocations are not allowed in constants + + --> $DIR/E0010-teach.rs:5:23 + + | + + LL | const CON: Vec<i32> = vec![1, 2, 3]; //~ ERROR E0010 + + | ^^^^^^^^^^^^^ allocation not allowed in constants + + = note: The runtime heap is not yet available at compile-time, so no runtime heap allocations can be created. + + + + + + diff --git a/tests/examples.rs b/tests/examples.rs index b6576629..77087320 100644 --- a/tests/examples.rs +++ b/tests/examples.rs @@ -19,6 +19,13 @@ fn format() { assert_example(target, expected); } +#[test] +fn highlight_source() { + let target = "highlight_source"; + let expected = snapbox::file!["../examples/highlight_source.svg": TermSvg]; + assert_example(target, expected); +} + #[test] fn multislice() { let target = "multislice"; From 222c013d9cb828d1171b26811e4530dc8cb6e068 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Sun, 9 Mar 2025 05:03:55 -0600 Subject: [PATCH 166/293] feat: Add ability to highlight source code --- examples/highlight_source.rs | 1 + examples/highlight_source.svg | 2 +- src/renderer/mod.rs | 12 ++++++++++++ src/renderer/source_map.rs | 14 +++++++++++++- src/snippet.rs | 7 +++++++ 5 files changed, 34 insertions(+), 2 deletions(-) diff --git a/examples/highlight_source.rs b/examples/highlight_source.rs index d49ff765..2bb4ec24 100644 --- a/examples/highlight_source.rs +++ b/examples/highlight_source.rs @@ -22,6 +22,7 @@ fn main() {} AnnotationKind::Primary .span(72..85) .label("allocation not allowed in constants") + .highlight_source(true), ), ) .element( diff --git a/examples/highlight_source.svg b/examples/highlight_source.svg index b6f9e822..391a097d 100644 --- a/examples/highlight_source.svg +++ b/examples/highlight_source.svg @@ -25,7 +25,7 @@ | - LL | const CON: Vec<i32> = vec![1, 2, 3]; //~ ERROR E0010 + LL | const CON: Vec<i32> = vec![1, 2, 3]; //~ ERROR E0010 | ^^^^^^^^^^^^^ allocation not allowed in constants diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 85de0f5c..10f2b59a 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -1260,6 +1260,15 @@ impl Renderer { underline.style, ); } + _ if annotation.highlight_source => { + buffer.set_style_range( + line_offset, + (code_offset + annotation.start.display).saturating_sub(left), + (code_offset + annotation.end.display).saturating_sub(left), + underline.style, + annotation.is_primary(), + ); + } _ => {} } } @@ -2471,6 +2480,9 @@ pub(crate) struct LineAnnotation<'a> { /// Is this a single line, multiline or multiline span minimized down to a /// smaller span. pub annotation_type: LineAnnotationType, + + /// Whether the source code should be highlighted + pub highlight_source: bool, } impl LineAnnotation<'_> { diff --git a/src/renderer/source_map.rs b/src/renderer/source_map.rs index 416337c3..33fe1897 100644 --- a/src/renderer/source_map.rs +++ b/src/renderer/source_map.rs @@ -149,7 +149,13 @@ impl<'a> SourceMap<'a> { .collect::>(); let mut multiline_annotations = vec![]; - for Annotation { range, label, kind } in annotations { + for Annotation { + range, + label, + kind, + highlight_source, + } in annotations + { let (lo, mut hi) = self.span_to_locations(range.clone()); // Watch out for "empty spans". If we get a span like 6..6, we @@ -169,6 +175,7 @@ impl<'a> SourceMap<'a> { kind, label, annotation_type: LineAnnotationType::Singleline, + highlight_source, }; self.add_annotation_to_file(&mut annotated_line_infos, lo.line, line_ann); } else { @@ -179,6 +186,7 @@ impl<'a> SourceMap<'a> { kind, label, overlaps_exactly: false, + highlight_source, }); } } @@ -502,6 +510,7 @@ pub(crate) struct MultilineAnnotation<'a> { pub kind: AnnotationKind, pub label: Option<&'a str>, pub overlaps_exactly: bool, + pub highlight_source: bool, } impl<'a> MultilineAnnotation<'a> { @@ -526,6 +535,7 @@ impl<'a> MultilineAnnotation<'a> { kind: self.kind, label: None, annotation_type: LineAnnotationType::MultilineStart(self.depth), + highlight_source: self.highlight_source, } } @@ -541,6 +551,7 @@ impl<'a> MultilineAnnotation<'a> { kind: self.kind, label: self.label, annotation_type: LineAnnotationType::MultilineEnd(self.depth), + highlight_source: self.highlight_source, } } @@ -551,6 +562,7 @@ impl<'a> MultilineAnnotation<'a> { kind: self.kind, label: None, annotation_type: LineAnnotationType::MultilineLine(self.depth), + highlight_source: self.highlight_source, } } } diff --git a/src/snippet.rs b/src/snippet.rs index d371ab85..64002842 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -273,6 +273,7 @@ pub struct Annotation<'a> { pub(crate) range: Range, pub(crate) label: Option<&'a str>, pub(crate) kind: AnnotationKind, + pub(crate) highlight_source: bool, } impl<'a> Annotation<'a> { @@ -280,6 +281,11 @@ impl<'a> Annotation<'a> { self.label = Some(label); self } + + pub fn highlight_source(mut self, highlight_source: bool) -> Self { + self.highlight_source = highlight_source; + self + } } #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] @@ -296,6 +302,7 @@ impl AnnotationKind { range: span, label: None, kind: self, + highlight_source: false, } } From 481920d56fd1b573dfac210ab32bd255b8f2ad84 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Tue, 15 Apr 2025 22:11:46 -0600 Subject: [PATCH 167/293] test: Add a test for passing precolored text --- examples/highlight_title.rs | 68 ++++++++++++++++++++++++++++++++++++ examples/highlight_title.svg | 44 +++++++++++++++++++++++ tests/examples.rs | 7 ++++ 3 files changed, 119 insertions(+) create mode 100644 examples/highlight_title.rs create mode 100644 examples/highlight_title.svg diff --git a/examples/highlight_title.rs b/examples/highlight_title.rs new file mode 100644 index 00000000..bb09049c --- /dev/null +++ b/examples/highlight_title.rs @@ -0,0 +1,68 @@ +use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; +use anstyle::Effects; + +fn main() { + let source = r#"// Make sure "highlighted" code is colored purple + +//@ compile-flags: --error-format=human --color=always +//@ error-pattern:for<'a>  +//@ edition:2018 + +use core::pin::Pin; +use core::future::Future; +use core::any::Any; + +fn query(_: fn(Box<(dyn Any + Send + '_)>) -> Pin, String>> + Send + 'static +)>>) {} + +fn wrapped_fn<'a>(_: Box<(dyn Any + Send)>) -> Pin, String>> + Send + 'static +)>> { + Box::pin(async { Err("nope".into()) }) +} + +fn main() { + query(wrapped_fn); +} +"#; + + let magenta = annotate_snippets::renderer::AnsiColor::Magenta + .on_default() + .effects(Effects::BOLD); + let title = format!( + "expected fn pointer `{}for<'a>{} fn(Box<{}(dyn Any + Send + 'a){}>) -> Pin<_>` + found fn item `fn(Box<{}(dyn Any + Send + 'static){}>) -> Pin<_> {}{{wrapped_fn}}{}`", + magenta.render(), + magenta.render_reset(), + magenta.render(), + magenta.render_reset(), + magenta.render(), + magenta.render_reset(), + magenta.render(), + magenta.render_reset() + ); + + let message = Level::Error.message("mismatched types").id("E0308").group( + Group::new() + .element( + Snippet::source(source) + .fold(true) + .origin("$DIR/highlighting.rs") + .annotation( + AnnotationKind::Primary + .span(589..599) + .label("one type is more general than the other"), + ) + .annotation( + AnnotationKind::Context + .span(583..588) + .label("arguments to this function are incorrect"), + ), + ) + .element(Level::Note.title(&title)), + ); + + let renderer = Renderer::styled().anonymized_line_numbers(true); + anstream::println!("{}", renderer.render(message)); +} diff --git a/examples/highlight_title.svg b/examples/highlight_title.svg new file mode 100644 index 00000000..763d33b8 --- /dev/null +++ b/examples/highlight_title.svg @@ -0,0 +1,44 @@ + + + + + + + error[E0308]: mismatched types + + --> $DIR/highlighting.rs:22:11 + + | + + LL | query(wrapped_fn); + + | ----- ^^^^^^^^^^ one type is more general than the other + + | | + + | arguments to this function are incorrect + + = note: expected fn pointer `␛[1m␛[35mfor<'a>␛[0m fn(Box<␛[1m␛[35m(dyn Any + Send + 'a)␛[0m>) -> Pin<_>` + + found fn item `fn(Box<␛[1m␛[35m(dyn Any + Send + 'static)␛[0m>) -> Pin<_> ␛[1m␛[35m{wrapped_fn}␛[0m` + + + + + + diff --git a/tests/examples.rs b/tests/examples.rs index 77087320..a0504c11 100644 --- a/tests/examples.rs +++ b/tests/examples.rs @@ -26,6 +26,13 @@ fn highlight_source() { assert_example(target, expected); } +#[test] +fn highlight_title() { + let target = "highlight_title"; + let expected = snapbox::file!["../examples/highlight_title.svg": TermSvg]; + assert_example(target, expected); +} + #[test] fn multislice() { let target = "multislice"; From 19f692d1f9b6c3e089556af2cd29811dfe9795cb Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Wed, 16 Apr 2025 09:56:43 -0600 Subject: [PATCH 168/293] feat: Don't normailze title text --- examples/highlight_title.svg | 7 ++++--- src/lib.rs | 7 +++++++ src/renderer/mod.rs | 7 +++---- src/snippet.rs | 4 ++++ 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/examples/highlight_title.svg b/examples/highlight_title.svg index 763d33b8..ad358761 100644 --- a/examples/highlight_title.svg +++ b/examples/highlight_title.svg @@ -1,9 +1,10 @@ - + | arguments to this function are incorrect - = note: expected fn pointer `␛[1m␛[35mfor<'a>␛[0m fn(Box<␛[1m␛[35m(dyn Any + Send + 'a)␛[0m>) -> Pin<_>` + = note: expected fn pointer `for<'a> fn(Box<(dyn Any + Send + 'a)>) -> Pin<_>` - found fn item `fn(Box<␛[1m␛[35m(dyn Any + Send + 'static)␛[0m>) -> Pin<_> ␛[1m␛[35m{wrapped_fn}␛[0m` + found fn item `fn(Box<(dyn Any + Send + 'static)>) -> Pin<_> {wrapped_fn}` diff --git a/src/lib.rs b/src/lib.rs index 533e8f73..e6c49c62 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,6 +45,13 @@ pub mod renderer; mod snippet; +/// Normalize the string to avoid any unicode control characters. +/// This is important for untrusted input, as it can contain +/// invalid unicode sequences. +pub fn normalize_untrusted_str(s: &str) -> String { + renderer::normalize_whitespace(s) +} + #[doc(inline)] pub use renderer::Renderer; pub use snippet::ColumnSeparator; diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 10f2b59a..ab3db82e 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -573,8 +573,7 @@ impl Renderer { } else { ElementStyle::NoStyle }; - let text = &normalize_whitespace(title); - let lines = text.split('\n').collect::>(); + let lines = title.split('\n').collect::>(); if lines.len() > 1 { for (i, line) in lines.iter().enumerate() { if i != 0 { @@ -584,7 +583,7 @@ impl Renderer { buffer.append(line_number, line, style); } } else { - buffer.append(line_number, text, style); + buffer.append(line_number, title, style); } line_number } @@ -2590,7 +2589,7 @@ const OUTPUT_REPLACEMENTS: &[(char, &str)] = &[ ('\u{2069}', "�"), ]; -fn normalize_whitespace(s: &str) -> String { +pub(crate) fn normalize_whitespace(s: &str) -> String { // Scan the input string for a character in the ordered table above. // If it's present, replace it with its alternative string (it can be more than 1 char!). // Otherwise, retain the input char. diff --git a/src/snippet.rs b/src/snippet.rs index 64002842..f71c392a 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -177,6 +177,10 @@ impl Level { } } + /// Text passed to this function is allowed to be pre-styled, as such all + /// text is considered "trusted input" and has no normalizations applied to + /// it. [`normalize_untrusted_str`](crate::normalize_untrusted_str) can be + /// used to normalize untrusted text before it is passed to this function. pub fn title(self, title: &str) -> Title<'_> { Title { level: self, From b4373f3effd8a0899c496393f87eb6802d546f23 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Wed, 16 Apr 2025 10:02:22 -0600 Subject: [PATCH 169/293] docs: Add when text is normalized --- src/snippet.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/snippet.rs b/src/snippet.rs index f71c392a..e8fa18c4 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -166,6 +166,9 @@ pub enum Level { } impl Level { + /// Text passed to this function is considered "untrusted input", as such + /// all text is passed through a normalization function. Pre-styled text is + /// not allowed to be passed to this function. pub fn message(self, title: &str) -> Message<'_> { Message { id: None, @@ -222,6 +225,9 @@ pub struct Snippet<'a, T> { } impl<'a, T: Clone> Snippet<'a, T> { + /// Text passed to this function is considered "untrusted input", as such + /// all text is passed through a normalization function. Pre-styled text is + /// not allowed to be passed to this function. pub fn source(source: &'a str) -> Self { Self { origin: None, @@ -237,6 +243,9 @@ impl<'a, T: Clone> Snippet<'a, T> { self } + /// Text passed to this function is considered "untrusted input", as such + /// all text is passed through a normalization function. Pre-styled text is + /// not allowed to be passed to this function. pub fn origin(mut self, origin: &'a str) -> Self { self.origin = Some(origin); self @@ -281,6 +290,9 @@ pub struct Annotation<'a> { } impl<'a> Annotation<'a> { + /// Text passed to this function is considered "untrusted input", as such + /// all text is passed through a normalization function. Pre-styled text is + /// not allowed to be passed to this function. pub fn label(mut self, label: &'a str) -> Self { self.label = Some(label); self @@ -322,6 +334,9 @@ pub struct Patch<'a> { } impl<'a> Patch<'a> { + /// Text passed to this function is considered "untrusted input", as such + /// all text is passed through a normalization function. Pre-styled text is + /// not allowed to be passed to this function. pub fn new(range: Range, replacement: &'a str) -> Self { Self { range, replacement } } @@ -384,6 +399,9 @@ pub struct Origin<'a> { } impl<'a> Origin<'a> { + /// Text passed to this function is considered "untrusted input", as such + /// all text is passed through a normalization function. Pre-styled text is + /// not allowed to be passed to this function. pub fn new(origin: &'a str) -> Self { Self { origin, @@ -409,6 +427,9 @@ impl<'a> Origin<'a> { self } + /// Text passed to this function is considered "untrusted input", as such + /// all text is passed through a normalization function. Pre-styled text is + /// not allowed to be passed to this function. pub fn label(mut self, label: &'a str) -> Self { self.label = Some(label); self From 15fbf20cbc84c822378fa5b5cf8d33dd9aeb9e59 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Sat, 29 Mar 2025 22:31:44 -0600 Subject: [PATCH 170/293] test: Add tests margin cutting --- tests/formatter.rs | 273 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 273 insertions(+) diff --git a/tests/formatter.rs b/tests/formatter.rs index 6304cf41..df6f965b 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -2112,3 +2112,276 @@ LL │ ┃ )>>) {} .anonymized_line_numbers(true); assert_data_eq!(renderer.render(input_new), expected); } + +// This tests that an ellipsis is not inserted into Unicode text when a line +// wasn't actually trimmed. +// +// This is a regression test where `...` was inserted because the code wasn't +// properly accounting for the *rendered* length versus the length in bytes in +// all cases. +#[test] +fn unicode_cut_handling() { + let source = "version = \"0.1.0\"\n# Ensure that the spans from toml handle utf-8 correctly\nauthors = [\n { name = \"Z\u{351}\u{36b}\u{343}\u{36a}\u{302}\u{36b}\u{33d}\u{34f}\u{334}\u{319}\u{324}\u{31e}\u{349}\u{35a}\u{32f}\u{31e}\u{320}\u{34d}A\u{36b}\u{357}\u{334}\u{362}\u{335}\u{31c}\u{330}\u{354}L\u{368}\u{367}\u{369}\u{358}\u{320}G\u{311}\u{357}\u{30e}\u{305}\u{35b}\u{341}\u{334}\u{33b}\u{348}\u{34d}\u{354}\u{339}O\u{342}\u{30c}\u{30c}\u{358}\u{328}\u{335}\u{339}\u{33b}\u{31d}\u{333}\", email = 1 }\n]\n"; + let input = Level::Error.message("title").group( + Group::new().element( + Snippet::source(source) + .fold(false) + .annotation(AnnotationKind::Primary.span(85..228).label("annotation")), + ), + ); + let expected = str![[r#" +error: title + | +1 | version = "0.1.0" +2 | # Ensure that the spans from toml handle utf-8 correctly +3 | authors = [ + | ___________^ +4 | | { name = "Z͑ͫ̓ͪ̂ͫ̽͏̴̙̤̞͉͚̯...A̴̵̜̰͔ͫ͗͢L̠ͨͧͩ͘G̴̻͈͍͔̹̑͗̎̅͛́Ǫ̵̹̻̝̳͂̌̌͘", email = 1 } +5 | | ] + | |_^ annotation +"#]]; + let renderer = Renderer::plain(); + assert_data_eq!(renderer.render(input), expected); +} + +#[test] +fn unicode_cut_handling2() { + let source = "/*这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。*/?"; + let input = Level::Error + .message("expected item, found `?`") + .group( + Group::new().element( + Snippet::source(source) + .fold(false) + .annotation(AnnotationKind::Primary.span(499..500).label("expected item")) + ).element( + Level::Note.title("for a full list of items that can appear in modules, see ") + ) + ); + + let expected = str![[r#" +error: expected item, found `?` + | +1.|.... + |^ expected item + = note: for a full list of items that can appear in modules, see +"#]]; + + let renderer = Renderer::plain(); + assert_data_eq!(renderer.render(input), expected); +} + +#[test] +fn unicode_cut_handling3() { + let source = "/*这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。*/?"; + let input = Level::Error + .message("expected item, found `?`") + .group( + Group::new().element( + Snippet::source(source) + .fold(false) + .annotation(AnnotationKind::Primary.span(251..254).label("expected item")) + ).element( + Level::Note.title("for a full list of items that can appear in modules, see ") + ) + ); + + let expected = str![[r#" +error: expected item, found `?` + | +1 | ...的。这是宽的。*/? ... +^ | expected item + = note: for a full list of items that can appear in modules, see +"#]]; + + let renderer = Renderer::plain().term_width(43); + assert_data_eq!(renderer.render(input), expected); +} + +#[test] +fn unicode_cut_handling4() { + let source = "/*aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa*/?"; + let input = Level::Error + .message("expected item, found `?`") + .group( + Group::new().element( + Snippet::source(source) + .fold(false) + .annotation(AnnotationKind::Primary.span(334..335).label("expected item")) + ).element( + Level::Note.title("for a full list of items that can appear in modules, see ") + ) + ); + + let expected = str![[r#" +error: expected item, found `?` + | +1 | ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa*/? + | ^ expected item + = note: for a full list of items that can appear in modules, see +"#]]; + + let renderer = Renderer::plain(); + assert_data_eq!(renderer.render(input), expected); +} + +#[test] +fn diagnostic_width() { + let source = r##"// ignore-tidy-linelength + +fn main() { + let _: &str = "🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓ ☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♏♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♏♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4🦀🦀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♏♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4"; let _: () = 42; let _: &str = "🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓ ☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♏♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♏♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4🦀🦀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♏♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4"; +//~^ ERROR mismatched types +} +"##; + let input = Level::Error.message("mismatched types").id("E0308").group( + Group::new().element( + Snippet::source(source) + .origin("$DIR/non-whitespace-trimming-unicode.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(1207..1209) + .label("expected `()`, found integer"), + ) + .annotation( + AnnotationKind::Context + .span(1202..1204) + .label("expected due to this"), + ), + ), + ); + + let expected = str![[r#" +error[E0308]: mismatched types + --> $DIR/non-whitespace-trimming-unicode.rs:4:415 + | +LL | ...♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4"; let _: () = 42; let _: &str = "🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓ ☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂... + | -- ^^ expected `()`, found integer + | | + | expected due to this +"#]]; + + let renderer = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer.render(input), expected); +} + +#[test] +fn diagnostic_width2() { + let source = r##"//@ revisions: ascii unicode +//@[unicode] compile-flags: -Zunstable-options --error-format=human-unicode +// ignore-tidy-linelength + +fn main() { + let unicode_is_fun = "؁‱ஹ௸௵꧄.ဪ꧅⸻𒈙𒐫﷽𒌄𒈟𒍼𒁎𒀱𒌧𒅃 𒈓𒍙𒊎𒄡𒅌𒁏𒀰𒐪𒐩𒈙𒐫𪚥"; + let _ = "ༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇ཈ཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬ཭཮཯཰ཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!"; + //[ascii]~^ ERROR cannot add `&str` to `&str` +} +"##; + let input = Level::Error + .message("cannot add `&str` to `&str`") + .id("E0369") + .group( + Group::new() + .element( + Snippet::source(source) + .origin("$DIR/non-1-width-unicode-multiline-label.rs") + .fold(true) + .annotation(AnnotationKind::Context.span(970..984).label("&str")) + .annotation(AnnotationKind::Context.span(987..1001).label("&str")) + .annotation( + AnnotationKind::Primary + .span(985..986) + .label("`+` cannot be used to concatenate two `&str` strings"), + ), + ) + .element( + Level::Note + .title("string concatenation requires an owned `String` on the left"), + ), + ) + .group( + Group::new() + .element(Level::Help.title("create an owned `String` from a string reference")) + .element( + Snippet::source(source) + .origin("$DIR/non-1-width-unicode-multiline-label.rs") + .fold(true) + .patch(Patch::new(984..984, ".to_owned()")), + ), + ); + + let expected = str![[r#" +error[E0369]: cannot add `&str` to `&str` + ╭▸ $DIR/non-1-width-unicode-multiline-label.rs:7:260 + │ +LL │ …ཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋…࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!"; + │ ┬───────────── ┯ ────────────── &str + │ │ │ + │ │ `+` cannot be used to concatenate two `&str` strings + │ &str + │ + ╰ note: string concatenation requires an owned `String` on the left +help: create an owned `String` from a string reference + ╭╴ +LL │ let _ = "ༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇ཈ཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬ཭཮཯཰ཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun.to_owned() + " really fun!"; + ╰╴ +++++++++++ +"#]]; + + let renderer = Renderer::plain() + .anonymized_line_numbers(true) + .theme(OutputTheme::Unicode); + assert_data_eq!(renderer.render(input), expected); +} + +#[test] +fn macros_not_utf8() { + let source = r##"//@ error-pattern: did not contain valid UTF-8 +//@ reference: input.encoding.utf8 +//@ reference: input.encoding.invalid + +fn foo() { + include!("not-utf8.bin"); +} +"##; + let bin_source = "�|�\u{0002}!5�cc\u{0015}\u{0002}�Ӻi��WWj�ȥ�'�}�\u{0012}�J�ȉ��W�\u{001e}O�@����\u{001c}w�V���LO����\u{0014}[ \u{0003}_�'���SQ�~ذ��ų&��-\t��lN~��!@␌ _#���kQ��h�\u{001d}�:�\u{001c}\u{0007}�"; + let input = Level::Error + .message("couldn't read `$DIR/not-utf8.bin`: stream did not contain valid UTF-8") + .group( + Group::new().element( + Snippet::source(source) + .origin("$DIR/not-utf8.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(136..160)), + ), + ) + .group( + Group::new() + .element(Level::Note.title("byte `193` is not valid utf-8")) + .element( + Snippet::source(bin_source) + .origin("$DIR/not-utf8.bin") + .fold(true) + .annotation(AnnotationKind::Primary.span(0..0)), + ) + .element(Level::Note.title("this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)")), + ); + + let expected = str![[r#" +error: couldn't read `$DIR/not-utf8.bin`: stream did not contain valid UTF-8 + --> $DIR/not-utf8.rs:6:5 + | +LL | include!("not-utf8.bin"); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: byte `193` is not valid utf-8 + --> $DIR/not-utf8.bin:1:1 + | +LL | �|�␂!5�cc␕␂�Ӻi��WWj�ȥ�'�}�␒�J�ȉ��W�␞O�@����␜w�V���LO����␔[ ␃_�'���SQ�~ذ��ų&��- ��lN~��!@␌ _#���kQ��h�␝�:�... + | ^ + = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) +"#]]; + + let renderer = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer.render(input), expected); +} From 604b6f95a979ef1b2273d3e13d96907638f1f585 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Sat, 29 Mar 2025 22:31:44 -0600 Subject: [PATCH 171/293] fix: Handle margin cutting when encountering multibyte chars --- src/renderer/mod.rs | 72 +++++++++++++++++++++++++++++++++++---------- tests/formatter.rs | 30 +++++++++---------- 2 files changed, 71 insertions(+), 31 deletions(-) diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index ab3db82e..7d4fd0ff 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -956,12 +956,19 @@ impl Renderer { let line_offset = buffer.num_lines(); // Left trim - let left = margin.left(source_string.len()); + let left = margin.left(str_width(&source_string)); // FIXME: This looks fishy. See #132860. // Account for unicode characters of width !=0 that were removed. - let left = source_string.chars().take(left).map(char_width).sum(); + let mut taken = 0; + source_string.chars().for_each(|ch| { + let next = char_width(ch); + if taken + next <= left { + taken += next; + } + }); + let left = taken; self.draw_line( buffer, &source_string, @@ -2020,48 +2027,81 @@ impl Renderer { ) { // Tabs are assumed to have been replaced by spaces in calling code. debug_assert!(!source_string.contains('\t')); - let line_len = source_string.len(); + let line_len = str_width(source_string); // Create the source line we will highlight. let left = margin.left(line_len); let right = margin.right(line_len); // FIXME: The following code looks fishy. See #132860. // On long lines, we strip the source line, accounting for unicode. let mut taken = 0; + let mut skipped = 0; let code: String = source_string .chars() - .skip(left) + .skip_while(|ch| { + skipped += char_width(*ch); + skipped <= left + }) .take_while(|ch| { // Make sure that the trimming on the right will fall within the terminal width. - let next = char_width(*ch); - if taken + next > right - left { - return false; - } - taken += next; - true + taken += char_width(*ch); + taken <= (right - left) }) .collect(); buffer.puts(line_offset, code_offset, &code, ElementStyle::Quotation); let placeholder = self.margin(); - if margin.was_cut_left() { + let padding = str_width(placeholder); + let (width_taken, bytes_taken) = if margin.was_cut_left() { // We have stripped some code/whitespace from the beginning, make it clear. + let mut bytes_taken = 0; + let mut width_taken = 0; + for ch in code.chars() { + width_taken += char_width(ch); + bytes_taken += ch.len_utf8(); + + if width_taken >= padding { + break; + } + } buffer.puts( line_offset, code_offset, - placeholder, + &format!("{placeholder:>width_taken$}"), ElementStyle::LineNumber, ); - } + (width_taken, bytes_taken) + } else { + (0, 0) + }; + + buffer.puts( + line_offset, + code_offset + width_taken, + &code[bytes_taken..], + ElementStyle::Quotation, + ); + if margin.was_cut_right(line_len) { - let padding = str_width(placeholder); - // We have stripped some code after the rightmost span end, make it clear we did so. + // We have stripped some code/whitespace from the beginning, make it clear. + let mut char_taken = 0; + let mut width_taken_inner = 0; + for ch in code.chars().rev() { + width_taken_inner += char_width(ch); + char_taken += 1; + + if width_taken_inner >= padding { + break; + } + } + buffer.puts( line_offset, - code_offset + taken - padding, + code_offset + width_taken + code[bytes_taken..].chars().count() - char_taken, placeholder, ElementStyle::LineNumber, ); } + buffer.puts( line_offset, 0, diff --git a/tests/formatter.rs b/tests/formatter.rs index df6f965b..5deb21ab 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -2136,7 +2136,7 @@ error: title 2 | # Ensure that the spans from toml handle utf-8 correctly 3 | authors = [ | ___________^ -4 | | { name = "Z͑ͫ̓ͪ̂ͫ̽͏̴̙̤̞͉͚̯...A̴̵̜̰͔ͫ͗͢L̠ͨͧͩ͘G̴̻͈͍͔̹̑͗̎̅͛́Ǫ̵̹̻̝̳͂̌̌͘", email = 1 } +4 | | { name = "Z͑ͫ̓ͪ̂ͫ̽͏̴̙̤̞͉͚̯̞̠͍A̴̵̜̰͔ͫ͗͢L̠ͨͧͩ͘G̴̻͈͍͔̹̑͗̎̅͛́Ǫ̵̹̻̝̳͂̌̌͘", email = 1 } 5 | | ] | |_^ annotation "#]]; @@ -2162,8 +2162,8 @@ fn unicode_cut_handling2() { let expected = str![[r#" error: expected item, found `?` | -1.|.... - |^ expected item +1 | ...的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。*/? + | ^ expected item = note: for a full list of items that can appear in modules, see "#]]; @@ -2189,8 +2189,8 @@ fn unicode_cut_handling3() { let expected = str![[r#" error: expected item, found `?` | -1 | ...的。这是宽的。*/? ... -^ | expected item +1 | ...。这是宽的。这是宽的。这是宽的... + | ^^ expected item = note: for a full list of items that can appear in modules, see "#]]; @@ -2256,10 +2256,10 @@ fn main() { error[E0308]: mismatched types --> $DIR/non-whitespace-trimming-unicode.rs:4:415 | -LL | ...♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4"; let _: () = 42; let _: &str = "🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓ ☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂... - | -- ^^ expected `()`, found integer - | | - | expected due to this +LL | ...♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4"; let _: () = 42; let _: &str = "🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓ ☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷... + | -- ^^ expected `()`, found integer + | | + | expected due to this "#]]; let renderer = Renderer::plain().anonymized_line_numbers(true); @@ -2315,11 +2315,11 @@ fn main() { error[E0369]: cannot add `&str` to `&str` ╭▸ $DIR/non-1-width-unicode-multiline-label.rs:7:260 │ -LL │ …ཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋…࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!"; - │ ┬───────────── ┯ ────────────── &str - │ │ │ - │ │ `+` cannot be used to concatenate two `&str` strings - │ &str +LL │ …࿆࿇࿈࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!"; + │ ┬───────────── ┯ ────────────── &str + │ │ │ + │ │ `+` cannot be used to concatenate two `&str` strings + │ &str │ ╰ note: string concatenation requires an owned `String` on the left help: create an owned `String` from a string reference @@ -2377,7 +2377,7 @@ LL | include!("not-utf8.bin"); note: byte `193` is not valid utf-8 --> $DIR/not-utf8.bin:1:1 | -LL | �|�␂!5�cc␕␂�Ӻi��WWj�ȥ�'�}�␒�J�ȉ��W�␞O�@����␜w�V���LO����␔[ ␃_�'���SQ�~ذ��ų&��- ��lN~��!@␌ _#���kQ��h�␝�:�... +LL | �|�␂!5�cc␕␂�Ӻi��WWj�ȥ�'�}�␒�J�ȉ��W�␞O�@����␜w�V���LO����␔[ ␃_�'���SQ�~ذ��ų&��- ��lN~��!@␌ _#���kQ��h�␝�:�␜␇� | ^ = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) "#]]; From ab5ca1802efc7d34a861da156133ff0ba57f0878 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Tue, 15 Apr 2025 02:17:40 -0600 Subject: [PATCH 172/293] test: Add tests for custom Levels --- examples/custom_error.rs | 35 ++++++++++++++++++++ examples/custom_error.svg | 35 ++++++++++++++++++++ examples/custom_level.rs | 69 +++++++++++++++++++++++++++++++++++++++ examples/custom_level.svg | 61 ++++++++++++++++++++++++++++++++++ tests/examples.rs | 14 ++++++++ 5 files changed, 214 insertions(+) create mode 100644 examples/custom_error.rs create mode 100644 examples/custom_error.svg create mode 100644 examples/custom_level.rs create mode 100644 examples/custom_level.svg diff --git a/examples/custom_error.rs b/examples/custom_error.rs new file mode 100644 index 00000000..3ba234d3 --- /dev/null +++ b/examples/custom_error.rs @@ -0,0 +1,35 @@ +use annotate_snippets::renderer::OutputTheme; +use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; + +fn main() { + let source = r#"//@ compile-flags: -Ztreat-err-as-bug +//@ failure-status: 101 +//@ error-pattern: aborting due to `-Z treat-err-as-bug=1` +//@ error-pattern: [eval_static_initializer] evaluating initializer of static `C` +//@ normalize-stderr: "note: .*\n\n" -> "" +//@ normalize-stderr: "thread 'rustc' panicked.*:\n.*\n" -> "" +//@ rustc-env:RUST_BACKTRACE=0 + +#![crate_type = "rlib"] + +pub static C: u32 = 0 - 1; +//~^ ERROR could not evaluate static initializer +"#; + let message = Level::None + .message("error: internal compiler error[E0080]: could not evaluate static initializer") + .group( + Group::new().element( + Snippet::source(source) + .origin("$DIR/err.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(386..391) + .label("attempt to compute `0_u32 - 1_u32`, which would overflow"), + ), + ), + ); + + let renderer = Renderer::styled().theme(OutputTheme::Unicode); + anstream::println!("{}", renderer.render(message)); +} diff --git a/examples/custom_error.svg b/examples/custom_error.svg new file mode 100644 index 00000000..5cb0c720 --- /dev/null +++ b/examples/custom_error.svg @@ -0,0 +1,35 @@ + + + + + + + error: internal compiler error[E0080]: could not evaluate static initializer + + ╭▸ $DIR/err.rs:11:21 + + + + 11 pub static C: u32 = 0 - 1; + + ╰╴ ━━━━━ attempt to compute `0_u32 - 1_u32`, which would overflow + + + + + + diff --git a/examples/custom_level.rs b/examples/custom_level.rs new file mode 100644 index 00000000..c19cdc43 --- /dev/null +++ b/examples/custom_level.rs @@ -0,0 +1,69 @@ +use annotate_snippets::renderer::OutputTheme; +use annotate_snippets::{AnnotationKind, Group, Level, Patch, Renderer, Snippet}; + +fn main() { + let source = r#"// Regression test for issue #114529 +// Tests that we do not ICE during const eval for a +// break-with-value in contexts where it is illegal + +#[allow(while_true)] +fn main() { + [(); { + while true { + break 9; //~ ERROR `break` with value from a `while` loop + }; + 51 + }]; + + [(); { + while let Some(v) = Some(9) { + break v; //~ ERROR `break` with value from a `while` loop + }; + 51 + }]; + + while true { + break (|| { //~ ERROR `break` with value from a `while` loop + let local = 9; + }); + } +} +"#; + let message = Level::Error + .message("`break` with value from a `while` loop") + .id("E0571") + .group( + Group::new().element( + Snippet::source(source) + .line_start(1) + .origin("$DIR/issue-114529-illegal-break-with-value.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(483..581) + .label("can only break with a value inside `loop` or breakable block"), + ) + .annotation( + AnnotationKind::Context + .span(462..472) + .label("you can't `break` with a value in a `while` loop"), + ), + ), + ) + .group( + Group::new() + .element(Level::None.title( + "suggestion: use `break` on its own without a value inside this `while` loop", + )) + .element( + Snippet::source(source) + .line_start(1) + .origin("$DIR/issue-114529-illegal-break-with-value.rs") + .fold(true) + .patch(Patch::new(483..581, "break")), + ), + ); + + let renderer = Renderer::styled().theme(OutputTheme::Unicode); + anstream::println!("{}", renderer.render(message)); +} diff --git a/examples/custom_level.svg b/examples/custom_level.svg new file mode 100644 index 00000000..1f31e651 --- /dev/null +++ b/examples/custom_level.svg @@ -0,0 +1,61 @@ + + + + + + + error[E0571]: `break` with value from a `while` loop + + ╭▸ $DIR/issue-114529-illegal-break-with-value.rs:22:9 + + + + 21 while true { + + ────────── you can't `break` with a value in a `while` loop + + 22 break (|| { //~ ERROR `break` with value from a `while` loop + + 23 let local = 9; + + 24 }); + + ┗━━━━━━━━━━┛ can only break with a value inside `loop` or breakable block + + ╰╴ + + suggestion: use `break` on its own without a value inside this `while` loop + + ╭╴ + + 22 - break (|| { //~ ERROR `break` with value from a `while` loop + + 23 - let local = 9; + + 24 - }); + + 22 + break; + + ╰╴ + + + + + + diff --git a/tests/examples.rs b/tests/examples.rs index a0504c11..66dd94be 100644 --- a/tests/examples.rs +++ b/tests/examples.rs @@ -1,3 +1,17 @@ +#[test] +fn custom_error() { + let target = "custom_error"; + let expected = snapbox::file!["../examples/custom_error.svg": TermSvg]; + assert_example(target, expected); +} + +#[test] +fn custom_level() { + let target = "custom_level"; + let expected = snapbox::file!["../examples/custom_level.svg": TermSvg]; + assert_example(target, expected); +} + #[test] fn expected_type() { let target = "expected_type"; From 353a040447d6284df6711c7b9cb8ed86302971d8 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Tue, 1 Apr 2025 18:27:45 -0600 Subject: [PATCH 173/293] feat: Add custom Levels --- benches/bench.rs | 6 +- examples/custom_error.rs | 8 +- examples/custom_error.svg | 5 +- examples/custom_level.rs | 12 ++- examples/custom_level.svg | 3 +- examples/expected_type.rs | 4 +- examples/footer.rs | 6 +- examples/format.rs | 4 +- examples/highlight_source.rs | 6 +- examples/highlight_title.rs | 6 +- examples/multislice.rs | 4 +- src/level.rs | 128 +++++++++++++++++++++++ src/lib.rs | 1 + src/renderer/mod.rs | 36 +++---- src/renderer/styled_buffer.rs | 6 +- src/snippet.rs | 65 +----------- tests/fixtures/deserialize.rs | 35 +++++-- tests/formatter.rs | 192 +++++++++++++++++----------------- tests/rustc_tests.rs | 88 ++++++++-------- 19 files changed, 352 insertions(+), 263 deletions(-) create mode 100644 src/level.rs diff --git a/benches/bench.rs b/benches/bench.rs index 01364af7..d50cf435 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -1,4 +1,4 @@ -use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; +use annotate_snippets::{level::Level, AnnotationKind, Group, Renderer, Snippet}; #[divan::bench] fn simple() -> String { @@ -24,7 +24,7 @@ fn simple() -> String { _ => continue, } }"#; - let message = Level::Error.message("mismatched types").id("E0308").group( + let message = Level::ERROR.message("mismatched types").id("E0308").group( Group::new().element( Snippet::source(source) .line_start(51) @@ -69,7 +69,7 @@ fn fold(bencher: divan::Bencher<'_, '_>, context: usize) { (input, span) }) .bench_values(|(input, span)| { - let message = Level::Error.message("mismatched types").id("E0308").group( + let message = Level::ERROR.message("mismatched types").id("E0308").group( Group::new().element( Snippet::source(&input) .fold(true) diff --git a/examples/custom_error.rs b/examples/custom_error.rs index 3ba234d3..4050d400 100644 --- a/examples/custom_error.rs +++ b/examples/custom_error.rs @@ -1,5 +1,5 @@ use annotate_snippets::renderer::OutputTheme; -use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; +use annotate_snippets::{level::Level, AnnotationKind, Group, Renderer, Snippet}; fn main() { let source = r#"//@ compile-flags: -Ztreat-err-as-bug @@ -15,8 +15,10 @@ fn main() { pub static C: u32 = 0 - 1; //~^ ERROR could not evaluate static initializer "#; - let message = Level::None - .message("error: internal compiler error[E0080]: could not evaluate static initializer") + let message = Level::ERROR + .text(Some("error: internal compiler error")) + .message("could not evaluate static initializer") + .id("E0080") .group( Group::new().element( Snippet::source(source) diff --git a/examples/custom_error.svg b/examples/custom_error.svg index 5cb0c720..af3611a9 100644 --- a/examples/custom_error.svg +++ b/examples/custom_error.svg @@ -3,6 +3,7 @@ .fg { fill: #AAAAAA } .bg { background: #000000 } .fg-bright-blue { fill: #5555FF } + .fg-bright-red { fill: #FF5555 } .container { padding: 0 10px; line-height: 18px; @@ -18,7 +19,7 @@ - error: internal compiler error[E0080]: could not evaluate static initializer + error: internal compiler error[E0080]: could not evaluate static initializer ╭▸ $DIR/err.rs:11:21 @@ -26,7 +27,7 @@ 11 pub static C: u32 = 0 - 1; - ╰╴ ━━━━━ attempt to compute `0_u32 - 1_u32`, which would overflow + ╰╴ ━━━━━ attempt to compute `0_u32 - 1_u32`, which would overflow diff --git a/examples/custom_level.rs b/examples/custom_level.rs index c19cdc43..804f7741 100644 --- a/examples/custom_level.rs +++ b/examples/custom_level.rs @@ -1,5 +1,5 @@ use annotate_snippets::renderer::OutputTheme; -use annotate_snippets::{AnnotationKind, Group, Level, Patch, Renderer, Snippet}; +use annotate_snippets::{level::Level, AnnotationKind, Group, Patch, Renderer, Snippet}; fn main() { let source = r#"// Regression test for issue #114529 @@ -29,7 +29,7 @@ fn main() { } } "#; - let message = Level::Error + let message = Level::ERROR .message("`break` with value from a `while` loop") .id("E0571") .group( @@ -52,9 +52,11 @@ fn main() { ) .group( Group::new() - .element(Level::None.title( - "suggestion: use `break` on its own without a value inside this `while` loop", - )) + .element( + Level::HELP + .text(Some("suggestion")) + .title("use `break` on its own without a value inside this `while` loop"), + ) .element( Snippet::source(source) .line_start(1) diff --git a/examples/custom_level.svg b/examples/custom_level.svg index 1f31e651..eebff280 100644 --- a/examples/custom_level.svg +++ b/examples/custom_level.svg @@ -3,6 +3,7 @@ .fg { fill: #AAAAAA } .bg { background: #000000 } .fg-bright-blue { fill: #5555FF } + .fg-bright-cyan { fill: #55FFFF } .fg-bright-green { fill: #55FF55 } .fg-bright-red { fill: #FF5555 } .container { @@ -40,7 +41,7 @@ ╰╴ - suggestion: use `break` on its own without a value inside this `while` loop + suggestion: use `break` on its own without a value inside this `while` loop ╭╴ diff --git a/examples/expected_type.rs b/examples/expected_type.rs index f61999da..9a51dce5 100644 --- a/examples/expected_type.rs +++ b/examples/expected_type.rs @@ -1,4 +1,4 @@ -use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; +use annotate_snippets::{level::Level, AnnotationKind, Group, Renderer, Snippet}; fn main() { let source = r#" annotations: vec![SourceAnnotation { @@ -6,7 +6,7 @@ fn main() { , range: <22, 25>,"#; let message = - Level::Error.message("expected type, found `22`").group( + Level::ERROR.message("expected type, found `22`").group( Group::new().element( Snippet::source(source) .line_start(26) diff --git a/examples/footer.rs b/examples/footer.rs index 29b27c14..d61e84b4 100644 --- a/examples/footer.rs +++ b/examples/footer.rs @@ -1,7 +1,7 @@ -use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; +use annotate_snippets::{level::Level, AnnotationKind, Group, Renderer, Snippet}; fn main() { - let message = Level::Error + let message = Level::ERROR .message("mismatched types") .id("E0308") .group( @@ -14,7 +14,7 @@ fn main() { )), ), ) - .group(Group::new().element(Level::Note.title( + .group(Group::new().element(Level::NOTE.title( "expected type: `snippet::Annotation`\n found type: `__&__snippet::Annotation`", ))); diff --git a/examples/format.rs b/examples/format.rs index df6f9274..5324413c 100644 --- a/examples/format.rs +++ b/examples/format.rs @@ -1,4 +1,4 @@ -use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; +use annotate_snippets::{level::Level, AnnotationKind, Group, Renderer, Snippet}; fn main() { let source = r#") -> Option { @@ -23,7 +23,7 @@ fn main() { _ => continue, } }"#; - let message = Level::Error.message("mismatched types").id("E0308").group( + let message = Level::ERROR.message("mismatched types").id("E0308").group( Group::new().element( Snippet::source(source) .line_start(51) diff --git a/examples/highlight_source.rs b/examples/highlight_source.rs index 2bb4ec24..9962542d 100644 --- a/examples/highlight_source.rs +++ b/examples/highlight_source.rs @@ -1,4 +1,4 @@ -use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; +use annotate_snippets::{level::Level, AnnotationKind, Group, Renderer, Snippet}; fn main() { let source = r#"//@ compile-flags: -Z teach @@ -9,7 +9,7 @@ const CON: Vec = vec![1, 2, 3]; //~ ERROR E0010 //~| ERROR cannot call non-const method fn main() {} "#; - let message = Level::Error + let message = Level::ERROR .message("allocations are not allowed in constants") .id("E0010") .group( @@ -26,7 +26,7 @@ fn main() {} ), ) .element( - Level::Note.title("The runtime heap is not yet available at compile-time, so no runtime heap allocations can be created."), + Level::NOTE.title("The runtime heap is not yet available at compile-time, so no runtime heap allocations can be created."), ), ); diff --git a/examples/highlight_title.rs b/examples/highlight_title.rs index bb09049c..e2da54ff 100644 --- a/examples/highlight_title.rs +++ b/examples/highlight_title.rs @@ -1,4 +1,4 @@ -use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; +use annotate_snippets::{level::Level, AnnotationKind, Group, Renderer, Snippet}; use anstyle::Effects; fn main() { @@ -43,7 +43,7 @@ fn main() { magenta.render_reset() ); - let message = Level::Error.message("mismatched types").id("E0308").group( + let message = Level::ERROR.message("mismatched types").id("E0308").group( Group::new() .element( Snippet::source(source) @@ -60,7 +60,7 @@ fn main() { .label("arguments to this function are incorrect"), ), ) - .element(Level::Note.title(&title)), + .element(Level::NOTE.title(&title)), ); let renderer = Renderer::styled().anonymized_line_numbers(true); diff --git a/examples/multislice.rs b/examples/multislice.rs index d1ad72ac..ddd938e4 100644 --- a/examples/multislice.rs +++ b/examples/multislice.rs @@ -1,7 +1,7 @@ -use annotate_snippets::{Annotation, Group, Level, Renderer, Snippet}; +use annotate_snippets::{level::Level, Annotation, Group, Renderer, Snippet}; fn main() { - let message = Level::Error.message("mismatched types").group( + let message = Level::ERROR.message("mismatched types").group( Group::new() .element( Snippet::>::source("Foo") diff --git a/src/level.rs b/src/level.rs new file mode 100644 index 00000000..7f920249 --- /dev/null +++ b/src/level.rs @@ -0,0 +1,128 @@ +use crate::renderer::stylesheet::Stylesheet; +use crate::snippet::{ERROR_TXT, HELP_TXT, INFO_TXT, NOTE_TXT, WARNING_TXT}; +use crate::{Element, Group, Message, Title}; +use anstyle::Style; + +pub const ERROR: Level<'_> = Level { + name: None, + level: LevelInner::Error, +}; + +pub const WARNING: Level<'_> = Level { + name: None, + level: LevelInner::Warning, +}; + +pub const INFO: Level<'_> = Level { + name: None, + level: LevelInner::Info, +}; + +pub const NOTE: Level<'_> = Level { + name: None, + level: LevelInner::Note, +}; + +pub const HELP: Level<'_> = Level { + name: None, + level: LevelInner::Help, +}; + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Level<'a> { + pub(crate) name: Option>, + pub(crate) level: LevelInner, +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum Level2<'a> { + Builtin(LevelInner), + Custom { + name: Option<&'a str>, + level: LevelInner, + }, + None, +} + +impl<'a> Level<'a> { + pub const ERROR: Level<'a> = ERROR; + pub const WARNING: Level<'a> = WARNING; + pub const INFO: Level<'a> = INFO; + pub const NOTE: Level<'a> = NOTE; + pub const HELP: Level<'a> = HELP; + + /// Text passed to this function is considered "untrusted input", as such + /// all text is passed through a normalization function. Pre-styled text is + /// not allowed to be passed to this function. + pub fn text(self, text: Option<&'a str>) -> Level<'a> { + Level { + name: Some(text), + level: self.level, + } + } +} + +impl<'a> Level<'a> { + /// Text passed to this function is considered "untrusted input", as such + /// all text is passed through a normalization function. Pre-styled text is + /// not allowed to be passed to this function. + pub fn message(self, title: &'a str) -> Message<'a> { + Message { + id: None, + groups: vec![Group::new().element(Element::Title(Title { + level: self, + title, + primary: true, + }))], + } + } + + /// Text passed to this function is allowed to be pre-styled, as such all + /// text is considered "trusted input" and has no normalizations applied to + /// it. [`normalize_untrusted_str`](crate::normalize_untrusted_str) can be + /// used to normalize untrusted text before it is passed to this function. + pub fn title(self, title: &'a str) -> Title<'a> { + Title { + level: self, + title, + primary: false, + } + } + + pub(crate) fn as_str(&self) -> &'a str { + match (self.name, self.level) { + (Some(Some(name)), _) => name, + (Some(None), _) => "", + (None, LevelInner::Error) => ERROR_TXT, + (None, LevelInner::Warning) => WARNING_TXT, + (None, LevelInner::Info) => INFO_TXT, + (None, LevelInner::Note) => NOTE_TXT, + (None, LevelInner::Help) => HELP_TXT, + } + } + + pub(crate) fn style(&self, stylesheet: &Stylesheet) -> Style { + self.level.style(stylesheet) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum LevelInner { + Error, + Warning, + Info, + Note, + Help, +} + +impl LevelInner { + pub(crate) fn style(self, stylesheet: &Stylesheet) -> Style { + match self { + LevelInner::Error => stylesheet.error, + LevelInner::Warning => stylesheet.warning, + LevelInner::Info => stylesheet.info, + LevelInner::Note => stylesheet.note, + LevelInner::Help => stylesheet.help, + } + } +} diff --git a/src/lib.rs b/src/lib.rs index e6c49c62..eee2b6f3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,6 +42,7 @@ #![warn(clippy::print_stdout)] #![warn(missing_debug_implementations)] +pub mod level; pub mod renderer; mod snippet; diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 7d4fd0ff..8efcff84 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -5,6 +5,7 @@ //! # Example //! ``` //! use annotate_snippets::*; +//! use annotate_snippets::level::Level; //! //! let source = r#" //! use baz::zed::bar; @@ -17,7 +18,7 @@ //! bar(); //! } //! "#; -//! Level::Error +//! Level::ERROR //! .message("unresolved import `baz::zed`") //! .id("E0432") //! .group( @@ -40,13 +41,12 @@ pub(crate) mod source_map; mod styled_buffer; pub(crate) mod stylesheet; +use crate::level::{Level, LevelInner}; use crate::renderer::source_map::{ AnnotatedLineInfo, LineInfo, Loc, SourceMap, SubstitutionHighlight, }; use crate::renderer::styled_buffer::StyledBuffer; -use crate::{ - Annotation, AnnotationKind, Element, Group, Level, Message, Origin, Patch, Snippet, Title, -}; +use crate::{Annotation, AnnotationKind, Element, Group, Message, Origin, Patch, Snippet, Title}; pub use anstyle::*; use margin::Margin; use std::borrow::Cow; @@ -207,7 +207,7 @@ impl Renderer { }; let title = message.groups.remove(0).elements.remove(0); let level = if let Element::Title(title) = &title { - title.level + title.level.clone() } else { panic!("Expected a title as the first element of the message") }; @@ -345,7 +345,7 @@ impl Renderer { ); if g == 0 && group_len > 1 { - if matches!(peek, Some(Element::Title(level)) if level.level != Level::None) + if matches!(peek, Some(Element::Title(level)) if level.level.name != Some(None)) { self.draw_col_separator_no_space( buffer, @@ -394,7 +394,7 @@ impl Renderer { if g == 0 && (matches!(section, Element::Origin(_)) || (matches!(section, Element::Title(_)) && i == 0) - || matches!(section, Element::Title(level) if level.level == Level::None)) + || matches!(section, Element::Title(level) if level.level.name == Some(None))) { if peek.is_none() && group_len > 1 { self.draw_col_separator_end( @@ -402,7 +402,7 @@ impl Renderer { buffer.num_lines(), max_line_num_len + 1, ); - } else if matches!(peek, Some(Element::Title(level)) if level.level != Level::None) + } else if matches!(peek, Some(Element::Title(level)) if level.level.name != Some(None)) { self.draw_col_separator_no_space( buffer, @@ -445,7 +445,7 @@ impl Renderer { buffer.prepend(line_offset, " ", ElementStyle::NoStyle); } - if title.level != Level::None { + if title.level.name != Some(None) { self.draw_note_separator(buffer, line_offset, max_line_num_len + 1, is_cont); buffer.append( line_offset, @@ -476,18 +476,18 @@ impl Renderer { } else { let mut label_width = 0; - if title.level != Level::None { + if title.level.name != Some(None) { buffer.append( line_offset, title.level.as_str(), - ElementStyle::Level(title.level), + ElementStyle::Level(title.level.level), ); } label_width += title.level.as_str().len(); if let Some(id) = id { - buffer.append(line_offset, "[", ElementStyle::Level(title.level)); - buffer.append(line_offset, id, ElementStyle::Level(title.level)); - buffer.append(line_offset, "]", ElementStyle::Level(title.level)); + buffer.append(line_offset, "[", ElementStyle::Level(title.level.level)); + buffer.append(line_offset, id, ElementStyle::Level(title.level.level)); + buffer.append(line_offset, "]", ElementStyle::Level(title.level.level)); label_width += 2 + id.len(); } let header_style = if is_secondary { @@ -495,7 +495,7 @@ impl Renderer { } else { ElementStyle::MainHeaderMsg }; - if title.level != Level::None { + if title.level.name != Some(None) { buffer.append(line_offset, ": ", header_style); label_width += 2; } @@ -647,7 +647,7 @@ impl Renderer { buffer_msg_line_offset + 1, max_line_num_len + 1, ); - let title = Level::Note.title(label); + let title = Level::NOTE.title(label); self.render_title(buffer, &title, None, max_line_num_len, true, None, false); } } @@ -2654,13 +2654,13 @@ pub(crate) enum ElementStyle { LabelPrimary, LabelSecondary, NoStyle, - Level(Level), + Level(LevelInner), Addition, Removal, } impl ElementStyle { - fn color_spec(&self, level: Level, stylesheet: &Stylesheet) -> Style { + fn color_spec(&self, level: &Level<'_>, stylesheet: &Stylesheet) -> Style { match self { ElementStyle::Addition => stylesheet.addition, ElementStyle::Removal => stylesheet.removal, diff --git a/src/renderer/styled_buffer.rs b/src/renderer/styled_buffer.rs index 8a4cc672..7114683b 100644 --- a/src/renderer/styled_buffer.rs +++ b/src/renderer/styled_buffer.rs @@ -2,9 +2,9 @@ //! //! [styled_buffer]: https://github.com/rust-lang/rust/blob/894f7a4ba6554d3797404bbf550d9919df060b97/compiler/rustc_errors/src/styled_buffer.rs +use crate::level::Level; use crate::renderer::stylesheet::Stylesheet; use crate::renderer::ElementStyle; -use crate::Level; use std::fmt; use std::fmt::Write; @@ -41,14 +41,14 @@ impl StyledBuffer { pub(crate) fn render( &self, - level: Level, + level: Level<'_>, stylesheet: &Stylesheet, ) -> Result { let mut str = String::new(); for (i, line) in self.lines.iter().enumerate() { let mut current_style = stylesheet.none; for StyledChar { ch, style } in line { - let ch_style = style.color_spec(level, stylesheet); + let ch_style = style.color_spec(&level, stylesheet); if ch_style != current_style { if !line.is_empty() { write!(str, "{}", current_style.render_reset())?; diff --git a/src/snippet.rs b/src/snippet.rs index e8fa18c4..fe1239d4 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -1,8 +1,7 @@ //! Structures used as an input for the library. +use crate::level::Level; use crate::renderer::source_map::SourceMap; -use crate::renderer::stylesheet::Stylesheet; -use anstyle::Style; use std::ops::Range; pub(crate) const ERROR_TXT: &str = "error"; @@ -143,7 +142,7 @@ pub struct ColumnSeparator; #[derive(Debug)] pub struct Title<'a> { - pub(crate) level: Level, + pub(crate) level: Level<'a>, pub(crate) title: &'a str, pub(crate) primary: bool, } @@ -155,66 +154,6 @@ impl Title<'_> { } } -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub enum Level { - Error, - Warning, - Info, - Note, - Help, - None, -} - -impl Level { - /// Text passed to this function is considered "untrusted input", as such - /// all text is passed through a normalization function. Pre-styled text is - /// not allowed to be passed to this function. - pub fn message(self, title: &str) -> Message<'_> { - Message { - id: None, - groups: vec![Group::new().element(Element::Title(Title { - level: self, - title, - primary: true, - }))], - } - } - - /// Text passed to this function is allowed to be pre-styled, as such all - /// text is considered "trusted input" and has no normalizations applied to - /// it. [`normalize_untrusted_str`](crate::normalize_untrusted_str) can be - /// used to normalize untrusted text before it is passed to this function. - pub fn title(self, title: &str) -> Title<'_> { - Title { - level: self, - title, - primary: false, - } - } - - pub(crate) fn as_str(self) -> &'static str { - match self { - Level::Error => ERROR_TXT, - Level::Warning => WARNING_TXT, - Level::Info => INFO_TXT, - Level::Note => NOTE_TXT, - Level::Help => HELP_TXT, - Level::None => "", - } - } - - pub(crate) fn style(&self, stylesheet: &Stylesheet) -> Style { - match self { - Level::Error => stylesheet.error, - Level::Warning => stylesheet.warning, - Level::Info => stylesheet.info, - Level::Note => stylesheet.note, - Level::Help => stylesheet.help, - Level::None => stylesheet.none, - } - } -} - #[derive(Debug)] pub struct Snippet<'a, T> { pub(crate) origin: Option<&'a str>, diff --git a/tests/fixtures/deserialize.rs b/tests/fixtures/deserialize.rs index 065c395e..8f45b363 100644 --- a/tests/fixtures/deserialize.rs +++ b/tests/fixtures/deserialize.rs @@ -3,7 +3,7 @@ use std::ops::Range; use annotate_snippets::renderer::DEFAULT_TERM_WIDTH; use annotate_snippets::{ - Annotation, AnnotationKind, Element, Group, Level, Message, Patch, Renderer, Snippet, + level::Level, Annotation, AnnotationKind, Element, Group, Message, Patch, Renderer, Snippet, }; #[derive(Deserialize)] @@ -15,8 +15,7 @@ pub(crate) struct Fixture { #[derive(Deserialize)] pub struct MessageDef { - #[serde(with = "LevelDef")] - pub level: Level, + pub level: LevelDef, pub title: String, #[serde(default)] pub id: Option, @@ -32,13 +31,15 @@ impl<'a> From<&'a MessageDef> for Message<'a> { id, sections, } = val; - let mut message = level.message(title); + let mut message = Level::from(level).message(title); if let Some(id) = id { message = message.id(id); } message = message.group(Group::new().elements(sections.iter().map(|s| match s { - ElementDef::Title(title) => Element::Title(title.level.title(&title.title)), + ElementDef::Title(title) => { + Element::Title(Level::from(&title.level).title(&title.title)) + } ElementDef::Cause(cause) => Element::Cause(Snippet::from(cause)), ElementDef::Suggestion(suggestion) => Element::Suggestion(Snippet::from(suggestion)), }))); @@ -57,7 +58,9 @@ pub enum ElementDef { impl<'a> From<&'a ElementDef> for Element<'a> { fn from(val: &'a ElementDef) -> Self { match val { - ElementDef::Title(title) => Element::Title(title.level.title(&title.title)), + ElementDef::Title(title) => { + Element::Title(Level::from(&title.level).title(&title.title)) + } ElementDef::Cause(cause) => Element::Cause(Snippet::from(cause)), ElementDef::Suggestion(suggestion) => Element::Suggestion(Snippet::from(suggestion)), } @@ -67,8 +70,7 @@ impl<'a> From<&'a ElementDef> for Element<'a> { #[derive(Deserialize)] pub struct TitleDef { pub title: String, - #[serde(with = "LevelDef")] - pub level: Level, + pub level: LevelDef, } #[derive(Deserialize)] @@ -164,9 +166,8 @@ impl<'a> From<&'a PatchDef> for Patch<'a> { } #[allow(dead_code)] -#[derive(Deserialize)] -#[serde(remote = "Level")] -enum LevelDef { +#[derive(Clone, Copy, Deserialize)] +pub enum LevelDef { Error, Warning, Info, @@ -174,6 +175,18 @@ enum LevelDef { Help, } +impl<'a> From<&'a LevelDef> for Level<'a> { + fn from(val: &'a LevelDef) -> Self { + match val { + LevelDef::Error => Level::ERROR, + LevelDef::Warning => Level::WARNING, + LevelDef::Info => Level::INFO, + LevelDef::Note => Level::NOTE, + LevelDef::Help => Level::HELP, + } + } +} + #[derive(Default, Deserialize)] pub struct RendererDef { #[serde(default)] diff --git a/tests/formatter.rs b/tests/formatter.rs index 5deb21ab..3f0e7cd4 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -1,11 +1,13 @@ -use annotate_snippets::{Annotation, AnnotationKind, Group, Level, Patch, Renderer, Snippet}; +use annotate_snippets::{ + level::Level, Annotation, AnnotationKind, Group, Patch, Renderer, Snippet, +}; use annotate_snippets::renderer::OutputTheme; use snapbox::{assert_data_eq, str}; #[test] fn test_i_29() { - let snippets = Level::Error.message("oops").group( + let snippets = Level::ERROR.message("oops").group( Group::new().element( Snippet::source("First line\r\nSecond oops line") .origin("") @@ -27,7 +29,7 @@ error: oops #[test] fn test_point_to_double_width_characters() { - let snippets = Level::Error.message("").group( + let snippets = Level::ERROR.message("").group( Group::new().element( Snippet::source("こんにちは、世界") .origin("") @@ -49,7 +51,7 @@ error: #[test] fn test_point_to_double_width_characters_across_lines() { - let snippets = Level::Error.message("").group( + let snippets = Level::ERROR.message("").group( Group::new().element( Snippet::source("おはよう\nございます") .origin("") @@ -73,7 +75,7 @@ error: #[test] fn test_point_to_double_width_characters_multiple() { - let snippets = Level::Error.message("").group( + let snippets = Level::ERROR.message("").group( Group::new().element( Snippet::source("お寿司\n食べたい🍣") .origin("") @@ -98,7 +100,7 @@ error: #[test] fn test_point_to_double_width_characters_mixed() { - let snippets = Level::Error.message("").group( + let snippets = Level::ERROR.message("").group( Group::new().element( Snippet::source("こんにちは、新しいWorld!") .origin("") @@ -120,7 +122,7 @@ error: #[test] fn test_format_title() { - let input = Level::Error.message("This is a title").id("E0001"); + let input = Level::ERROR.message("This is a title").id("E0001"); let expected = str![r#"error[E0001]: This is a title"#]; let renderer = Renderer::plain(); @@ -130,7 +132,7 @@ fn test_format_title() { #[test] fn test_format_snippet_only() { let source = "This is line 1\nThis is line 2"; - let input = Level::Error + let input = Level::ERROR .message("") .group(Group::new().element(Snippet::>::source(source).line_start(5402))); @@ -148,7 +150,7 @@ error: fn test_format_snippets_continuation() { let src_0 = "This is slice 1"; let src_1 = "This is slice 2"; - let input = Level::Error.message("").group( + let input = Level::ERROR.message("").group( Group::new() .element( Snippet::>::source(src_0) @@ -182,7 +184,7 @@ fn test_format_snippet_annotation_standalone() { let source = [line_1, line_2].join("\n"); // In line 2 let range = 22..24; - let input = Level::Error.message("").group( + let input = Level::ERROR.message("").group( Group::new().element( Snippet::source(&source).line_start(5402).annotation( AnnotationKind::Context @@ -204,9 +206,9 @@ error: #[test] fn test_format_footer_title() { - let input = Level::Error + let input = Level::ERROR .message("") - .group(Group::new().element(Level::Error.title("This __is__ a title"))); + .group(Group::new().element(Level::ERROR.title("This __is__ a title"))); let expected = str![[r#" error: | @@ -221,7 +223,7 @@ error: fn test_i26() { let source = "short"; let label = "label"; - let input = Level::Error.message("").group( + let input = Level::ERROR.message("").group( Group::new().element( Snippet::source(source).line_start(0).annotation( AnnotationKind::Primary @@ -237,7 +239,7 @@ fn test_i26() { #[test] fn test_source_content() { let source = "This is an example\nof content lines"; - let input = Level::Error + let input = Level::ERROR .message("") .group(Group::new().element(Snippet::>::source(source).line_start(56))); let expected = str![[r#" @@ -253,7 +255,7 @@ error: #[test] fn test_source_annotation_standalone_singleline() { let source = "tests"; - let input = Level::Error.message("").group( + let input = Level::ERROR.message("").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -273,7 +275,7 @@ error: #[test] fn test_source_annotation_standalone_multiline() { let source = "tests"; - let input = Level::Error.message("").group( + let input = Level::ERROR.message("").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -296,7 +298,7 @@ error: #[test] fn test_only_source() { - let input = Level::Error + let input = Level::ERROR .message("") .group(Group::new().element(Snippet::>::source("").origin("file.rs"))); let expected = str![[r#" @@ -311,7 +313,7 @@ error: #[test] fn test_anon_lines() { let source = "This is an example\nof content lines\n\nabc"; - let input = Level::Error + let input = Level::ERROR .message("") .group(Group::new().element(Snippet::>::source(source).line_start(56))); let expected = str![[r#" @@ -328,7 +330,7 @@ LL | abc #[test] fn issue_130() { - let input = Level::Error.message("dummy").group( + let input = Level::ERROR.message("dummy").group( Group::new().element( Snippet::source("foo\nbar\nbaz") .origin("file/path") @@ -356,7 +358,7 @@ fn unterminated_string_multiline() { a\" // ... "; - let input = Level::Error.message("").group( + let input = Level::ERROR.message("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -380,7 +382,7 @@ error: #[test] fn char_and_nl_annotate_char() { let source = "a\r\nb"; - let input = Level::Error.message("").group( + let input = Level::ERROR.message("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -403,7 +405,7 @@ error: #[test] fn char_eol_annotate_char() { let source = "a\r\nb"; - let input = Level::Error.message("").group( + let input = Level::ERROR.message("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -425,7 +427,7 @@ error: #[test] fn char_eol_annotate_char_double_width() { - let snippets = Level::Error.message("").group( + let snippets = Level::ERROR.message("").group( Group::new().element( Snippet::source("こん\r\nにちは\r\n世界") .origin("") @@ -450,7 +452,7 @@ error: #[test] fn annotate_eol() { let source = "a\r\nb"; - let input = Level::Error.message("").group( + let input = Level::ERROR.message("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -473,7 +475,7 @@ error: #[test] fn annotate_eol2() { let source = "a\r\nb"; - let input = Level::Error.message("").group( + let input = Level::ERROR.message("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -496,7 +498,7 @@ error: #[test] fn annotate_eol3() { let source = "a\r\nb"; - let input = Level::Error.message("").group( + let input = Level::ERROR.message("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -519,7 +521,7 @@ error: #[test] fn annotate_eol4() { let source = "a\r\nb"; - let input = Level::Error.message("").group( + let input = Level::ERROR.message("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -541,7 +543,7 @@ error: #[test] fn annotate_eol_double_width() { - let snippets = Level::Error.message("").group( + let snippets = Level::ERROR.message("").group( Group::new().element( Snippet::source("こん\r\nにちは\r\n世界") .origin("") @@ -566,7 +568,7 @@ error: #[test] fn multiline_eol_start() { let source = "a\r\nb"; - let input = Level::Error.message("").group( + let input = Level::ERROR.message("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -590,7 +592,7 @@ error: #[test] fn multiline_eol_start2() { let source = "a\r\nb"; - let input = Level::Error.message("").group( + let input = Level::ERROR.message("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -614,7 +616,7 @@ error: #[test] fn multiline_eol_start3() { let source = "a\nb"; - let input = Level::Error.message("").group( + let input = Level::ERROR.message("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -637,7 +639,7 @@ error: #[test] fn multiline_eol_start_double_width() { - let snippets = Level::Error.message("").group( + let snippets = Level::ERROR.message("").group( Group::new().element( Snippet::source("こん\r\nにちは\r\n世界") .origin("") @@ -663,7 +665,7 @@ error: #[test] fn multiline_eol_start_eol_end() { let source = "a\nb\nc"; - let input = Level::Error.message("").group( + let input = Level::ERROR.message("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -688,7 +690,7 @@ error: #[test] fn multiline_eol_start_eol_end2() { let source = "a\r\nb\r\nc"; - let input = Level::Error.message("").group( + let input = Level::ERROR.message("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -713,7 +715,7 @@ error: #[test] fn multiline_eol_start_eol_end3() { let source = "a\r\nb\r\nc"; - let input = Level::Error.message("").group( + let input = Level::ERROR.message("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -738,7 +740,7 @@ error: #[test] fn multiline_eol_start_eof_end() { let source = "a\r\nb"; - let input = Level::Error.message("").group( + let input = Level::ERROR.message("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -762,7 +764,7 @@ error: #[test] fn multiline_eol_start_eof_end_double_width() { let source = "ん\r\nに"; - let input = Level::Error.message("").group( + let input = Level::ERROR.message("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -786,7 +788,7 @@ error: #[test] fn two_single_line_same_line() { let source = r#"bar = { version = "0.1.0", optional = true }"#; - let input = Level::Error.message("unused optional dependency").group( + let input = Level::ERROR.message("unused optional dependency").group( Group::new().element( Snippet::source(source) .origin("Cargo.toml") @@ -823,7 +825,7 @@ this is another line so is this bar = { version = "0.1.0", optional = true } "#; - let input = Level::Error.message("unused optional dependency").group( + let input = Level::ERROR.message("unused optional dependency").group( Group::new().element( Snippet::source(source) .line_start(4) @@ -862,7 +864,7 @@ this is another line so is this bar = { version = "0.1.0", optional = true } "#; - let input = Level::Error.message("unused optional dependency").group( + let input = Level::ERROR.message("unused optional dependency").group( Group::new().element( Snippet::source(source) .line_start(4) @@ -910,7 +912,7 @@ so is this bar = { version = "0.1.0", optional = true } this is another line "#; - let input = Level::Error.message("unused optional dependency").group( + let input = Level::ERROR.message("unused optional dependency").group( Group::new().element( Snippet::source(source) .line_start(4) @@ -961,7 +963,7 @@ error: unused optional dependency #[test] fn origin_correct_start_line() { let source = "aaa\nbbb\nccc\nddd\n"; - let input = Level::Error.message("title").group( + let input = Level::ERROR.message("title").group( Group::new().element( Snippet::source(source) .origin("origin.txt") @@ -987,7 +989,7 @@ error: title #[test] fn origin_correct_mid_line() { let source = "aaa\nbbb\nccc\nddd\n"; - let input = Level::Error.message("title").group( + let input = Level::ERROR.message("title").group( Group::new().element( Snippet::source(source) .origin("origin.txt") @@ -1017,7 +1019,7 @@ error: title #[test] fn two_suggestions_same_span() { let source = r#" A.foo();"#; - let input_new = Level::Error + let input_new = Level::ERROR .message("expected value, found enum `A`") .id("E0423") .group( @@ -1030,7 +1032,7 @@ fn two_suggestions_same_span() { .group( Group::new() .element( - Level::Help + Level::HELP .title("you might have meant to use one of the following enum variants"), ) .element( @@ -1085,7 +1087,7 @@ fn main() { banana::Chaenomeles.pick() }"#; let input_new = - Level::Error + Level::ERROR .message("no method named `pick` found for struct `Chaenomeles` in the current scope") .id("E0599") .group( @@ -1107,7 +1109,7 @@ fn main() { ) .group( Group::new() - .element(Level::Help.title( + .element(Level::HELP.title( "the following traits which provide `pick` are implemented but not in scope; perhaps you want to import one of them", )) .element( @@ -1145,7 +1147,7 @@ LL + use banana::Peach; fn single_line_non_overlapping_suggestions() { let source = r#" A.foo();"#; - let input_new = Level::Error + let input_new = Level::ERROR .message("expected value, found enum `A`") .id("E0423") .group( @@ -1158,7 +1160,7 @@ fn single_line_non_overlapping_suggestions() { ) .group( Group::new() - .element(Level::Help.title("make these changes and things will work")) + .element(Level::HELP.title("make these changes and things will work")) .element( Snippet::source(source) .fold(true) @@ -1187,7 +1189,7 @@ LL + (A::Tuple()).bar(); #[test] fn single_line_non_overlapping_suggestions2() { let source = r#" ThisIsVeryLong.foo();"#; - let input_new = Level::Error + let input_new = Level::ERROR .message("Found `ThisIsVeryLong`") .id("E0423") .group( @@ -1200,7 +1202,7 @@ fn single_line_non_overlapping_suggestions2() { ) .group( Group::new() - .element(Level::Help.title("make these changes and things will work")) + .element(Level::HELP.title("make these changes and things will work")) .element( Snippet::source(source) .fold(true) @@ -1236,7 +1238,7 @@ fn multiple_replacements() { y(); "#; - let input_new = Level::Error + let input_new = Level::ERROR .message("cannot borrow `*self` as mutable because it is also borrowed as immutable") .id("E0502") .group( @@ -1269,7 +1271,7 @@ fn multiple_replacements() { .group( Group::new() .element( - Level::Help + Level::HELP .title("try explicitly pass `&Self` into the Closure as an argument"), ) .element( @@ -1320,7 +1322,7 @@ fn main() { test1(); }"#; - let input_new = Level::Error + let input_new = Level::ERROR .message("cannot borrow `chars` as mutable more than once at a time") .id("E0499") .group( @@ -1348,7 +1350,7 @@ fn main() { .group( Group::new() .element( - Level::Help + Level::HELP .title("if you want to call `next` on a iterator within the loop, consider using `while let`") ) .element( @@ -1404,7 +1406,7 @@ struct Foo { fn main() {}"#; - let input_new = Level::Error + let input_new = Level::ERROR .message("failed to resolve: use of undeclared crate or module `st`") .id("E0433") .group( @@ -1418,7 +1420,7 @@ fn main() {}"#; ) .group( Group::new() - .element(Level::Help.title("there is a crate or module with a similar name")) + .element(Level::HELP.title("there is a crate or module with a similar name")) .element( Snippet::source(source) .fold(true) @@ -1427,7 +1429,7 @@ fn main() {}"#; ) .group( Group::new() - .element(Level::Help.title("consider importing this module")) + .element(Level::HELP.title("consider importing this module")) .element( Snippet::source(source) .fold(true) @@ -1436,7 +1438,7 @@ fn main() {}"#; ) .group( Group::new() - .element(Level::Help.title("if you import `cell`, refer to it directly")) + .element(Level::HELP.title("if you import `cell`, refer to it directly")) .element( Snippet::source(source) .fold(true) @@ -1486,7 +1488,7 @@ where fn main() {}"#; - let input_new = Level::Error + let input_new = Level::ERROR .message("the size for values of type `T` cannot be known at compilation time") .id("E0277") .group( @@ -1508,7 +1510,7 @@ fn main() {}"#; ) .group( Group::new() - .element(Level::Help.title( + .element(Level::HELP.title( "consider removing the `?Sized` bound to make the type parameter `Sized`", )) .element( @@ -1555,7 +1557,7 @@ and where } fn main() {}"#; - let input_new = Level::Error + let input_new = Level::ERROR .message("the size for values of type `T` cannot be known at compilation time") .id("E0277") .group(Group::new().element(Snippet::source(source) @@ -1573,7 +1575,7 @@ fn main() {}"#; .label("this type parameter needs to be `Sized`"), ))) .group(Group::new().element( - Level::Note + Level::NOTE .title("required by an implicit `Sized` bound in `Wrapper`") ).element( Snippet::source(source) @@ -1587,7 +1589,7 @@ fn main() {}"#; ) )) .group(Group::new().element( - Level::Help + Level::HELP .title("you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box`") ) .element( @@ -1608,7 +1610,7 @@ fn main() {}"#; )) .group(Group::new().element( - Level::Help + Level::HELP .title("consider removing the `?Sized` bound to make the type parameter `Sized`") ).element( Snippet::source(source) @@ -1660,12 +1662,12 @@ quack zappy "#; - let input_new = Level::Error + let input_new = Level::ERROR .message("the size for values of type `T` cannot be known at compilation time") .id("E0277") .group( Group::new() - .element(Level::Help.title( + .element(Level::HELP.title( "consider removing the `?Sized` bound to make the type parameter `Sized`", )) .element( @@ -1728,7 +1730,7 @@ fn main() { } "#; - let input_new = Level::Error + let input_new = Level::ERROR .message("type mismatch resolving `>, ...>>, ...>>, ...> as Future>::Error == Foo`") .id("E0271") .group(Group::new().element(Snippet::source(source) @@ -1741,7 +1743,7 @@ fn main() { .label("type mismatch resolving `, ...>>, ...> as Future>::Error == Foo`"), ))) .group(Group::new().element( - Level::Note.title("expected this to be `Foo`") + Level::NOTE.title("expected this to be `Foo`") ).element( Snippet::source(source) .line_start(4) @@ -1749,7 +1751,7 @@ fn main() { .fold(true) .annotation(AnnotationKind::Primary.span(89..90)) ).element( - Level::Note + Level::NOTE .title("required for the cast from `Box>, ()>>, ()>>, ()>>` to `Box<(dyn Future + 'static)>`") , )); @@ -1816,7 +1818,7 @@ fn main() { } "#; - let input_new = Level::Error + let input_new = Level::ERROR .message("type mismatch resolving `>, ...>>, ...>>, ...> as Future>::Error == Foo`") .id("E0271") .group(Group::new().element(Snippet::source(source) @@ -1829,7 +1831,7 @@ fn main() { .label("type mismatch resolving `, ...>>, ...> as Future>::Error == Foo`"), ))) .group(Group::new().element( - Level::Note.title("expected this to be `Foo`") + Level::NOTE.title("expected this to be `Foo`") ).element( Snippet::source(source) .line_start(4) @@ -1837,10 +1839,10 @@ fn main() { .fold(true) .annotation(AnnotationKind::Primary.span(89..90)) ).element( - Level::Note + Level::NOTE .title("required for the cast from `Box>, ()>>, ()>>, ()>>` to `Box<(dyn Future + 'static)>`") ).element( - Level::Note.title("a second note"), + Level::NOTE.title("a second note"), )); let expected = str![[r#" @@ -1969,7 +1971,7 @@ fn main() { } "#; - let input_new = Level::Error + let input_new = Level::ERROR .message("mismatched types") .id("E0308") .group(Group::new().element( @@ -1988,13 +1990,13 @@ fn main() { .label("expected due to this"), ) ).element( - Level::Note + Level::NOTE .title("expected struct `Atype, i32>`\n found enum `Result, _>`") ).element( - Level::Note + Level::NOTE .title("the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt'") ).element( - Level::Note + Level::NOTE .title("consider using `--verbose` to print the full type name to the console") , )); @@ -2053,7 +2055,7 @@ fn main() { } "#; - let input_new = Level::Error + let input_new = Level::ERROR .message("mismatched types") .id("E0308") .group(Group::new().element( @@ -2072,12 +2074,12 @@ fn main() { .label("arguments to this function are incorrect"), ), ).element( - Level::Note + Level::NOTE .title("expected fn pointer `for<'a> fn(Box<(dyn Any + Send + 'a)>) -> Pin<_>`\n found fn item `fn(Box<(dyn Any + Send + 'static)>) -> Pin<_> {wrapped_fn}`") , )) .group(Group::new().element( - Level::Note.title("function defined here"), + Level::NOTE.title("function defined here"), ).element( Snippet::source(source) .line_start(7) @@ -2122,7 +2124,7 @@ LL │ ┃ )>>) {} #[test] fn unicode_cut_handling() { let source = "version = \"0.1.0\"\n# Ensure that the spans from toml handle utf-8 correctly\nauthors = [\n { name = \"Z\u{351}\u{36b}\u{343}\u{36a}\u{302}\u{36b}\u{33d}\u{34f}\u{334}\u{319}\u{324}\u{31e}\u{349}\u{35a}\u{32f}\u{31e}\u{320}\u{34d}A\u{36b}\u{357}\u{334}\u{362}\u{335}\u{31c}\u{330}\u{354}L\u{368}\u{367}\u{369}\u{358}\u{320}G\u{311}\u{357}\u{30e}\u{305}\u{35b}\u{341}\u{334}\u{33b}\u{348}\u{34d}\u{354}\u{339}O\u{342}\u{30c}\u{30c}\u{358}\u{328}\u{335}\u{339}\u{33b}\u{31d}\u{333}\", email = 1 }\n]\n"; - let input = Level::Error.message("title").group( + let input = Level::ERROR.message("title").group( Group::new().element( Snippet::source(source) .fold(false) @@ -2147,7 +2149,7 @@ error: title #[test] fn unicode_cut_handling2() { let source = "/*这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。*/?"; - let input = Level::Error + let input = Level::ERROR .message("expected item, found `?`") .group( Group::new().element( @@ -2155,7 +2157,7 @@ fn unicode_cut_handling2() { .fold(false) .annotation(AnnotationKind::Primary.span(499..500).label("expected item")) ).element( - Level::Note.title("for a full list of items that can appear in modules, see ") + Level::NOTE.title("for a full list of items that can appear in modules, see ") ) ); @@ -2174,7 +2176,7 @@ error: expected item, found `?` #[test] fn unicode_cut_handling3() { let source = "/*这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。*/?"; - let input = Level::Error + let input = Level::ERROR .message("expected item, found `?`") .group( Group::new().element( @@ -2182,7 +2184,7 @@ fn unicode_cut_handling3() { .fold(false) .annotation(AnnotationKind::Primary.span(251..254).label("expected item")) ).element( - Level::Note.title("for a full list of items that can appear in modules, see ") + Level::NOTE.title("for a full list of items that can appear in modules, see ") ) ); @@ -2201,7 +2203,7 @@ error: expected item, found `?` #[test] fn unicode_cut_handling4() { let source = "/*aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa*/?"; - let input = Level::Error + let input = Level::ERROR .message("expected item, found `?`") .group( Group::new().element( @@ -2209,7 +2211,7 @@ fn unicode_cut_handling4() { .fold(false) .annotation(AnnotationKind::Primary.span(334..335).label("expected item")) ).element( - Level::Note.title("for a full list of items that can appear in modules, see ") + Level::NOTE.title("for a full list of items that can appear in modules, see ") ) ); @@ -2234,7 +2236,7 @@ fn main() { //~^ ERROR mismatched types } "##; - let input = Level::Error.message("mismatched types").id("E0308").group( + let input = Level::ERROR.message("mismatched types").id("E0308").group( Group::new().element( Snippet::source(source) .origin("$DIR/non-whitespace-trimming-unicode.rs") @@ -2278,7 +2280,7 @@ fn main() { //[ascii]~^ ERROR cannot add `&str` to `&str` } "##; - let input = Level::Error + let input = Level::ERROR .message("cannot add `&str` to `&str`") .id("E0369") .group( @@ -2296,13 +2298,13 @@ fn main() { ), ) .element( - Level::Note + Level::NOTE .title("string concatenation requires an owned `String` on the left"), ), ) .group( Group::new() - .element(Level::Help.title("create an owned `String` from a string reference")) + .element(Level::HELP.title("create an owned `String` from a string reference")) .element( Snippet::source(source) .origin("$DIR/non-1-width-unicode-multiline-label.rs") @@ -2345,7 +2347,7 @@ fn foo() { } "##; let bin_source = "�|�\u{0002}!5�cc\u{0015}\u{0002}�Ӻi��WWj�ȥ�'�}�\u{0012}�J�ȉ��W�\u{001e}O�@����\u{001c}w�V���LO����\u{0014}[ \u{0003}_�'���SQ�~ذ��ų&��-\t��lN~��!@␌ _#���kQ��h�\u{001d}�:�\u{001c}\u{0007}�"; - let input = Level::Error + let input = Level::ERROR .message("couldn't read `$DIR/not-utf8.bin`: stream did not contain valid UTF-8") .group( Group::new().element( @@ -2357,14 +2359,14 @@ fn foo() { ) .group( Group::new() - .element(Level::Note.title("byte `193` is not valid utf-8")) + .element(Level::NOTE.title("byte `193` is not valid utf-8")) .element( Snippet::source(bin_source) .origin("$DIR/not-utf8.bin") .fold(true) .annotation(AnnotationKind::Primary.span(0..0)), ) - .element(Level::Note.title("this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)")), + .element(Level::NOTE.title("this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)")), ); let expected = str![[r#" diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index 47a33990..7a795dbc 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -2,7 +2,7 @@ //! //! [parser-tests]: https://github.com/rust-lang/rust/blob/894f7a4ba6554d3797404bbf550d9919df060b97/compiler/rustc_parse/src/parser/tests.rs -use annotate_snippets::{AnnotationKind, Group, Level, Origin, Renderer, Snippet}; +use annotate_snippets::{level::Level, AnnotationKind, Group, Origin, Renderer, Snippet}; use snapbox::{assert_data_eq, str}; @@ -12,7 +12,7 @@ fn ends_on_col0() { fn foo() { } "#; - let input = Level::Error.message("foo").group( + let input = Level::ERROR.message("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -42,7 +42,7 @@ fn foo() { } "#; - let input = Level::Error.message("foo").group( + let input = Level::ERROR.message("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -74,7 +74,7 @@ fn foo() { X2 Y2 } "#; - let input = Level::Error.message("foo").group( + let input = Level::ERROR.message("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -117,7 +117,7 @@ fn foo() { Y1 X1 } "#; - let input = Level::Error.message("foo").group( + let input = Level::ERROR.message("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -161,7 +161,7 @@ fn foo() { X3 Y3 Z3 } "#; - let input = Level::Error.message("foo").group( + let input = Level::ERROR.message("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -205,7 +205,7 @@ fn foo() { X2 Y2 Z2 } "#; - let input = Level::Error.message("foo").group( + let input = Level::ERROR.message("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -252,7 +252,7 @@ fn foo() { X2 Y2 Z2 } "#; - let input = Level::Error.message("foo").group( + let input = Level::ERROR.message("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -300,7 +300,7 @@ fn foo() { X3 Y3 Z3 } "#; - let input = Level::Error.message("foo").group( + let input = Level::ERROR.message("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -350,7 +350,7 @@ fn foo() { X3 Y3 Z3 } "#; - let input = Level::Error.message("foo").group( + let input = Level::ERROR.message("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -394,7 +394,7 @@ fn foo() { X3 Y3 Z3 } "#; - let input = Level::Error.message("foo").group( + let input = Level::ERROR.message("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -437,7 +437,7 @@ fn foo() { a { b { c } d } } "#; - let input = Level::Error.message("foo").group( + let input = Level::ERROR.message("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -470,7 +470,7 @@ fn foo() { a { b { c } d } } "#; - let input = Level::Error.message("foo").group( + let input = Level::ERROR.message("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -502,7 +502,7 @@ fn foo() { a { b { c } d } } "#; - let input = Level::Error.message("foo").group( + let input = Level::ERROR.message("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -537,7 +537,7 @@ fn foo() { a { b { c } d } } "#; - let input = Level::Error.message("foo").group( + let input = Level::ERROR.message("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -571,7 +571,7 @@ fn foo() { a bc d } "#; - let input = Level::Error.message("foo").group( + let input = Level::ERROR.message("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -605,7 +605,7 @@ fn foo() { a { b { c } d } } "#; - let input = Level::Error.message("foo").group( + let input = Level::ERROR.message("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -633,7 +633,7 @@ fn foo() { a { b { c } d } } "#; - let input = Level::Error.message("foo").group( + let input = Level::ERROR.message("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -662,7 +662,7 @@ fn foo() { a { b { c } d } } "#; - let input = Level::Error.message("foo").group( + let input = Level::ERROR.message("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -701,7 +701,7 @@ fn foo() { a { b { c } d } } "#; - let input = Level::Error.message("foo").group( + let input = Level::ERROR.message("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -732,7 +732,7 @@ fn foo() { a { b { c } d } } "#; - let input = Level::Error.message("foo").group( + let input = Level::ERROR.message("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -772,7 +772,7 @@ fn foo() { X3 Y3 Z3 } "#; - let input = Level::Error.message("foo").group( + let input = Level::ERROR.message("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -832,7 +832,7 @@ fn foo() { X3 Y3 Z3 } "#; - let input = Level::Error.message("foo").group( + let input = Level::ERROR.message("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -886,7 +886,7 @@ fn issue_91334() { fn f(){||yield(((){), "#; - let input = Level::Error + let input = Level::ERROR .message("this file contains an unclosed delimiter") .group( Group::new().element( @@ -957,7 +957,7 @@ fn main() { } } "#; - let input = Level::Error + let input = Level::ERROR .message("`break` with value from a `while` loop") .id("E0571") .group( @@ -981,7 +981,7 @@ fn main() { .group( Group::new() .element( - Level::Help + Level::HELP .title("use `break` on its own without a value inside this `while` loop"), ) .element( @@ -1167,7 +1167,7 @@ fn nsize() { } "#; let input = - Level::Error + Level::ERROR .message("`V0usize` cannot be safely transmuted into `[usize; 2]`") .id("E0277") .group( @@ -1183,7 +1183,7 @@ fn nsize() { ) .group( Group::new() - .element(Level::Note.title("required by a bound in `is_transmutable`")) + .element(Level::NOTE.title("required by a bound in `is_transmutable`")) .element( Snippet::source(source) .line_start(1) @@ -1253,7 +1253,7 @@ fn main() { assert::is_maybe_transmutable::<&'static [u8; 0], &'static [u16; 0]>(); //~ ERROR `&[u8; 0]` cannot be safely transmuted into `&[u16; 0]` } "#; - let input = Level::Error + let input = Level::ERROR .message("`&[u8; 0]` cannot be safely transmuted into `&[u16; 0]`") .id("E027s7") .group( @@ -1322,7 +1322,7 @@ fn g() { } fn main() {} "#; - let input = Level::Error + let input = Level::ERROR .message("expected function, found `{integer}`") .id("E0618") .group( @@ -1413,7 +1413,7 @@ macro_rules! outer_macro { outer_macro!(FirstStruct, FirstAttrStruct); "#; - let input = Level::Warning + let input = Level::WARNING .message("non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module") .group( Group::new() @@ -1441,17 +1441,17 @@ outer_macro!(FirstStruct, FirstAttrStruct); ), ) .element( - Level::Help + Level::HELP .title("remove the `#[macro_export]` or move this `macro_rules!` outside the of the current function `main`") ) .element( - Level::Note + Level::NOTE .title("a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute") ), ) .group( Group::new() - .element(Level::Note.title("the lint level is defined here")) + .element(Level::NOTE.title("the lint level is defined here")) .element( Snippet::source(source) .line_start(1) @@ -1546,7 +1546,7 @@ macro_rules! inline { () => () } "#; - let input = Level::Error + let input = Level::ERROR .message("can't call method `pow` on ambiguous numeric type `{integer}`") .id("E0689") .group( @@ -1560,7 +1560,7 @@ macro_rules! inline { ) .group( Group::new() - .element(Level::Help.title("you must specify a type for this binding, like `i32`")) + .element(Level::HELP.title("you must specify a type for this binding, like `i32`")) .element( Snippet::source(aux_source) .line_start(1) @@ -1610,7 +1610,7 @@ fn courier_to_des_moines_and_points_west(data: &[u32]) -> String { fn main() {} "#; - let input = Level::Error + let input = Level::ERROR .message("type annotations needed") .id("E0282") .group( @@ -1716,7 +1716,7 @@ fn nonempty(arrayN_of_empty: [!; N]) { fn main() {} "##; - let input = Level::Error + let input = Level::ERROR .message( "non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered" ) @@ -1736,7 +1736,7 @@ fn main() {} ) .group( Group::new() - .element(Level::Note.title("`NonEmptyEnum5` defined here")) + .element(Level::NOTE.title("`NonEmptyEnum5` defined here")) .element( Snippet::source(source) .line_start(1) @@ -1749,13 +1749,13 @@ fn main() {} .annotation(AnnotationKind::Context.span(878..880).label("not covered")) .annotation(AnnotationKind::Context.span(890..892).label("not covered")) ) - .element(Level::Note.title("the matched value is of type `NonEmptyEnum5`")) - .element(Level::Note.title("match arms with guards don't count towards exhaustivity")) + .element(Level::NOTE.title("the matched value is of type `NonEmptyEnum5`")) + .element(Level::NOTE.title("match arms with guards don't count towards exhaustivity")) ) .group( Group::new() .element( - Level::Help + Level::HELP .title("ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms") ) .element( @@ -1818,7 +1818,7 @@ fn main() { //~^ ERROR must be specified } "#; - let input = Level::Error + let input = Level::ERROR .message("the trait alias `EqAlias` is not dyn compatible") .id("E0038") .group( @@ -1837,7 +1837,7 @@ fn main() { .group( Group::new() .element( - Level::Note + Level::NOTE .title("for a trait to be dyn compatible it needs to allow building a vtable\nfor more information, visit ")) .element( Origin::new("$SRC_DIR/core/src/cmp.rs") From a1a11a53235087853a98c9404627abf90a8d383d Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 16 Apr 2025 15:09:13 -0500 Subject: [PATCH 174/293] fix: Remove unused Level2 --- src/level.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/level.rs b/src/level.rs index 7f920249..81aea8c9 100644 --- a/src/level.rs +++ b/src/level.rs @@ -34,16 +34,6 @@ pub struct Level<'a> { pub(crate) level: LevelInner, } -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub enum Level2<'a> { - Builtin(LevelInner), - Custom { - name: Option<&'a str>, - level: LevelInner, - }, - None, -} - impl<'a> Level<'a> { pub const ERROR: Level<'a> = ERROR; pub const WARNING: Level<'a> = WARNING; From a792c392cd720e11a3a03e2fa2d1fa609979821c Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 16 Apr 2025 15:09:46 -0500 Subject: [PATCH 175/293] fix: Hide LevelInner --- src/level.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/level.rs b/src/level.rs index 81aea8c9..46eaef14 100644 --- a/src/level.rs +++ b/src/level.rs @@ -97,7 +97,7 @@ impl<'a> Level<'a> { } #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub enum LevelInner { +pub(crate) enum LevelInner { Error, Warning, Info, From 1d802c3480aedbebff07ad950c51b86422635b42 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 16 Apr 2025 15:12:03 -0500 Subject: [PATCH 176/293] fix: Re-export Level at the top-level --- benches/bench.rs | 2 +- examples/custom_error.rs | 2 +- examples/custom_level.rs | 2 +- examples/expected_type.rs | 2 +- examples/footer.rs | 2 +- examples/format.rs | 2 +- examples/highlight_source.rs | 2 +- examples/highlight_title.rs | 2 +- examples/multislice.rs | 2 +- src/lib.rs | 2 ++ src/renderer/mod.rs | 2 +- src/renderer/styled_buffer.rs | 2 +- src/snippet.rs | 2 +- tests/fixtures/deserialize.rs | 2 +- tests/formatter.rs | 4 +--- tests/rustc_tests.rs | 2 +- 16 files changed, 17 insertions(+), 17 deletions(-) diff --git a/benches/bench.rs b/benches/bench.rs index d50cf435..a6cdb37d 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -1,4 +1,4 @@ -use annotate_snippets::{level::Level, AnnotationKind, Group, Renderer, Snippet}; +use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; #[divan::bench] fn simple() -> String { diff --git a/examples/custom_error.rs b/examples/custom_error.rs index 4050d400..418d3425 100644 --- a/examples/custom_error.rs +++ b/examples/custom_error.rs @@ -1,5 +1,5 @@ use annotate_snippets::renderer::OutputTheme; -use annotate_snippets::{level::Level, AnnotationKind, Group, Renderer, Snippet}; +use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; fn main() { let source = r#"//@ compile-flags: -Ztreat-err-as-bug diff --git a/examples/custom_level.rs b/examples/custom_level.rs index 804f7741..87cad9ad 100644 --- a/examples/custom_level.rs +++ b/examples/custom_level.rs @@ -1,5 +1,5 @@ use annotate_snippets::renderer::OutputTheme; -use annotate_snippets::{level::Level, AnnotationKind, Group, Patch, Renderer, Snippet}; +use annotate_snippets::{AnnotationKind, Group, Level, Patch, Renderer, Snippet}; fn main() { let source = r#"// Regression test for issue #114529 diff --git a/examples/expected_type.rs b/examples/expected_type.rs index 9a51dce5..5c801c71 100644 --- a/examples/expected_type.rs +++ b/examples/expected_type.rs @@ -1,4 +1,4 @@ -use annotate_snippets::{level::Level, AnnotationKind, Group, Renderer, Snippet}; +use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; fn main() { let source = r#" annotations: vec![SourceAnnotation { diff --git a/examples/footer.rs b/examples/footer.rs index d61e84b4..95de15c6 100644 --- a/examples/footer.rs +++ b/examples/footer.rs @@ -1,4 +1,4 @@ -use annotate_snippets::{level::Level, AnnotationKind, Group, Renderer, Snippet}; +use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; fn main() { let message = Level::ERROR diff --git a/examples/format.rs b/examples/format.rs index 5324413c..eb68d828 100644 --- a/examples/format.rs +++ b/examples/format.rs @@ -1,4 +1,4 @@ -use annotate_snippets::{level::Level, AnnotationKind, Group, Renderer, Snippet}; +use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; fn main() { let source = r#") -> Option { diff --git a/examples/highlight_source.rs b/examples/highlight_source.rs index 9962542d..165dd860 100644 --- a/examples/highlight_source.rs +++ b/examples/highlight_source.rs @@ -1,4 +1,4 @@ -use annotate_snippets::{level::Level, AnnotationKind, Group, Renderer, Snippet}; +use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; fn main() { let source = r#"//@ compile-flags: -Z teach diff --git a/examples/highlight_title.rs b/examples/highlight_title.rs index e2da54ff..ea746129 100644 --- a/examples/highlight_title.rs +++ b/examples/highlight_title.rs @@ -1,4 +1,4 @@ -use annotate_snippets::{level::Level, AnnotationKind, Group, Renderer, Snippet}; +use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; use anstyle::Effects; fn main() { diff --git a/examples/multislice.rs b/examples/multislice.rs index ddd938e4..9be82e96 100644 --- a/examples/multislice.rs +++ b/examples/multislice.rs @@ -1,4 +1,4 @@ -use annotate_snippets::{level::Level, Annotation, Group, Renderer, Snippet}; +use annotate_snippets::{Annotation, Group, Level, Renderer, Snippet}; fn main() { let message = Level::ERROR.message("mismatched types").group( diff --git a/src/lib.rs b/src/lib.rs index eee2b6f3..0d23b29a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,6 +53,8 @@ pub fn normalize_untrusted_str(s: &str) -> String { renderer::normalize_whitespace(s) } +#[doc(inline)] +pub use level::Level; #[doc(inline)] pub use renderer::Renderer; pub use snippet::ColumnSeparator; diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 8efcff84..12fc5d96 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -5,7 +5,7 @@ //! # Example //! ``` //! use annotate_snippets::*; -//! use annotate_snippets::level::Level; +//! use annotate_snippets::Level; //! //! let source = r#" //! use baz::zed::bar; diff --git a/src/renderer/styled_buffer.rs b/src/renderer/styled_buffer.rs index 7114683b..c9b805a0 100644 --- a/src/renderer/styled_buffer.rs +++ b/src/renderer/styled_buffer.rs @@ -2,9 +2,9 @@ //! //! [styled_buffer]: https://github.com/rust-lang/rust/blob/894f7a4ba6554d3797404bbf550d9919df060b97/compiler/rustc_errors/src/styled_buffer.rs -use crate::level::Level; use crate::renderer::stylesheet::Stylesheet; use crate::renderer::ElementStyle; +use crate::Level; use std::fmt; use std::fmt::Write; diff --git a/src/snippet.rs b/src/snippet.rs index fe1239d4..aa5f9ff4 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -1,7 +1,7 @@ //! Structures used as an input for the library. -use crate::level::Level; use crate::renderer::source_map::SourceMap; +use crate::Level; use std::ops::Range; pub(crate) const ERROR_TXT: &str = "error"; diff --git a/tests/fixtures/deserialize.rs b/tests/fixtures/deserialize.rs index 8f45b363..55374df0 100644 --- a/tests/fixtures/deserialize.rs +++ b/tests/fixtures/deserialize.rs @@ -3,7 +3,7 @@ use std::ops::Range; use annotate_snippets::renderer::DEFAULT_TERM_WIDTH; use annotate_snippets::{ - level::Level, Annotation, AnnotationKind, Element, Group, Message, Patch, Renderer, Snippet, + Annotation, AnnotationKind, Element, Group, Level, Message, Patch, Renderer, Snippet, }; #[derive(Deserialize)] diff --git a/tests/formatter.rs b/tests/formatter.rs index 3f0e7cd4..22b517b6 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -1,6 +1,4 @@ -use annotate_snippets::{ - level::Level, Annotation, AnnotationKind, Group, Patch, Renderer, Snippet, -}; +use annotate_snippets::{Annotation, AnnotationKind, Group, Level, Patch, Renderer, Snippet}; use annotate_snippets::renderer::OutputTheme; use snapbox::{assert_data_eq, str}; diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index 7a795dbc..93860d0e 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -2,7 +2,7 @@ //! //! [parser-tests]: https://github.com/rust-lang/rust/blob/894f7a4ba6554d3797404bbf550d9919df060b97/compiler/rustc_parse/src/parser/tests.rs -use annotate_snippets::{level::Level, AnnotationKind, Group, Origin, Renderer, Snippet}; +use annotate_snippets::{AnnotationKind, Group, Level, Origin, Renderer, Snippet}; use snapbox::{assert_data_eq, str}; From 4c113cca128ffe8e1d62625daddd58ed6181a7db Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 16 Apr 2025 15:23:22 -0500 Subject: [PATCH 177/293] fix!: Rename `Renderer::line_no` to `Renderer::line_num` Fixes #175 --- src/renderer/mod.rs | 8 ++++---- src/renderer/stylesheet.rs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 12fc5d96..f421c2df 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -101,7 +101,7 @@ impl Renderer { info: BRIGHT_BLUE.effects(Effects::BOLD), note: AnsiColor::BrightGreen.on_default().effects(Effects::BOLD), help: AnsiColor::BrightCyan.on_default().effects(Effects::BOLD), - line_no: BRIGHT_BLUE.effects(Effects::BOLD), + line_num: BRIGHT_BLUE.effects(Effects::BOLD), emphasis: if USE_WINDOWS_COLORS { AnsiColor::BrightWhite.on_default() } else { @@ -178,8 +178,8 @@ impl Renderer { } /// Set the output style for line numbers - pub const fn line_no(mut self, style: Style) -> Self { - self.stylesheet.line_no = style; + pub const fn line_num(mut self, style: Style) -> Self { + self.stylesheet.line_num = style; self } @@ -2665,7 +2665,7 @@ impl ElementStyle { ElementStyle::Addition => stylesheet.addition, ElementStyle::Removal => stylesheet.removal, ElementStyle::LineAndColumn => stylesheet.none, - ElementStyle::LineNumber => stylesheet.line_no, + ElementStyle::LineNumber => stylesheet.line_num, ElementStyle::Quotation => stylesheet.none, ElementStyle::MainHeaderMsg => stylesheet.emphasis, ElementStyle::UnderlinePrimary | ElementStyle::LabelPrimary => level.style(stylesheet), diff --git a/src/renderer/stylesheet.rs b/src/renderer/stylesheet.rs index 4aa21a5a..075cad42 100644 --- a/src/renderer/stylesheet.rs +++ b/src/renderer/stylesheet.rs @@ -7,7 +7,7 @@ pub(crate) struct Stylesheet { pub(crate) info: Style, pub(crate) note: Style, pub(crate) help: Style, - pub(crate) line_no: Style, + pub(crate) line_num: Style, pub(crate) emphasis: Style, pub(crate) none: Style, pub(crate) context: Style, @@ -29,7 +29,7 @@ impl Stylesheet { info: Style::new(), note: Style::new(), help: Style::new(), - line_no: Style::new(), + line_num: Style::new(), emphasis: Style::new(), none: Style::new(), context: Style::new(), From f6d191440268c5309c5c70755f1eaf49d2e1db33 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 16 Apr 2025 15:36:57 -0500 Subject: [PATCH 178/293] fix: Clarify ColumnSeparator is Padding --- src/lib.rs | 2 +- src/renderer/mod.rs | 4 ++-- src/snippet.rs | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0d23b29a..021ed524 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,5 +57,5 @@ pub fn normalize_untrusted_str(s: &str) -> String { pub use level::Level; #[doc(inline)] pub use renderer::Renderer; -pub use snippet::ColumnSeparator; +pub use snippet::Padding; pub use snippet::*; diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index f421c2df..1e88bca9 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -383,7 +383,7 @@ impl Renderer { self.render_origin(buffer, max_line_num_len, origin); last_was_suggestion = false; } - Element::ColumnSeparator(_) => { + Element::Padding(_) => { self.draw_col_separator_no_space( buffer, buffer.num_lines(), @@ -430,7 +430,7 @@ impl Renderer { let (has_primary_spans, has_span_labels) = next_section.map_or((false, false), |s| match s { - Element::Title(_) | Element::ColumnSeparator(_) => (false, false), + Element::Title(_) | Element::Padding(_) => (false, false), Element::Cause(cause) => ( cause.markers.iter().any(|m| m.kind.is_primary()), cause.markers.iter().any(|m| m.label.is_some()), diff --git a/src/snippet.rs b/src/snippet.rs index aa5f9ff4..bf22c5be 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -34,7 +34,7 @@ impl<'a> Message<'a> { v.elements .iter() .map(|s| match s { - Element::Title(_) | Element::Origin(_) | Element::ColumnSeparator(_) => 0, + Element::Title(_) | Element::Origin(_) | Element::Padding(_) => 0, Element::Cause(cause) => { let end = cause .markers @@ -104,7 +104,7 @@ pub enum Element<'a> { Cause(Snippet<'a, Annotation<'a>>), Suggestion(Snippet<'a, Patch<'a>>), Origin(Origin<'a>), - ColumnSeparator(ColumnSeparator), + Padding(Padding), } impl<'a> From> for Element<'a> { @@ -131,14 +131,14 @@ impl<'a> From> for Element<'a> { } } -impl From for Element<'_> { - fn from(value: ColumnSeparator) -> Self { - Self::ColumnSeparator(value) +impl From for Element<'_> { + fn from(value: Padding) -> Self { + Self::Padding(value) } } #[derive(Debug)] -pub struct ColumnSeparator; +pub struct Padding; #[derive(Debug)] pub struct Title<'a> { From d3b79b6466562c810d55b3d256de94ce5c352812 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 16 Apr 2025 15:59:54 -0500 Subject: [PATCH 179/293] fix!: Rename Level::title/Level::message to Level::header This doesn't completely take care of #118 because of #196 --- benches/bench.rs | 4 +- examples/custom_error.rs | 2 +- examples/custom_level.rs | 2 +- examples/expected_type.rs | 2 +- examples/footer.rs | 2 +- examples/format.rs | 2 +- examples/highlight_source.rs | 2 +- examples/highlight_title.rs | 2 +- examples/multislice.rs | 2 +- src/level.rs | 4 +- src/renderer/mod.rs | 2 +- tests/fixtures/color/ann_eof.toml | 2 +- tests/fixtures/color/ann_insertion.toml | 2 +- tests/fixtures/color/ann_multiline.toml | 2 +- tests/fixtures/color/ann_multiline2.toml | 2 +- tests/fixtures/color/ann_removed_nl.toml | 2 +- .../color/ensure-emoji-highlight-width.toml | 2 +- tests/fixtures/color/fold_ann_multiline.toml | 2 +- .../fixtures/color/fold_bad_origin_line.toml | 2 +- tests/fixtures/color/fold_leading.toml | 2 +- tests/fixtures/color/fold_trailing.toml | 2 +- tests/fixtures/color/issue_9.toml | 2 +- .../fixtures/color/multiple_annotations.toml | 2 +- tests/fixtures/color/simple.toml | 2 +- tests/fixtures/color/strip_line.toml | 2 +- tests/fixtures/color/strip_line_char.toml | 2 +- tests/fixtures/color/strip_line_non_ws.toml | 2 +- tests/fixtures/deserialize.rs | 6 +- tests/formatter.rs | 124 +++++++++--------- tests/rustc_tests.rs | 64 ++++----- 30 files changed, 126 insertions(+), 126 deletions(-) diff --git a/benches/bench.rs b/benches/bench.rs index a6cdb37d..c3799fbd 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -24,7 +24,7 @@ fn simple() -> String { _ => continue, } }"#; - let message = Level::ERROR.message("mismatched types").id("E0308").group( + let message = Level::ERROR.header("mismatched types").id("E0308").group( Group::new().element( Snippet::source(source) .line_start(51) @@ -69,7 +69,7 @@ fn fold(bencher: divan::Bencher<'_, '_>, context: usize) { (input, span) }) .bench_values(|(input, span)| { - let message = Level::ERROR.message("mismatched types").id("E0308").group( + let message = Level::ERROR.header("mismatched types").id("E0308").group( Group::new().element( Snippet::source(&input) .fold(true) diff --git a/examples/custom_error.rs b/examples/custom_error.rs index 418d3425..b9e27b31 100644 --- a/examples/custom_error.rs +++ b/examples/custom_error.rs @@ -17,7 +17,7 @@ pub static C: u32 = 0 - 1; "#; let message = Level::ERROR .text(Some("error: internal compiler error")) - .message("could not evaluate static initializer") + .header("could not evaluate static initializer") .id("E0080") .group( Group::new().element( diff --git a/examples/custom_level.rs b/examples/custom_level.rs index 87cad9ad..b2af361a 100644 --- a/examples/custom_level.rs +++ b/examples/custom_level.rs @@ -30,7 +30,7 @@ fn main() { } "#; let message = Level::ERROR - .message("`break` with value from a `while` loop") + .header("`break` with value from a `while` loop") .id("E0571") .group( Group::new().element( diff --git a/examples/expected_type.rs b/examples/expected_type.rs index 5c801c71..02abdecf 100644 --- a/examples/expected_type.rs +++ b/examples/expected_type.rs @@ -6,7 +6,7 @@ fn main() { , range: <22, 25>,"#; let message = - Level::ERROR.message("expected type, found `22`").group( + Level::ERROR.header("expected type, found `22`").group( Group::new().element( Snippet::source(source) .line_start(26) diff --git a/examples/footer.rs b/examples/footer.rs index 95de15c6..ca6f1dc7 100644 --- a/examples/footer.rs +++ b/examples/footer.rs @@ -2,7 +2,7 @@ use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; fn main() { let message = Level::ERROR - .message("mismatched types") + .header("mismatched types") .id("E0308") .group( Group::new().element( diff --git a/examples/format.rs b/examples/format.rs index eb68d828..4b688d4b 100644 --- a/examples/format.rs +++ b/examples/format.rs @@ -23,7 +23,7 @@ fn main() { _ => continue, } }"#; - let message = Level::ERROR.message("mismatched types").id("E0308").group( + let message = Level::ERROR.header("mismatched types").id("E0308").group( Group::new().element( Snippet::source(source) .line_start(51) diff --git a/examples/highlight_source.rs b/examples/highlight_source.rs index 165dd860..92d8114f 100644 --- a/examples/highlight_source.rs +++ b/examples/highlight_source.rs @@ -10,7 +10,7 @@ const CON: Vec = vec![1, 2, 3]; //~ ERROR E0010 fn main() {} "#; let message = Level::ERROR - .message("allocations are not allowed in constants") + .header("allocations are not allowed in constants") .id("E0010") .group( Group::new() diff --git a/examples/highlight_title.rs b/examples/highlight_title.rs index ea746129..12c106a6 100644 --- a/examples/highlight_title.rs +++ b/examples/highlight_title.rs @@ -43,7 +43,7 @@ fn main() { magenta.render_reset() ); - let message = Level::ERROR.message("mismatched types").id("E0308").group( + let message = Level::ERROR.header("mismatched types").id("E0308").group( Group::new() .element( Snippet::source(source) diff --git a/examples/multislice.rs b/examples/multislice.rs index 9be82e96..a7d340ad 100644 --- a/examples/multislice.rs +++ b/examples/multislice.rs @@ -1,7 +1,7 @@ use annotate_snippets::{Annotation, Group, Level, Renderer, Snippet}; fn main() { - let message = Level::ERROR.message("mismatched types").group( + let message = Level::ERROR.header("mismatched types").group( Group::new() .element( Snippet::>::source("Foo") diff --git a/src/level.rs b/src/level.rs index 46eaef14..3fd504de 100644 --- a/src/level.rs +++ b/src/level.rs @@ -56,12 +56,12 @@ impl<'a> Level<'a> { /// Text passed to this function is considered "untrusted input", as such /// all text is passed through a normalization function. Pre-styled text is /// not allowed to be passed to this function. - pub fn message(self, title: &'a str) -> Message<'a> { + pub fn header(self, header: &'a str) -> Message<'a> { Message { id: None, groups: vec![Group::new().element(Element::Title(Title { level: self, - title, + title: header, primary: true, }))], } diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 1e88bca9..e5572e5e 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -19,7 +19,7 @@ //! } //! "#; //! Level::ERROR -//! .message("unresolved import `baz::zed`") +//! .header("unresolved import `baz::zed`") //! .id("E0432") //! .group( //! Group::new().element( diff --git a/tests/fixtures/color/ann_eof.toml b/tests/fixtures/color/ann_eof.toml index ac129f3f..ef711dee 100644 --- a/tests/fixtures/color/ann_eof.toml +++ b/tests/fixtures/color/ann_eof.toml @@ -1,6 +1,6 @@ [message] level = "Error" -title = "expected `.`, `=`" +header = "expected `.`, `=`" [[message.sections]] type = "Cause" diff --git a/tests/fixtures/color/ann_insertion.toml b/tests/fixtures/color/ann_insertion.toml index 13bc13ca..30af1bfb 100644 --- a/tests/fixtures/color/ann_insertion.toml +++ b/tests/fixtures/color/ann_insertion.toml @@ -1,6 +1,6 @@ [message] level = "Error" -title = "expected `.`, `=`" +header = "expected `.`, `=`" [[message.sections]] type = "Cause" diff --git a/tests/fixtures/color/ann_multiline.toml b/tests/fixtures/color/ann_multiline.toml index 722c3e18..2a5f206b 100644 --- a/tests/fixtures/color/ann_multiline.toml +++ b/tests/fixtures/color/ann_multiline.toml @@ -1,7 +1,7 @@ [message] level = "Error" id = "E0027" -title = "pattern does not mention fields `lineno`, `content`" +header = "pattern does not mention fields `lineno`, `content`" [[message.sections]] type = "Cause" diff --git a/tests/fixtures/color/ann_multiline2.toml b/tests/fixtures/color/ann_multiline2.toml index 329beb49..854b38a7 100644 --- a/tests/fixtures/color/ann_multiline2.toml +++ b/tests/fixtures/color/ann_multiline2.toml @@ -1,7 +1,7 @@ [message] level = "Error" id = "E####" -title = "spacing error found" +header = "spacing error found" [[message.sections]] type = "Cause" diff --git a/tests/fixtures/color/ann_removed_nl.toml b/tests/fixtures/color/ann_removed_nl.toml index 8ed96bcc..6ffeb7a0 100644 --- a/tests/fixtures/color/ann_removed_nl.toml +++ b/tests/fixtures/color/ann_removed_nl.toml @@ -1,6 +1,6 @@ [message] level = "Error" -title = "expected `.`, `=`" +header = "expected `.`, `=`" [[message.sections]] type = "Cause" diff --git a/tests/fixtures/color/ensure-emoji-highlight-width.toml b/tests/fixtures/color/ensure-emoji-highlight-width.toml index 8d7a14aa..669959f6 100644 --- a/tests/fixtures/color/ensure-emoji-highlight-width.toml +++ b/tests/fixtures/color/ensure-emoji-highlight-width.toml @@ -1,5 +1,5 @@ [message] -title = "invalid character ` ` in package name: `haha this isn't a valid name 🐛`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters)" +header = "invalid character ` ` in package name: `haha this isn't a valid name 🐛`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters)" level = "Error" diff --git a/tests/fixtures/color/fold_ann_multiline.toml b/tests/fixtures/color/fold_ann_multiline.toml index 745ef42e..2cee27d6 100644 --- a/tests/fixtures/color/fold_ann_multiline.toml +++ b/tests/fixtures/color/fold_ann_multiline.toml @@ -1,7 +1,7 @@ [message] level = "Error" id = "E0308" -title = "mismatched types" +header = "mismatched types" [[message.sections]] type = "Cause" diff --git a/tests/fixtures/color/fold_bad_origin_line.toml b/tests/fixtures/color/fold_bad_origin_line.toml index 3b0d827f..2fab2d64 100644 --- a/tests/fixtures/color/fold_bad_origin_line.toml +++ b/tests/fixtures/color/fold_bad_origin_line.toml @@ -1,6 +1,6 @@ [message] level = "Error" -title = "" +header = "" [[message.sections]] type = "Cause" diff --git a/tests/fixtures/color/fold_leading.toml b/tests/fixtures/color/fold_leading.toml index 564187be..0ef043c9 100644 --- a/tests/fixtures/color/fold_leading.toml +++ b/tests/fixtures/color/fold_leading.toml @@ -1,7 +1,7 @@ [message] level = "Error" id = "E0308" -title = "invalid type: integer `20`, expected a bool" +header = "invalid type: integer `20`, expected a bool" [[message.sections]] type = "Cause" diff --git a/tests/fixtures/color/fold_trailing.toml b/tests/fixtures/color/fold_trailing.toml index eea6365e..91e4ab4f 100644 --- a/tests/fixtures/color/fold_trailing.toml +++ b/tests/fixtures/color/fold_trailing.toml @@ -1,7 +1,7 @@ [message] level = "Error" id = "E0308" -title = "invalid type: integer `20`, expected a lints table" +header = "invalid type: integer `20`, expected a lints table" [[message.sections]] type = "Cause" diff --git a/tests/fixtures/color/issue_9.toml b/tests/fixtures/color/issue_9.toml index 96ad2c07..f4239154 100644 --- a/tests/fixtures/color/issue_9.toml +++ b/tests/fixtures/color/issue_9.toml @@ -1,6 +1,6 @@ [message] level = "Error" -title = "expected one of `.`, `;`, `?`, or an operator, found `for`" +header = "expected one of `.`, `;`, `?`, or an operator, found `for`" [[message.sections]] type = "Cause" diff --git a/tests/fixtures/color/multiple_annotations.toml b/tests/fixtures/color/multiple_annotations.toml index f4c90a4e..367c53ee 100644 --- a/tests/fixtures/color/multiple_annotations.toml +++ b/tests/fixtures/color/multiple_annotations.toml @@ -1,6 +1,6 @@ [message] level = "Error" -title = "" +header = "" [[message.sections]] type = "Cause" diff --git a/tests/fixtures/color/simple.toml b/tests/fixtures/color/simple.toml index b70f11cc..d5a36474 100644 --- a/tests/fixtures/color/simple.toml +++ b/tests/fixtures/color/simple.toml @@ -1,6 +1,6 @@ [message] level = "Error" -title = "expected one of `.`, `;`, `?`, or an operator, found `for`" +header = "expected one of `.`, `;`, `?`, or an operator, found `for`" [[message.sections]] type = "Cause" diff --git a/tests/fixtures/color/strip_line.toml b/tests/fixtures/color/strip_line.toml index d7af6862..18a7805d 100644 --- a/tests/fixtures/color/strip_line.toml +++ b/tests/fixtures/color/strip_line.toml @@ -1,7 +1,7 @@ [message] level = "Error" id = "E0308" -title = "mismatched types" +header = "mismatched types" [[message.sections]] type = "Cause" diff --git a/tests/fixtures/color/strip_line_char.toml b/tests/fixtures/color/strip_line_char.toml index 6585005c..3174cedc 100644 --- a/tests/fixtures/color/strip_line_char.toml +++ b/tests/fixtures/color/strip_line_char.toml @@ -1,7 +1,7 @@ [message] level = "Error" id = "E0308" -title = "mismatched types" +header = "mismatched types" [[message.sections]] type = "Cause" diff --git a/tests/fixtures/color/strip_line_non_ws.toml b/tests/fixtures/color/strip_line_non_ws.toml index 1f085b5f..b7844ec2 100644 --- a/tests/fixtures/color/strip_line_non_ws.toml +++ b/tests/fixtures/color/strip_line_non_ws.toml @@ -1,7 +1,7 @@ [message] level = "Error" id = "E0308" -title = "mismatched types" +header = "mismatched types" [[message.sections]] type = "Cause" diff --git a/tests/fixtures/deserialize.rs b/tests/fixtures/deserialize.rs index 55374df0..20429665 100644 --- a/tests/fixtures/deserialize.rs +++ b/tests/fixtures/deserialize.rs @@ -16,7 +16,7 @@ pub(crate) struct Fixture { #[derive(Deserialize)] pub struct MessageDef { pub level: LevelDef, - pub title: String, + pub header: String, #[serde(default)] pub id: Option, #[serde(default)] @@ -27,11 +27,11 @@ impl<'a> From<&'a MessageDef> for Message<'a> { fn from(val: &'a MessageDef) -> Self { let MessageDef { level, - title, + header, id, sections, } = val; - let mut message = Level::from(level).message(title); + let mut message = Level::from(level).header(header); if let Some(id) = id { message = message.id(id); } diff --git a/tests/formatter.rs b/tests/formatter.rs index 22b517b6..75cf8532 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -5,7 +5,7 @@ use snapbox::{assert_data_eq, str}; #[test] fn test_i_29() { - let snippets = Level::ERROR.message("oops").group( + let snippets = Level::ERROR.header("oops").group( Group::new().element( Snippet::source("First line\r\nSecond oops line") .origin("") @@ -27,7 +27,7 @@ error: oops #[test] fn test_point_to_double_width_characters() { - let snippets = Level::ERROR.message("").group( + let snippets = Level::ERROR.header("").group( Group::new().element( Snippet::source("こんにちは、世界") .origin("") @@ -49,7 +49,7 @@ error: #[test] fn test_point_to_double_width_characters_across_lines() { - let snippets = Level::ERROR.message("").group( + let snippets = Level::ERROR.header("").group( Group::new().element( Snippet::source("おはよう\nございます") .origin("") @@ -73,7 +73,7 @@ error: #[test] fn test_point_to_double_width_characters_multiple() { - let snippets = Level::ERROR.message("").group( + let snippets = Level::ERROR.header("").group( Group::new().element( Snippet::source("お寿司\n食べたい🍣") .origin("") @@ -98,7 +98,7 @@ error: #[test] fn test_point_to_double_width_characters_mixed() { - let snippets = Level::ERROR.message("").group( + let snippets = Level::ERROR.header("").group( Group::new().element( Snippet::source("こんにちは、新しいWorld!") .origin("") @@ -120,7 +120,7 @@ error: #[test] fn test_format_title() { - let input = Level::ERROR.message("This is a title").id("E0001"); + let input = Level::ERROR.header("This is a title").id("E0001"); let expected = str![r#"error[E0001]: This is a title"#]; let renderer = Renderer::plain(); @@ -131,7 +131,7 @@ fn test_format_title() { fn test_format_snippet_only() { let source = "This is line 1\nThis is line 2"; let input = Level::ERROR - .message("") + .header("") .group(Group::new().element(Snippet::>::source(source).line_start(5402))); let expected = str![[r#" @@ -148,7 +148,7 @@ error: fn test_format_snippets_continuation() { let src_0 = "This is slice 1"; let src_1 = "This is slice 2"; - let input = Level::ERROR.message("").group( + let input = Level::ERROR.header("").group( Group::new() .element( Snippet::>::source(src_0) @@ -182,7 +182,7 @@ fn test_format_snippet_annotation_standalone() { let source = [line_1, line_2].join("\n"); // In line 2 let range = 22..24; - let input = Level::ERROR.message("").group( + let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(&source).line_start(5402).annotation( AnnotationKind::Context @@ -205,7 +205,7 @@ error: #[test] fn test_format_footer_title() { let input = Level::ERROR - .message("") + .header("") .group(Group::new().element(Level::ERROR.title("This __is__ a title"))); let expected = str![[r#" error: @@ -221,7 +221,7 @@ error: fn test_i26() { let source = "short"; let label = "label"; - let input = Level::ERROR.message("").group( + let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source).line_start(0).annotation( AnnotationKind::Primary @@ -238,7 +238,7 @@ fn test_i26() { fn test_source_content() { let source = "This is an example\nof content lines"; let input = Level::ERROR - .message("") + .header("") .group(Group::new().element(Snippet::>::source(source).line_start(56))); let expected = str![[r#" error: @@ -253,7 +253,7 @@ error: #[test] fn test_source_annotation_standalone_singleline() { let source = "tests"; - let input = Level::ERROR.message("").group( + let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -273,7 +273,7 @@ error: #[test] fn test_source_annotation_standalone_multiline() { let source = "tests"; - let input = Level::ERROR.message("").group( + let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -297,7 +297,7 @@ error: #[test] fn test_only_source() { let input = Level::ERROR - .message("") + .header("") .group(Group::new().element(Snippet::>::source("").origin("file.rs"))); let expected = str![[r#" error: @@ -312,7 +312,7 @@ error: fn test_anon_lines() { let source = "This is an example\nof content lines\n\nabc"; let input = Level::ERROR - .message("") + .header("") .group(Group::new().element(Snippet::>::source(source).line_start(56))); let expected = str![[r#" error: @@ -328,7 +328,7 @@ LL | abc #[test] fn issue_130() { - let input = Level::ERROR.message("dummy").group( + let input = Level::ERROR.header("dummy").group( Group::new().element( Snippet::source("foo\nbar\nbaz") .origin("file/path") @@ -356,7 +356,7 @@ fn unterminated_string_multiline() { a\" // ... "; - let input = Level::ERROR.message("").group( + let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -380,7 +380,7 @@ error: #[test] fn char_and_nl_annotate_char() { let source = "a\r\nb"; - let input = Level::ERROR.message("").group( + let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -403,7 +403,7 @@ error: #[test] fn char_eol_annotate_char() { let source = "a\r\nb"; - let input = Level::ERROR.message("").group( + let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -425,7 +425,7 @@ error: #[test] fn char_eol_annotate_char_double_width() { - let snippets = Level::ERROR.message("").group( + let snippets = Level::ERROR.header("").group( Group::new().element( Snippet::source("こん\r\nにちは\r\n世界") .origin("") @@ -450,7 +450,7 @@ error: #[test] fn annotate_eol() { let source = "a\r\nb"; - let input = Level::ERROR.message("").group( + let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -473,7 +473,7 @@ error: #[test] fn annotate_eol2() { let source = "a\r\nb"; - let input = Level::ERROR.message("").group( + let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -496,7 +496,7 @@ error: #[test] fn annotate_eol3() { let source = "a\r\nb"; - let input = Level::ERROR.message("").group( + let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -519,7 +519,7 @@ error: #[test] fn annotate_eol4() { let source = "a\r\nb"; - let input = Level::ERROR.message("").group( + let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -541,7 +541,7 @@ error: #[test] fn annotate_eol_double_width() { - let snippets = Level::ERROR.message("").group( + let snippets = Level::ERROR.header("").group( Group::new().element( Snippet::source("こん\r\nにちは\r\n世界") .origin("") @@ -566,7 +566,7 @@ error: #[test] fn multiline_eol_start() { let source = "a\r\nb"; - let input = Level::ERROR.message("").group( + let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -590,7 +590,7 @@ error: #[test] fn multiline_eol_start2() { let source = "a\r\nb"; - let input = Level::ERROR.message("").group( + let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -614,7 +614,7 @@ error: #[test] fn multiline_eol_start3() { let source = "a\nb"; - let input = Level::ERROR.message("").group( + let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -637,7 +637,7 @@ error: #[test] fn multiline_eol_start_double_width() { - let snippets = Level::ERROR.message("").group( + let snippets = Level::ERROR.header("").group( Group::new().element( Snippet::source("こん\r\nにちは\r\n世界") .origin("") @@ -663,7 +663,7 @@ error: #[test] fn multiline_eol_start_eol_end() { let source = "a\nb\nc"; - let input = Level::ERROR.message("").group( + let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -688,7 +688,7 @@ error: #[test] fn multiline_eol_start_eol_end2() { let source = "a\r\nb\r\nc"; - let input = Level::ERROR.message("").group( + let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -713,7 +713,7 @@ error: #[test] fn multiline_eol_start_eol_end3() { let source = "a\r\nb\r\nc"; - let input = Level::ERROR.message("").group( + let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -738,7 +738,7 @@ error: #[test] fn multiline_eol_start_eof_end() { let source = "a\r\nb"; - let input = Level::ERROR.message("").group( + let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -762,7 +762,7 @@ error: #[test] fn multiline_eol_start_eof_end_double_width() { let source = "ん\r\nに"; - let input = Level::ERROR.message("").group( + let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) .origin("file/path") @@ -786,7 +786,7 @@ error: #[test] fn two_single_line_same_line() { let source = r#"bar = { version = "0.1.0", optional = true }"#; - let input = Level::ERROR.message("unused optional dependency").group( + let input = Level::ERROR.header("unused optional dependency").group( Group::new().element( Snippet::source(source) .origin("Cargo.toml") @@ -823,7 +823,7 @@ this is another line so is this bar = { version = "0.1.0", optional = true } "#; - let input = Level::ERROR.message("unused optional dependency").group( + let input = Level::ERROR.header("unused optional dependency").group( Group::new().element( Snippet::source(source) .line_start(4) @@ -862,7 +862,7 @@ this is another line so is this bar = { version = "0.1.0", optional = true } "#; - let input = Level::ERROR.message("unused optional dependency").group( + let input = Level::ERROR.header("unused optional dependency").group( Group::new().element( Snippet::source(source) .line_start(4) @@ -910,7 +910,7 @@ so is this bar = { version = "0.1.0", optional = true } this is another line "#; - let input = Level::ERROR.message("unused optional dependency").group( + let input = Level::ERROR.header("unused optional dependency").group( Group::new().element( Snippet::source(source) .line_start(4) @@ -961,7 +961,7 @@ error: unused optional dependency #[test] fn origin_correct_start_line() { let source = "aaa\nbbb\nccc\nddd\n"; - let input = Level::ERROR.message("title").group( + let input = Level::ERROR.header("title").group( Group::new().element( Snippet::source(source) .origin("origin.txt") @@ -987,7 +987,7 @@ error: title #[test] fn origin_correct_mid_line() { let source = "aaa\nbbb\nccc\nddd\n"; - let input = Level::ERROR.message("title").group( + let input = Level::ERROR.header("title").group( Group::new().element( Snippet::source(source) .origin("origin.txt") @@ -1018,7 +1018,7 @@ error: title fn two_suggestions_same_span() { let source = r#" A.foo();"#; let input_new = Level::ERROR - .message("expected value, found enum `A`") + .header("expected value, found enum `A`") .id("E0423") .group( Group::new().element( @@ -1086,7 +1086,7 @@ fn main() { }"#; let input_new = Level::ERROR - .message("no method named `pick` found for struct `Chaenomeles` in the current scope") + .header("no method named `pick` found for struct `Chaenomeles` in the current scope") .id("E0599") .group( Group::new().element( @@ -1146,7 +1146,7 @@ fn single_line_non_overlapping_suggestions() { let source = r#" A.foo();"#; let input_new = Level::ERROR - .message("expected value, found enum `A`") + .header("expected value, found enum `A`") .id("E0423") .group( Group::new().element( @@ -1188,7 +1188,7 @@ LL + (A::Tuple()).bar(); fn single_line_non_overlapping_suggestions2() { let source = r#" ThisIsVeryLong.foo();"#; let input_new = Level::ERROR - .message("Found `ThisIsVeryLong`") + .header("Found `ThisIsVeryLong`") .id("E0423") .group( Group::new().element( @@ -1237,7 +1237,7 @@ fn multiple_replacements() { "#; let input_new = Level::ERROR - .message("cannot borrow `*self` as mutable because it is also borrowed as immutable") + .header("cannot borrow `*self` as mutable because it is also borrowed as immutable") .id("E0502") .group( Group::new().element( @@ -1321,7 +1321,7 @@ fn main() { }"#; let input_new = Level::ERROR - .message("cannot borrow `chars` as mutable more than once at a time") + .header("cannot borrow `chars` as mutable more than once at a time") .id("E0499") .group( Group::new().element( @@ -1405,7 +1405,7 @@ struct Foo { fn main() {}"#; let input_new = Level::ERROR - .message("failed to resolve: use of undeclared crate or module `st`") + .header("failed to resolve: use of undeclared crate or module `st`") .id("E0433") .group( Group::new().element( @@ -1487,7 +1487,7 @@ where fn main() {}"#; let input_new = Level::ERROR - .message("the size for values of type `T` cannot be known at compilation time") + .header("the size for values of type `T` cannot be known at compilation time") .id("E0277") .group( Group::new().element( @@ -1556,7 +1556,7 @@ and where fn main() {}"#; let input_new = Level::ERROR - .message("the size for values of type `T` cannot be known at compilation time") + .header("the size for values of type `T` cannot be known at compilation time") .id("E0277") .group(Group::new().element(Snippet::source(source) .line_start(1) @@ -1661,7 +1661,7 @@ zappy "#; let input_new = Level::ERROR - .message("the size for values of type `T` cannot be known at compilation time") + .header("the size for values of type `T` cannot be known at compilation time") .id("E0277") .group( Group::new() @@ -1729,7 +1729,7 @@ fn main() { "#; let input_new = Level::ERROR - .message("type mismatch resolving `>, ...>>, ...>>, ...> as Future>::Error == Foo`") + .header("type mismatch resolving `>, ...>>, ...>>, ...> as Future>::Error == Foo`") .id("E0271") .group(Group::new().element(Snippet::source(source) .line_start(4) @@ -1817,7 +1817,7 @@ fn main() { "#; let input_new = Level::ERROR - .message("type mismatch resolving `>, ...>>, ...>>, ...> as Future>::Error == Foo`") + .header("type mismatch resolving `>, ...>>, ...>>, ...> as Future>::Error == Foo`") .id("E0271") .group(Group::new().element(Snippet::source(source) .line_start(4) @@ -1970,7 +1970,7 @@ fn main() { "#; let input_new = Level::ERROR - .message("mismatched types") + .header("mismatched types") .id("E0308") .group(Group::new().element( Snippet::source(source) @@ -2054,7 +2054,7 @@ fn main() { "#; let input_new = Level::ERROR - .message("mismatched types") + .header("mismatched types") .id("E0308") .group(Group::new().element( Snippet::source(source) @@ -2122,7 +2122,7 @@ LL │ ┃ )>>) {} #[test] fn unicode_cut_handling() { let source = "version = \"0.1.0\"\n# Ensure that the spans from toml handle utf-8 correctly\nauthors = [\n { name = \"Z\u{351}\u{36b}\u{343}\u{36a}\u{302}\u{36b}\u{33d}\u{34f}\u{334}\u{319}\u{324}\u{31e}\u{349}\u{35a}\u{32f}\u{31e}\u{320}\u{34d}A\u{36b}\u{357}\u{334}\u{362}\u{335}\u{31c}\u{330}\u{354}L\u{368}\u{367}\u{369}\u{358}\u{320}G\u{311}\u{357}\u{30e}\u{305}\u{35b}\u{341}\u{334}\u{33b}\u{348}\u{34d}\u{354}\u{339}O\u{342}\u{30c}\u{30c}\u{358}\u{328}\u{335}\u{339}\u{33b}\u{31d}\u{333}\", email = 1 }\n]\n"; - let input = Level::ERROR.message("title").group( + let input = Level::ERROR.header("title").group( Group::new().element( Snippet::source(source) .fold(false) @@ -2148,7 +2148,7 @@ error: title fn unicode_cut_handling2() { let source = "/*这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。*/?"; let input = Level::ERROR - .message("expected item, found `?`") + .header("expected item, found `?`") .group( Group::new().element( Snippet::source(source) @@ -2175,7 +2175,7 @@ error: expected item, found `?` fn unicode_cut_handling3() { let source = "/*这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。*/?"; let input = Level::ERROR - .message("expected item, found `?`") + .header("expected item, found `?`") .group( Group::new().element( Snippet::source(source) @@ -2202,7 +2202,7 @@ error: expected item, found `?` fn unicode_cut_handling4() { let source = "/*aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa*/?"; let input = Level::ERROR - .message("expected item, found `?`") + .header("expected item, found `?`") .group( Group::new().element( Snippet::source(source) @@ -2234,7 +2234,7 @@ fn main() { //~^ ERROR mismatched types } "##; - let input = Level::ERROR.message("mismatched types").id("E0308").group( + let input = Level::ERROR.header("mismatched types").id("E0308").group( Group::new().element( Snippet::source(source) .origin("$DIR/non-whitespace-trimming-unicode.rs") @@ -2279,7 +2279,7 @@ fn main() { } "##; let input = Level::ERROR - .message("cannot add `&str` to `&str`") + .header("cannot add `&str` to `&str`") .id("E0369") .group( Group::new() @@ -2346,7 +2346,7 @@ fn foo() { "##; let bin_source = "�|�\u{0002}!5�cc\u{0015}\u{0002}�Ӻi��WWj�ȥ�'�}�\u{0012}�J�ȉ��W�\u{001e}O�@����\u{001c}w�V���LO����\u{0014}[ \u{0003}_�'���SQ�~ذ��ų&��-\t��lN~��!@␌ _#���kQ��h�\u{001d}�:�\u{001c}\u{0007}�"; let input = Level::ERROR - .message("couldn't read `$DIR/not-utf8.bin`: stream did not contain valid UTF-8") + .header("couldn't read `$DIR/not-utf8.bin`: stream did not contain valid UTF-8") .group( Group::new().element( Snippet::source(source) diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index 93860d0e..69986292 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -12,7 +12,7 @@ fn ends_on_col0() { fn foo() { } "#; - let input = Level::ERROR.message("foo").group( + let input = Level::ERROR.header("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -42,7 +42,7 @@ fn foo() { } "#; - let input = Level::ERROR.message("foo").group( + let input = Level::ERROR.header("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -74,7 +74,7 @@ fn foo() { X2 Y2 } "#; - let input = Level::ERROR.message("foo").group( + let input = Level::ERROR.header("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -117,7 +117,7 @@ fn foo() { Y1 X1 } "#; - let input = Level::ERROR.message("foo").group( + let input = Level::ERROR.header("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -161,7 +161,7 @@ fn foo() { X3 Y3 Z3 } "#; - let input = Level::ERROR.message("foo").group( + let input = Level::ERROR.header("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -205,7 +205,7 @@ fn foo() { X2 Y2 Z2 } "#; - let input = Level::ERROR.message("foo").group( + let input = Level::ERROR.header("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -252,7 +252,7 @@ fn foo() { X2 Y2 Z2 } "#; - let input = Level::ERROR.message("foo").group( + let input = Level::ERROR.header("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -300,7 +300,7 @@ fn foo() { X3 Y3 Z3 } "#; - let input = Level::ERROR.message("foo").group( + let input = Level::ERROR.header("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -350,7 +350,7 @@ fn foo() { X3 Y3 Z3 } "#; - let input = Level::ERROR.message("foo").group( + let input = Level::ERROR.header("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -394,7 +394,7 @@ fn foo() { X3 Y3 Z3 } "#; - let input = Level::ERROR.message("foo").group( + let input = Level::ERROR.header("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -437,7 +437,7 @@ fn foo() { a { b { c } d } } "#; - let input = Level::ERROR.message("foo").group( + let input = Level::ERROR.header("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -470,7 +470,7 @@ fn foo() { a { b { c } d } } "#; - let input = Level::ERROR.message("foo").group( + let input = Level::ERROR.header("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -502,7 +502,7 @@ fn foo() { a { b { c } d } } "#; - let input = Level::ERROR.message("foo").group( + let input = Level::ERROR.header("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -537,7 +537,7 @@ fn foo() { a { b { c } d } } "#; - let input = Level::ERROR.message("foo").group( + let input = Level::ERROR.header("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -571,7 +571,7 @@ fn foo() { a bc d } "#; - let input = Level::ERROR.message("foo").group( + let input = Level::ERROR.header("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -605,7 +605,7 @@ fn foo() { a { b { c } d } } "#; - let input = Level::ERROR.message("foo").group( + let input = Level::ERROR.header("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -633,7 +633,7 @@ fn foo() { a { b { c } d } } "#; - let input = Level::ERROR.message("foo").group( + let input = Level::ERROR.header("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -662,7 +662,7 @@ fn foo() { a { b { c } d } } "#; - let input = Level::ERROR.message("foo").group( + let input = Level::ERROR.header("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -701,7 +701,7 @@ fn foo() { a { b { c } d } } "#; - let input = Level::ERROR.message("foo").group( + let input = Level::ERROR.header("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -732,7 +732,7 @@ fn foo() { a { b { c } d } } "#; - let input = Level::ERROR.message("foo").group( + let input = Level::ERROR.header("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -772,7 +772,7 @@ fn foo() { X3 Y3 Z3 } "#; - let input = Level::ERROR.message("foo").group( + let input = Level::ERROR.header("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -832,7 +832,7 @@ fn foo() { X3 Y3 Z3 } "#; - let input = Level::ERROR.message("foo").group( + let input = Level::ERROR.header("foo").group( Group::new().element( Snippet::source(source) .line_start(1) @@ -887,7 +887,7 @@ fn issue_91334() { fn f(){||yield(((){), "#; let input = Level::ERROR - .message("this file contains an unclosed delimiter") + .header("this file contains an unclosed delimiter") .group( Group::new().element( Snippet::source(source) @@ -958,7 +958,7 @@ fn main() { } "#; let input = Level::ERROR - .message("`break` with value from a `while` loop") + .header("`break` with value from a `while` loop") .id("E0571") .group( Group::new().element( @@ -1168,7 +1168,7 @@ fn nsize() { "#; let input = Level::ERROR - .message("`V0usize` cannot be safely transmuted into `[usize; 2]`") + .header("`V0usize` cannot be safely transmuted into `[usize; 2]`") .id("E0277") .group( Group::new().element( @@ -1254,7 +1254,7 @@ fn main() { } "#; let input = Level::ERROR - .message("`&[u8; 0]` cannot be safely transmuted into `&[u16; 0]`") + .header("`&[u8; 0]` cannot be safely transmuted into `&[u16; 0]`") .id("E027s7") .group( Group::new().element( @@ -1323,7 +1323,7 @@ fn g() { fn main() {} "#; let input = Level::ERROR - .message("expected function, found `{integer}`") + .header("expected function, found `{integer}`") .id("E0618") .group( Group::new().element( @@ -1414,7 +1414,7 @@ macro_rules! outer_macro { outer_macro!(FirstStruct, FirstAttrStruct); "#; let input = Level::WARNING - .message("non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module") + .header("non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module") .group( Group::new() .element( @@ -1547,7 +1547,7 @@ macro_rules! inline { } "#; let input = Level::ERROR - .message("can't call method `pow` on ambiguous numeric type `{integer}`") + .header("can't call method `pow` on ambiguous numeric type `{integer}`") .id("E0689") .group( Group::new().element( @@ -1611,7 +1611,7 @@ fn main() {} "#; let input = Level::ERROR - .message("type annotations needed") + .header("type annotations needed") .id("E0282") .group( Group::new().element( @@ -1717,7 +1717,7 @@ fn main() {} "##; let input = Level::ERROR - .message( + .header( "non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered" ) .id("E0004") @@ -1819,7 +1819,7 @@ fn main() { } "#; let input = Level::ERROR - .message("the trait alias `EqAlias` is not dyn compatible") + .header("the trait alias `EqAlias` is not dyn compatible") .id("E0038") .group( Group::new().element( From a928524d03391efbc6952b09670737b84d6c8d8a Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 16 Apr 2025 16:11:38 -0500 Subject: [PATCH 180/293] refactor: Remove redundant re-export --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 021ed524..76836d0c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,5 +57,4 @@ pub fn normalize_untrusted_str(s: &str) -> String { pub use level::Level; #[doc(inline)] pub use renderer::Renderer; -pub use snippet::Padding; pub use snippet::*; From 21ca62eaf23d9fabd75ad787b9c8cde541d60213 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 16 Apr 2025 16:33:28 -0500 Subject: [PATCH 181/293] docs: Rename 'range' parameter to 'span' --- src/renderer/mod.rs | 14 +++++++------- src/renderer/source_map.rs | 18 +++++++++--------- src/snippet.rs | 24 ++++++++++++------------ 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index e5572e5e..be2abab4 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -1523,7 +1523,7 @@ impl Renderer { } if suggestion.origin != primary_origin { if let Some(origin) = suggestion.origin { - let (loc, _) = sm.span_to_locations(parts[0].range.clone()); + let (loc, _) = sm.span_to_locations(parts[0].span.clone()); // --> file.rs:line:col // | let arrow = self.file_start(); @@ -1563,8 +1563,8 @@ impl Renderer { row_num += 1; } - let file_lines = sm.span_to_lines(parts[0].range.clone()); - let (line_start, line_end) = sm.span_to_locations(parts[0].range.clone()); + let file_lines = sm.span_to_lines(parts[0].span.clone()); + let (line_start, line_end) = sm.span_to_locations(parts[0].span.clone()); let mut lines = complete.lines(); if lines.clone().next().is_none() { // Account for a suggestion to completely remove a line(s) with whitespace (#94192). @@ -1697,8 +1697,8 @@ impl Renderer { // already existing code, despite the colors and UI elements. // We special case `#[derive(_)]\n` and other attribute suggestions, because those // are the ones where context is most useful. - let file_lines = sm.span_to_lines(parts[0].range.end..parts[0].range.end); - let (lo, _) = sm.span_to_locations(parts[0].range.clone()); + let file_lines = sm.span_to_lines(parts[0].span.end..parts[0].span.end); + let (lo, _) = sm.span_to_locations(parts[0].span.clone()); let line_num = lo.line; if let Some(line) = sm.get_line(line_num) { let line = normalize_whitespace(line); @@ -1724,7 +1724,7 @@ impl Renderer { show_code_change { for part in parts { - let (span_start, span_end) = sm.span_to_locations(part.range.clone()); + let (span_start, span_end) = sm.span_to_locations(part.span.clone()); let span_start_pos = span_start.display; let span_end_pos = span_end.display; @@ -1764,7 +1764,7 @@ impl Renderer { let padding: usize = max_line_num_len + 3; for p in underline_start..underline_end { if matches!(show_code_change, DisplaySuggestion::Underline) - && is_different(sm, part.replacement, part.range.clone()) + && is_different(sm, part.replacement, part.span.clone()) { // If this is a replacement, underline with `~`, if this is an addition // underline with `+`. diff --git a/src/renderer/source_map.rs b/src/renderer/source_map.rs index 33fe1897..d014bb01 100644 --- a/src/renderer/source_map.rs +++ b/src/renderer/source_map.rs @@ -129,8 +129,8 @@ impl<'a> SourceMap<'a> { let source_len = self.source.len(); if let Some(bigger) = annotations.iter().find_map(|x| { // Allow highlighting one past the last character in the source. - if source_len + 1 < x.range.end { - Some(&x.range) + if source_len + 1 < x.span.end { + Some(&x.span) } else { None } @@ -150,13 +150,13 @@ impl<'a> SourceMap<'a> { let mut multiline_annotations = vec![]; for Annotation { - range, + span, label, kind, highlight_source, } in annotations { - let (lo, mut hi) = self.span_to_locations(range.clone()); + let (lo, mut hi) = self.span_to_locations(span.clone()); // Watch out for "empty spans". If we get a span like 6..6, we // want to just display a `^` at 6, so convert that to @@ -374,13 +374,13 @@ impl<'a> SourceMap<'a> { } // Assumption: all spans are in the same file, and all spans // are disjoint. Sort in ascending order. - patches.sort_by_key(|p| p.range.start); + patches.sort_by_key(|p| p.span.start); // Find the bounding span. - let Some(lo) = patches.iter().map(|p| p.range.start).min() else { + let Some(lo) = patches.iter().map(|p| p.span.start).min() else { return Vec::new(); }; - let Some(hi) = patches.iter().map(|p| p.range.end).max() else { + let Some(hi) = patches.iter().map(|p| p.span.end).max() else { return Vec::new(); }; @@ -410,7 +410,7 @@ impl<'a> SourceMap<'a> { // suggestion and snippet to look as if we just suggested to add // `"b"`, which is typically much easier for the user to understand. part.trim_trivial_replacements(self); - let (cur_lo, cur_hi) = self.span_to_locations(part.range.clone()); + let (cur_lo, cur_hi) = self.span_to_locations(part.span.clone()); if prev_hi.line == cur_lo.line { let mut count = push_trailing(&mut buf, prev_line, &prev_hi, Some(&cur_lo)); while count > 0 { @@ -454,7 +454,7 @@ impl<'a> SourceMap<'a> { _ => 1, }) .sum(); - if !is_different(self, part.replacement, part.range.clone()) { + if !is_different(self, part.replacement, part.span.clone()) { // Account for cases where we are suggesting the same code that's already // there. This shouldn't happen often, but in some cases for multipart // suggestions it's much easier to handle it here than in the origin. diff --git a/src/snippet.rs b/src/snippet.rs index bf22c5be..f37a0482 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -39,7 +39,7 @@ impl<'a> Message<'a> { let end = cause .markers .iter() - .map(|a| a.range.end) + .map(|a| a.span.end) .max() .unwrap_or(cause.source.len()) .min(cause.source.len()); @@ -50,7 +50,7 @@ impl<'a> Message<'a> { let end = suggestion .markers .iter() - .map(|a| a.range.end) + .map(|a| a.span.end) .max() .unwrap_or(suggestion.source.len()) .min(suggestion.source.len()); @@ -222,7 +222,7 @@ impl<'a> Snippet<'a, Patch<'a>> { #[derive(Clone, Debug)] pub struct Annotation<'a> { - pub(crate) range: Range, + pub(crate) span: Range, pub(crate) label: Option<&'a str>, pub(crate) kind: AnnotationKind, pub(crate) highlight_source: bool, @@ -254,7 +254,7 @@ pub enum AnnotationKind { impl AnnotationKind { pub fn span<'a>(self, span: Range) -> Annotation<'a> { Annotation { - range: span, + span, label: None, kind: self, highlight_source: false, @@ -268,7 +268,7 @@ impl AnnotationKind { #[derive(Clone, Debug)] pub struct Patch<'a> { - pub(crate) range: Range, + pub(crate) span: Range, pub(crate) replacement: &'a str, } @@ -276,8 +276,8 @@ impl<'a> Patch<'a> { /// Text passed to this function is considered "untrusted input", as such /// all text is passed through a normalization function. Pre-styled text is /// not allowed to be passed to this function. - pub fn new(range: Range, replacement: &'a str) -> Self { - Self { range, replacement } + pub fn new(span: Range, replacement: &'a str) -> Self { + Self { span, replacement } } pub(crate) fn is_addition(&self, sm: &SourceMap<'_>) -> bool { @@ -299,7 +299,7 @@ impl<'a> Patch<'a> { pub(crate) fn is_destructive_replacement(&self, sm: &SourceMap<'_>) -> bool { self.is_replacement(sm) && !sm - .span_to_snippet(self.range.clone()) + .span_to_snippet(self.span.clone()) // This should use `is_some_and` when our MSRV is >= 1.70 .map_or(false, |s| { as_substr(s.trim(), self.replacement.trim()).is_some() @@ -307,8 +307,8 @@ impl<'a> Patch<'a> { } fn replaces_meaningful_content(&self, sm: &SourceMap<'_>) -> bool { - sm.span_to_snippet(self.range.clone()) - .map_or(!self.range.is_empty(), |snippet| !snippet.trim().is_empty()) + sm.span_to_snippet(self.span.clone()) + .map_or(!self.span.is_empty(), |snippet| !snippet.trim().is_empty()) } /// Try to turn a replacement into an addition when the span that is being @@ -317,12 +317,12 @@ impl<'a> Patch<'a> { if self.replacement.is_empty() { return; } - let Some(snippet) = sm.span_to_snippet(self.range.clone()) else { + let Some(snippet) = sm.span_to_snippet(self.span.clone()) else { return; }; if let Some((prefix, substr, suffix)) = as_substr(snippet, self.replacement) { - self.range = self.range.start + prefix..self.range.end.saturating_sub(suffix); + self.span = self.span.start + prefix..self.span.end.saturating_sub(suffix); self.replacement = substr; } } From 66369feec323d89b8209e69ecdf365321a01ac47 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 16 Apr 2025 16:46:45 -0500 Subject: [PATCH 182/293] docs: Make an attempt --- src/level.rs | 20 ++++++++++++++ src/snippet.rs | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/src/level.rs b/src/level.rs index 3fd504de..87d1a9f6 100644 --- a/src/level.rs +++ b/src/level.rs @@ -1,33 +1,41 @@ +//! [`Level`] constants for easy importing + use crate::renderer::stylesheet::Stylesheet; use crate::snippet::{ERROR_TXT, HELP_TXT, INFO_TXT, NOTE_TXT, WARNING_TXT}; use crate::{Element, Group, Message, Title}; use anstyle::Style; +/// Default `error:` [`Level`] pub const ERROR: Level<'_> = Level { name: None, level: LevelInner::Error, }; +/// Default `warning:` [`Level`] pub const WARNING: Level<'_> = Level { name: None, level: LevelInner::Warning, }; +/// Default `info:` [`Level`] pub const INFO: Level<'_> = Level { name: None, level: LevelInner::Info, }; +/// Default `note:` [`Level`] pub const NOTE: Level<'_> = Level { name: None, level: LevelInner::Note, }; +/// Default `help:` [`Level`] pub const HELP: Level<'_> = Level { name: None, level: LevelInner::Help, }; +/// [`Message`] or [`Title`] severity level #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct Level<'a> { pub(crate) name: Option>, @@ -41,9 +49,13 @@ impl<'a> Level<'a> { pub const NOTE: Level<'a> = NOTE; pub const HELP: Level<'a> = HELP; + ///
+ /// /// Text passed to this function is considered "untrusted input", as such /// all text is passed through a normalization function. Pre-styled text is /// not allowed to be passed to this function. + /// + ///
pub fn text(self, text: Option<&'a str>) -> Level<'a> { Level { name: Some(text), @@ -53,9 +65,13 @@ impl<'a> Level<'a> { } impl<'a> Level<'a> { + ///
+ /// /// Text passed to this function is considered "untrusted input", as such /// all text is passed through a normalization function. Pre-styled text is /// not allowed to be passed to this function. + /// + ///
pub fn header(self, header: &'a str) -> Message<'a> { Message { id: None, @@ -67,10 +83,14 @@ impl<'a> Level<'a> { } } + ///
+ /// /// Text passed to this function is allowed to be pre-styled, as such all /// text is considered "trusted input" and has no normalizations applied to /// it. [`normalize_untrusted_str`](crate::normalize_untrusted_str) can be /// used to normalize untrusted text before it is passed to this function. + /// + ///
pub fn title(self, title: &'a str) -> Title<'a> { Title { level: self, diff --git a/src/snippet.rs b/src/snippet.rs index f37a0482..03bfe3dd 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -10,6 +10,7 @@ pub(crate) const INFO_TXT: &str = "info"; pub(crate) const NOTE_TXT: &str = "note"; pub(crate) const WARNING_TXT: &str = "warning"; +/// Top-level user message #[derive(Debug)] pub struct Message<'a> { pub(crate) id: Option<&'a str>, // for "correctness", could be sloppy and be on Title @@ -17,11 +18,19 @@ pub struct Message<'a> { } impl<'a> Message<'a> { + ///
+ /// + /// Text passed to this function is considered "untrusted input", as such + /// all text is passed through a normalization function. Pre-styled text is + /// not allowed to be passed to this function. + /// + ///
pub fn id(mut self, id: &'a str) -> Self { self.id = Some(id); self } + /// Add an [`Element`] container pub fn group(mut self, group: Group<'a>) -> Self { self.groups.push(group); self @@ -66,6 +75,7 @@ impl<'a> Message<'a> { } } +/// An [`Element`] container #[derive(Debug)] pub struct Group<'a> { pub(crate) elements: Vec>, @@ -97,6 +107,7 @@ impl<'a> Group<'a> { } } +/// A section of content within a [`Group`] #[derive(Debug)] #[non_exhaustive] pub enum Element<'a> { @@ -137,9 +148,13 @@ impl From for Element<'_> { } } +/// A whitespace [`Element`] in a [`Group`] #[derive(Debug)] pub struct Padding; +/// A text [`Element`] in a [`Group`] +/// +/// See [`Level::title`] to create this. #[derive(Debug)] pub struct Title<'a> { pub(crate) level: Level<'a>, @@ -154,6 +169,7 @@ impl Title<'_> { } } +/// A source view [`Element`] in a [`Group`] #[derive(Debug)] pub struct Snippet<'a, T> { pub(crate) origin: Option<&'a str>, @@ -164,9 +180,15 @@ pub struct Snippet<'a, T> { } impl<'a, T: Clone> Snippet<'a, T> { + /// The source code to be rendered + /// + ///
+ /// /// Text passed to this function is considered "untrusted input", as such /// all text is passed through a normalization function. Pre-styled text is /// not allowed to be passed to this function. + /// + ///
pub fn source(source: &'a str) -> Self { Self { origin: None, @@ -177,19 +199,28 @@ impl<'a, T: Clone> Snippet<'a, T> { } } + /// When manually [`fold`][Self::fold]ing, + /// the [`source`][Self::source]s line offset from the original start pub fn line_start(mut self, line_start: usize) -> Self { self.line_start = line_start; self } + /// The location of the [`source`][Self::source] (e.g. a path) + /// + ///
+ /// /// Text passed to this function is considered "untrusted input", as such /// all text is passed through a normalization function. Pre-styled text is /// not allowed to be passed to this function. + /// + ///
pub fn origin(mut self, origin: &'a str) -> Self { self.origin = Some(origin); self } + /// Hide lines without [`Annotation`]s pub fn fold(mut self, fold: bool) -> Self { self.fold = fold; self @@ -197,11 +228,13 @@ impl<'a, T: Clone> Snippet<'a, T> { } impl<'a> Snippet<'a, Annotation<'a>> { + /// Highlight and describe a span of text within the [`source`][Self::source] pub fn annotation(mut self, annotation: Annotation<'a>) -> Snippet<'a, Annotation<'a>> { self.markers.push(annotation); self } + /// Highlight and describe spans of text within the [`source`][Self::source] pub fn annotations(mut self, annotation: impl IntoIterator>) -> Self { self.markers.extend(annotation); self @@ -209,17 +242,22 @@ impl<'a> Snippet<'a, Annotation<'a>> { } impl<'a> Snippet<'a, Patch<'a>> { + /// Suggest to the user an edit to the [`source`][Self::source] pub fn patch(mut self, patch: Patch<'a>) -> Snippet<'a, Patch<'a>> { self.markers.push(patch); self } + /// Suggest to the user edits to the [`source`][Self::source] pub fn patches(mut self, patches: impl IntoIterator>) -> Self { self.markers.extend(patches); self } } +/// Highlighted and describe a span of text within a [`Snippet`] +/// +/// See [`AnnotationKind`] to create an annotation. #[derive(Clone, Debug)] pub struct Annotation<'a> { pub(crate) span: Range, @@ -229,20 +267,30 @@ pub struct Annotation<'a> { } impl<'a> Annotation<'a> { + /// Describe the reason the span is highlighted + /// + /// This will be styled according to the [`AnnotationKind`] + /// + ///
+ /// /// Text passed to this function is considered "untrusted input", as such /// all text is passed through a normalization function. Pre-styled text is /// not allowed to be passed to this function. + /// + ///
pub fn label(mut self, label: &'a str) -> Self { self.label = Some(label); self } + /// Style the source according to the [`AnnotationKind`] pub fn highlight_source(mut self, highlight_source: bool) -> Self { self.highlight_source = highlight_source; self } } +/// The category of the [`Annotation`] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum AnnotationKind { /// Color to [`Message`]'s [`Level`] @@ -266,6 +314,7 @@ impl AnnotationKind { } } +/// Suggested edit to the [`Snippet`] #[derive(Clone, Debug)] pub struct Patch<'a> { pub(crate) span: Range, @@ -273,9 +322,15 @@ pub struct Patch<'a> { } impl<'a> Patch<'a> { + /// Splice `replacement` into the [`Snippet`] at the `span` + /// + ///
+ /// /// Text passed to this function is considered "untrusted input", as such /// all text is passed through a normalization function. Pre-styled text is /// not allowed to be passed to this function. + /// + ///
pub fn new(span: Range, replacement: &'a str) -> Self { Self { span, replacement } } @@ -328,6 +383,7 @@ impl<'a> Patch<'a> { } } +/// The location of the [`Snippet`] (e.g. a path) #[derive(Clone, Debug)] pub struct Origin<'a> { pub(crate) origin: &'a str, @@ -338,9 +394,13 @@ pub struct Origin<'a> { } impl<'a> Origin<'a> { + ///
+ /// /// Text passed to this function is considered "untrusted input", as such /// all text is passed through a normalization function. Pre-styled text is /// not allowed to be passed to this function. + /// + ///
pub fn new(origin: &'a str) -> Self { Self { origin, @@ -351,11 +411,17 @@ impl<'a> Origin<'a> { } } + /// Set the default line number to display + /// + /// Otherwise this will be inferred from the primary [`Annotation`] pub fn line(mut self, line: usize) -> Self { self.line = Some(line); self } + /// Set the default column to display + /// + /// Otherwise this will be inferred from the primary [`Annotation`] pub fn char_column(mut self, char_column: usize) -> Self { self.char_column = Some(char_column); self @@ -366,9 +432,15 @@ impl<'a> Origin<'a> { self } + /// Like [`Annotation::label`], but when there is no source + /// + ///
+ /// /// Text passed to this function is considered "untrusted input", as such /// all text is passed through a normalization function. Pre-styled text is /// not allowed to be passed to this function. + /// + ///
pub fn label(mut self, label: &'a str) -> Self { self.label = Some(label); self From 17eb40e020e119d8f9bf20987050015d761d54c7 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Sat, 26 Apr 2025 06:29:03 -0600 Subject: [PATCH 183/293] test(fixtures): Move to source code based color tests --- Cargo.lock | 327 +----------------- Cargo.toml | 6 - tests/color/ann_eof.rs | 18 + .../ann_eof.svg => color/ann_eof.term.svg} | 0 tests/color/ann_insertion.rs | 18 + .../ann_insertion.term.svg} | 0 tests/color/ann_multiline.rs | 31 ++ .../ann_multiline.term.svg} | 0 tests/color/ann_multiline2.rs | 31 ++ .../ann_multiline2.term.svg} | 0 tests/color/ann_removed_nl.rs | 18 + .../ann_removed_nl.term.svg} | 0 tests/color/ensure_emoji_highlight_width.rs | 24 ++ .../ensure_emoji_highlight_width.term.svg} | 0 tests/color/fold_ann_multiline.rs | 50 +++ .../fold_ann_multiline.term.svg} | 0 tests/color/fold_bad_origin_line.rs | 24 ++ .../fold_bad_origin_line.term.svg} | 0 tests/color/fold_leading.rs | 35 ++ .../fold_leading.term.svg} | 0 tests/color/fold_trailing.rs | 34 ++ .../fold_trailing.term.svg} | 0 tests/color/issue_9.rs | 31 ++ .../issue_9.svg => color/issue_9.term.svg} | 0 tests/color/main.rs | 16 + tests/color/multiple_annotations.rs | 42 +++ .../multiple_annotations.term.svg} | 0 tests/color/simple.rs | 34 ++ .../simple.svg => color/simple.term.svg} | 0 tests/color/strip_line.rs | 24 ++ .../strip_line.term.svg} | 0 tests/color/strip_line_char.rs | 24 ++ .../strip_line_char.term.svg} | 0 tests/color/strip_line_non_ws.rs | 30 ++ .../strip_line_non_ws.term.svg} | 0 tests/fixtures/color/ann_eof.toml | 15 - tests/fixtures/color/ann_insertion.toml | 15 - tests/fixtures/color/ann_multiline.toml | 21 -- tests/fixtures/color/ann_multiline2.toml | 21 -- tests/fixtures/color/ann_removed_nl.toml | 15 - .../color/ensure-emoji-highlight-width.toml | 18 - tests/fixtures/color/fold_ann_multiline.toml | 41 --- .../fixtures/color/fold_bad_origin_line.toml | 20 -- tests/fixtures/color/fold_leading.toml | 29 -- tests/fixtures/color/fold_trailing.toml | 28 -- tests/fixtures/color/issue_9.toml | 34 -- .../fixtures/color/multiple_annotations.toml | 33 -- tests/fixtures/color/simple.toml | 23 -- tests/fixtures/color/strip_line.toml | 19 - tests/fixtures/color/strip_line_char.toml | 19 - tests/fixtures/color/strip_line_non_ws.toml | 27 -- tests/fixtures/deserialize.rs | 217 ------------ tests/fixtures/main.rs | 42 --- 53 files changed, 489 insertions(+), 965 deletions(-) create mode 100644 tests/color/ann_eof.rs rename tests/{fixtures/color/ann_eof.svg => color/ann_eof.term.svg} (100%) create mode 100644 tests/color/ann_insertion.rs rename tests/{fixtures/color/ann_insertion.svg => color/ann_insertion.term.svg} (100%) create mode 100644 tests/color/ann_multiline.rs rename tests/{fixtures/color/ann_multiline.svg => color/ann_multiline.term.svg} (100%) create mode 100644 tests/color/ann_multiline2.rs rename tests/{fixtures/color/ann_multiline2.svg => color/ann_multiline2.term.svg} (100%) create mode 100644 tests/color/ann_removed_nl.rs rename tests/{fixtures/color/ann_removed_nl.svg => color/ann_removed_nl.term.svg} (100%) create mode 100644 tests/color/ensure_emoji_highlight_width.rs rename tests/{fixtures/color/ensure-emoji-highlight-width.svg => color/ensure_emoji_highlight_width.term.svg} (100%) create mode 100644 tests/color/fold_ann_multiline.rs rename tests/{fixtures/color/fold_ann_multiline.svg => color/fold_ann_multiline.term.svg} (100%) create mode 100644 tests/color/fold_bad_origin_line.rs rename tests/{fixtures/color/fold_bad_origin_line.svg => color/fold_bad_origin_line.term.svg} (100%) create mode 100644 tests/color/fold_leading.rs rename tests/{fixtures/color/fold_leading.svg => color/fold_leading.term.svg} (100%) create mode 100644 tests/color/fold_trailing.rs rename tests/{fixtures/color/fold_trailing.svg => color/fold_trailing.term.svg} (100%) create mode 100644 tests/color/issue_9.rs rename tests/{fixtures/color/issue_9.svg => color/issue_9.term.svg} (100%) create mode 100644 tests/color/main.rs create mode 100644 tests/color/multiple_annotations.rs rename tests/{fixtures/color/multiple_annotations.svg => color/multiple_annotations.term.svg} (100%) create mode 100644 tests/color/simple.rs rename tests/{fixtures/color/simple.svg => color/simple.term.svg} (100%) create mode 100644 tests/color/strip_line.rs rename tests/{fixtures/color/strip_line.svg => color/strip_line.term.svg} (100%) create mode 100644 tests/color/strip_line_char.rs rename tests/{fixtures/color/strip_line_char.svg => color/strip_line_char.term.svg} (100%) create mode 100644 tests/color/strip_line_non_ws.rs rename tests/{fixtures/color/strip_line_non_ws.svg => color/strip_line_non_ws.term.svg} (100%) delete mode 100644 tests/fixtures/color/ann_eof.toml delete mode 100644 tests/fixtures/color/ann_insertion.toml delete mode 100644 tests/fixtures/color/ann_multiline.toml delete mode 100644 tests/fixtures/color/ann_multiline2.toml delete mode 100644 tests/fixtures/color/ann_removed_nl.toml delete mode 100644 tests/fixtures/color/ensure-emoji-highlight-width.toml delete mode 100644 tests/fixtures/color/fold_ann_multiline.toml delete mode 100644 tests/fixtures/color/fold_bad_origin_line.toml delete mode 100644 tests/fixtures/color/fold_leading.toml delete mode 100644 tests/fixtures/color/fold_trailing.toml delete mode 100644 tests/fixtures/color/issue_9.toml delete mode 100644 tests/fixtures/color/multiple_annotations.toml delete mode 100644 tests/fixtures/color/simple.toml delete mode 100644 tests/fixtures/color/strip_line.toml delete mode 100644 tests/fixtures/color/strip_line_char.toml delete mode 100644 tests/fixtures/color/strip_line_non_ws.toml delete mode 100644 tests/fixtures/deserialize.rs delete mode 100644 tests/fixtures/main.rs diff --git a/Cargo.lock b/Cargo.lock index 8838e31a..dd4fd20b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,21 +2,12 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - [[package]] name = "annotate-snippets" version = "0.11.5" dependencies = [ "annotate-snippets", - "anstream 0.6.18", + "anstream", "anstyle", "difference", "divan", @@ -24,26 +15,9 @@ dependencies = [ "memchr", "serde", "snapbox", - "toml", - "tryfn", "unicode-width 0.2.0", ] -[[package]] -name = "anstream" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon 1.0.2", - "colorchoice", - "is-terminal", - "utf8parse", -] - [[package]] name = "anstream" version = "0.6.18" @@ -53,7 +27,7 @@ dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", - "anstyle-wincon 3.0.6", + "anstyle-wincon", "colorchoice", "is_terminal_polyfill", "utf8parse", @@ -98,23 +72,13 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbbf0bf947d663010f0b4132f28ca08da9151f3b9035fa7578a38de521c1d1aa" dependencies = [ - "anstream 0.6.18", + "anstream", "anstyle", "anstyle-lossy", "html-escape", "unicode-width 0.1.13", ] -[[package]] -name = "anstyle-wincon" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c" -dependencies = [ - "anstyle", - "windows-sys 0.48.0", -] - [[package]] name = "anstyle-wincon" version = "3.0.6" @@ -131,16 +95,6 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "bstr" -version = "1.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" -dependencies = [ - "memchr", - "serde", -] - [[package]] name = "cfg-if" version = "1.0.0" @@ -154,8 +108,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb690e81c7840c0d7aade59f242ea3b41b9bc27bcd5997890e7702ae4b32e487" dependencies = [ "clap_builder", - "clap_derive", - "once_cell", ] [[package]] @@ -164,25 +116,11 @@ version = "4.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ed2e96bc16d8d740f6f48d663eddf4b8a0983e79210fd55479b7bcd0a69860e" dependencies = [ - "anstream 0.3.2", "anstyle", "clap_lex", - "strsim", "terminal_size", ] -[[package]] -name = "clap_derive" -version = "4.3.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "clap_lex" version = "0.5.0" @@ -232,12 +170,6 @@ dependencies = [ "syn", ] -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - [[package]] name = "errno" version = "0.3.9" @@ -248,15 +180,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "escape8259" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4f4911e3666fcd7826997b4745c8224295a6f3072f1418c3067b97a67557ee" -dependencies = [ - "rustversion", -] - [[package]] name = "escargot" version = "0.5.13" @@ -275,31 +198,6 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" -[[package]] -name = "globset" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" -dependencies = [ - "aho-corasick", - "bstr", - "log", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "hashbrown" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "hermit-abi" version = "0.3.9" @@ -315,33 +213,6 @@ dependencies = [ "utf8-width", ] -[[package]] -name = "ignore" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" -dependencies = [ - "globset", - "lazy_static", - "log", - "memchr", - "regex", - "same-file", - "thread_local", - "walkdir", - "winapi-util", -] - -[[package]] -name = "indexmap" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" -dependencies = [ - "equivalent", - "hashbrown", -] - [[package]] name = "io-lifetimes" version = "1.0.11" @@ -379,30 +250,12 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - [[package]] name = "libc" version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" -[[package]] -name = "libtest-mimic" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc0bda45ed5b3a2904262c1bb91e526127aa70e7ef3758aba2ef93cf896b9b58" -dependencies = [ - "clap", - "escape8259", - "termcolor", - "threadpool", -] - [[package]] name = "linux-raw-sys" version = "0.3.8" @@ -427,16 +280,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "once_cell" version = "1.19.0" @@ -471,41 +314,12 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "regex" -version = "1.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - [[package]] name = "regex-lite" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" -[[package]] -name = "regex-syntax" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" - [[package]] name = "rustix" version = "0.37.27" @@ -520,27 +334,12 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "rustversion" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" - [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - [[package]] name = "serde" version = "1.0.219" @@ -572,15 +371,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_spanned" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" -dependencies = [ - "serde", -] - [[package]] name = "similar" version = "2.5.0" @@ -593,7 +383,7 @@ version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96dcfc4581e3355d70ac2ee14cfdf81dce3d85c85f1ed9e2c1d3013f53b3436b" dependencies = [ - "anstream 0.6.18", + "anstream", "anstyle", "anstyle-svg", "escargot", @@ -613,15 +403,9 @@ version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16569f53ca23a41bb6f62e0a5084aa1661f4814a67fa33696a79073e03a664af" dependencies = [ - "anstream 0.6.18", + "anstream", ] -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - [[package]] name = "syn" version = "2.0.86" @@ -633,15 +417,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - [[package]] name = "terminal_size" version = "0.2.6" @@ -652,70 +427,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "thread_local" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "threadpool" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" -dependencies = [ - "num_cpus", -] - -[[package]] -name = "toml" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.22.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - -[[package]] -name = "tryfn" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fe242ee9e646acec9ab73a5c540e8543ed1b107f0ce42be831e0775d423c396" -dependencies = [ - "ignore", - "libtest-mimic", - "snapbox", -] - [[package]] name = "unicode-ident" version = "1.0.12" @@ -755,25 +466,6 @@ dependencies = [ "libc", ] -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "winapi-util" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" -dependencies = [ - "windows-sys 0.52.0", -] - [[package]] name = "windows-sys" version = "0.48.0" @@ -921,12 +613,3 @@ name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "winnow" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1" -dependencies = [ - "memchr", -] diff --git a/Cargo.toml b/Cargo.toml index f30c64f9..4a8adf00 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -128,17 +128,11 @@ divan = "0.1.14" glob = "0.3.1" serde = { version = "1.0.199", features = ["derive"] } snapbox = { version = "0.6.0", features = ["diff", "term-svg", "cmd", "examples"] } -toml = "0.8.0" -tryfn = "0.2.1" [[bench]] name = "bench" harness = false -[[test]] -name = "fixtures" -harness = false - [features] default = [] simd = ["memchr"] diff --git a/tests/color/ann_eof.rs b/tests/color/ann_eof.rs new file mode 100644 index 00000000..00e34b16 --- /dev/null +++ b/tests/color/ann_eof.rs @@ -0,0 +1,18 @@ +use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; + +use snapbox::{assert_data_eq, file}; + +#[test] +fn case() { + let input = Level::ERROR.header("expected `.`, `=`").group( + Group::new().element( + Snippet::source("asdf") + .origin("Cargo.toml") + .line_start(1) + .annotation(AnnotationKind::Primary.span(4..4).label("")), + ), + ); + let expected = file!["ann_eof.term.svg"]; + let renderer = Renderer::styled(); + assert_data_eq!(renderer.render(input), expected); +} diff --git a/tests/fixtures/color/ann_eof.svg b/tests/color/ann_eof.term.svg similarity index 100% rename from tests/fixtures/color/ann_eof.svg rename to tests/color/ann_eof.term.svg diff --git a/tests/color/ann_insertion.rs b/tests/color/ann_insertion.rs new file mode 100644 index 00000000..802a0c78 --- /dev/null +++ b/tests/color/ann_insertion.rs @@ -0,0 +1,18 @@ +use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; + +use snapbox::{assert_data_eq, file}; + +#[test] +fn case() { + let input = Level::ERROR.header("expected `.`, `=`").group( + Group::new().element( + Snippet::source("asf") + .origin("Cargo.toml") + .line_start(1) + .annotation(AnnotationKind::Primary.span(2..2).label("'d' belongs here")), + ), + ); + let expected = file!["ann_insertion.term.svg"]; + let renderer = Renderer::styled(); + assert_data_eq!(renderer.render(input), expected); +} diff --git a/tests/fixtures/color/ann_insertion.svg b/tests/color/ann_insertion.term.svg similarity index 100% rename from tests/fixtures/color/ann_insertion.svg rename to tests/color/ann_insertion.term.svg diff --git a/tests/color/ann_multiline.rs b/tests/color/ann_multiline.rs new file mode 100644 index 00000000..4b561ed3 --- /dev/null +++ b/tests/color/ann_multiline.rs @@ -0,0 +1,31 @@ +use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; + +use snapbox::{assert_data_eq, file}; + +#[test] +fn case() { + let source = r#" if let DisplayLine::Source { + ref mut inline_marks, + } = body[body_idx] +"#; + + let input = Level::ERROR + .header("pattern does not mention fields `lineno`, `content`") + .id("E0027") + .group( + Group::new().element( + Snippet::source(source) + .origin("src/display_list.rs") + .line_start(139) + .fold(false) + .annotation( + AnnotationKind::Primary + .span(31..128) + .label("missing fields `lineno`, `content`"), + ), + ), + ); + let expected = file!["ann_multiline.term.svg"]; + let renderer = Renderer::styled(); + assert_data_eq!(renderer.render(input), expected); +} diff --git a/tests/fixtures/color/ann_multiline.svg b/tests/color/ann_multiline.term.svg similarity index 100% rename from tests/fixtures/color/ann_multiline.svg rename to tests/color/ann_multiline.term.svg diff --git a/tests/color/ann_multiline2.rs b/tests/color/ann_multiline2.rs new file mode 100644 index 00000000..9996fa97 --- /dev/null +++ b/tests/color/ann_multiline2.rs @@ -0,0 +1,31 @@ +use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; + +use snapbox::{assert_data_eq, file}; + +#[test] +fn case() { + let source = r#"This is an example +of an edge case of an annotation overflowing +to exactly one character on next line. +"#; + + let input = Level::ERROR + .header("spacing error found") + .id("E####") + .group( + Group::new().element( + Snippet::source(source) + .origin("foo.txt") + .line_start(26) + .fold(false) + .annotation( + AnnotationKind::Primary + .span(11..19) + .label("this should not be on separate lines"), + ), + ), + ); + let expected = file!["ann_multiline2.term.svg"]; + let renderer = Renderer::styled(); + assert_data_eq!(renderer.render(input), expected); +} diff --git a/tests/fixtures/color/ann_multiline2.svg b/tests/color/ann_multiline2.term.svg similarity index 100% rename from tests/fixtures/color/ann_multiline2.svg rename to tests/color/ann_multiline2.term.svg diff --git a/tests/color/ann_removed_nl.rs b/tests/color/ann_removed_nl.rs new file mode 100644 index 00000000..45a64626 --- /dev/null +++ b/tests/color/ann_removed_nl.rs @@ -0,0 +1,18 @@ +use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; + +use snapbox::{assert_data_eq, file}; + +#[test] +fn case() { + let input = Level::ERROR.header("expected `.`, `=`").group( + Group::new().element( + Snippet::source("asdf") + .origin("Cargo.toml") + .line_start(1) + .annotation(AnnotationKind::Primary.span(4..5).label("")), + ), + ); + let expected = file!["ann_removed_nl.term.svg"]; + let renderer = Renderer::styled(); + assert_data_eq!(renderer.render(input), expected); +} diff --git a/tests/fixtures/color/ann_removed_nl.svg b/tests/color/ann_removed_nl.term.svg similarity index 100% rename from tests/fixtures/color/ann_removed_nl.svg rename to tests/color/ann_removed_nl.term.svg diff --git a/tests/color/ensure_emoji_highlight_width.rs b/tests/color/ensure_emoji_highlight_width.rs new file mode 100644 index 00000000..b2397845 --- /dev/null +++ b/tests/color/ensure_emoji_highlight_width.rs @@ -0,0 +1,24 @@ +use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; + +use snapbox::{assert_data_eq, file}; + +#[test] +fn case() { + let source = r#""haha this isn't a valid name 🐛" = { package = "libc", version = "0.1" } +"#; + + let input = Level::ERROR.header("invalid character ` ` in package name: `haha this isn't a valid name 🐛`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters)") + .group( + Group::new() + .element( + Snippet::source(source) + .origin("") + .line_start(7) + .annotation(AnnotationKind::Primary.span(0..35).label("")) + ) + ) +; + let expected = file!["ensure_emoji_highlight_width.term.svg"]; + let renderer = Renderer::styled(); + assert_data_eq!(renderer.render(input), expected); +} diff --git a/tests/fixtures/color/ensure-emoji-highlight-width.svg b/tests/color/ensure_emoji_highlight_width.term.svg similarity index 100% rename from tests/fixtures/color/ensure-emoji-highlight-width.svg rename to tests/color/ensure_emoji_highlight_width.term.svg diff --git a/tests/color/fold_ann_multiline.rs b/tests/color/fold_ann_multiline.rs new file mode 100644 index 00000000..3995b686 --- /dev/null +++ b/tests/color/fold_ann_multiline.rs @@ -0,0 +1,50 @@ +use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; + +use snapbox::{assert_data_eq, file}; + +#[test] +fn case() { + let source = r#") -> Option { + for ann in annotations { + match (ann.range.0, ann.range.1) { + (None, None) => continue, + (Some(start), Some(end)) if start > end_index || end < start_index => continue, + (Some(start), Some(end)) if start >= start_index && end <= end_index => { + let label = if let Some(ref label) = ann.label { + format!(" {}", label) + } else { + String::from("") + }; + + return Some(format!( + "{}{}{}", + " ".repeat(start - start_index), + "^".repeat(end - start), + label + )); + } + _ => continue, + } + } +"#; + + let input = Level::ERROR.header("mismatched types").id("E0308").group( + Group::new().element( + Snippet::source(source) + .origin("src/format.rs") + .line_start(51) + .fold(true) + .annotation(AnnotationKind::Context.span(5..19).label( + "expected `std::option::Option` because of return type", + )) + .annotation( + AnnotationKind::Primary + .span(22..766) + .label("expected enum `std::option::Option`, found ()"), + ), + ), + ); + let expected = file!["fold_ann_multiline.term.svg"]; + let renderer = Renderer::styled(); + assert_data_eq!(renderer.render(input), expected); +} diff --git a/tests/fixtures/color/fold_ann_multiline.svg b/tests/color/fold_ann_multiline.term.svg similarity index 100% rename from tests/fixtures/color/fold_ann_multiline.svg rename to tests/color/fold_ann_multiline.term.svg diff --git a/tests/color/fold_bad_origin_line.rs b/tests/color/fold_bad_origin_line.rs new file mode 100644 index 00000000..1a21a5ef --- /dev/null +++ b/tests/color/fold_bad_origin_line.rs @@ -0,0 +1,24 @@ +use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; + +use snapbox::{assert_data_eq, file}; + +#[test] +fn case() { + let source = r#" + +invalid syntax +"#; + + let input = Level::ERROR.header("").group( + Group::new().element( + Snippet::source(source) + .origin("path/to/error.rs") + .line_start(1) + .fold(true) + .annotation(AnnotationKind::Context.span(2..16).label("error here")), + ), + ); + let expected = file!["fold_bad_origin_line.term.svg"]; + let renderer = Renderer::styled(); + assert_data_eq!(renderer.render(input), expected); +} diff --git a/tests/fixtures/color/fold_bad_origin_line.svg b/tests/color/fold_bad_origin_line.term.svg similarity index 100% rename from tests/fixtures/color/fold_bad_origin_line.svg rename to tests/color/fold_bad_origin_line.term.svg diff --git a/tests/color/fold_leading.rs b/tests/color/fold_leading.rs new file mode 100644 index 00000000..93ba4992 --- /dev/null +++ b/tests/color/fold_leading.rs @@ -0,0 +1,35 @@ +use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; + +use snapbox::{assert_data_eq, file}; + +#[test] +fn case() { + let source = r#"[workspace] + +[package] +name = "hello" +version = "1.0.0" +license = "MIT" +rust-version = "1.70" +edition = "2021" + +[lints] +workspace = 20 +"#; + + let input = Level::ERROR + .header("invalid type: integer `20`, expected a bool") + .id("E0308") + .group( + Group::new().element( + Snippet::source(source) + .origin("Cargo.toml") + .line_start(1) + .fold(true) + .annotation(AnnotationKind::Primary.span(132..134).label("")), + ), + ); + let expected = file!["fold_leading.term.svg"]; + let renderer = Renderer::styled(); + assert_data_eq!(renderer.render(input), expected); +} diff --git a/tests/fixtures/color/fold_leading.svg b/tests/color/fold_leading.term.svg similarity index 100% rename from tests/fixtures/color/fold_leading.svg rename to tests/color/fold_leading.term.svg diff --git a/tests/color/fold_trailing.rs b/tests/color/fold_trailing.rs new file mode 100644 index 00000000..f86ade78 --- /dev/null +++ b/tests/color/fold_trailing.rs @@ -0,0 +1,34 @@ +use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; + +use snapbox::{assert_data_eq, file}; + +#[test] +fn case() { + let source = r#"lints = 20 + +[workspace] + +[package] +name = "hello" +version = "1.0.0" +license = "MIT" +rust-version = "1.70" +edition = "2021" +"#; + + let input = Level::ERROR + .header("invalid type: integer `20`, expected a lints table") + .id("E0308") + .group( + Group::new().element( + Snippet::source(source) + .origin("Cargo.toml") + .line_start(1) + .fold(true) + .annotation(AnnotationKind::Primary.span(8..10).label("")), + ), + ); + let expected = file!["fold_trailing.term.svg"]; + let renderer = Renderer::styled(); + assert_data_eq!(renderer.render(input), expected); +} diff --git a/tests/fixtures/color/fold_trailing.svg b/tests/color/fold_trailing.term.svg similarity index 100% rename from tests/fixtures/color/fold_trailing.svg rename to tests/color/fold_trailing.term.svg diff --git a/tests/color/issue_9.rs b/tests/color/issue_9.rs new file mode 100644 index 00000000..2accd2f2 --- /dev/null +++ b/tests/color/issue_9.rs @@ -0,0 +1,31 @@ +use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; + +use snapbox::{assert_data_eq, file}; + +#[test] +fn case() { + let input = Level::ERROR.header("expected one of `.`, `;`, `?`, or an operator, found `for`") + .group( + Group::new() + .element( + Snippet::source("let x = vec![1];") + .origin("/code/rust/src/test/ui/annotate-snippet/suggestion.rs") + .line_start(4) + .annotation(AnnotationKind::Context.span(4..5).label("move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait")) + ) + .element( + Snippet::source("let y = x;") + .line_start(7) + .annotation(AnnotationKind::Context.span(8..9).label("value moved here")) + ) + .element( + Snippet::source("x;") + .line_start(9) + .annotation(AnnotationKind::Primary.span(0..1).label("value used here after move")) + ) + ) +; + let expected = file!["issue_9.term.svg"]; + let renderer = Renderer::styled(); + assert_data_eq!(renderer.render(input), expected); +} diff --git a/tests/fixtures/color/issue_9.svg b/tests/color/issue_9.term.svg similarity index 100% rename from tests/fixtures/color/issue_9.svg rename to tests/color/issue_9.term.svg diff --git a/tests/color/main.rs b/tests/color/main.rs new file mode 100644 index 00000000..f954bb7a --- /dev/null +++ b/tests/color/main.rs @@ -0,0 +1,16 @@ +mod ann_eof; +mod ann_insertion; +mod ann_multiline; +mod ann_multiline2; +mod ann_removed_nl; +mod ensure_emoji_highlight_width; +mod fold_ann_multiline; +mod fold_bad_origin_line; +mod fold_leading; +mod fold_trailing; +mod issue_9; +mod multiple_annotations; +mod simple; +mod strip_line; +mod strip_line_char; +mod strip_line_non_ws; diff --git a/tests/color/multiple_annotations.rs b/tests/color/multiple_annotations.rs new file mode 100644 index 00000000..b568b919 --- /dev/null +++ b/tests/color/multiple_annotations.rs @@ -0,0 +1,42 @@ +use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; + +use snapbox::{assert_data_eq, file}; + +#[test] +fn case() { + let source = r#"fn add_title_line(result: &mut Vec, main_annotation: Option<&Annotation>) { + if let Some(annotation) = main_annotation { + result.push(format_title_line( + &annotation.annotation_type, + None, + &annotation.label, + )); + } +} +"#; + + let input = Level::ERROR.header("").group( + Group::new().element( + Snippet::source(source) + .line_start(96) + .annotation( + AnnotationKind::Primary + .span(100..110) + .label("Variable defined here"), + ) + .annotation( + AnnotationKind::Primary + .span(184..194) + .label("Referenced here"), + ) + .annotation( + AnnotationKind::Primary + .span(243..253) + .label("Referenced again here"), + ), + ), + ); + let expected = file!["multiple_annotations.term.svg"]; + let renderer = Renderer::styled(); + assert_data_eq!(renderer.render(input), expected); +} diff --git a/tests/fixtures/color/multiple_annotations.svg b/tests/color/multiple_annotations.term.svg similarity index 100% rename from tests/fixtures/color/multiple_annotations.svg rename to tests/color/multiple_annotations.term.svg diff --git a/tests/color/simple.rs b/tests/color/simple.rs new file mode 100644 index 00000000..35e83d38 --- /dev/null +++ b/tests/color/simple.rs @@ -0,0 +1,34 @@ +use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; + +use snapbox::{assert_data_eq, file}; + +#[test] +fn case() { + let source = r#" }) + + for line in &self.body { +"#; + + let input = Level::ERROR + .header("expected one of `.`, `;`, `?`, or an operator, found `for`") + .group( + Group::new().element( + Snippet::source(source) + .origin("src/format_color.rs") + .line_start(169) + .annotation( + AnnotationKind::Primary + .span(20..23) + .label("unexpected token"), + ) + .annotation( + AnnotationKind::Context + .span(10..11) + .label("expected one of `.`, `;`, `?`, or an operator here"), + ), + ), + ); + let expected = file!["simple.term.svg"]; + let renderer = Renderer::styled(); + assert_data_eq!(renderer.render(input), expected); +} diff --git a/tests/fixtures/color/simple.svg b/tests/color/simple.term.svg similarity index 100% rename from tests/fixtures/color/simple.svg rename to tests/color/simple.term.svg diff --git a/tests/color/strip_line.rs b/tests/color/strip_line.rs new file mode 100644 index 00000000..fd1ba588 --- /dev/null +++ b/tests/color/strip_line.rs @@ -0,0 +1,24 @@ +use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; + +use snapbox::{assert_data_eq, file}; + +#[test] +fn case() { + let source = r#" let _: () = 42;"#; + + let input = Level::ERROR.header("mismatched types").id("E0308").group( + Group::new().element( + Snippet::source(source) + .origin("$DIR/whitespace-trimming.rs") + .line_start(4) + .annotation( + AnnotationKind::Primary + .span(192..194) + .label("expected (), found integer"), + ), + ), + ); + let expected = file!["strip_line.term.svg"]; + let renderer = Renderer::styled().anonymized_line_numbers(true); + assert_data_eq!(renderer.render(input), expected); +} diff --git a/tests/fixtures/color/strip_line.svg b/tests/color/strip_line.term.svg similarity index 100% rename from tests/fixtures/color/strip_line.svg rename to tests/color/strip_line.term.svg diff --git a/tests/color/strip_line_char.rs b/tests/color/strip_line_char.rs new file mode 100644 index 00000000..df609e2f --- /dev/null +++ b/tests/color/strip_line_char.rs @@ -0,0 +1,24 @@ +use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; + +use snapbox::{assert_data_eq, file}; + +#[test] +fn case() { + let source = r#" let _: () = 42ñ"#; + + let input = Level::ERROR.header("mismatched types").id("E0308").group( + Group::new().element( + Snippet::source(source) + .origin("$DIR/whitespace-trimming.rs") + .line_start(4) + .annotation( + AnnotationKind::Primary + .span(192..194) + .label("expected (), found integer"), + ), + ), + ); + let expected = file!["strip_line_char.term.svg"]; + let renderer = Renderer::styled().anonymized_line_numbers(true); + assert_data_eq!(renderer.render(input), expected); +} diff --git a/tests/fixtures/color/strip_line_char.svg b/tests/color/strip_line_char.term.svg similarity index 100% rename from tests/fixtures/color/strip_line_char.svg rename to tests/color/strip_line_char.term.svg diff --git a/tests/color/strip_line_non_ws.rs b/tests/color/strip_line_non_ws.rs new file mode 100644 index 00000000..f82d369b --- /dev/null +++ b/tests/color/strip_line_non_ws.rs @@ -0,0 +1,30 @@ +use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; + +use snapbox::{assert_data_eq, file}; + +#[test] +fn case() { + let source = r#" let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = 42; let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); +"#; + + let input = Level::ERROR.header("mismatched types").id("E0308").group( + Group::new().element( + Snippet::source(source) + .origin("$DIR/non-whitespace-trimming.rs") + .line_start(4) + .annotation( + AnnotationKind::Primary + .span(237..239) + .label("expected `()`, found integer"), + ) + .annotation( + AnnotationKind::Primary + .span(232..234) + .label("expected due to this"), + ), + ), + ); + let expected = file!["strip_line_non_ws.term.svg"]; + let renderer = Renderer::styled().anonymized_line_numbers(true); + assert_data_eq!(renderer.render(input), expected); +} diff --git a/tests/fixtures/color/strip_line_non_ws.svg b/tests/color/strip_line_non_ws.term.svg similarity index 100% rename from tests/fixtures/color/strip_line_non_ws.svg rename to tests/color/strip_line_non_ws.term.svg diff --git a/tests/fixtures/color/ann_eof.toml b/tests/fixtures/color/ann_eof.toml deleted file mode 100644 index ef711dee..00000000 --- a/tests/fixtures/color/ann_eof.toml +++ /dev/null @@ -1,15 +0,0 @@ -[message] -level = "Error" -header = "expected `.`, `=`" - -[[message.sections]] -type = "Cause" -source = "asdf" -line_start = 1 -origin = "Cargo.toml" -annotations = [ - { label = "", kind = "Primary", range = [4, 4] }, -] - -[renderer] -color = true diff --git a/tests/fixtures/color/ann_insertion.toml b/tests/fixtures/color/ann_insertion.toml deleted file mode 100644 index 30af1bfb..00000000 --- a/tests/fixtures/color/ann_insertion.toml +++ /dev/null @@ -1,15 +0,0 @@ -[message] -level = "Error" -header = "expected `.`, `=`" - -[[message.sections]] -type = "Cause" -source = "asf" -line_start = 1 -origin = "Cargo.toml" -annotations = [ - { label = "'d' belongs here", kind = "Primary", range = [2, 2] } -] - -[renderer] -color = true diff --git a/tests/fixtures/color/ann_multiline.toml b/tests/fixtures/color/ann_multiline.toml deleted file mode 100644 index 2a5f206b..00000000 --- a/tests/fixtures/color/ann_multiline.toml +++ /dev/null @@ -1,21 +0,0 @@ -[message] -level = "Error" -id = "E0027" -header = "pattern does not mention fields `lineno`, `content`" - -[[message.sections]] -type = "Cause" -source = """ - if let DisplayLine::Source { - ref mut inline_marks, - } = body[body_idx] -""" -line_start = 139 -origin = "src/display_list.rs" -fold = false -annotations = [ - { label = "missing fields `lineno`, `content`", kind = "Primary", range = [31, 128] } -] - -[renderer] -color = true diff --git a/tests/fixtures/color/ann_multiline2.toml b/tests/fixtures/color/ann_multiline2.toml deleted file mode 100644 index 854b38a7..00000000 --- a/tests/fixtures/color/ann_multiline2.toml +++ /dev/null @@ -1,21 +0,0 @@ -[message] -level = "Error" -id = "E####" -header = "spacing error found" - -[[message.sections]] -type = "Cause" -source = """ -This is an example -of an edge case of an annotation overflowing -to exactly one character on next line. -""" -line_start = 26 -origin = "foo.txt" -fold = false -annotations = [ - { label = "this should not be on separate lines", kind = "Primary", range = [11, 19] }, -] - -[renderer] -color = true diff --git a/tests/fixtures/color/ann_removed_nl.toml b/tests/fixtures/color/ann_removed_nl.toml deleted file mode 100644 index 6ffeb7a0..00000000 --- a/tests/fixtures/color/ann_removed_nl.toml +++ /dev/null @@ -1,15 +0,0 @@ -[message] -level = "Error" -header = "expected `.`, `=`" - -[[message.sections]] -type = "Cause" -source = "asdf" -line_start = 1 -origin = "Cargo.toml" -annotations = [ - { label = "", kind = "Primary", range = [4, 5] }, -] - -[renderer] -color = true diff --git a/tests/fixtures/color/ensure-emoji-highlight-width.toml b/tests/fixtures/color/ensure-emoji-highlight-width.toml deleted file mode 100644 index 669959f6..00000000 --- a/tests/fixtures/color/ensure-emoji-highlight-width.toml +++ /dev/null @@ -1,18 +0,0 @@ -[message] -header = "invalid character ` ` in package name: `haha this isn't a valid name 🐛`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters)" -level = "Error" - - -[[message.sections]] -type = "Cause" -source = """ -"haha this isn't a valid name 🐛" = { package = "libc", version = "0.1" } -""" -line_start = 7 -origin = "" -annotations = [ - { label = "", kind = "Primary", range = [0, 35] }, -] - -[renderer] -color = true diff --git a/tests/fixtures/color/fold_ann_multiline.toml b/tests/fixtures/color/fold_ann_multiline.toml deleted file mode 100644 index 2cee27d6..00000000 --- a/tests/fixtures/color/fold_ann_multiline.toml +++ /dev/null @@ -1,41 +0,0 @@ -[message] -level = "Error" -id = "E0308" -header = "mismatched types" - -[[message.sections]] -type = "Cause" -source = """ -) -> Option { - for ann in annotations { - match (ann.range.0, ann.range.1) { - (None, None) => continue, - (Some(start), Some(end)) if start > end_index || end < start_index => continue, - (Some(start), Some(end)) if start >= start_index && end <= end_index => { - let label = if let Some(ref label) = ann.label { - format!(" {}", label) - } else { - String::from("") - }; - - return Some(format!( - "{}{}{}", - " ".repeat(start - start_index), - "^".repeat(end - start), - label - )); - } - _ => continue, - } - } -""" -line_start = 51 -origin = "src/format.rs" -fold = true -annotations = [ - { label = "expected `std::option::Option` because of return type", kind = "Context", range = [5, 19] }, - { label = "expected enum `std::option::Option`, found ()", kind = "Primary", range = [22, 766] }, -] - -[renderer] -color = true diff --git a/tests/fixtures/color/fold_bad_origin_line.toml b/tests/fixtures/color/fold_bad_origin_line.toml deleted file mode 100644 index 2fab2d64..00000000 --- a/tests/fixtures/color/fold_bad_origin_line.toml +++ /dev/null @@ -1,20 +0,0 @@ -[message] -level = "Error" -header = "" - -[[message.sections]] -type = "Cause" -source = """ - - -invalid syntax -""" -line_start = 1 -origin = "path/to/error.rs" -fold = true -annotations = [ - { label = "error here", kind = "Context", range = [2,16] }, -] - -[renderer] -color = true diff --git a/tests/fixtures/color/fold_leading.toml b/tests/fixtures/color/fold_leading.toml deleted file mode 100644 index 0ef043c9..00000000 --- a/tests/fixtures/color/fold_leading.toml +++ /dev/null @@ -1,29 +0,0 @@ -[message] -level = "Error" -id = "E0308" -header = "invalid type: integer `20`, expected a bool" - -[[message.sections]] -type = "Cause" -source = """ -[workspace] - -[package] -name = "hello" -version = "1.0.0" -license = "MIT" -rust-version = "1.70" -edition = "2021" - -[lints] -workspace = 20 -""" -line_start = 1 -origin = "Cargo.toml" -fold = true -annotations = [ - { label = "", kind = "Primary", range = [132, 134] }, -] - -[renderer] -color = true diff --git a/tests/fixtures/color/fold_trailing.toml b/tests/fixtures/color/fold_trailing.toml deleted file mode 100644 index 91e4ab4f..00000000 --- a/tests/fixtures/color/fold_trailing.toml +++ /dev/null @@ -1,28 +0,0 @@ -[message] -level = "Error" -id = "E0308" -header = "invalid type: integer `20`, expected a lints table" - -[[message.sections]] -type = "Cause" -source = """ -lints = 20 - -[workspace] - -[package] -name = "hello" -version = "1.0.0" -license = "MIT" -rust-version = "1.70" -edition = "2021" -""" -line_start = 1 -origin = "Cargo.toml" -fold = true -annotations = [ - { label = "", kind = "Primary", range = [8, 10] }, -] - -[renderer] -color = true diff --git a/tests/fixtures/color/issue_9.toml b/tests/fixtures/color/issue_9.toml deleted file mode 100644 index f4239154..00000000 --- a/tests/fixtures/color/issue_9.toml +++ /dev/null @@ -1,34 +0,0 @@ -[message] -level = "Error" -header = "expected one of `.`, `;`, `?`, or an operator, found `for`" - -[[message.sections]] -type = "Cause" -source = "let x = vec![1];" -line_start = 4 -origin = "/code/rust/src/test/ui/annotate-snippet/suggestion.rs" -[[message.sections.annotations]] -label = "move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait" -kind = "Context" -range = [4, 5] - -[[message.sections]] -type = "Cause" -source = "let y = x;" -line_start = 7 -[[message.sections.annotations]] -label = "value moved here" -kind = "Context" -range = [8, 9] - -[[message.sections]] -type = "Cause" -source = "x;" -line_start = 9 -[[message.sections.annotations]] -label = "value used here after move" -kind = "Primary" -range = [0, 1] - -[renderer] -color = true diff --git a/tests/fixtures/color/multiple_annotations.toml b/tests/fixtures/color/multiple_annotations.toml deleted file mode 100644 index 367c53ee..00000000 --- a/tests/fixtures/color/multiple_annotations.toml +++ /dev/null @@ -1,33 +0,0 @@ -[message] -level = "Error" -header = "" - -[[message.sections]] -type = "Cause" -source = """ -fn add_title_line(result: &mut Vec, main_annotation: Option<&Annotation>) { - if let Some(annotation) = main_annotation { - result.push(format_title_line( - &annotation.annotation_type, - None, - &annotation.label, - )); - } -} -""" -line_start = 96 -[[message.sections.annotations]] -label = "Variable defined here" -kind = "Primary" -range = [100, 110] -[[message.sections.annotations]] -label = "Referenced here" -kind = "Primary" -range = [184, 194] -[[message.sections.annotations]] -label = "Referenced again here" -kind = "Primary" -range = [243, 253] - -[renderer] -color = true diff --git a/tests/fixtures/color/simple.toml b/tests/fixtures/color/simple.toml deleted file mode 100644 index d5a36474..00000000 --- a/tests/fixtures/color/simple.toml +++ /dev/null @@ -1,23 +0,0 @@ -[message] -level = "Error" -header = "expected one of `.`, `;`, `?`, or an operator, found `for`" - -[[message.sections]] -type = "Cause" -source = """ - }) - - for line in &self.body {""" -line_start = 169 -origin = "src/format_color.rs" -[[message.sections.annotations]] -label = "unexpected token" -kind = "Primary" -range = [20, 23] -[[message.sections.annotations]] -label = "expected one of `.`, `;`, `?`, or an operator here" -kind = "Context" -range = [10, 11] - -[renderer] -color = true diff --git a/tests/fixtures/color/strip_line.toml b/tests/fixtures/color/strip_line.toml deleted file mode 100644 index 18a7805d..00000000 --- a/tests/fixtures/color/strip_line.toml +++ /dev/null @@ -1,19 +0,0 @@ -[message] -level = "Error" -id = "E0308" -header = "mismatched types" - -[[message.sections]] -type = "Cause" -source = " let _: () = 42;" -line_start = 4 -origin = "$DIR/whitespace-trimming.rs" - -[[message.sections.annotations]] -label = "expected (), found integer" -kind = "Primary" -range = [192, 194] - -[renderer] -color = true -anonymized_line_numbers = true diff --git a/tests/fixtures/color/strip_line_char.toml b/tests/fixtures/color/strip_line_char.toml deleted file mode 100644 index 3174cedc..00000000 --- a/tests/fixtures/color/strip_line_char.toml +++ /dev/null @@ -1,19 +0,0 @@ -[message] -level = "Error" -id = "E0308" -header = "mismatched types" - -[[message.sections]] -type = "Cause" -source = " let _: () = 42ñ" -line_start = 4 -origin = "$DIR/whitespace-trimming.rs" - -[[message.sections.annotations]] -label = "expected (), found integer" -kind = "Primary" -range = [192, 194] - -[renderer] -color = true -anonymized_line_numbers = true diff --git a/tests/fixtures/color/strip_line_non_ws.toml b/tests/fixtures/color/strip_line_non_ws.toml deleted file mode 100644 index b7844ec2..00000000 --- a/tests/fixtures/color/strip_line_non_ws.toml +++ /dev/null @@ -1,27 +0,0 @@ -[message] -level = "Error" -id = "E0308" -header = "mismatched types" - -[[message.sections]] -type = "Cause" -source = """ - let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = 42; let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); -""" -line_start = 4 -origin = "$DIR/non-whitespace-trimming.rs" - -[[message.sections.annotations]] -label = "expected `()`, found integer" -kind = "Primary" -range = [237, 239] - -[[message.sections.annotations]] -label = "expected due to this" -kind = "Primary" -range = [232, 234] - - -[renderer] -anonymized_line_numbers = true -color = true diff --git a/tests/fixtures/deserialize.rs b/tests/fixtures/deserialize.rs deleted file mode 100644 index 20429665..00000000 --- a/tests/fixtures/deserialize.rs +++ /dev/null @@ -1,217 +0,0 @@ -use serde::Deserialize; -use std::ops::Range; - -use annotate_snippets::renderer::DEFAULT_TERM_WIDTH; -use annotate_snippets::{ - Annotation, AnnotationKind, Element, Group, Level, Message, Patch, Renderer, Snippet, -}; - -#[derive(Deserialize)] -pub(crate) struct Fixture { - #[serde(default)] - pub(crate) renderer: RendererDef, - pub(crate) message: MessageDef, -} - -#[derive(Deserialize)] -pub struct MessageDef { - pub level: LevelDef, - pub header: String, - #[serde(default)] - pub id: Option, - #[serde(default)] - pub sections: Vec, -} - -impl<'a> From<&'a MessageDef> for Message<'a> { - fn from(val: &'a MessageDef) -> Self { - let MessageDef { - level, - header, - id, - sections, - } = val; - let mut message = Level::from(level).header(header); - if let Some(id) = id { - message = message.id(id); - } - - message = message.group(Group::new().elements(sections.iter().map(|s| match s { - ElementDef::Title(title) => { - Element::Title(Level::from(&title.level).title(&title.title)) - } - ElementDef::Cause(cause) => Element::Cause(Snippet::from(cause)), - ElementDef::Suggestion(suggestion) => Element::Suggestion(Snippet::from(suggestion)), - }))); - message - } -} - -#[derive(Deserialize)] -#[serde(tag = "type")] -pub enum ElementDef { - Title(TitleDef), - Cause(SnippetAnnotationDef), - Suggestion(SnippetPatchDef), -} - -impl<'a> From<&'a ElementDef> for Element<'a> { - fn from(val: &'a ElementDef) -> Self { - match val { - ElementDef::Title(title) => { - Element::Title(Level::from(&title.level).title(&title.title)) - } - ElementDef::Cause(cause) => Element::Cause(Snippet::from(cause)), - ElementDef::Suggestion(suggestion) => Element::Suggestion(Snippet::from(suggestion)), - } - } -} - -#[derive(Deserialize)] -pub struct TitleDef { - pub title: String, - pub level: LevelDef, -} - -#[derive(Deserialize)] -pub struct SnippetAnnotationDef { - pub(crate) origin: Option, - pub(crate) line_start: usize, - pub(crate) source: String, - pub(crate) annotations: Vec, - #[serde(default)] - pub(crate) fold: bool, -} - -impl<'a> From<&'a SnippetAnnotationDef> for Snippet<'a, Annotation<'a>> { - fn from(val: &'a SnippetAnnotationDef) -> Self { - let SnippetAnnotationDef { - origin, - line_start, - source, - annotations, - fold, - } = val; - let mut snippet = Snippet::source(source).line_start(*line_start).fold(*fold); - if let Some(origin) = origin { - snippet = snippet.origin(origin); - } - snippet = snippet.annotations(annotations.iter().map(Into::into)); - snippet - } -} - -#[derive(Deserialize)] -pub struct AnnotationDef { - pub range: Range, - pub label: String, - #[serde(with = "AnnotationKindDef")] - pub kind: AnnotationKind, -} - -impl<'a> From<&'a AnnotationDef> for Annotation<'a> { - fn from(val: &'a AnnotationDef) -> Self { - let AnnotationDef { range, label, kind } = val; - kind.span(range.start..range.end).label(label) - } -} - -#[allow(dead_code)] -#[derive(Deserialize)] -#[serde(remote = "AnnotationKind")] -enum AnnotationKindDef { - Primary, - Context, -} - -#[derive(Deserialize)] -pub struct SnippetPatchDef { - pub(crate) origin: Option, - pub(crate) line_start: usize, - pub(crate) source: String, - pub(crate) patches: Vec, - #[serde(default)] - pub(crate) fold: bool, -} - -impl<'a> From<&'a SnippetPatchDef> for Snippet<'a, Patch<'a>> { - fn from(val: &'a SnippetPatchDef) -> Self { - let SnippetPatchDef { - origin, - line_start, - source, - patches, - fold, - } = val; - let mut snippet = Snippet::source(source).line_start(*line_start).fold(*fold); - if let Some(origin) = origin { - snippet = snippet.origin(origin); - } - snippet = snippet.patches(patches.iter().map(Into::into)); - snippet - } -} - -#[derive(Deserialize)] -pub struct PatchDef { - pub range: Range, - pub replacement: String, -} - -impl<'a> From<&'a PatchDef> for Patch<'a> { - fn from(val: &'a PatchDef) -> Self { - let PatchDef { range, replacement } = val; - Patch::new(range.start..range.end, replacement) - } -} - -#[allow(dead_code)] -#[derive(Clone, Copy, Deserialize)] -pub enum LevelDef { - Error, - Warning, - Info, - Note, - Help, -} - -impl<'a> From<&'a LevelDef> for Level<'a> { - fn from(val: &'a LevelDef) -> Self { - match val { - LevelDef::Error => Level::ERROR, - LevelDef::Warning => Level::WARNING, - LevelDef::Info => Level::INFO, - LevelDef::Note => Level::NOTE, - LevelDef::Help => Level::HELP, - } - } -} - -#[derive(Default, Deserialize)] -pub struct RendererDef { - #[serde(default)] - anonymized_line_numbers: bool, - #[serde(default)] - term_width: Option, - #[serde(default)] - color: bool, -} - -impl From for Renderer { - fn from(val: RendererDef) -> Self { - let RendererDef { - anonymized_line_numbers, - term_width, - color, - } = val; - - let renderer = if color { - Renderer::styled() - } else { - Renderer::plain() - }; - renderer - .anonymized_line_numbers(anonymized_line_numbers) - .term_width(term_width.unwrap_or(DEFAULT_TERM_WIDTH)) - } -} diff --git a/tests/fixtures/main.rs b/tests/fixtures/main.rs deleted file mode 100644 index 27082622..00000000 --- a/tests/fixtures/main.rs +++ /dev/null @@ -1,42 +0,0 @@ -mod deserialize; - -use crate::deserialize::Fixture; -use annotate_snippets::{Message, Renderer}; -use snapbox::data::DataFormat; -use snapbox::Data; -use std::error::Error; - -fn main() { - #[cfg(not(windows))] - tryfn::Harness::new("tests/fixtures/", setup, test) - .select(["*/*.toml"]) - .test(); -} - -fn setup(input_path: std::path::PathBuf) -> tryfn::Case { - let parent = input_path - .parent() - .unwrap() - .file_name() - .unwrap() - .to_str() - .unwrap(); - let file_name = input_path.file_name().unwrap().to_str().unwrap(); - let name = format!("{parent}/{file_name}"); - let expected = Data::read_from(&input_path.with_extension("svg"), None); - tryfn::Case { - name, - fixture: input_path, - expected, - } -} - -fn test(input_path: &std::path::Path) -> Result> { - let src = std::fs::read_to_string(input_path)?; - let fixture: Fixture = toml::from_str(&src)?; - let renderer: Renderer = fixture.renderer.into(); - let message: Message<'_> = (&fixture.message).into(); - - let actual = renderer.render(message); - Ok(Data::from(actual).coerce_to(DataFormat::TermSvg)) -} From df05eb77a29bc9baa56764f6041b318f4e55ba4d Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Sat, 26 Apr 2025 08:23:27 -0600 Subject: [PATCH 184/293] chore: Remove unused dev-dependencies --- Cargo.lock | 15 --------------- Cargo.toml | 3 --- 2 files changed, 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dd4fd20b..e6431344 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9,11 +9,8 @@ dependencies = [ "annotate-snippets", "anstream", "anstyle", - "difference", "divan", - "glob", "memchr", - "serde", "snapbox", "unicode-width 0.2.0", ] @@ -139,12 +136,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf0a07a401f374238ab8e2f11a104d2851bf9ce711ec69804834de8af45c7af" -[[package]] -name = "difference" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" - [[package]] name = "divan" version = "0.1.17" @@ -192,12 +183,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "glob" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" - [[package]] name = "hermit-abi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 4a8adf00..84345673 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -123,10 +123,7 @@ unicode-width = "0.2.0" [dev-dependencies] annotate-snippets = { path = ".", features = ["testing-colors"] } anstream = "0.6.13" -difference = "2.0.0" divan = "0.1.14" -glob = "0.3.1" -serde = { version = "1.0.199", features = ["derive"] } snapbox = { version = "0.6.0", features = ["diff", "term-svg", "cmd", "examples"] } [[bench]] From 97755b3c011d292774d5a3199327bfb1dc29e6a6 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 30 Apr 2025 20:07:18 -0500 Subject: [PATCH 185/293] chore(ci): Improve perf at the cost of coverage --- .github/workflows/ci.yml | 4 ++-- .github/workflows/rust-next.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7bcbd419..baf17232 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,7 +50,7 @@ jobs: - name: Build run: cargo test --workspace --no-run - name: Test - run: cargo hack test --feature-powerset --workspace + run: cargo hack test --each-feature --workspace msrv: name: "Check MSRV" runs-on: ubuntu-latest @@ -64,7 +64,7 @@ jobs: - uses: Swatinem/rust-cache@v2 - uses: taiki-e/install-action@cargo-hack - name: Default features - run: cargo hack check --feature-powerset --locked --rust-version --ignore-private --workspace --all-targets --keep-going + run: cargo hack check --each-feature --locked --rust-version --ignore-private --workspace --all-targets --keep-going minimal-versions: name: Minimal versions runs-on: ubuntu-latest diff --git a/.github/workflows/rust-next.yml b/.github/workflows/rust-next.yml index e98386c4..be8b2dbe 100644 --- a/.github/workflows/rust-next.yml +++ b/.github/workflows/rust-next.yml @@ -40,7 +40,7 @@ jobs: - name: Build run: cargo test --workspace --no-run - name: Test - run: cargo hack test --feature-powerset --workspace + run: cargo hack test --each-feature --workspace latest: name: "Check latest dependencies" runs-on: ubuntu-latest @@ -58,4 +58,4 @@ jobs: - name: Build run: cargo test --workspace --no-run - name: Test - run: cargo hack test --feature-powerset --workspace + run: cargo hack test --each-feature --workspace From 9c5ba46e1cd041df9e4a62a2936130c1f5c8ceea Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 1 May 2025 03:41:39 +0000 Subject: [PATCH 186/293] chore(deps): Update Rust crate divan to v0.1.21 (#202) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e6431344..532bb57a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -138,9 +138,9 @@ checksum = "baf0a07a401f374238ab8e2f11a104d2851bf9ce711ec69804834de8af45c7af" [[package]] name = "divan" -version = "0.1.17" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0583193020b29b03682d8d33bb53a5b0f50df6daacece12ca99b904cfdcb8c4" +checksum = "a405457ec78b8fe08b0e32b4a3570ab5dff6dd16eb9e76a5ee0a9d9cbd898933" dependencies = [ "cfg-if", "clap", @@ -152,9 +152,9 @@ dependencies = [ [[package]] name = "divan-macros" -version = "0.1.17" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dc51d98e636f5e3b0759a39257458b22619cac7e96d932da6eeb052891bb67c" +checksum = "9556bc800956545d6420a640173e5ba7dfa82f38d3ea5a167eb555bc69ac3323" dependencies = [ "proc-macro2", "quote", From d1a562756a21d6ed9626ffcbb157af5841c4a1b5 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 7 May 2025 08:42:54 -0500 Subject: [PATCH 187/293] chore: Update RenovateBot --- .github/renovate.json5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 7ab13b9f..cf3c8fe7 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -9,7 +9,7 @@ customManagers: [ { customType: 'regex', - fileMatch: [ + managerFilePatterns: [ '^rust-toolchain\\.toml$', 'Cargo.toml$', 'clippy.toml$', From 8c5c6ad69f2da2abaf2f8254df40ee1d52478837 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 7 May 2025 14:06:57 -0500 Subject: [PATCH 188/293] chore: Fix regex for renovatebot --- .github/renovate.json5 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index cf3c8fe7..27749d4b 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -10,12 +10,12 @@ { customType: 'regex', managerFilePatterns: [ - '^rust-toolchain\\.toml$', - 'Cargo.toml$', - 'clippy.toml$', - '\\.clippy.toml$', - '^\\.github/workflows/ci.yml$', - '^\\.github/workflows/rust-next.yml$', + '/^rust-toolchain\\.toml$/', + '/Cargo.toml$/', + '/clippy.toml$/', + '/\\.clippy.toml$/', + '/^\\.github/workflows/ci.yml$/', + '/^\\.github/workflows/rust-next.yml$/', ], matchStrings: [ 'STABLE.*?(?\\d+\\.\\d+(\\.\\d+)?)', From 1c62b61c44c8384b7c891b352b0c303d0b6a992d Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Wed, 14 May 2025 12:32:39 +0200 Subject: [PATCH 189/293] chore: Address clippy lints --- src/renderer/mod.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index be2abab4..de1b77dd 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -2537,11 +2537,7 @@ impl LineAnnotation<'_> { /// Length of this annotation as displayed in the stderr output pub(crate) fn len(&self) -> usize { // Account for usize underflows - if self.end.display > self.start.display { - self.end.display - self.start.display - } else { - self.start.display - self.end.display - } + self.end.display.abs_diff(self.start.display) } pub(crate) fn has_label(&self) -> bool { From c47d7508c93c2471e240ded7bcfc2bcff7280f47 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Wed, 14 May 2025 12:30:34 +0200 Subject: [PATCH 190/293] chore: Add Clone to Message --- src/snippet.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/snippet.rs b/src/snippet.rs index 03bfe3dd..7226783d 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -11,7 +11,7 @@ pub(crate) const NOTE_TXT: &str = "note"; pub(crate) const WARNING_TXT: &str = "warning"; /// Top-level user message -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct Message<'a> { pub(crate) id: Option<&'a str>, // for "correctness", could be sloppy and be on Title pub(crate) groups: Vec>, @@ -76,7 +76,7 @@ impl<'a> Message<'a> { } /// An [`Element`] container -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct Group<'a> { pub(crate) elements: Vec>, } @@ -108,7 +108,7 @@ impl<'a> Group<'a> { } /// A section of content within a [`Group`] -#[derive(Debug)] +#[derive(Clone, Debug)] #[non_exhaustive] pub enum Element<'a> { Title(Title<'a>), @@ -149,13 +149,13 @@ impl From for Element<'_> { } /// A whitespace [`Element`] in a [`Group`] -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct Padding; /// A text [`Element`] in a [`Group`] /// /// See [`Level::title`] to create this. -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct Title<'a> { pub(crate) level: Level<'a>, pub(crate) title: &'a str, @@ -170,7 +170,7 @@ impl Title<'_> { } /// A source view [`Element`] in a [`Group`] -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct Snippet<'a, T> { pub(crate) origin: Option<&'a str>, pub(crate) line_start: usize, From 962407d6e2239ec2419c7f6f614a9d7068091234 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Wed, 14 May 2025 12:26:30 +0200 Subject: [PATCH 191/293] test: Add unicode varients for some tests --- tests/formatter.rs | 137 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 114 insertions(+), 23 deletions(-) diff --git a/tests/formatter.rs b/tests/formatter.rs index 75cf8532..4c536329 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -2129,7 +2129,7 @@ fn unicode_cut_handling() { .annotation(AnnotationKind::Primary.span(85..228).label("annotation")), ), ); - let expected = str![[r#" + let expected_ascii = str![[r#" error: title | 1 | version = "0.1.0" @@ -2140,8 +2140,22 @@ error: title 5 | | ] | |_^ annotation "#]]; - let renderer = Renderer::plain(); - assert_data_eq!(renderer.render(input), expected); + let renderer_ascii = Renderer::plain(); + assert_data_eq!(renderer_ascii.render(input.clone()), expected_ascii); + + let expected_unicode = str![[r#" +error: title + │ +1 │ version = "0.1.0" +2 │ # Ensure that the spans from toml handle utf-8 correctly +3 │ authors = [ + │ ┏━━━━━━━━━━━┛ +4 │ ┃ { name = "Z͑ͫ̓ͪ̂ͫ̽͏̴̙̤̞͉͚̯̞̠͍A̴̵̜̰͔ͫ͗͢L̠ͨͧͩ͘G̴̻͈͍͔̹̑͗̎̅͛́Ǫ̵̹̻̝̳͂̌̌͘", email = 1 } +5 │ ┃ ] + ╰╴┗━┛ annotation +"#]]; + let renderer_unicode = renderer_ascii.theme(OutputTheme::Unicode); + assert_data_eq!(renderer_unicode.render(input), expected_unicode); } #[test] @@ -2159,7 +2173,7 @@ fn unicode_cut_handling2() { ) ); - let expected = str![[r#" + let expected_ascii = str![[r#" error: expected item, found `?` | 1 | ...的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。*/? @@ -2167,8 +2181,18 @@ error: expected item, found `?` = note: for a full list of items that can appear in modules, see "#]]; - let renderer = Renderer::plain(); - assert_data_eq!(renderer.render(input), expected); + let renderer_ascii = Renderer::plain(); + assert_data_eq!(renderer_ascii.render(input.clone()), expected_ascii); + + let expected_unicode = str![[r#" +error: expected item, found `?` + │ +1 │ …宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。*/? + │ ━ expected item + ╰ note: for a full list of items that can appear in modules, see +"#]]; + let renderer_unicode = renderer_ascii.theme(OutputTheme::Unicode); + assert_data_eq!(renderer_unicode.render(input), expected_unicode); } #[test] @@ -2186,7 +2210,7 @@ fn unicode_cut_handling3() { ) ); - let expected = str![[r#" + let expected_ascii = str![[r#" error: expected item, found `?` | 1 | ...。这是宽的。这是宽的。这是宽的... @@ -2194,8 +2218,18 @@ error: expected item, found `?` = note: for a full list of items that can appear in modules, see "#]]; - let renderer = Renderer::plain().term_width(43); - assert_data_eq!(renderer.render(input), expected); + let renderer_ascii = Renderer::plain().term_width(43); + assert_data_eq!(renderer_ascii.render(input.clone()), expected_ascii); + + let expected_unicode = str![[r#" +error: expected item, found `?` + │ +1 │ …的。这是宽的。这是宽的。这是宽的。… + │ ━━ expected item + ╰ note: for a full list of items that can appear in modules, see +"#]]; + let renderer_unicode = renderer_ascii.theme(OutputTheme::Unicode); + assert_data_eq!(renderer_unicode.render(input), expected_unicode); } #[test] @@ -2213,7 +2247,7 @@ fn unicode_cut_handling4() { ) ); - let expected = str![[r#" + let expected_ascii = str![[r#" error: expected item, found `?` | 1 | ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa*/? @@ -2221,8 +2255,18 @@ error: expected item, found `?` = note: for a full list of items that can appear in modules, see "#]]; - let renderer = Renderer::plain(); - assert_data_eq!(renderer.render(input), expected); + let renderer_ascii = Renderer::plain(); + assert_data_eq!(renderer_ascii.render(input.clone()), expected_ascii); + + let expected_unicode = str![[r#" +error: expected item, found `?` + │ +1 │ …aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa*/? + │ ━ expected item + ╰ note: for a full list of items that can appear in modules, see +"#]]; + let renderer_unicode = renderer_ascii.theme(OutputTheme::Unicode); + assert_data_eq!(renderer_unicode.render(input), expected_unicode); } #[test] @@ -2252,7 +2296,7 @@ fn main() { ), ); - let expected = str![[r#" + let expected_ascii = str![[r#" error[E0308]: mismatched types --> $DIR/non-whitespace-trimming-unicode.rs:4:415 | @@ -2262,8 +2306,20 @@ LL | ...♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾ | expected due to this "#]]; - let renderer = Renderer::plain().anonymized_line_numbers(true); - assert_data_eq!(renderer.render(input), expected); + let renderer_ascii = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer_ascii.render(input.clone()), expected_ascii); + + let expected_unicode = str![[r#" +error[E0308]: mismatched types + ╭▸ $DIR/non-whitespace-trimming-unicode.rs:4:415 + │ +LL │ …♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚈⚉4"; let _: () = 42; let _: &str = "🦀☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓ ☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹… + │ ┬─ ━━ expected `()`, found integer + │ │ + ╰╴ expected due to this +"#]]; + let renderer_unicode = renderer_ascii.theme(OutputTheme::Unicode); + assert_data_eq!(renderer_unicode.render(input), expected_unicode); } #[test] @@ -2311,7 +2367,27 @@ fn main() { ), ); - let expected = str![[r#" + let expected_ascii = str![[r#" +error[E0369]: cannot add `&str` to `&str` + --> $DIR/non-1-width-unicode-multiline-label.rs:7:260 + | +LL | ...࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!";; + | -------------- ^ -------------- &str + | | | + | | `+` cannot be used to concatenate two `&str` strings + | &str + | + = note: string concatenation requires an owned `String` on the left +help: create an owned `String` from a string reference + | +LL | let _ = "ༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇ཈ཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬ཭཮཯཰ཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun.to_owned() + " really fun!"; + | +++++++++++ +"#]]; + + let renderer_ascii = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer_ascii.render(input.clone()), expected_ascii); + + let expected_unicode = str![[r#" error[E0369]: cannot add `&str` to `&str` ╭▸ $DIR/non-1-width-unicode-multiline-label.rs:7:260 │ @@ -2328,10 +2404,8 @@ LL │ let _ = "ༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓ ╰╴ +++++++++++ "#]]; - let renderer = Renderer::plain() - .anonymized_line_numbers(true) - .theme(OutputTheme::Unicode); - assert_data_eq!(renderer.render(input), expected); + let renderer_unicode = renderer_ascii.theme(OutputTheme::Unicode); + assert_data_eq!(renderer_unicode.render(input), expected_unicode); } #[test] @@ -2367,7 +2441,7 @@ fn foo() { .element(Level::NOTE.title("this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)")), ); - let expected = str![[r#" + let expected_ascii = str![[r#" error: couldn't read `$DIR/not-utf8.bin`: stream did not contain valid UTF-8 --> $DIR/not-utf8.rs:6:5 | @@ -2382,6 +2456,23 @@ LL | �|�␂!5�cc␕␂�Ӻi��WWj�ȥ�'�}�␒�J�ȉ��W = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) "#]]; - let renderer = Renderer::plain().anonymized_line_numbers(true); - assert_data_eq!(renderer.render(input), expected); + let renderer_ascii = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer_ascii.render(input.clone()), expected_ascii); + + let expected_unicode = str![[r#" +error: couldn't read `$DIR/not-utf8.bin`: stream did not contain valid UTF-8 + ╭▸ $DIR/not-utf8.rs:6:5 + │ +LL │ include!("not-utf8.bin"); + │ ━━━━━━━━━━━━━━━━━━━━━━━━ + ╰╴ +note: byte `193` is not valid utf-8 + ╭▸ $DIR/not-utf8.bin:1:1 + │ +LL │ �|�␂!5�cc␕␂�Ӻi��WWj�ȥ�'�}�␒�J�ȉ��W�␞O�@����␜w�V���LO����␔[ ␃_�'���SQ�~ذ��ų&��- ��lN~��!@␌ _#���kQ��h�␝�:�␜␇� + │ ━ + ╰ note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) +"#]]; + let renderer_unicode = renderer_ascii.theme(OutputTheme::Unicode); + assert_data_eq!(renderer_unicode.render(input), expected_unicode); } From 42c12f36980d5171ae5d82823ae31f8ee4bb3d34 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Wed, 14 May 2025 13:10:42 +0200 Subject: [PATCH 192/293] fix: Don't output some source chars twice --- src/renderer/mod.rs | 1 - tests/formatter.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index de1b77dd..81f08512 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -2048,7 +2048,6 @@ impl Renderer { }) .collect(); - buffer.puts(line_offset, code_offset, &code, ElementStyle::Quotation); let placeholder = self.margin(); let padding = str_width(placeholder); let (width_taken, bytes_taken) = if margin.was_cut_left() { diff --git a/tests/formatter.rs b/tests/formatter.rs index 4c536329..a0e4df87 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -2371,7 +2371,7 @@ fn main() { error[E0369]: cannot add `&str` to `&str` --> $DIR/non-1-width-unicode-multiline-label.rs:7:260 | -LL | ...࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!";; +LL | ...࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun + " really fun!"; | -------------- ^ -------------- &str | | | | | `+` cannot be used to concatenate two `&str` strings From 722a5a66f993fd31bb5a66c8b711b907a50536f7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 15 May 2025 22:39:11 +0000 Subject: [PATCH 193/293] chore(deps): Update Rust Stable to v1.87 (#206) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aa6d8bbd..e9e3450a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -104,7 +104,7 @@ jobs: - name: Install Rust uses: dtolnay/rust-toolchain@stable with: - toolchain: "1.86" # STABLE + toolchain: "1.87" # STABLE - uses: Swatinem/rust-cache@v2 - name: Check documentation env: @@ -119,7 +119,7 @@ jobs: - name: Install Rust uses: dtolnay/rust-toolchain@stable with: - toolchain: "1.86" # STABLE + toolchain: "1.87" # STABLE components: rustfmt - uses: Swatinem/rust-cache@v2 - name: Check formatting @@ -135,7 +135,7 @@ jobs: - name: Install Rust uses: dtolnay/rust-toolchain@stable with: - toolchain: "1.86" # STABLE + toolchain: "1.87" # STABLE components: clippy - uses: Swatinem/rust-cache@v2 - name: Install SARIF tools From cf166e316a92ce71afd467e4c10affe29b7b3395 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 20 May 2025 14:58:07 -0500 Subject: [PATCH 194/293] chore(pre-commit): Update default stages --- .pre-commit-config.yaml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 68db968e..4acd1787 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,22 +3,22 @@ repos: rev: v4.5.0 hooks: - id: check-yaml - stages: [commit] + stages: [pre-commit] - id: check-json - stages: [commit] + stages: [pre-commit] - id: check-toml - stages: [commit] + stages: [pre-commit] - id: check-merge-conflict - stages: [commit] + stages: [pre-commit] - id: check-case-conflict - stages: [commit] + stages: [pre-commit] - id: detect-private-key - stages: [commit] + stages: [pre-commit] - repo: https://github.com/crate-ci/typos rev: v1.16.20 hooks: - id: typos - stages: [commit] + stages: [pre-commit] - repo: https://github.com/crate-ci/committed rev: v1.0.20 hooks: From a7bfa220ca56e7c6b0c9785a46e88d125bd8797b Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 20 May 2025 15:00:06 -0500 Subject: [PATCH 195/293] chore(pre-commit): Use default stages --- .pre-commit-config.yaml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4acd1787..8f7afc59 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,24 +3,16 @@ repos: rev: v4.5.0 hooks: - id: check-yaml - stages: [pre-commit] - id: check-json - stages: [pre-commit] - id: check-toml - stages: [pre-commit] - id: check-merge-conflict - stages: [pre-commit] - id: check-case-conflict - stages: [pre-commit] - id: detect-private-key - stages: [pre-commit] - repo: https://github.com/crate-ci/typos rev: v1.16.20 hooks: - id: typos - stages: [pre-commit] - repo: https://github.com/crate-ci/committed rev: v1.0.20 hooks: - id: committed - stages: [commit-msg] From 65fdcf65ba58357ac3c2f85fe551627dbd22046f Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 20 May 2025 15:03:11 -0500 Subject: [PATCH 196/293] chore(pre-commit): Update hooks --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8f7afc59..dbaa86ce 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v5.0.0 hooks: - id: check-yaml - id: check-json @@ -9,10 +9,10 @@ repos: - id: check-case-conflict - id: detect-private-key - repo: https://github.com/crate-ci/typos - rev: v1.16.20 + rev: v1.32.0 hooks: - id: typos - repo: https://github.com/crate-ci/committed - rev: v1.0.20 + rev: v1.1.7 hooks: - id: committed From 7a72bd0e0dcfee16d8a59cb1c89042968e3d01f4 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 20 May 2025 15:04:41 -0500 Subject: [PATCH 197/293] chore(pre-commit): Ensure commit-msg hook is installed --- .pre-commit-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index dbaa86ce..656c68ec 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,3 +1,4 @@ +default_install_hook_types: ["pre-commit", "commit-msg"] repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v5.0.0 From 5e85d6859df1d28dc8208b5be9d8bd03756957b3 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 27 May 2025 09:01:17 -0500 Subject: [PATCH 198/293] chore: Strip benches on publish --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 92d8817d..71ae7cf8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,6 @@ include = [ "Cargo.lock", "LICENSE*", "README.md", - "benches/**/*", "examples/**/*" ] From f9842b3b3f920ef64c5fc06298b4762018d88809 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 2 Jun 2025 12:27:10 -0500 Subject: [PATCH 199/293] chore: Avoid MSRV problems out of the box --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 71ae7cf8..0de8e135 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -93,7 +93,7 @@ panic = "abort" panic = "abort" codegen-units = 1 lto = true -debug = "line-tables-only" +# debug = "line-tables-only" # requires Cargo 1.71 [package] name = "PROJECT" From 66a7d10ab2f97e2bebdafbb746227d392e4b4c5e Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 2 Jun 2025 12:14:03 -0500 Subject: [PATCH 200/293] docs(readme): Specify code fence --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 21f95c4b..97599d36 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,10 @@ which may look like this: Local Development ----------------- - cargo build - cargo test +```console +$ cargo build +$ cargo test +``` When submitting a PR please use [`cargo fmt`][] (nightly). From a56d445744e31f01c634060151274d3a55f5ffd9 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Tue, 10 Jun 2025 03:38:14 -0600 Subject: [PATCH 201/293] chore: Address clippy::needless_doctest_main --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 92584f63..bf5a720e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ //! # Example //! //! ```rust +//! # #[allow(clippy::needless_doctest_main)] #![doc = include_str!("../examples/expected_type.rs")] //! ``` //! From d4300058bd506fb83683bb8f4ca1275760bf03a8 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Wed, 11 Jun 2025 09:39:53 -0600 Subject: [PATCH 202/293] chore: Fix clippy warning --- src/renderer/source_map.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/renderer/source_map.rs b/src/renderer/source_map.rs index d014bb01..d42dccce 100644 --- a/src/renderer/source_map.rs +++ b/src/renderer/source_map.rs @@ -298,9 +298,9 @@ impl<'a> SourceMap<'a> { annotated_line_infos.retain(|l| !l.annotations.is_empty()); } - annotated_line_infos - .iter_mut() - .for_each(|l| l.annotations.sort_by(|a, b| a.start.cmp(&b.start))); + for l in annotated_line_infos.iter_mut() { + l.annotations.sort_by(|a, b| a.start.cmp(&b.start)); + } (max_depth, annotated_line_infos) } From 86cc0e44a468e52ecb6934c1a5a2cb601428f247 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Wed, 11 Jun 2025 04:52:30 -0600 Subject: [PATCH 203/293] test: Update highlight_title to match rustc --- examples/highlight_title.rs | 56 ++++++++++++++++++++++-------------- examples/highlight_title.svg | 29 +++++++++++++++---- 2 files changed, 58 insertions(+), 27 deletions(-) diff --git a/examples/highlight_title.rs b/examples/highlight_title.rs index 12c106a6..218e414f 100644 --- a/examples/highlight_title.rs +++ b/examples/highlight_title.rs @@ -5,7 +5,6 @@ fn main() { let source = r#"// Make sure "highlighted" code is colored purple //@ compile-flags: --error-format=human --color=always -//@ error-pattern:for<'a>  //@ edition:2018 use core::pin::Pin; @@ -24,8 +23,7 @@ fn wrapped_fn<'a>(_: Box<(dyn Any + Send)>) -> Pin +
LL | fn query(_: fn(Box<(dyn Any + Send + '_)>) -> Pin<Box<( - | ____^^^^^_- + | ____^^^^^_- LL | | dyn Future<Output = Result<Box<(dyn Any + 'static)>, String>> + Send + 'static diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 81f08512..24455add 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -52,6 +52,7 @@ use margin::Margin; use std::borrow::Cow; use std::cmp::{max, min, Ordering, Reverse}; use std::collections::{HashMap, VecDeque}; +use std::fmt; use std::ops::Range; use stylesheet::Stylesheet; @@ -198,7 +199,6 @@ impl Renderer { impl Renderer { pub fn render(&self, mut message: Message<'_>) -> String { - let mut buffer = StyledBuffer::new(); let max_line_num_len = if self.anonymized_line_numbers { ANONYMIZED_LINE_NUM.len() } else { @@ -206,27 +206,21 @@ impl Renderer { num_decimal_digits(n) }; let title = message.groups.remove(0).elements.remove(0); - let level = if let Element::Title(title) = &title { - title.level.clone() - } else { - panic!("Expected a title as the first element of the message") - }; if let Some(first) = message.groups.first_mut() { first.elements.insert(0, title); } else { message.groups.push(Group::new().element(title)); } - self.render_message(&mut buffer, message, max_line_num_len); - - buffer.render(level, &self.stylesheet).unwrap() + self.render_message(message, max_line_num_len).unwrap() } fn render_message( &self, - buffer: &mut StyledBuffer, message: Message<'_>, max_line_num_len: usize, - ) { + ) -> Result { + let mut out_string = String::new(); + let og_primary_origin = message .groups .iter() @@ -264,6 +258,7 @@ impl Renderer { ); let group_len = message.groups.len(); for (g, group) in message.groups.into_iter().enumerate() { + let mut buffer = StyledBuffer::new(); let primary_origin = group .elements .iter() @@ -295,6 +290,14 @@ impl Renderer { }) .unwrap_or_default(), ); + let level = group + .elements + .iter() + .find_map(|s| match &s { + Element::Title(title) => Some(title.level.clone()), + _ => None, + }) + .unwrap_or(Level::ERROR); let mut source_map_annotated_lines = VecDeque::new(); let mut max_depth = 0; for e in &group.elements { @@ -313,7 +316,7 @@ impl Renderer { match §ion { Element::Title(title) => { self.render_title( - buffer, + &mut buffer, title, peek, max_line_num_len, @@ -334,7 +337,7 @@ impl Renderer { source_map_annotated_lines.pop_front() { self.render_snippet_annotations( - buffer, + &mut buffer, max_line_num_len, cause, primary_origin, @@ -345,19 +348,20 @@ impl Renderer { ); if g == 0 && group_len > 1 { + let current_line = buffer.num_lines(); if matches!(peek, Some(Element::Title(level)) if level.level.name != Some(None)) { self.draw_col_separator_no_space( - buffer, - buffer.num_lines(), + &mut buffer, + current_line, max_line_num_len + 1, ); // We want to draw the separator when it is // requested, or when it is the last element } else if peek.is_none() { self.draw_col_separator_end( - buffer, - buffer.num_lines(), + &mut buffer, + current_line, max_line_num_len + 1, ); } @@ -369,7 +373,7 @@ impl Renderer { Element::Suggestion(suggestion) => { let source_map = SourceMap::new(suggestion.source, suggestion.line_start); self.emit_suggestion_default( - buffer, + &mut buffer, suggestion, max_line_num_len, &source_map, @@ -380,13 +384,14 @@ impl Renderer { } Element::Origin(origin) => { - self.render_origin(buffer, max_line_num_len, origin); + self.render_origin(&mut buffer, max_line_num_len, origin); last_was_suggestion = false; } Element::Padding(_) => { + let current_line = buffer.num_lines(); self.draw_col_separator_no_space( - buffer, - buffer.num_lines(), + &mut buffer, + current_line, max_line_num_len + 1, ); } @@ -396,23 +401,31 @@ impl Renderer { || (matches!(section, Element::Title(_)) && i == 0) || matches!(section, Element::Title(level) if level.level.name == Some(None))) { + let current_line = buffer.num_lines(); if peek.is_none() && group_len > 1 { self.draw_col_separator_end( - buffer, - buffer.num_lines(), + &mut buffer, + current_line, max_line_num_len + 1, ); } else if matches!(peek, Some(Element::Title(level)) if level.level.name != Some(None)) { self.draw_col_separator_no_space( - buffer, - buffer.num_lines(), + &mut buffer, + current_line, max_line_num_len + 1, ); } } } + buffer.render(level, &self.stylesheet, &mut out_string)?; + if g != group_len - 1 { + use std::fmt::Write; + + writeln!(out_string)?; + } } + Ok(out_string) } #[allow(clippy::too_many_arguments)] diff --git a/src/renderer/styled_buffer.rs b/src/renderer/styled_buffer.rs index c9b805a0..aa2a7a2a 100644 --- a/src/renderer/styled_buffer.rs +++ b/src/renderer/styled_buffer.rs @@ -43,8 +43,8 @@ impl StyledBuffer { &self, level: Level<'_>, stylesheet: &Stylesheet, - ) -> Result { - let mut str = String::new(); + str: &mut String, + ) -> Result<(), fmt::Error> { for (i, line) in self.lines.iter().enumerate() { let mut current_style = stylesheet.none; for StyledChar { ch, style } in line { @@ -63,7 +63,7 @@ impl StyledBuffer { writeln!(str)?; } } - Ok(str) + Ok(()) } /// Sets `chr` with `style` for given `line`, `col`. From f64b07d3038ffefaff11441a198194945e66bb2a Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Fri, 30 May 2025 19:50:40 -0600 Subject: [PATCH 205/293] fix: Only bold the first title of a message --- examples/custom_level.svg | 2 +- examples/footer.svg | 4 +-- examples/highlight_title.svg | 2 +- src/level.rs | 7 +----- src/renderer/mod.rs | 48 ++++++++++++++++++++---------------- src/snippet.rs | 8 ------ tests/formatter.rs | 2 ++ 7 files changed, 34 insertions(+), 39 deletions(-) diff --git a/examples/custom_level.svg b/examples/custom_level.svg index eebff280..62dded57 100644 --- a/examples/custom_level.svg +++ b/examples/custom_level.svg @@ -41,7 +41,7 @@ ╰╴ - suggestion: use `break` on its own without a value inside this `while` loop + suggestion: use `break` on its own without a value inside this `while` loop ╭╴ diff --git a/examples/footer.svg b/examples/footer.svg index e24ba5f5..e55ee041 100644 --- a/examples/footer.svg +++ b/examples/footer.svg @@ -32,9 +32,9 @@ | - note: expected type: `snippet::Annotation` + note: expected type: `snippet::Annotation` - found type: `__&__snippet::Annotation` + found type: `__&__snippet::Annotation` diff --git a/examples/highlight_title.svg b/examples/highlight_title.svg index 24f1b364..c748a1de 100644 --- a/examples/highlight_title.svg +++ b/examples/highlight_title.svg @@ -41,7 +41,7 @@ found fn item `fn(Box<(dyn Any + Send + 'static)>) -> Pin<_> {wrapped_fn}` - note: function defined here + note: function defined here --> $DIR/highlighting.rs:10:4 diff --git a/src/level.rs b/src/level.rs index 87d1a9f6..eaa95600 100644 --- a/src/level.rs +++ b/src/level.rs @@ -78,7 +78,6 @@ impl<'a> Level<'a> { groups: vec![Group::new().element(Element::Title(Title { level: self, title: header, - primary: true, }))], } } @@ -92,11 +91,7 @@ impl<'a> Level<'a> { /// /// pub fn title(self, title: &'a str) -> Title<'a> { - Title { - level: self, - title, - primary: false, - } + Title { level: self, title } } pub(crate) fn as_str(&self) -> &'a str { diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 24455add..6afe3183 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -315,12 +315,16 @@ impl Renderer { let peek = message_iter.peek().map(|(_, s)| s).copied(); match §ion { Element::Title(title) => { + let title_style = match (i == 0, g == 0) { + (true, true) => TitleStyle::MainHeader, + (true, false) => TitleStyle::Header, + (false, _) => TitleStyle::Secondary, + }; self.render_title( &mut buffer, title, - peek, max_line_num_len, - if i == 0 { false } else { !title.primary }, + title_style, message.id.as_ref().and_then(|id| { if g == 0 && i == 0 { Some(id) @@ -433,26 +437,14 @@ impl Renderer { &self, buffer: &mut StyledBuffer, title: &Title<'_>, - next_section: Option<&Element<'_>>, max_line_num_len: usize, - is_secondary: bool, + title_style: TitleStyle, id: Option<&&str>, is_cont: bool, ) { let line_offset = buffer.num_lines(); - let (has_primary_spans, has_span_labels) = - next_section.map_or((false, false), |s| match s { - Element::Title(_) | Element::Padding(_) => (false, false), - Element::Cause(cause) => ( - cause.markers.iter().any(|m| m.kind.is_primary()), - cause.markers.iter().any(|m| m.label.is_some()), - ), - Element::Suggestion(_) => (true, false), - Element::Origin(_) => (false, true), - }); - - if !has_primary_spans && !has_span_labels && is_secondary { + if title_style == TitleStyle::Secondary { // This is a secondary message with no span info for _ in 0..max_line_num_len { buffer.prepend(line_offset, " ", ElementStyle::NoStyle); @@ -503,10 +495,10 @@ impl Renderer { buffer.append(line_offset, "]", ElementStyle::Level(title.level.level)); label_width += 2 + id.len(); } - let header_style = if is_secondary { - ElementStyle::HeaderMsg - } else { - ElementStyle::MainHeaderMsg + let header_style = match title_style { + TitleStyle::MainHeader => ElementStyle::MainHeaderMsg, + TitleStyle::Header => ElementStyle::HeaderMsg, + TitleStyle::Secondary => unreachable!(), }; if title.level.name != Some(None) { buffer.append(line_offset, ": ", header_style); @@ -661,7 +653,14 @@ impl Renderer { max_line_num_len + 1, ); let title = Level::NOTE.title(label); - self.render_title(buffer, &title, None, max_line_num_len, true, None, false); + self.render_title( + buffer, + &title, + max_line_num_len, + TitleStyle::Secondary, + None, + false, + ); } } @@ -2717,6 +2716,13 @@ pub enum OutputTheme { Unicode, } +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum TitleStyle { + MainHeader, + Header, + Secondary, +} + #[cfg(test)] mod test { use super::OUTPUT_REPLACEMENTS; diff --git a/src/snippet.rs b/src/snippet.rs index 7226783d..d3f50104 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -159,14 +159,6 @@ pub struct Padding; pub struct Title<'a> { pub(crate) level: Level<'a>, pub(crate) title: &'a str, - pub(crate) primary: bool, -} - -impl Title<'_> { - pub fn primary(mut self, primary: bool) -> Self { - self.primary = primary; - self - } } /// A source view [`Element`] in a [`Group`] diff --git a/tests/formatter.rs b/tests/formatter.rs index a0e4df87..4fd96ff2 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -1663,6 +1663,8 @@ zappy let input_new = Level::ERROR .header("the size for values of type `T` cannot be known at compilation time") .id("E0277") + // We need an empty group here to ensure the HELP line is rendered correctly + .group(Group::new()) .group( Group::new() .element(Level::HELP.title( From c5dc85b7461b532196d38f6c542298254e89c660 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Fri, 30 May 2025 19:50:40 -0600 Subject: [PATCH 206/293] fix: Better account for unicode chars when trimming --- src/renderer/mod.rs | 29 +++++++++++------------------ tests/formatter.rs | 16 ++++++++-------- 2 files changed, 19 insertions(+), 26 deletions(-) diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 6afe3183..fc5d2673 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -967,21 +967,7 @@ impl Renderer { let line_offset = buffer.num_lines(); - // Left trim - let left = margin.left(str_width(&source_string)); - - // FIXME: This looks fishy. See #132860. - // Account for unicode characters of width !=0 that were removed. - let mut taken = 0; - source_string.chars().for_each(|ch| { - let next = char_width(ch); - if taken + next <= left { - taken += next; - } - }); - - let left = taken; - self.draw_line( + let left = self.draw_line( buffer, &source_string, line_info.line_index, @@ -2036,12 +2022,12 @@ impl Renderer { code_offset: usize, max_line_num_len: usize, margin: Margin, - ) { + ) -> usize { // Tabs are assumed to have been replaced by spaces in calling code. debug_assert!(!source_string.contains('\t')); let line_len = str_width(source_string); // Create the source line we will highlight. - let left = margin.left(line_len); + let mut left = margin.left(line_len); let right = margin.right(line_len); // FIXME: The following code looks fishy. See #132860. // On long lines, we strip the source line, accounting for unicode. @@ -2074,10 +2060,15 @@ impl Renderer { break; } } + + if width_taken > padding { + left -= width_taken - padding; + } + buffer.puts( line_offset, code_offset, - &format!("{placeholder:>width_taken$}"), + placeholder, ElementStyle::LineNumber, ); (width_taken, bytes_taken) @@ -2121,6 +2112,8 @@ impl Renderer { ); self.draw_col_separator_no_space(buffer, line_offset, width_offset - 2); + + left } fn draw_range( diff --git a/tests/formatter.rs b/tests/formatter.rs index 4fd96ff2..664bd78a 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -2178,8 +2178,8 @@ fn unicode_cut_handling2() { let expected_ascii = str![[r#" error: expected item, found `?` | -1 | ...的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。*/? - | ^ expected item +1 | ... 的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。*/? + | ^ expected item = note: for a full list of items that can appear in modules, see "#]]; @@ -2189,8 +2189,8 @@ error: expected item, found `?` let expected_unicode = str![[r#" error: expected item, found `?` │ -1 │ …宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。*/? - │ ━ expected item +1 │ … 宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。*/? + │ ━ expected item ╰ note: for a full list of items that can appear in modules, see "#]]; let renderer_unicode = renderer_ascii.theme(OutputTheme::Unicode); @@ -2215,8 +2215,8 @@ fn unicode_cut_handling3() { let expected_ascii = str![[r#" error: expected item, found `?` | -1 | ...。这是宽的。这是宽的。这是宽的... - | ^^ expected item +1 | ... 。这是宽的。这是宽的。这是宽的... + | ^^ expected item = note: for a full list of items that can appear in modules, see "#]]; @@ -2226,8 +2226,8 @@ error: expected item, found `?` let expected_unicode = str![[r#" error: expected item, found `?` │ -1 │ …的。这是宽的。这是宽的。这是宽的。… - │ ━━ expected item +1 │ … 的。这是宽的。这是宽的。这是宽的。… + │ ━━ expected item ╰ note: for a full list of items that can appear in modules, see "#]]; let renderer_unicode = renderer_ascii.theme(OutputTheme::Unicode); From 8b5e6a3c77c16214251ce8b4f0df2be3558d40f4 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Thu, 29 May 2025 21:49:14 -0600 Subject: [PATCH 207/293] test: Add middle folding tests --- tests/rustc_tests.rs | 139 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index 69986292..9f5b1411 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -4,6 +4,7 @@ use annotate_snippets::{AnnotationKind, Group, Level, Origin, Renderer, Snippet}; +use annotate_snippets::renderer::OutputTheme; use snapbox::{assert_data_eq, str}; #[test] @@ -1881,3 +1882,141 @@ LL | trait EqAlias = Eq; let renderer = Renderer::plain().anonymized_line_numbers(true); assert_data_eq!(renderer.render(input), expected); } + +#[test] +fn long_span_shortest() { + // tests/ui/diagnostic-width/long-span.rs + let source = r#" +const C: u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + +fn main() {} +"#; + let input = Level::ERROR.header("mismatched types").id("E0038").group( + Group::new().element( + Snippet::source(source) + .origin("$DIR/long-span.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(15..5055) + .label("expected `u8`, found `[{integer}; 1680]`"), + ), + ), + ); + let expected = str![[r#" +error[E0038]: mismatched types + --> $DIR/long-span.rs:2:15 + | +LL | ... = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `[{integer}; 1680]` +"#]]; + + let renderer = Renderer::plain() + .anonymized_line_numbers(true) + .term_width(8); + assert_data_eq!(renderer.render(input), expected); +} + +#[test] +fn long_span_short() { + // tests/ui/diagnostic-width/long-span.rs + let source = r#" +const C: u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + +fn main() {} +"#; + let input = Level::ERROR.header("mismatched types").id("E0038").group( + Group::new().element( + Snippet::source(source) + .origin("$DIR/long-span.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(15..5055) + .label("expected `u8`, found `[{integer}; 1680]`"), + ), + ), + ); + let expected = str![[r#" +error[E0038]: mismatched types + ╭▸ $DIR/long-span.rs:2:15 + │ +LL │ …u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]… + ╰╴ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ expected `u8`, found `[{integer}; 1680]` +"#]]; + + let renderer = Renderer::plain() + .anonymized_line_numbers(true) + .term_width(12) + .theme(OutputTheme::Unicode); + assert_data_eq!(renderer.render(input), expected); +} + +#[test] +fn long_span_long() { + // tests/ui/diagnostic-width/long-span.rs + let source = r#" +const C: u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + +fn main() {} +"#; + let input = Level::ERROR.header("mismatched types").id("E0038").group( + Group::new().element( + Snippet::source(source) + .origin("$DIR/long-span.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(15..5055) + .label("expected `u8`, found `[{integer}; 1680]`"), + ), + ), + ); + let expected = str![[r#" +error[E0038]: mismatched types + ╭▸ $DIR/long-span.rs:2:15 + │ +LL │ …u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]… + ╰╴ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ expected `u8`, found `[{integer}; 1680]` +"#]]; + + let renderer = Renderer::plain() + .anonymized_line_numbers(true) + .term_width(80) + .theme(OutputTheme::Unicode); + assert_data_eq!(renderer.render(input), expected); +} + +#[test] +fn long_span_longest() { + // tests/ui/diagnostic-width/long-span.rs + let source = r#" +const C: u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + +fn main() {} +"#; + let input = Level::ERROR.header("mismatched types").id("E0038").group( + Group::new().element( + Snippet::source(source) + .origin("$DIR/long-span.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(15..5055) + .label("expected `u8`, found `[{integer}; 1680]`"), + ), + ), + ); + let expected = str![[r#" +error[E0038]: mismatched types + --> $DIR/long-span.rs:2:15 + | +LL | ... = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `[{integer}; 1680]` +"#]]; + + let renderer = Renderer::plain() + .anonymized_line_numbers(true) + .term_width(120); + assert_data_eq!(renderer.render(input), expected); +} From 6819166f36e98ce01772621154a6472f50ed4eb4 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Thu, 29 May 2025 21:50:03 -0600 Subject: [PATCH 208/293] fix: Don't add margin when span is near line end --- src/renderer/margin.rs | 12 ------------ src/renderer/mod.rs | 2 +- tests/rustc_tests.rs | 8 ++++---- 3 files changed, 5 insertions(+), 17 deletions(-) diff --git a/src/renderer/margin.rs b/src/renderer/margin.rs index c4844166..59bd5507 100644 --- a/src/renderer/margin.rs +++ b/src/renderer/margin.rs @@ -58,18 +58,6 @@ impl Margin { self.computed_left > 0 } - pub(crate) fn was_cut_right(&self, line_len: usize) -> bool { - let right = - if self.computed_right == self.span_right || self.computed_right == self.label_right { - // Account for the "..." padding given above. Otherwise we end up with code lines that - // do fit but end in "..." as if they were trimmed. - self.computed_right - ELLIPSIS_PASSING - } else { - self.computed_right - }; - right < line_len && self.computed_left + self.term_width < line_len - } - fn compute(&mut self, max_line_len: usize) { // When there's a lot of whitespace (>20), we want to trim it as it is useless. self.computed_left = if self.whitespace_left > LONG_WHITESPACE { diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index fc5d2673..77411a19 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -2083,7 +2083,7 @@ impl Renderer { ElementStyle::Quotation, ); - if margin.was_cut_right(line_len) { + if line_len > right { // We have stripped some code/whitespace from the beginning, make it clear. let mut char_taken = 0; let mut width_taken_inner = 0; diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index 9f5b1411..dd7dceb9 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -1907,7 +1907,7 @@ fn main() {} error[E0038]: mismatched types --> $DIR/long-span.rs:2:15 | -LL | ... = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... +LL | ... = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `[{integer}; 1680]` "#]]; @@ -1941,7 +1941,7 @@ fn main() {} error[E0038]: mismatched types ╭▸ $DIR/long-span.rs:2:15 │ -LL │ …u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]… +LL │ …u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; ╰╴ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ expected `u8`, found `[{integer}; 1680]` "#]]; @@ -1976,7 +1976,7 @@ fn main() {} error[E0038]: mismatched types ╭▸ $DIR/long-span.rs:2:15 │ -LL │ …u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]… +LL │ …u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; ╰╴ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ expected `u8`, found `[{integer}; 1680]` "#]]; @@ -2011,7 +2011,7 @@ fn main() {} error[E0038]: mismatched types --> $DIR/long-span.rs:2:15 | -LL | ... = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... +LL | ... = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `[{integer}; 1680]` "#]]; From 76f8220673be3a3ea44f733ab2c0863f054f19e1 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Fri, 30 May 2025 13:42:35 -0600 Subject: [PATCH 209/293] feat: Trim the middle of long spans --- src/renderer/margin.rs | 2 +- src/renderer/mod.rs | 38 +++++++++++++++++++++++++++++++++++ src/renderer/styled_buffer.rs | 10 +++++++++ tests/rustc_tests.rs | 16 +++++++-------- 4 files changed, 57 insertions(+), 9 deletions(-) diff --git a/src/renderer/margin.rs b/src/renderer/margin.rs index 59bd5507..6d3989be 100644 --- a/src/renderer/margin.rs +++ b/src/renderer/margin.rs @@ -17,7 +17,7 @@ pub(crate) struct Margin { /// The end of the line to be displayed. computed_right: usize, /// The current width of the terminal. 140 by default and in tests. - term_width: usize, + pub(crate) term_width: usize, /// The end column of a span label, including the span. Doesn't account for labels not in the /// same line as the span. label_right: usize, diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 77411a19..04dacdb3 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -1122,11 +1122,16 @@ impl Renderer { // | x_span // // + let mut overlap = vec![false; annotations.len()]; let mut annotations_position = vec![]; let mut line_len: usize = 0; let mut p = 0; for (i, annotation) in annotations.iter().enumerate() { for (j, next) in annotations.iter().enumerate() { + if overlaps(next, annotation, 0) && j > 1 { + overlap[i] = true; + overlap[j] = true; + } if overlaps(next, annotation, 0) // This label overlaps with another one and both && annotation.has_label() // take space (they have text and are not && j > i // multiline lines). @@ -1474,6 +1479,39 @@ impl Renderer { ); } } + + // We look for individual *long* spans, and we trim the *middle*, so that we render + // LL | ...= [0, 0, 0, ..., 0, 0]; + // | ^^^^^^^^^^...^^^^^^^ expected `&[u8]`, found `[{integer}; 1680]` + for (i, (_pos, annotation)) in annotations_position.iter().enumerate() { + // Skip cases where multiple spans overlap eachother. + if overlap[i] { + continue; + }; + let LineAnnotationType::Singleline = annotation.annotation_type else { + continue; + }; + let width = annotation.end.display - annotation.start.display; + if width > margin.term_width * 2 && width > 10 { + // If the terminal is *too* small, we keep at least a tiny bit of the span for + // display. + let pad = max(margin.term_width / 3, 5); + // Code line + buffer.replace( + line_offset, + annotation.start.display + pad, + annotation.end.display - pad, + self.margin(), + ); + // Underline line + buffer.replace( + line_offset + 1, + annotation.start.display + pad, + annotation.end.display - pad, + self.margin(), + ); + } + } annotations_position .iter() .filter_map(|&(_, annotation)| match annotation.annotation_type { diff --git a/src/renderer/styled_buffer.rs b/src/renderer/styled_buffer.rs index aa2a7a2a..925bb446 100644 --- a/src/renderer/styled_buffer.rs +++ b/src/renderer/styled_buffer.rs @@ -99,6 +99,16 @@ impl StyledBuffer { } } + pub(crate) fn replace(&mut self, line: usize, start: usize, end: usize, string: &str) { + if start == end { + return; + } + let _ = self.lines[line].drain(start..(end - string.chars().count())); + for (i, c) in string.chars().enumerate() { + self.lines[line][start + i] = StyledChar::new(c, ElementStyle::LineNumber); + } + } + /// For given `line` inserts `string` with `style` before old content of that line, /// adding lines if needed pub(crate) fn prepend(&mut self, line: usize, string: &str, style: ElementStyle) { diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index dd7dceb9..642c84ee 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -1907,8 +1907,8 @@ fn main() {} error[E0038]: mismatched types --> $DIR/long-span.rs:2:15 | -LL | ... = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `[{integer}; 1680]` +LL | ... = [0, 0, 0...0]; + | ^^^^^^^^...^^ expected `u8`, found `[{integer}; 1680]` "#]]; let renderer = Renderer::plain() @@ -1941,8 +1941,8 @@ fn main() {} error[E0038]: mismatched types ╭▸ $DIR/long-span.rs:2:15 │ -LL │ …u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - ╰╴ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ expected `u8`, found `[{integer}; 1680]` +LL │ …u8 = [0, 0, 0…0]; + ╰╴ ━━━━━━━━…━━ expected `u8`, found `[{integer}; 1680]` "#]]; let renderer = Renderer::plain() @@ -1976,8 +1976,8 @@ fn main() {} error[E0038]: mismatched types ╭▸ $DIR/long-span.rs:2:15 │ -LL │ …u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - ╰╴ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ expected `u8`, found `[{integer}; 1680]` +LL │ …u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, …, 0, 0, 0, 0, 0, 0, 0]; + ╰╴ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━…━━━━━━━━━━━━━━━━━━━━━━ expected `u8`, found `[{integer}; 1680]` "#]]; let renderer = Renderer::plain() @@ -2011,8 +2011,8 @@ fn main() {} error[E0038]: mismatched types --> $DIR/long-span.rs:2:15 | -LL | ... = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `[{integer}; 1680]` +LL | ... = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `[{integer}; 1680]` "#]]; let renderer = Renderer::plain() From 14fb674cd6561a4631341fcd7f748cdff33de385 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Sat, 31 May 2025 00:09:21 -0600 Subject: [PATCH 210/293] fix: Match rustc's first group trailing line --- examples/highlight_source.svg | 8 +++++--- src/renderer/mod.rs | 28 +++++++++++++++------------- tests/formatter.rs | 7 +++++++ 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/examples/highlight_source.svg b/examples/highlight_source.svg index 391a097d..14014944 100644 --- a/examples/highlight_source.svg +++ b/examples/highlight_source.svg @@ -1,4 +1,4 @@ - + | ^^^^^^^^^^^^^ allocation not allowed in constants - = note: The runtime heap is not yet available at compile-time, so no runtime heap allocations can be created. + | - + = note: The runtime heap is not yet available at compile-time, so no runtime heap allocations can be created. + +
diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 04dacdb3..ab791edd 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -351,23 +351,25 @@ impl Renderer { peek.is_some() || (g == 0 && group_len > 1), ); - if g == 0 && group_len > 1 { + if g == 0 { let current_line = buffer.num_lines(); - if matches!(peek, Some(Element::Title(level)) if level.level.name != Some(None)) - { - self.draw_col_separator_no_space( - &mut buffer, - current_line, - max_line_num_len + 1, - ); - // We want to draw the separator when it is - // requested, or when it is the last element - } else if peek.is_none() { - self.draw_col_separator_end( + match peek { + Some(Element::Title(level)) + if level.level.name != Some(None) => + { + self.draw_col_separator_no_space( + &mut buffer, + current_line, + max_line_num_len + 1, + ); + } + + None if group_len > 1 => self.draw_col_separator_end( &mut buffer, current_line, max_line_num_len + 1, - ); + ), + _ => {} } } } diff --git a/tests/formatter.rs b/tests/formatter.rs index 664bd78a..7e25a011 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -2021,6 +2021,7 @@ LL │ ┃ Ok("") LL │ ┃ )))))))))))))))))))))))))))))) LL │ ┃ )))))))))))))))))))))))))))))); │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `Atype, i32>, i32>`, found `Result, _>, _>` + │ ├ note: expected struct `Atype, i32>` │ found enum `Result, _>` ├ note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' @@ -2180,6 +2181,7 @@ error: expected item, found `?` | 1 | ... 的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。*/? | ^ expected item + | = note: for a full list of items that can appear in modules, see "#]]; @@ -2191,6 +2193,7 @@ error: expected item, found `?` │ 1 │ … 宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。*/? │ ━ expected item + │ ╰ note: for a full list of items that can appear in modules, see "#]]; let renderer_unicode = renderer_ascii.theme(OutputTheme::Unicode); @@ -2217,6 +2220,7 @@ error: expected item, found `?` | 1 | ... 。这是宽的。这是宽的。这是宽的... | ^^ expected item + | = note: for a full list of items that can appear in modules, see "#]]; @@ -2228,6 +2232,7 @@ error: expected item, found `?` │ 1 │ … 的。这是宽的。这是宽的。这是宽的。… │ ━━ expected item + │ ╰ note: for a full list of items that can appear in modules, see "#]]; let renderer_unicode = renderer_ascii.theme(OutputTheme::Unicode); @@ -2254,6 +2259,7 @@ error: expected item, found `?` | 1 | ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa*/? | ^ expected item + | = note: for a full list of items that can appear in modules, see "#]]; @@ -2265,6 +2271,7 @@ error: expected item, found `?` │ 1 │ …aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa*/? │ ━ expected item + │ ╰ note: for a full list of items that can appear in modules, see "#]]; let renderer_unicode = renderer_ascii.theme(OutputTheme::Unicode); From a4c20fb6fecf5bfc54dd5204f29e4d9b5d1dd90e Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Mon, 2 Jun 2025 19:40:48 -0600 Subject: [PATCH 211/293] test: Add another rustc multiline test --- tests/rustc_tests.rs | 93 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index 642c84ee..9649c12b 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -2,7 +2,7 @@ //! //! [parser-tests]: https://github.com/rust-lang/rust/blob/894f7a4ba6554d3797404bbf550d9919df060b97/compiler/rustc_parse/src/parser/tests.rs -use annotate_snippets::{AnnotationKind, Group, Level, Origin, Renderer, Snippet}; +use annotate_snippets::{AnnotationKind, Group, Level, Origin, Patch, Renderer, Snippet}; use annotate_snippets::renderer::OutputTheme; use snapbox::{assert_data_eq, str}; @@ -2020,3 +2020,94 @@ LL | ... = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...0, 0, 0, 0, 0, 0, 0, 0, 0 .term_width(120); assert_data_eq!(renderer.render(input), expected); } + +#[test] +fn lint_map_unit_fn() { + // tests/ui/lint/lint_map_unit_fn.rs + let source = r#"#![deny(map_unit_fn)] + +fn foo(items: &mut Vec) { + items.sort(); +} + +fn main() { + let mut x: Vec> = vec![vec![0, 2, 1], vec![5, 4, 3]]; + x.iter_mut().map(foo); + //~^ ERROR `Iterator::map` call that discard the iterator's values + x.iter_mut().map(|items| { + //~^ ERROR `Iterator::map` call that discard the iterator's values + items.sort(); + }); + let f = |items: &mut Vec| { + items.sort(); + }; + x.iter_mut().map(f); + //~^ ERROR `Iterator::map` call that discard the iterator's values +} +"#; + + let input = Level::ERROR + .header("`Iterator::map` call that discard the iterator's values") + .group( + Group::new() + .element( + Snippet::source(source) + .origin("$DIR/lint_map_unit_fn.rs") + .fold(true) + .annotation(AnnotationKind::Context.span(271..278).label( + "this function returns `()`, which is likely not what you wanted", + )) + .annotation( + AnnotationKind::Context + .span(271..379) + .label("called `Iterator::map` with callable that returns `()`"), + ) + .annotation( + AnnotationKind::Context + .span(267..380) + .label("after this call to map, the resulting iterator is `impl Iterator`, which means the only information carried by the iterator is the number of items") + ) + .annotation(AnnotationKind::Primary.span(267..380)), + ) + .element( + Level::NOTE.title("`Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated")), + ) + .group( + Group::new() + .element(Level::HELP.title("you might have meant to use `Iterator::for_each`")) + .element( + Snippet::source(source) + .origin("$DIR/lint_map_unit_fn.rs") + .fold(true) + .patch(Patch::new(267..270, r#"for_each"#)), + ), + ); + + let expected = str![[r#" +error: `Iterator::map` call that discard the iterator's values + --> $DIR/lint_map_unit_fn.rs:11:18 + | +LL | x.iter_mut().map(|items| { + | ^ ------- + | | | + | __________________|___this function returns `()`, which is likely not what you wanted + | |__________________| + | || +LL | || //~^ ERROR `Iterator::map` call that discard the iterator's values +LL | || items.sort(); +LL | || }); + | || -^ after this call to map, the resulting iterator is `impl Iterator`, which means the only information carried by the iterator is the number of items + | ||_____|| + | |_____| + | called `Iterator::map` with callable that returns `()` + | + = note: `Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated +help: you might have meant to use `Iterator::for_each` + | +LL - x.iter_mut().map(|items| { +LL + x.iter_mut().for_each(|items| { + | +"#]]; + let renderer = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer.render(input), expected); +} From c8041fe43246091b2e7a0158c8ab89146568321c Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Sat, 31 May 2025 00:09:21 -0600 Subject: [PATCH 212/293] fix: Match rustc's multiline reordering --- src/renderer/source_map.rs | 3 +-- tests/formatter.rs | 16 ++++++++-------- tests/rustc_tests.rs | 26 +++++++++++++------------- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/renderer/source_map.rs b/src/renderer/source_map.rs index d42dccce..eca057ee 100644 --- a/src/renderer/source_map.rs +++ b/src/renderer/source_map.rs @@ -194,8 +194,7 @@ impl<'a> SourceMap<'a> { let mut primary_spans = vec![]; // Find overlapping multiline annotations, put them at different depths - multiline_annotations - .sort_by_key(|ml| (ml.start.line, usize::MAX - ml.end.line, ml.start.byte)); + multiline_annotations.sort_by_key(|ml| (ml.start.line, usize::MAX - ml.end.line)); for ann in multiline_annotations.clone() { if ann.kind.is_primary() { primary_spans.push((ann.start, ann.end)); diff --git a/tests/formatter.rs b/tests/formatter.rs index 7e25a011..bf998539 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -887,15 +887,15 @@ bar = { version = "0.1.0", optional = true } error: unused optional dependency | 4 | bar = { version = "0.1.0", optional = true } - | _________^__________________--------------^ - | | | | - | |_________| This should also be long but not too long + | __________^__________________--------------^ + | | | | + | | _________| This should also be long but not too long | || 5 | || this is another line 6 | || so is this 7 | || bar = { version = "0.1.0", optional = true } | ||_________________________^________________^ I need this to be really long so I can test overlaps - | |__________________________| + | |_________________________| | I need this to be really long so I can test overlaps "#]]; let renderer = Renderer::plain(); @@ -940,16 +940,16 @@ this is another line error: unused optional dependency | 4 | bar = { version = "0.1.0", optional = true } - | __________^__________________--------------^ - | | | | - | |__________| This should also be long but not too long + | ___________^__________________--------------^ + | | | | + | | __________| This should also be long but not too long | || 5 | || this is another line | || ____^ 6 | ||| so is this 7 | ||| bar = { version = "0.1.0", optional = true } | |||_________________________^________________^ I need this to be really long so I can test overlaps - | |_|_________________________| + | ||_________________________| | | I need this to be really long so I can test overlaps 8 | | this is another line | |____^ I need this to be really long so I can test overlaps diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index 9649c12b..cf33969a 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -2087,19 +2087,19 @@ fn main() { error: `Iterator::map` call that discard the iterator's values --> $DIR/lint_map_unit_fn.rs:11:18 | -LL | x.iter_mut().map(|items| { - | ^ ------- - | | | - | __________________|___this function returns `()`, which is likely not what you wanted - | |__________________| - | || -LL | || //~^ ERROR `Iterator::map` call that discard the iterator's values -LL | || items.sort(); -LL | || }); - | || -^ after this call to map, the resulting iterator is `impl Iterator`, which means the only information carried by the iterator is the number of items - | ||_____|| - | |_____| - | called `Iterator::map` with callable that returns `()` +LL | x.iter_mut().map(|items| { + | ^ ------- + | | | + | ____________________|___this function returns `()`, which is likely not what you wanted + | | __________________| + | | | +LL | | | //~^ ERROR `Iterator::map` call that discard the iterator's values +LL | | | items.sort(); +LL | | | }); + | | | -^ after this call to map, the resulting iterator is `impl Iterator`, which means the only information carried by the iterator is the number of items + | | |_____|| + | |_______| + | called `Iterator::map` with callable that returns `()` | = note: `Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated help: you might have meant to use `Iterator::for_each` From 5cc5a3c8905e8a29f5a7c59408057f7484ccb324 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Tue, 3 Jun 2025 09:45:06 -0600 Subject: [PATCH 213/293] test: Add rustc tests for pointing at end of line --- tests/rustc_tests.rs | 352 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 352 insertions(+) diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index cf33969a..d013aa33 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -2111,3 +2111,355 @@ LL + x.iter_mut().for_each(|items| { let renderer = Renderer::plain().anonymized_line_numbers(true); assert_data_eq!(renderer.render(input), expected); } + +#[test] +fn bad_char_literals() { + // tests/ui/parser/bad-char-literals.rs + + let source = r#"// ignore-tidy-cr +// ignore-tidy-tab + +fn main() { + // these literals are just silly. + '''; + //~^ ERROR: character constant must be escaped: `'` + + // note that this is a literal "\n" byte + ' +'; + //~^^ ERROR: character constant must be escaped: `\n` + + // note that this is a literal "\r" byte +; //~ ERROR: character constant must be escaped: `\r` + + // note that this is a literal NULL + '--'; //~ ERROR: character literal may only contain one codepoint + + // note that this is a literal tab character here + ' '; + //~^ ERROR: character constant must be escaped: `\t` +} +"#; + + let input = Level::ERROR + .header("character constant must be escaped: `\\n`") + .group( + Group::new().element( + Snippet::source(source) + .origin("$DIR/bad-char-literals.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(204..205)), + ), + ) + .group( + Group::new() + .element(Level::HELP.title("escape the character")) + .element( + Snippet::source(source) + .origin("$DIR/bad-char-literals.rs") + .line_start(1) + .fold(true) + .patch(Patch::new(204..205, r#"\n"#)), + ), + ); + let expected = str![[r#" +error: character constant must be escaped: `/n` + --> $DIR/bad-char-literals.rs:10:6 + | +LL | ' + | ^ + | +help: escape the character + | +LL | '/n + | ++ +"#]]; + let renderer = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer.render(input), expected); +} + +#[test] +fn unclosed_1() { + // tests/ui/frontmatter/unclosed-1.rs + + let source = r#"----cargo +//~^ ERROR: unclosed frontmatter + +// This test checks that the #! characters can help us recover a frontmatter +// close. There should not be a "missing `main` function" error as the rest +// are properly parsed. + +#![feature(frontmatter)] + +fn main() {} +"#; + + let input = Level::ERROR + .header("unclosed frontmatter") + .group( + Group::new().element( + Snippet::source(source) + .origin("$DIR/unclosed-1.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(0..221)), + ), + ) + .group( + Group::new() + .element(Level::NOTE.title("frontmatter opening here was not closed")) + .element( + Snippet::source(source) + .origin("$DIR/unclosed-1.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(0..4)), + ), + ); + let expected = str![[r#" +error: unclosed frontmatter + --> $DIR/unclosed-1.rs:1:1 + | +LL | / ----cargo +... | +LL | | // are properly parsed. + | |________________________^ + | +note: frontmatter opening here was not closed + --> $DIR/unclosed-1.rs:1:1 + | +LL | ----cargo + | ^^^^ +"#]]; + let renderer = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer.render(input), expected); +} + +#[test] +fn unclosed_2() { + // tests/ui/frontmatter/unclosed-2.rs + + let source = r#"----cargo +//~^ ERROR: unclosed frontmatter +//~| ERROR: frontmatters are experimental + +//@ compile-flags: --crate-type lib + +// Leading whitespace on the feature line prevents recovery. However +// the dashes quoted will not be used for recovery and the entire file +// should be treated as within the frontmatter block. + + #![feature(frontmatter)] + +fn foo() -> &str { + "----" +} +"#; + + let input = Level::ERROR + .header("unclosed frontmatter") + .group( + Group::new().element( + Snippet::source(source) + .origin("$DIR/unclosed-2.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(0..377)), + ), + ) + .group( + Group::new() + .element(Level::NOTE.title("frontmatter opening here was not closed")) + .element( + Snippet::source(source) + .origin("$DIR/unclosed-2.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(0..4)), + ), + ); + let expected = str![[r#" +error: unclosed frontmatter + --> $DIR/unclosed-2.rs:1:1 + | +LL | / ----cargo +... | +LL | | "----" +LL | | } + | |__^ + | +note: frontmatter opening here was not closed + --> $DIR/unclosed-2.rs:1:1 + | +LL | ----cargo + | ^^^^ +"#]]; + let renderer = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer.render(input), expected); +} + +#[test] +fn unclosed_3() { + // tests/ui/frontmatter/unclosed-3.rs + + let source = r#"----cargo +//~^ ERROR: frontmatter close does not match the opening + +//@ compile-flags: --crate-type lib + +// Unfortunate recovery situation. Not really preventable with improving the +// recovery strategy, but this type of code is rare enough already. + + #![feature(frontmatter)] + +fn foo(x: i32) -> i32 { + ---x + //~^ ERROR: invalid preceding whitespace for frontmatter close + //~| ERROR: extra characters after frontmatter close are not allowed +} +//~^ ERROR: unexpected closing delimiter: `}` +"#; + + let input = Level::ERROR + .header("invalid preceding whitespace for frontmatter close") + .group( + Group::new().element( + Snippet::source(source) + .origin("$DIR/unclosed-3.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(302..310)), + ), + ) + .group( + Group::new() + .element( + Level::NOTE.title("frontmatter close should not be preceded by whitespace"), + ) + .element( + Snippet::source(source) + .origin("$DIR/unclosed-3.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(302..306)), + ), + ); + let expected = str![[r#" +error: invalid preceding whitespace for frontmatter close + --> $DIR/unclosed-3.rs:12:1 + | +LL | ---x + | ^^^^^^^^ + | +note: frontmatter close should not be preceded by whitespace + --> $DIR/unclosed-3.rs:12:1 + | +LL | ---x + | ^^^^ +"#]]; + let renderer = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer.render(input), expected); +} + +#[test] +fn unclosed_4() { + // tests/ui/frontmatter/unclosed-4.rs + + let source = r#"----cargo +//~^ ERROR: unclosed frontmatter + +//! Similarly, a module-level content should allow for recovery as well (as +//! per unclosed-1.rs) + +#![feature(frontmatter)] + +fn main() {} +"#; + + let input = Level::ERROR + .header("unclosed frontmatter") + .group( + Group::new().element( + Snippet::source(source) + .origin("$DIR/unclosed-4.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(0..43)), + ), + ) + .group( + Group::new() + .element(Level::NOTE.title("frontmatter opening here was not closed")) + .element( + Snippet::source(source) + .origin("$DIR/unclosed-4.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(0..4)), + ), + ); + let expected = str![[r#" +error: unclosed frontmatter + --> $DIR/unclosed-4.rs:1:1 + | +LL | / ----cargo +LL | | //~^ ERROR: unclosed frontmatter + | |_________________________________^ + | +note: frontmatter opening here was not closed + --> $DIR/unclosed-4.rs:1:1 + | +LL | ----cargo + | ^^^^ +"#]]; + let renderer = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer.render(input), expected); +} + +#[test] +fn unclosed_5() { + // tests/ui/frontmatter/unclosed-5.rs + + let source = r#"----cargo +//~^ ERROR: unclosed frontmatter +//~| ERROR: frontmatters are experimental + +// Similarly, a use statement should allow for recovery as well (as +// per unclosed-1.rs) + +use std::env; + +fn main() {} +"#; + + let input = Level::ERROR + .header("unclosed frontmatter") + .group( + Group::new().element( + Snippet::source(source) + .origin("$DIR/unclosed-5.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(0..176)), + ), + ) + .group( + Group::new() + .element(Level::NOTE.title("frontmatter opening here was not closed")) + .element( + Snippet::source(source) + .origin("$DIR/unclosed-5.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(0..4)), + ), + ); + + let expected = str![[r#" +error: unclosed frontmatter + --> $DIR/unclosed-5.rs:1:1 + | +LL | / ----cargo +... | +LL | | // per unclosed-1.rs) + | |______________________^ + | +note: frontmatter opening here was not closed + --> $DIR/unclosed-5.rs:1:1 + | +LL | ----cargo + | ^^^^ +"#]]; + let renderer = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer.render(input), expected); +} From 47e7ec6a8c10ab9766e6812a744c7ae8b7cff972 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Tue, 3 Jun 2025 09:45:06 -0600 Subject: [PATCH 214/293] fix: Match how rustc handles annotating newlines --- src/renderer/source_map.rs | 8 ++--- tests/color/ann_multiline2.term.svg | 12 ++++--- tests/color/simple.term.svg | 14 ++++---- tests/formatter.rs | 55 +++++++++++++++++------------ tests/rustc_tests.rs | 19 +++++----- 5 files changed, 60 insertions(+), 48 deletions(-) diff --git a/src/renderer/source_map.rs b/src/renderer/source_map.rs index eca057ee..403c1c63 100644 --- a/src/renderer/source_map.rs +++ b/src/renderer/source_map.rs @@ -73,9 +73,9 @@ impl<'a> SourceMap<'a> { let end_info = self .lines .iter() - .find(|info| info.end_byte > span.end.saturating_sub(1)) + .find(|info| span.end >= info.start_byte && span.end < info.end_byte) .unwrap_or(self.lines.last().unwrap()); - let (mut end_char_pos, end_display_pos) = end_info.line + let (end_char_pos, end_display_pos) = end_info.line [0..(span.end - end_info.start_byte).min(end_info.line.len())] .chars() .fold((0, 0), |(char_pos, byte_pos), c| { @@ -83,10 +83,6 @@ impl<'a> SourceMap<'a> { (char_pos + 1, byte_pos + display) }); - // correct the char pos if we are highlighting the end of a line - if (span.end - end_info.start_byte).saturating_sub(end_info.line.len()) > 0 { - end_char_pos += 1; - } let mut end = Loc { line: end_info.line_index, char: end_char_pos, diff --git a/tests/color/ann_multiline2.term.svg b/tests/color/ann_multiline2.term.svg index 24827f66..2f7eb902 100644 --- a/tests/color/ann_multiline2.term.svg +++ b/tests/color/ann_multiline2.term.svg @@ -1,4 +1,4 @@ - +
| - 26 | This is an example + 26 | This is an example - | ^^^^^^^ this should not be on separate lines + | ____________^ - 27 | of an edge case of an annotation overflowing + 27 | | of an edge case of an annotation overflowing - 28 | to exactly one character on next line. + | |_^ this should not be on separate lines + + 28 | to exactly one character on next line. diff --git a/tests/color/simple.term.svg b/tests/color/simple.term.svg index b849cf46..76aa393e 100644 --- a/tests/color/simple.term.svg +++ b/tests/color/simple.term.svg @@ -1,4 +1,4 @@ - + | - 169 | }) + 169 | }) - | - expected one of `.`, `;`, `?`, or an operator here + | ___________- - 170 | + 170 | | - 171 | for line in &self.body { + | |_- expected one of `.`, `;`, `?`, or an operator here - | ^^^ unexpected token + 171 | for line in &self.body { + + | ^^^ unexpected token diff --git a/tests/formatter.rs b/tests/formatter.rs index bf998539..e5647b8c 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -415,9 +415,9 @@ fn char_eol_annotate_char() { error: --> file/path:3:1 | -3 | a - | ^ -4 | b +3 | / a +4 | | b + | |_^ "#]]; let renderer = Renderer::plain().anonymized_line_numbers(false); assert_data_eq!(renderer.render(input), expected); @@ -437,10 +437,11 @@ fn char_eol_annotate_char_double_width() { error: --> :1:2 | -1 | こん - | ^^ -2 | にちは -3 | 世界 +1 | こん + | ___^ +2 | | にちは + | |_^ +3 | 世界 "#]]; let renderer = Renderer::plain(); @@ -485,9 +486,10 @@ fn annotate_eol2() { error: --> file/path:3:2 | -3 | a - | ^ -4 | b +3 | a + | __^ +4 | | b + | |_^ "#]]; let renderer = Renderer::plain().anonymized_line_numbers(false); assert_data_eq!(renderer.render(input), expected); @@ -508,9 +510,10 @@ fn annotate_eol3() { error: --> file/path:3:3 | -3 | a - | ^ -4 | b +3 | a + | __^ +4 | | b + | |_^ "#]]; let renderer = Renderer::plain().anonymized_line_numbers(false); assert_data_eq!(renderer.render(input), expected); @@ -553,10 +556,11 @@ fn annotate_eol_double_width() { error: --> :1:4 | -1 | こん - | ^ -2 | にちは -3 | 世界 +1 | こん + | _____^ +2 | | にちは + | |_^ +3 | 世界 "#]]; let renderer = Renderer::plain(); @@ -678,8 +682,8 @@ error: 3 | a | __^ 4 | | b - | |__^ -5 | c +5 | | c + | |_^ "#]]; let renderer = Renderer::plain().anonymized_line_numbers(false); assert_data_eq!(renderer.render(input), expected); @@ -728,8 +732,8 @@ error: 3 | a | __^ 4 | | b - | |__^ -5 | c +5 | | c + | |_^ "#]]; let renderer = Renderer::plain().anonymized_line_numbers(false); assert_data_eq!(renderer.render(input), expected); @@ -1532,6 +1536,7 @@ LL - T LL - : LL - ? LL - Sized +LL + { | "#]]; let renderer = Renderer::plain().anonymized_line_numbers(true); @@ -1640,8 +1645,12 @@ LL | struct Wrapper(T); | this could be changed to `T: ?Sized`... help: consider removing the `?Sized` bound to make the type parameter `Sized` | -LL ~ and -LL ~ + Send{ +LL - and where +LL - T +LL - : +LL - ? +LL - Sized +LL + and + Send{ | "#]]; let renderer = Renderer::plain().anonymized_line_numbers(true); diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index d013aa33..4979e77a 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -2166,12 +2166,14 @@ fn main() { error: character constant must be escaped: `/n` --> $DIR/bad-char-literals.rs:10:6 | -LL | ' - | ^ +LL | ' + | ______^ +LL | | '; + | |_^ | help: escape the character | -LL | '/n +LL | '/n'; | ++ "#]]; let renderer = Renderer::plain().anonymized_line_numbers(true); @@ -2220,8 +2222,8 @@ error: unclosed frontmatter | LL | / ----cargo ... | -LL | | // are properly parsed. - | |________________________^ +LL | | + | |_^ | note: frontmatter opening here was not closed --> $DIR/unclosed-1.rs:1:1 @@ -2396,7 +2398,8 @@ error: unclosed frontmatter | LL | / ----cargo LL | | //~^ ERROR: unclosed frontmatter - | |_________________________________^ +LL | | + | |_^ | note: frontmatter opening here was not closed --> $DIR/unclosed-4.rs:1:1 @@ -2451,8 +2454,8 @@ error: unclosed frontmatter | LL | / ----cargo ... | -LL | | // per unclosed-1.rs) - | |______________________^ +LL | | + | |_^ | note: frontmatter opening here was not closed --> $DIR/unclosed-5.rs:1:1 From 7a77fce612eecced766a905074ed5bd0c33e6c49 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Tue, 3 Jun 2025 09:45:06 -0600 Subject: [PATCH 215/293] test: Add rustc tests for annotation sorting --- tests/rustc_tests.rs | 212 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 212 insertions(+) diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index 4979e77a..ec8ee7f6 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -2466,3 +2466,215 @@ LL | ----cargo let renderer = Renderer::plain().anonymized_line_numbers(true); assert_data_eq!(renderer.render(input), expected); } + +#[test] +fn pat_tuple_field_count_cross() { + // tests/ui/pattern/pat-tuple-field-count-cross.stderr + + let source = r#"//@ aux-build:declarations-for-tuple-field-count-errors.rs + +extern crate declarations_for_tuple_field_count_errors; + +use declarations_for_tuple_field_count_errors::*; + +fn main() { + match Z0 { + Z0() => {} //~ ERROR expected tuple struct or tuple variant, found unit struct `Z0` + Z0(x) => {} //~ ERROR expected tuple struct or tuple variant, found unit struct `Z0` + } + match Z1() { + Z1 => {} //~ ERROR match bindings cannot shadow tuple structs + Z1(x) => {} //~ ERROR this pattern has 1 field, but the corresponding tuple struct has 0 fields + } + + match S(1, 2, 3) { + S() => {} //~ ERROR this pattern has 0 fields, but the corresponding tuple struct has 3 fields + S(1) => {} //~ ERROR this pattern has 1 field, but the corresponding tuple struct has 3 fields + S(xyz, abc) => {} //~ ERROR this pattern has 2 fields, but the corresponding tuple struct has 3 fields + S(1, 2, 3, 4) => {} //~ ERROR this pattern has 4 fields, but the corresponding tuple struct has 3 fields + } + match M(1, 2, 3) { + M() => {} //~ ERROR this pattern has 0 fields, but the corresponding tuple struct has 3 fields + M(1) => {} //~ ERROR this pattern has 1 field, but the corresponding tuple struct has 3 fields + M(xyz, abc) => {} //~ ERROR this pattern has 2 fields, but the corresponding tuple struct has 3 fields + M(1, 2, 3, 4) => {} //~ ERROR this pattern has 4 fields, but the corresponding tuple struct has 3 fields + } + + match E1::Z0 { + E1::Z0() => {} //~ ERROR expected tuple struct or tuple variant, found unit variant `E1::Z0` + E1::Z0(x) => {} //~ ERROR expected tuple struct or tuple variant, found unit variant `E1::Z0` + } + match E1::Z1() { + E1::Z1 => {} //~ ERROR expected unit struct, unit variant or constant, found tuple variant `E1::Z1` + E1::Z1(x) => {} //~ ERROR this pattern has 1 field, but the corresponding tuple variant has 0 fields + } + match E1::S(1, 2, 3) { + E1::S() => {} //~ ERROR this pattern has 0 fields, but the corresponding tuple variant has 3 fields + E1::S(1) => {} //~ ERROR this pattern has 1 field, but the corresponding tuple variant has 3 fields + E1::S(xyz, abc) => {} //~ ERROR this pattern has 2 fields, but the corresponding tuple variant has 3 fields + E1::S(1, 2, 3, 4) => {} //~ ERROR this pattern has 4 fields, but the corresponding tuple variant has 3 fields + } + + match E2::S(1, 2, 3) { + E2::S() => {} //~ ERROR this pattern has 0 fields, but the corresponding tuple variant has 3 fields + E2::S(1) => {} //~ ERROR this pattern has 1 field, but the corresponding tuple variant has 3 fields + E2::S(xyz, abc) => {} //~ ERROR this pattern has 2 fields, but the corresponding tuple variant has 3 fields + E2::S(1, 2, 3, 4) => {} //~ ERROR this pattern has 4 fields, but the corresponding tuple variant has 3 fields + } + match E2::M(1, 2, 3) { + E2::M() => {} //~ ERROR this pattern has 0 fields, but the corresponding tuple variant has 3 fields + E2::M(1) => {} //~ ERROR this pattern has 1 field, but the corresponding tuple variant has 3 fields + E2::M(xyz, abc) => {} //~ ERROR this pattern has 2 fields, but the corresponding tuple variant has 3 fields + E2::M(1, 2, 3, 4) => {} //~ ERROR this pattern has 4 fields, but the corresponding tuple variant has 3 fields + } +} +"#; + let source1 = r#"pub struct Z0; +pub struct Z1(); + +pub struct S(pub u8, pub u8, pub u8); +pub struct M( + pub u8, + pub u8, + pub u8, +); + +pub enum E1 { Z0, Z1(), S(u8, u8, u8) } + +pub enum E2 { + S(u8, u8, u8), + M( + u8, + u8, + u8, + ), +} +"#; + + let input = Level::ERROR + .header("expected unit struct, unit variant or constant, found tuple variant `E1::Z1`") + .id(r#"E0532"#) + .group( + Group::new() + .element( + Snippet::source(source) + .origin("$DIR/pat-tuple-field-count-cross.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(1760..1766)), + ) + .element( + Snippet::source(source1) + .origin("$DIR/auxiliary/declarations-for-tuple-field-count-errors.rs") + .fold(true) + .annotation( + AnnotationKind::Context + .span(143..145) + .label("`E1::Z1` defined here"), + ) + .annotation( + AnnotationKind::Context + .span(139..141) + .label("similarly named unit variant `Z0` defined here"), + ), + ), + ) + .group( + Group::new() + .element(Level::HELP.title("use the tuple variant pattern syntax instead")) + .element( + Snippet::source(source) + .origin("$DIR/pat-tuple-field-count-cross.rs") + .fold(true) + .patch(Patch::new(1760..1766, r#"E1::Z1()"#)), + ), + ) + .group( + Group::new() + .element(Level::HELP.title("a unit variant with a similar name exists")) + .element( + Snippet::source(source) + .origin("$DIR/pat-tuple-field-count-cross.rs") + .fold(true) + .patch(Patch::new(1764..1766, r#"Z0"#)), + ), + ); + let expected = str![[r#" +error[E0532]: expected unit struct, unit variant or constant, found tuple variant `E1::Z1` + --> $DIR/pat-tuple-field-count-cross.rs:35:9 + | +LL | E1::Z1 => {} //~ ERROR expected unit struct, unit variant or constant, found tuple variant `E1::Z1` + | ^^^^^^ + | + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:11:15 + | +LL | pub enum E1 { Z0, Z1(), S(u8, u8, u8) } + | -- -- `E1::Z1` defined here + | | + | similarly named unit variant `Z0` defined here + | +help: use the tuple variant pattern syntax instead + | +LL | E1::Z1() => {} //~ ERROR expected unit struct, unit variant or constant, found tuple variant `E1::Z1` + | ++ +help: a unit variant with a similar name exists + | +LL - E1::Z1 => {} //~ ERROR expected unit struct, unit variant or constant, found tuple variant `E1::Z1` +LL + E1::Z0 => {} //~ ERROR expected unit struct, unit variant or constant, found tuple variant `E1::Z1` + | +"#]]; + let renderer = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer.render(input), expected); +} + +#[test] +fn unterminated_nested_comment() { + // tests/ui/lexer/unterminated-nested-comment.rs + + let source = r#"/* //~ ERROR E0758 +/* */ +/* +*/ +"#; + + let input = Level::ERROR.header("unterminated block comment").id("E0758").group( + Group::new().element( + Snippet::source(source) + .origin("$DIR/unterminated-nested-comment.rs") + .fold(true) + .annotation( + AnnotationKind::Context + .span(0..2) + .label("unterminated block comment"), + ) + .annotation(AnnotationKind::Context.span(25..27).label( + "...as last nested comment starts here, maybe you want to close this instead?", + )) + .annotation( + AnnotationKind::Context + .span(28..30) + .label("...and last nested comment terminates here."), + ) + .annotation(AnnotationKind::Primary.span(0..31)), + ), + ); + + let expected = str![[r#" +error[E0758]: unterminated block comment + --> $DIR/unterminated-nested-comment.rs:1:1 + | +LL | /* //~ ERROR E0758 + | ^- + | | + | _unterminated block comment + | | +LL | | /* */ +LL | | /* + | | -- ...as last nested comment starts here, maybe you want to close this instead? +LL | | */ + | |_--^ + | | + | ...and last nested comment terminates here. +"#]]; + let renderer = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer.render(input), expected); +} From 0c8bb3717a24627fd6576acd56757996074dc098 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Tue, 3 Jun 2025 09:45:06 -0600 Subject: [PATCH 216/293] fix: Remove unneeded annotation sorting --- src/renderer/mod.rs | 3 +-- src/renderer/source_map.rs | 4 ---- tests/rustc_tests.rs | 6 ++++-- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index ab791edd..590c83d9 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -695,8 +695,7 @@ impl Renderer { if let Some(first_annotation) = primary_line .annotations .iter() - .find(|a| a.is_primary()) - .or(primary_line.annotations.first()) + .min_by_key(|a| (Reverse(a.is_primary()), a.start.char)) { origin.char_column = Some(first_annotation.start.char + 1); } diff --git a/src/renderer/source_map.rs b/src/renderer/source_map.rs index 403c1c63..d5f91a1c 100644 --- a/src/renderer/source_map.rs +++ b/src/renderer/source_map.rs @@ -293,10 +293,6 @@ impl<'a> SourceMap<'a> { annotated_line_infos.retain(|l| !l.annotations.is_empty()); } - for l in annotated_line_infos.iter_mut() { - l.annotations.sort_by(|a, b| a.start.cmp(&b.start)); - } - (max_depth, annotated_line_infos) } diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index ec8ee7f6..eec19e56 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -2605,7 +2605,7 @@ error[E0532]: expected unit struct, unit variant or constant, found tuple varian LL | E1::Z1 => {} //~ ERROR expected unit struct, unit variant or constant, found tuple variant `E1::Z1` | ^^^^^^ | - ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:11:15 + ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:11:19 | LL | pub enum E1 { Z0, Z1(), S(u8, u8, u8) } | -- -- `E1::Z1` defined here @@ -2669,7 +2669,9 @@ LL | /* //~ ERROR E0758 | | LL | | /* */ LL | | /* - | | -- ...as last nested comment starts here, maybe you want to close this instead? + | | -- + | | | + | | ...as last nested comment starts here, maybe you want to close this instead? LL | | */ | |_--^ | | From 857817778442f1662ecabaa54e10275ea0abe2b9 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Wed, 4 Jun 2025 15:16:07 -0600 Subject: [PATCH 217/293] fix!: Remove of Origin::label --- src/renderer/mod.rs | 17 ----------------- src/snippet.rs | 16 ---------------- tests/rustc_tests.rs | 6 +++--- 3 files changed, 3 insertions(+), 36 deletions(-) diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 590c83d9..07abf539 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -647,23 +647,6 @@ impl Renderer { for _ in 0..max_line_num_len { buffer.prepend(buffer_msg_line_offset, " ", ElementStyle::NoStyle); } - - if let Some(label) = &origin.label { - self.draw_col_separator_no_space( - buffer, - buffer_msg_line_offset + 1, - max_line_num_len + 1, - ); - let title = Level::NOTE.title(label); - self.render_title( - buffer, - &title, - max_line_num_len, - TitleStyle::Secondary, - None, - false, - ); - } } #[allow(clippy::too_many_arguments)] diff --git a/src/snippet.rs b/src/snippet.rs index d3f50104..16f337ad 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -382,7 +382,6 @@ pub struct Origin<'a> { pub(crate) line: Option, pub(crate) char_column: Option, pub(crate) primary: bool, - pub(crate) label: Option<&'a str>, } impl<'a> Origin<'a> { @@ -399,7 +398,6 @@ impl<'a> Origin<'a> { line: None, char_column: None, primary: false, - label: None, } } @@ -423,20 +421,6 @@ impl<'a> Origin<'a> { self.primary = primary; self } - - /// Like [`Annotation::label`], but when there is no source - /// - ///
- /// - /// Text passed to this function is considered "untrusted input", as such - /// all text is passed through a normalization function. Pre-styled text is - /// not allowed to be passed to this function. - /// - ///
- pub fn label(mut self, label: &'a str) -> Self { - self.label = Some(label); - self - } } fn newline_count(body: &str) -> usize { diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index eec19e56..0a1c5317 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -2,7 +2,7 @@ //! //! [parser-tests]: https://github.com/rust-lang/rust/blob/894f7a4ba6554d3797404bbf550d9919df060b97/compiler/rustc_parse/src/parser/tests.rs -use annotate_snippets::{AnnotationKind, Group, Level, Origin, Patch, Renderer, Snippet}; +use annotate_snippets::{AnnotationKind, Group, Level, Origin, Padding, Patch, Renderer, Snippet}; use annotate_snippets::renderer::OutputTheme; use snapbox::{assert_data_eq, str}; @@ -1845,9 +1845,9 @@ fn main() { .line(334) .char_column(14) .primary(true) - .label("...because it uses `Self` as a type parameter") - ) + .element(Padding) + .element(Level::NOTE.title("...because it uses `Self` as a type parameter")) .element( Snippet::source(source) .line_start(1) From f41055266537a3dfa9ea22970df73403e618e963 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Tue, 10 Jun 2025 04:00:02 -0600 Subject: [PATCH 218/293] test: Add rustc test with empty source --- tests/rustc_tests.rs | 114 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index 0a1c5317..13924c8e 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -2680,3 +2680,117 @@ LL | | */ let renderer = Renderer::plain().anonymized_line_numbers(true); assert_data_eq!(renderer.render(input), expected); } + +#[test] +#[should_panic(expected = "called `Option::unwrap()` on a `None` value")] +fn mismatched_types1() { + // tests/ui/include-macros/mismatched-types.rs + + let file_txt_source = r#""#; + + let rust_source = r#"fn main() { + let b: &[u8] = include_str!("file.txt"); //~ ERROR mismatched types + let s: &str = include_bytes!("file.txt"); //~ ERROR mismatched types +}"#; + + let input = Level::ERROR.header("mismatched types").id("E0308").group( + Group::new() + .element( + Snippet::source(file_txt_source) + .fold(true) + .line_start(3) + .origin("$DIR/file.txt") + .annotation( + AnnotationKind::Primary + .span(0..0) + .label("expected `&[u8]`, found `&str`"), + ), + ) + .element( + Snippet::source(rust_source) + .origin("$DIR/mismatched-types.rs") + .fold(true) + .annotation( + AnnotationKind::Context + .span(23..28) + .label("expected due to this"), + ) + .annotation( + AnnotationKind::Context + .span(31..55) + .label("in this macro invocation"), + ), + ) + .element( + Level::NOTE.title("expected reference `&[u8]`\n found reference `&'static str`"), + ), + ); + + let expected = str![[r#" +error[E0308]: mismatched types + --> $DIR/file.txt:3:1 + | +LL | + | ^ expected `&[u8]`, found `&str` + | + ::: $DIR/mismatched-types.rs:2:12 + | +LL | let b: &[u8] = include_str!("file.txt"); //~ ERROR mismatched types + | ----- ------------------------ in this macro invocation + | | + | expected due to this + | + = note: expected reference `&[u8]` + found reference `&'static str` +"#]]; + let renderer = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer.render(input), expected); +} + +#[test] +fn mismatched_types2() { + // tests/ui/include-macros/mismatched-types.rs + + let source = r#"fn main() { + let b: &[u8] = include_str!("file.txt"); //~ ERROR mismatched types + let s: &str = include_bytes!("file.txt"); //~ ERROR mismatched types +}"#; + + let input = Level::ERROR.header("mismatched types").id("E0308").group( + Group::new() + .element( + Snippet::source(source) + .origin("$DIR/mismatched-types.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(105..131) + .label("expected `&str`, found `&[u8; 0]`"), + ) + .annotation( + AnnotationKind::Context + .span(98..102) + .label("expected due to this"), + ), + ) + .element( + Level::NOTE + .title("expected reference `&str`\n found reference `&'static [u8; 0]`"), + ), + ); + + let expected = str![[r#" +error[E0308]: mismatched types + --> $DIR/mismatched-types.rs:3:19 + | +LL | let s: &str = include_bytes!("file.txt"); //~ ERROR mismatched types + | ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&str`, found `&[u8; 0]` + | | + | expected due to this + | + = note: expected reference `&str` + found reference `&'static [u8; 0]` +"#]]; + let renderer = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer.render(input), expected); +} From 23242144f51cc7902d6bcc5d69420600f9426459 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Wed, 4 Jun 2025 15:16:07 -0600 Subject: [PATCH 219/293] fix: Ensure empty sources have one "line" --- src/renderer/source_map.rs | 15 +++++++++++++++ tests/formatter.rs | 1 + tests/rustc_tests.rs | 1 - 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/renderer/source_map.rs b/src/renderer/source_map.rs index d5f91a1c..7401fb96 100644 --- a/src/renderer/source_map.rs +++ b/src/renderer/source_map.rs @@ -11,6 +11,21 @@ pub(crate) struct SourceMap<'a> { impl<'a> SourceMap<'a> { pub(crate) fn new(source: &'a str, line_start: usize) -> Self { + // Empty sources do have a "line", but it is empty, so we need to add + // a line with an empty string to the source map. + if source.is_empty() { + return Self { + lines: vec![LineInfo { + line: "", + line_index: line_start, + start_byte: 0, + end_byte: 0, + end_line_size: 0, + }], + source, + }; + } + let mut current_index = 0; let mut mapping = vec![]; diff --git a/tests/formatter.rs b/tests/formatter.rs index e5647b8c..61277ecc 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -303,6 +303,7 @@ fn test_only_source() { error: --> file.rs | +1 | "#]]; let renderer = Renderer::plain(); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index 13924c8e..b1505d72 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -2682,7 +2682,6 @@ LL | | */ } #[test] -#[should_panic(expected = "called `Option::unwrap()` on a `None` value")] fn mismatched_types1() { // tests/ui/include-macros/mismatched-types.rs From 51b2678794203e915a7ae1595e2c16a4d072543c Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Tue, 10 Jun 2025 02:55:42 -0600 Subject: [PATCH 220/293] test: Add rustc short error format test --- tests/rustc_tests.rs | 108 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index b1505d72..736a069e 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -2793,3 +2793,111 @@ LL | let s: &str = include_bytes!("file.txt"); //~ ERROR mismatched types let renderer = Renderer::plain().anonymized_line_numbers(true); assert_data_eq!(renderer.render(input), expected); } + +#[test] +fn short_error_format1() { + // tests/ui/short-error-format.rs + + let source = r#"//@ compile-flags: --error-format=short + +fn foo(_: u32) {} + +fn main() { + foo("Bonjour".to_owned()); + let x = 0u32; + x.salut(); +} +"#; + + let input = Level::ERROR + .header("mismatched types") + .id("E0308") + .group( + Group::new().element( + Snippet::source(source) + .origin("$DIR/short-error-format.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(80..100) + .label("expected `u32`, found `String`"), + ) + .annotation( + AnnotationKind::Context + .span(76..79) + .label("arguments to this function are incorrect"), + ), + ), + ) + .group( + Group::new() + .element(Level::NOTE.title("function defined here")) + .element( + Snippet::source(source) + .origin("$DIR/short-error-format.rs") + .fold(true) + .annotation(AnnotationKind::Context.span(48..54).label("")) + .annotation(AnnotationKind::Primary.span(44..47)), + ), + ); + + let expected = str![[r#" +error[E0308]: mismatched types + --> $DIR/short-error-format.rs:6:9 + | +LL | foo("Bonjour".to_owned()); + | --- ^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `String` + | | + | arguments to this function are incorrect + | +note: function defined here + --> $DIR/short-error-format.rs:3:4 + | +LL | fn foo(_: u32) {} + | ^^^ ------ +"#]]; + let renderer = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer.render(input), expected); +} + +#[test] +fn short_error_format2() { + // tests/ui/short-error-format.rs + + let source = r#"//@ compile-flags: --error-format=short + +fn foo(_: u32) {} + +fn main() { + foo("Bonjour".to_owned()); + let x = 0u32; + x.salut(); +} +"#; + + let input = Level::ERROR + .header("no method named `salut` found for type `u32` in the current scope") + .id("E0599") + .group( + Group::new().element( + Snippet::source(source) + .origin("$DIR/short-error-format.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(127..132) + .label("method not found in `u32`"), + ), + ), + ); + + let expected = str![[r#" +error[E0599]: no method named `salut` found for type `u32` in the current scope + --> $DIR/short-error-format.rs:8:7 + | +LL | x.salut(); + | ^^^^^ method not found in `u32` +"#]]; + let renderer = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer.render(input), expected); +} From 7a776963b6116c48de7c5987fba44bbb5fbe92dc Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Wed, 4 Jun 2025 15:16:07 -0600 Subject: [PATCH 221/293] feat: Add support for "short message" --- src/renderer/mod.rs | 194 ++++++++++++++++++++++++++++++++++++------- tests/rustc_tests.rs | 28 ++----- 2 files changed, 170 insertions(+), 52 deletions(-) diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 07abf539..f6af1e3b 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -66,6 +66,7 @@ pub struct Renderer { term_width: usize, theme: OutputTheme, stylesheet: Stylesheet, + short_message: bool, } impl Renderer { @@ -76,6 +77,7 @@ impl Renderer { term_width: DEFAULT_TERM_WIDTH, theme: OutputTheme::Ascii, stylesheet: Stylesheet::plain(), + short_message: false, } } @@ -137,6 +139,11 @@ impl Renderer { self } + pub const fn short_message(mut self, short_message: bool) -> Self { + self.short_message = short_message; + self + } + // Set the terminal width pub const fn term_width(mut self, term_width: usize) -> Self { self.term_width = term_width; @@ -199,19 +206,23 @@ impl Renderer { impl Renderer { pub fn render(&self, mut message: Message<'_>) -> String { - let max_line_num_len = if self.anonymized_line_numbers { - ANONYMIZED_LINE_NUM.len() + if self.short_message { + self.render_short_message(message).unwrap() } else { - let n = message.max_line_number(); - num_decimal_digits(n) - }; - let title = message.groups.remove(0).elements.remove(0); - if let Some(first) = message.groups.first_mut() { - first.elements.insert(0, title); - } else { - message.groups.push(Group::new().element(title)); + let max_line_num_len = if self.anonymized_line_numbers { + ANONYMIZED_LINE_NUM.len() + } else { + let n = message.max_line_number(); + num_decimal_digits(n) + }; + let title = message.groups.remove(0).elements.remove(0); + if let Some(first) = message.groups.first_mut() { + first.elements.insert(0, title); + } else { + message.groups.push(Group::new().element(title)); + } + self.render_message(message, max_line_num_len).unwrap() } - self.render_message(message, max_line_num_len).unwrap() } fn render_message( @@ -320,6 +331,7 @@ impl Renderer { (true, false) => TitleStyle::Header, (false, _) => TitleStyle::Secondary, }; + let buffer_msg_line_offset = buffer.num_lines(); self.render_title( &mut buffer, title, @@ -333,6 +345,7 @@ impl Renderer { } }), matches!(peek, Some(Element::Title(_))), + buffer_msg_line_offset, ); last_was_suggestion = false; } @@ -390,7 +403,13 @@ impl Renderer { } Element::Origin(origin) => { - self.render_origin(&mut buffer, max_line_num_len, origin); + let buffer_msg_line_offset = buffer.num_lines(); + self.render_origin( + &mut buffer, + max_line_num_len, + origin, + buffer_msg_line_offset, + ); last_was_suggestion = false; } Element::Padding(_) => { @@ -434,6 +453,91 @@ impl Renderer { Ok(out_string) } + fn render_short_message(&self, mut message: Message<'_>) -> Result { + let mut buffer = StyledBuffer::new(); + + let Element::Title(title) = message.groups.remove(0).elements.remove(0) else { + panic!( + "Expected first element to be a Title, got: {:?}", + message.groups + ); + }; + + let mut labels = None; + + if let Some(Element::Cause(cause)) = message.groups.first().and_then(|group| { + group + .elements + .iter() + .find(|e| matches!(e, Element::Cause(_))) + }) { + let labels_inner = cause + .markers + .iter() + .filter_map(|ann| match ann.label { + Some(msg) if ann.kind.is_primary() => { + if !msg.trim().is_empty() { + Some(msg.to_owned()) + } else { + None + } + } + _ => None, + }) + .collect::>() + .join(", "); + if !labels_inner.is_empty() { + labels = Some(labels_inner); + } + + if let Some(origin) = cause.origin { + let mut origin = Origin::new(origin); + origin.primary = true; + + let source_map = SourceMap::new(cause.source, cause.line_start); + let (_depth, annotated_lines) = + source_map.annotated_lines(cause.markers.clone(), cause.fold); + + if let Some(primary_line) = annotated_lines + .iter() + .find(|l| l.annotations.iter().any(LineAnnotation::is_primary)) + .or(annotated_lines.iter().find(|l| !l.annotations.is_empty())) + { + origin.line = Some(primary_line.line_index); + if let Some(first_annotation) = primary_line + .annotations + .iter() + .min_by_key(|a| (Reverse(a.is_primary()), a.start.char)) + { + origin.char_column = Some(first_annotation.start.char + 1); + } + } + + self.render_origin(&mut buffer, 0, &origin, 0); + buffer.append(0, ": ", ElementStyle::LineAndColumn); + } + } + + self.render_title( + &mut buffer, + &title, + 0, // No line numbers in short messages + TitleStyle::MainHeader, + message.id.as_ref(), + false, + 0, + ); + + if let Some(labels) = labels { + buffer.append(0, &format!(": {labels}"), ElementStyle::NoStyle); + } + + let mut out_string = String::new(); + buffer.render(title.level, &self.stylesheet, &mut out_string)?; + + Ok(out_string) + } + #[allow(clippy::too_many_arguments)] fn render_title( &self, @@ -443,23 +547,27 @@ impl Renderer { title_style: TitleStyle, id: Option<&&str>, is_cont: bool, + buffer_msg_line_offset: usize, ) { - let line_offset = buffer.num_lines(); - if title_style == TitleStyle::Secondary { // This is a secondary message with no span info for _ in 0..max_line_num_len { - buffer.prepend(line_offset, " ", ElementStyle::NoStyle); + buffer.prepend(buffer_msg_line_offset, " ", ElementStyle::NoStyle); } if title.level.name != Some(None) { - self.draw_note_separator(buffer, line_offset, max_line_num_len + 1, is_cont); + self.draw_note_separator( + buffer, + buffer_msg_line_offset, + max_line_num_len + 1, + is_cont, + ); buffer.append( - line_offset, + buffer_msg_line_offset, title.level.as_str(), ElementStyle::MainHeaderMsg, ); - buffer.append(line_offset, ": ", ElementStyle::NoStyle); + buffer.append(buffer_msg_line_offset, ": ", ElementStyle::NoStyle); } let printed_lines = @@ -476,7 +584,7 @@ impl Renderer { // │ bar // ╰ note: foo // bar - for i in line_offset + 1..=printed_lines { + for i in buffer_msg_line_offset + 1..=printed_lines { self.draw_col_separator_no_space(buffer, i, max_line_num_len + 1); } } @@ -485,31 +593,49 @@ impl Renderer { if title.level.name != Some(None) { buffer.append( - line_offset, + buffer_msg_line_offset, title.level.as_str(), ElementStyle::Level(title.level.level), ); } label_width += title.level.as_str().len(); if let Some(id) = id { - buffer.append(line_offset, "[", ElementStyle::Level(title.level.level)); - buffer.append(line_offset, id, ElementStyle::Level(title.level.level)); - buffer.append(line_offset, "]", ElementStyle::Level(title.level.level)); + buffer.append( + buffer_msg_line_offset, + "[", + ElementStyle::Level(title.level.level), + ); + buffer.append( + buffer_msg_line_offset, + id, + ElementStyle::Level(title.level.level), + ); + buffer.append( + buffer_msg_line_offset, + "]", + ElementStyle::Level(title.level.level), + ); label_width += 2 + id.len(); } let header_style = match title_style { - TitleStyle::MainHeader => ElementStyle::MainHeaderMsg, + TitleStyle::MainHeader => { + if self.short_message { + ElementStyle::NoStyle + } else { + ElementStyle::MainHeaderMsg + } + } TitleStyle::Header => ElementStyle::HeaderMsg, TitleStyle::Secondary => unreachable!(), }; if title.level.name != Some(None) { - buffer.append(line_offset, ": ", header_style); + buffer.append(buffer_msg_line_offset, ": ", header_style); label_width += 2; } if !title.title.is_empty() { for (line, text) in normalize_whitespace(title.title).lines().enumerate() { buffer.append( - line_offset + line, + buffer_msg_line_offset + line, &format!( "{}{}", if line == 0 { @@ -600,15 +726,15 @@ impl Renderer { buffer: &mut StyledBuffer, max_line_num_len: usize, origin: &Origin<'_>, + buffer_msg_line_offset: usize, ) { - let buffer_msg_line_offset = buffer.num_lines(); - if origin.primary { + if origin.primary && !self.short_message { buffer.prepend( buffer_msg_line_offset, self.file_start(), ElementStyle::LineNumber, ); - } else { + } else if !self.short_message { // if !origin.standalone { // // Add spacing line, as shown: // // --> $DIR/file:54:15 @@ -643,9 +769,12 @@ impl Renderer { (Some(line), None) => format!("{}:{}", origin.origin, line), _ => origin.origin.to_owned(), }; + buffer.append(buffer_msg_line_offset, &str, ElementStyle::LineAndColumn); - for _ in 0..max_line_num_len { - buffer.prepend(buffer_msg_line_offset, " ", ElementStyle::NoStyle); + if !self.short_message { + for _ in 0..max_line_num_len { + buffer.prepend(buffer_msg_line_offset, " ", ElementStyle::NoStyle); + } } } @@ -707,7 +836,8 @@ impl Renderer { } } } - self.render_origin(buffer, max_line_num_len, &origin); + let buffer_msg_line_offset = buffer.num_lines(); + self.render_origin(buffer, max_line_num_len, &origin, buffer_msg_line_offset); } // Put in the spacer between the location and annotated source diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index 736a069e..bdffe38b 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -2842,21 +2842,11 @@ fn main() { ); let expected = str![[r#" -error[E0308]: mismatched types - --> $DIR/short-error-format.rs:6:9 - | -LL | foo("Bonjour".to_owned()); - | --- ^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `String` - | | - | arguments to this function are incorrect - | -note: function defined here - --> $DIR/short-error-format.rs:3:4 - | -LL | fn foo(_: u32) {} - | ^^^ ------ +$DIR/short-error-format.rs:6:9: error[E0308]: mismatched types: expected `u32`, found `String` "#]]; - let renderer = Renderer::plain().anonymized_line_numbers(true); + let renderer = Renderer::plain() + .short_message(true) + .anonymized_line_numbers(true); assert_data_eq!(renderer.render(input), expected); } @@ -2892,12 +2882,10 @@ fn main() { ); let expected = str![[r#" -error[E0599]: no method named `salut` found for type `u32` in the current scope - --> $DIR/short-error-format.rs:8:7 - | -LL | x.salut(); - | ^^^^^ method not found in `u32` +$DIR/short-error-format.rs:8:7: error[E0599]: no method named `salut` found for type `u32` in the current scope: method not found in `u32` "#]]; - let renderer = Renderer::plain().anonymized_line_numbers(true); + let renderer = Renderer::plain() + .short_message(true) + .anonymized_line_numbers(true); assert_data_eq!(renderer.render(input), expected); } From a0d26c6aaf7e880dc6c37830ecd983e5537c97ce Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Tue, 10 Jun 2025 06:06:08 -0600 Subject: [PATCH 222/293] test: Ensure all examples have a test --- tests/examples.rs | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/examples.rs b/tests/examples.rs index 66dd94be..02e961c8 100644 --- a/tests/examples.rs +++ b/tests/examples.rs @@ -1,3 +1,5 @@ +use std::collections::BTreeSet; + #[test] fn custom_error() { let target = "custom_error"; @@ -63,3 +65,40 @@ fn assert_example(target: &str, expected: snapbox::Data) { .success() .stdout_eq(expected.raw()); } + +#[test] +fn ensure_all_examples_have_tests() { + let path = snapbox::utils::current_rs!(); + let actual = std::fs::read_to_string(&path).unwrap(); + let actual = actual + .lines() + .filter_map(|l| { + if l.starts_with("fn ") + && !l.starts_with("fn all_examples_have_tests") + && !l.starts_with("fn assert_example") + { + Some(l[3..l.len() - 4].to_string()) + } else { + None + } + }) + .collect::>(); + + let expected = std::fs::read_dir("examples") + .unwrap() + .map(|res| res.map(|e| e.path().file_stem().unwrap().display().to_string())) + .collect::, std::io::Error>>() + .unwrap(); + + let mut diff = expected.difference(&actual).collect::>(); + diff.sort(); + + let mut need_added = String::new(); + for name in &diff { + need_added.push_str(&format!("{name}\n")); + } + assert!( + diff.is_empty(), + "\n`Please add a test for the following examples to `tests/examples.rs`:\n{need_added}", + ); +} From 2ef8888285326bdb76457e698b3a3fae48dfd725 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Mon, 2 Jun 2025 18:28:50 -0600 Subject: [PATCH 223/293] test: Add a test for out of bounds replacement --- tests/rustc_tests.rs | 76 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index bdffe38b..d5c24af2 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -2889,3 +2889,79 @@ $DIR/short-error-format.rs:8:7: error[E0599]: no method named `salut` found for .anonymized_line_numbers(true); assert_data_eq!(renderer.render(input), expected); } + +#[test] +#[should_panic(expected = "range end index 47 out of range for slice of length 26")] +fn rustdoc_ui_diagnostic_width() { + // tests/rustdoc-ui/diagnostic-width.rs + + let source_0 = r#"//@ compile-flags: --diagnostic-width=10 +#![deny(rustdoc::bare_urls)] + +/// This is a long line that contains a http://link.com +pub struct Foo; //~^ ERROR +"#; + let source_1 = r#"/// This is a long line that contains a http://link.com +"#; + + let input = Level::ERROR + .header("this URL is not a hyperlink") + .group( + Group::new() + .element( + Snippet::source(source_0) + .origin("$DIR/diagnostic-width.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(111..126)), + ) + .element( + Level::NOTE + .title("bare URLs are not automatically turned into clickable links"), + ), + ) + .group( + Group::new() + .element(Level::NOTE.title("the lint level is defined here")) + .element( + Snippet::source(source_0) + .origin("$DIR/diagnostic-width.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(49..67)), + ), + ) + .group( + Group::new() + .element(Level::HELP.title("use an automatic link instead")) + .element( + Snippet::source(source_1) + .origin("$DIR/diagnostic-width.rs") + .line_start(4) + .fold(true) + .patch(Patch::new(40..40, "<")) + .patch(Patch::new(55..55, ">")), + ), + ); + + let expected = str![[r#" +error: this URL is not a hyperlink + --> $DIR/diagnostic-width.rs:4:41 + | +LL | ... a http://link.com + | ^^^^^^^^^^^^^^^ + | + = note: bare URLs are not automatically turned into clickable links +note: the lint level is defined here + --> $DIR/diagnostic-width.rs:2:9 + | +LL | ...ny(ru...are_urls)] + | ^^...^^^^^^^^ +help: use an automatic link instead + | +LL | /// This is a long line that contains a + | + + +"#]]; + let renderer = Renderer::plain() + .anonymized_line_numbers(true) + .term_width(10); + assert_data_eq!(renderer.render(input), expected); +} From 22e1e546822c640cf351a97d41a9733ab627499e Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Mon, 2 Jun 2025 18:28:50 -0600 Subject: [PATCH 224/293] fix: Don't attempt out of bounds buffer replacments --- src/renderer/styled_buffer.rs | 5 +++++ tests/rustc_tests.rs | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/renderer/styled_buffer.rs b/src/renderer/styled_buffer.rs index 925bb446..f72c58c6 100644 --- a/src/renderer/styled_buffer.rs +++ b/src/renderer/styled_buffer.rs @@ -103,6 +103,11 @@ impl StyledBuffer { if start == end { return; } + // If the replacement range would be out of bounds, do nothing, as we + // can't replace things that don't exist. + if start > self.lines[line].len() || end > self.lines[line].len() { + return; + } let _ = self.lines[line].drain(start..(end - string.chars().count())); for (i, c) in string.chars().enumerate() { self.lines[line][start + i] = StyledChar::new(c, ElementStyle::LineNumber); diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index d5c24af2..13306590 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -2891,7 +2891,6 @@ $DIR/short-error-format.rs:8:7: error[E0599]: no method named `salut` found for } #[test] -#[should_panic(expected = "range end index 47 out of range for slice of length 26")] fn rustdoc_ui_diagnostic_width() { // tests/rustdoc-ui/diagnostic-width.rs From eb800f6fd9f4810335ff44c6dc7dc5bb230aa1aa Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Wed, 25 Jun 2025 15:37:11 -0600 Subject: [PATCH 225/293] test: Adjust spans to match original test spans --- tests/formatter.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/formatter.rs b/tests/formatter.rs index 61277ecc..b48d8f52 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -1519,7 +1519,7 @@ fn main() {}"#; .element( Snippet::source(source) .fold(true) - .patch(Patch::new(52..86, "")), + .patch(Patch::new(52..85, "")), ), ); let expected = str![[r#" @@ -1537,7 +1537,6 @@ LL - T LL - : LL - ? LL - Sized -LL + { | "#]]; let renderer = Renderer::plain().anonymized_line_numbers(true); @@ -1619,8 +1618,8 @@ fn main() {}"#; ).element( Snippet::source(source) .fold(true) - .patch(Patch::new(56..90, "")) - .patch(Patch::new(90..90, "+ Send")) + .patch(Patch::new(56..89, "")) + .patch(Patch::new(89..89, "+ Send")) , )); let expected = str![[r#" @@ -1651,7 +1650,7 @@ LL - T LL - : LL - ? LL - Sized -LL + and + Send{ +LL + and + Send | "#]]; let renderer = Renderer::plain().anonymized_line_numbers(true); From e8ac4395014fce3f2578b0bd5232196d0166c356 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Fri, 30 May 2025 15:00:25 -0600 Subject: [PATCH 226/293] test: Add test for Suggestion with range 0..0 --- tests/rustc_tests.rs | 80 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index 13306590..9360b0af 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -2964,3 +2964,83 @@ LL | /// This is a long line that contains a .term_width(10); assert_data_eq!(renderer.render(input), expected); } + +#[test] +#[should_panic = "attempt to subtract with overflow"] +fn array_into_iter() { + let source1 = r#"#![allow(unused)] +fn main() { +[1, 2, 3].into_iter().for_each(|n| { *n; }); +} +"#; + let source2 = r#"[1, 2, 3].into_iter().for_each(|n| { *n; }); +"#; + + let long_title1 ="this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021"; + let long_title2 = "for more information, see "; + let long_title3 = "or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value"; + + let input = Level::WARNING + .header(long_title1) + .group( + Group::new() + .element( + Snippet::source(source1) + .origin("lint_example.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(40..49)), + ) + .element(Level::WARNING.title("this changes meaning in Rust 2021")) + .element(Level::NOTE.title(long_title2)) + .element(Level::NOTE.title("`#[warn(array_into_iter)]` on by default")), + ) + .group( + Group::new() + .element( + Level::HELP.title("use `.iter()` instead of `.into_iter()` to avoid ambiguity"), + ) + .element( + Snippet::source(source2) + .origin("lint_example.rs") + .line_start(3) + .fold(true) + .patch(Patch::new(10..19, "iter")), + ), + ) + .group( + Group::new() + .element(Level::HELP.title(long_title3)) + .element( + Snippet::source(source2) + .origin("lint_example.rs") + .line_start(3) + .fold(true) + .patch(Patch::new(0..0, "IntoIterator::into_iter(")) + .patch(Patch::new(9..21, ")")), + ), + ); + + let expected = str![[r#" +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 + --> lint_example.rs:3:11 + | +3 | [1, 2, 3].into_iter().for_each(|n| { *n; }); + | ^^^^^^^^^ + | + = warning: this changes meaning in Rust 2021 + = note: for more information, see + = note: `#[warn(array_into_iter)]` on by default +help: use `.iter()` instead of `.into_iter()` to avoid ambiguity + | +3 - [1, 2, 3].into_iter().for_each(|n| { *n; }); +3 + [1, 2, 3].iter().for_each(|n| { *n; }); + | +help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value + | +3 - [1, 2, 3].into_iter().for_each(|n| { *n; }); +3 + IntoIterator::into_iter([1, 2, 3]).for_each(|n| { *n; }); + | +"#]]; + let renderer = Renderer::plain(); + assert_data_eq!(renderer.render(input), expected); +} From 3d4d913682c99f0de9ab204a0ef7611d392b3f3d Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Fri, 30 May 2025 15:00:25 -0600 Subject: [PATCH 227/293] fix: Make span_to_lines return at least one line --- src/renderer/source_map.rs | 2 +- tests/rustc_tests.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/renderer/source_map.rs b/src/renderer/source_map.rs index 7401fb96..026b2a42 100644 --- a/src/renderer/source_map.rs +++ b/src/renderer/source_map.rs @@ -124,7 +124,7 @@ impl<'a> SourceMap<'a> { if start >= line_info.end_byte { continue; } - if end <= line_info.start_byte { + if end < line_info.start_byte { break; } lines.push(line_info); diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index 9360b0af..23c178bf 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -2966,7 +2966,6 @@ LL | /// This is a long line that contains a } #[test] -#[should_panic = "attempt to subtract with overflow"] fn array_into_iter() { let source1 = r#"#![allow(unused)] fn main() { From e284907061eef3c38a2403bb702c85060080857f Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Tue, 10 Jun 2025 05:12:11 -0600 Subject: [PATCH 228/293] test: Add rustc multiline-removal-suggestion --- tests/color/main.rs | 1 + tests/color/multiline_removal_suggestion.rs | 113 ++++++++++++++++++ .../multiline_removal_suggestion.term.svg | 68 +++++++++++ 3 files changed, 182 insertions(+) create mode 100644 tests/color/multiline_removal_suggestion.rs create mode 100644 tests/color/multiline_removal_suggestion.term.svg diff --git a/tests/color/main.rs b/tests/color/main.rs index f954bb7a..a9885a0b 100644 --- a/tests/color/main.rs +++ b/tests/color/main.rs @@ -9,6 +9,7 @@ mod fold_bad_origin_line; mod fold_leading; mod fold_trailing; mod issue_9; +mod multiline_removal_suggestion; mod multiple_annotations; mod simple; mod strip_line; diff --git a/tests/color/multiline_removal_suggestion.rs b/tests/color/multiline_removal_suggestion.rs new file mode 100644 index 00000000..fbc47540 --- /dev/null +++ b/tests/color/multiline_removal_suggestion.rs @@ -0,0 +1,113 @@ +use annotate_snippets::{AnnotationKind, Group, Level, Origin, Patch, Renderer, Snippet}; + +use snapbox::{assert_data_eq, file}; + +#[test] +fn case() { + let source = r#"// Make sure suggestion for removal of a span that covers multiple lines is properly highlighted. +//@ compile-flags: --error-format=human --color=always +//@ edition:2018 +//@ only-linux +// ignore-tidy-tab +// We use `\t` instead of spaces for indentation to ensure that the highlighting logic properly +// accounts for replaced characters (like we do for `\t` with ` `). The naïve way of highlighting +// could be counting chars of the original code, instead of operating on the code as it is being +// displayed. +use std::collections::{HashMap, HashSet}; +fn foo() -> Vec<(bool, HashSet)> { + let mut hm = HashMap::>>::new(); + hm.into_iter() + .map(|(is_true, ts)| { + ts.into_iter() + .map(|t| { + ( + is_true, + t, + ) + }).flatten() + }) + .flatten() + .collect() +} +fn bar() -> Vec<(bool, HashSet)> { + let mut hm = HashMap::>>::new(); + hm.into_iter() + .map(|(is_true, ts)| { + ts.into_iter() + .map(|t| (is_true, t)) + .flatten() + }) + .flatten() + .collect() +} +fn baz() -> Vec<(bool, HashSet)> { + let mut hm = HashMap::>>::new(); + hm.into_iter() + .map(|(is_true, ts)| { + ts.into_iter().map(|t| { + (is_true, t) + }).flatten() + }) + .flatten() + .collect() +} +fn bay() -> Vec<(bool, HashSet)> { + let mut hm = HashMap::>>::new(); + hm.into_iter() + .map(|(is_true, ts)| { + ts.into_iter() + .map(|t| (is_true, t)).flatten() + }) + .flatten() + .collect() +} +fn main() {} +"#; + + let input = Level::ERROR + .header("`(bool, HashSet)` is not an iterator") + .id("E0277") + .group( + Group::new() + .element( + Snippet::source(source) + .origin("$DIR/multiline-removal-suggestion.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(769..776) + .label("`(bool, HashSet)` is not an iterator"), + ), + ) + .element( + Level::HELP + .title("the trait `Iterator` is not implemented for `(bool, HashSet)`"), + ) + .element( + Level::NOTE + .title("required for `(bool, HashSet)` to implement `IntoIterator`"), + ), + ) + .group( + Group::new() + .element(Level::NOTE.title("required by a bound in `flatten`")) + .element( + Origin::new("/rustc/FAKE_PREFIX/library/core/src/iter/traits/iterator.rs") + .line(1556) + .char_column(4), + ), + ) + .group( + Group::new() + .element(Level::HELP.title("consider removing this method call, as the receiver has type `std::vec::IntoIter>` and `std::vec::IntoIter>: Iterator` trivially holds")) + .element( + Snippet::source(source) + .origin("$DIR/multiline-removal-suggestion.rs") + .fold(true) + .patch(Patch::new(708..768, "")), + ), + ); + let expected = file!["multiline_removal_suggestion.term.svg"]; + let renderer = Renderer::styled(); + assert_data_eq!(renderer.render(input), expected); +} diff --git a/tests/color/multiline_removal_suggestion.term.svg b/tests/color/multiline_removal_suggestion.term.svg new file mode 100644 index 00000000..bef4b25a --- /dev/null +++ b/tests/color/multiline_removal_suggestion.term.svg @@ -0,0 +1,68 @@ + + + + + + + error[E0277]: `(bool, HashSet<u8>)` is not an iterator + + --> $DIR/multiline-removal-suggestion.rs:21:8 + + | + + 21 | }).flatten() + + | ^^^^^^^ `(bool, HashSet<u8>)` is not an iterator + + | + + = help: the trait `Iterator` is not implemented for `(bool, HashSet<u8>)` + + = note: required for `(bool, HashSet<u8>)` to implement `IntoIterator` + + note: required by a bound in `flatten` + + ::: /rustc/FAKE_PREFIX/library/core/src/iter/traits/iterator.rs:1556:4 + + help: consider removing this method call, as the receiver has type `std::vec::IntoIter<HashSet<u8>>` and `std::vec::IntoIter<HashSet<u8>>: Iterator` trivially holds + + | + + 15 - ts.into_iter() + + 16 - .map(|t| { + + 17 - ( + + 18 - is_true, + + 19 - t, + + 20 - ) + + 21 - }).flatten() + + 15 + ts.into_iter().flatten() + + | + + + + From 01b8da75479b6b4f64bad39a06c8cffe0c8c17ad Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Tue, 3 Jun 2025 09:45:06 -0600 Subject: [PATCH 229/293] fix: Color suggestion removal diff --- examples/custom_level.svg | 6 +- src/renderer/mod.rs | 88 +++++++++++++++++-- .../multiline_removal_suggestion.term.svg | 12 +-- 3 files changed, 90 insertions(+), 16 deletions(-) diff --git a/examples/custom_level.svg b/examples/custom_level.svg index 62dded57..46d3165c 100644 --- a/examples/custom_level.svg +++ b/examples/custom_level.svg @@ -45,11 +45,11 @@
╭╴ - 22 - break (|| { //~ ERROR `break` with value from a `while` loop + 22 - break (|| { //~ ERROR `break` with value from a `while` loop - 23 - let local = 9; + 23 - let local = 9; - 24 - }); + 24 - }); 22 + break; diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index f6af1e3b..fadf7805 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -1874,6 +1874,7 @@ impl Renderer { show_code_change { for part in parts { + let snippet = sm.span_to_snippet(part.span.clone()).unwrap_or_default(); let (span_start, span_end) = sm.span_to_locations(part.span.clone()); let span_start_pos = span_start.display; let span_end_pos = span_end.display; @@ -1932,13 +1933,86 @@ impl Renderer { } if let DisplaySuggestion::Diff = show_code_change { // Colorize removal with red in diff format. - buffer.set_style_range( - row_num - 2, - (padding as isize + span_start_pos as isize) as usize, - (padding as isize + span_end_pos as isize) as usize, - ElementStyle::Removal, - true, - ); + + // Below, there's some tricky buffer indexing going on. `row_num` at this + // point corresponds to: + // + // | + // LL | CODE + // | ++++ <- `row_num` + // + // in the buffer. When we have a diff format output, we end up with + // + // | + // LL - OLDER <- row_num - 2 + // LL + NEWER + // | <- row_num + // + // The `row_num - 2` is to select the buffer line that has the "old version + // of the diff" at that point. When the removal is a single line, `i` is + // `0`, `newlines` is `1` so `(newlines - i - 1)` ends up being `0`, so row + // points at `LL - OLDER`. When the removal corresponds to multiple lines, + // we end up with `newlines > 1` and `i` being `0..newlines - 1`. + // + // | + // LL - OLDER <- row_num - 2 - (newlines - last_i - 1) + // LL - CODE + // LL - BEING + // LL - REMOVED <- row_num - 2 - (newlines - first_i - 1) + // LL + NEWER + // | <- row_num + + let newlines = snippet.lines().count(); + if newlines > 0 && row_num > newlines { + // Account for removals where the part being removed spans multiple + // lines. + // FIXME: We check the number of rows because in some cases, like in + // `tests/ui/lint/invalid-nan-comparison-suggestion.rs`, the rendered + // suggestion will only show the first line of code being replaced. The + // proper way of doing this would be to change the suggestion rendering + // logic to show the whole prior snippet, but the current output is not + // too bad to begin with, so we side-step that issue here. + for (i, line) in snippet.lines().enumerate() { + let line = normalize_whitespace(line); + let row = row_num - 2 - (newlines - i - 1); + // On the first line, we highlight between the start of the part + // span, and the end of that line. + // On the last line, we highlight between the start of the line, and + // the column of the part span end. + // On all others, we highlight the whole line. + let start = if i == 0 { + (padding as isize + span_start_pos as isize) as usize + } else { + padding + }; + let end = if i == 0 { + (padding as isize + + span_start_pos as isize + + line.len() as isize) + as usize + } else if i == newlines - 1 { + (padding as isize + span_end_pos as isize) as usize + } else { + (padding as isize + line.len() as isize) as usize + }; + buffer.set_style_range( + row, + start, + end, + ElementStyle::Removal, + true, + ); + } + } else { + // The removed code fits all in one line. + buffer.set_style_range( + row_num - 2, + (padding as isize + span_start_pos as isize) as usize, + (padding as isize + span_end_pos as isize) as usize, + ElementStyle::Removal, + true, + ); + } } // length of the code after substitution diff --git a/tests/color/multiline_removal_suggestion.term.svg b/tests/color/multiline_removal_suggestion.term.svg index bef4b25a..ed203237 100644 --- a/tests/color/multiline_removal_suggestion.term.svg +++ b/tests/color/multiline_removal_suggestion.term.svg @@ -47,17 +47,17 @@ 15 - ts.into_iter() - 16 - .map(|t| { + 16 - .map(|t| { - 17 - ( + 17 - ( - 18 - is_true, + 18 - is_true, - 19 - t, + 19 - t, - 20 - ) + 20 - ) - 21 - }).flatten() + 21 - }).flatten() 15 + ts.into_iter().flatten() From 7305271c52251ef46d67e8c2476be0806e82ad19 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Thu, 26 Jun 2025 14:34:06 -0600 Subject: [PATCH 230/293] refactor!: Rename origin fields to path --- benches/bench.rs | 4 +- examples/custom_error.rs | 2 +- examples/custom_level.rs | 4 +- examples/expected_type.rs | 2 +- examples/footer.rs | 2 +- examples/format.rs | 2 +- examples/highlight_source.rs | 2 +- examples/highlight_title.rs | 4 +- examples/multislice.rs | 4 +- src/renderer/mod.rs | 52 +++---- src/snippet.rs | 14 +- tests/color/ann_eof.rs | 2 +- tests/color/ann_insertion.rs | 2 +- tests/color/ann_multiline.rs | 2 +- tests/color/ann_multiline2.rs | 2 +- tests/color/ann_removed_nl.rs | 2 +- tests/color/ensure_emoji_highlight_width.rs | 2 +- tests/color/fold_ann_multiline.rs | 2 +- tests/color/fold_bad_origin_line.rs | 2 +- tests/color/fold_leading.rs | 2 +- tests/color/fold_trailing.rs | 2 +- tests/color/issue_9.rs | 2 +- tests/color/multiline_removal_suggestion.rs | 4 +- tests/color/simple.rs | 2 +- tests/color/strip_line.rs | 2 +- tests/color/strip_line_char.rs | 2 +- tests/color/strip_line_non_ws.rs | 2 +- tests/formatter.rs | 90 ++++++------ tests/rustc_tests.rs | 150 ++++++++++---------- 29 files changed, 183 insertions(+), 183 deletions(-) diff --git a/benches/bench.rs b/benches/bench.rs index c3799fbd..32b67c3f 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -28,7 +28,7 @@ fn simple() -> String { Group::new().element( Snippet::source(source) .line_start(51) - .origin("src/format.rs") + .path("src/format.rs") .annotation( AnnotationKind::Context .span(5..19) @@ -73,7 +73,7 @@ fn fold(bencher: divan::Bencher<'_, '_>, context: usize) { Group::new().element( Snippet::source(&input) .fold(true) - .origin("src/format.rs") + .path("src/format.rs") .annotation( AnnotationKind::Context .span(span) diff --git a/examples/custom_error.rs b/examples/custom_error.rs index b9e27b31..dfb8fc6c 100644 --- a/examples/custom_error.rs +++ b/examples/custom_error.rs @@ -22,7 +22,7 @@ pub static C: u32 = 0 - 1; .group( Group::new().element( Snippet::source(source) - .origin("$DIR/err.rs") + .path("$DIR/err.rs") .fold(true) .annotation( AnnotationKind::Primary diff --git a/examples/custom_level.rs b/examples/custom_level.rs index b2af361a..57f2fb5a 100644 --- a/examples/custom_level.rs +++ b/examples/custom_level.rs @@ -36,7 +36,7 @@ fn main() { Group::new().element( Snippet::source(source) .line_start(1) - .origin("$DIR/issue-114529-illegal-break-with-value.rs") + .path("$DIR/issue-114529-illegal-break-with-value.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -60,7 +60,7 @@ fn main() { .element( Snippet::source(source) .line_start(1) - .origin("$DIR/issue-114529-illegal-break-with-value.rs") + .path("$DIR/issue-114529-illegal-break-with-value.rs") .fold(true) .patch(Patch::new(483..581, "break")), ), diff --git a/examples/expected_type.rs b/examples/expected_type.rs index 02abdecf..440c64c3 100644 --- a/examples/expected_type.rs +++ b/examples/expected_type.rs @@ -10,7 +10,7 @@ fn main() { Group::new().element( Snippet::source(source) .line_start(26) - .origin("examples/footer.rs") + .path("examples/footer.rs") .fold(true) .annotation(AnnotationKind::Primary.span(193..195).label( "expected struct `annotate_snippets::snippet::Slice`, found reference", diff --git a/examples/footer.rs b/examples/footer.rs index ca6f1dc7..36173350 100644 --- a/examples/footer.rs +++ b/examples/footer.rs @@ -8,7 +8,7 @@ fn main() { Group::new().element( Snippet::source(" slices: vec![\"A\",") .line_start(13) - .origin("src/multislice.rs") + .path("src/multislice.rs") .annotation(AnnotationKind::Primary.span(21..24).label( "expected struct `annotate_snippets::snippet::Slice`, found reference", )), diff --git a/examples/format.rs b/examples/format.rs index 4b688d4b..4268e315 100644 --- a/examples/format.rs +++ b/examples/format.rs @@ -27,7 +27,7 @@ fn main() { Group::new().element( Snippet::source(source) .line_start(51) - .origin("src/format.rs") + .path("src/format.rs") .annotation( AnnotationKind::Context .span(5..19) diff --git a/examples/highlight_source.rs b/examples/highlight_source.rs index 92d8114f..f5871453 100644 --- a/examples/highlight_source.rs +++ b/examples/highlight_source.rs @@ -17,7 +17,7 @@ fn main() {} .element( Snippet::source(source) .fold(true) - .origin("$DIR/E0010-teach.rs") + .path("$DIR/E0010-teach.rs") .annotation( AnnotationKind::Primary .span(72..85) diff --git a/examples/highlight_title.rs b/examples/highlight_title.rs index 218e414f..2f74a37b 100644 --- a/examples/highlight_title.rs +++ b/examples/highlight_title.rs @@ -49,7 +49,7 @@ fn main() { .element( Snippet::source(source) .fold(true) - .origin("$DIR/highlighting.rs") + .path("$DIR/highlighting.rs") .annotation( AnnotationKind::Primary .span(553..563) @@ -69,7 +69,7 @@ fn main() { .element( Snippet::source(source) .fold(true) - .origin("$DIR/highlighting.rs") + .path("$DIR/highlighting.rs") .annotation(AnnotationKind::Context.span(200..333).label("")) .annotation(AnnotationKind::Primary.span(194..199)), ), diff --git a/examples/multislice.rs b/examples/multislice.rs index a7d340ad..b8b4ac74 100644 --- a/examples/multislice.rs +++ b/examples/multislice.rs @@ -6,12 +6,12 @@ fn main() { .element( Snippet::>::source("Foo") .line_start(51) - .origin("src/format.rs"), + .path("src/format.rs"), ) .element( Snippet::>::source("Faa") .line_start(129) - .origin("src/display.rs"), + .path("src/display.rs"), ), ); diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index fadf7805..93996075 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -24,7 +24,7 @@ //! .group( //! Group::new().element( //! Snippet::source(source) -//! .origin("temp.rs") +//! .path("temp.rs") //! .line_start(1) //! .fold(true) //! .annotation( @@ -232,21 +232,21 @@ impl Renderer { ) -> Result { let mut out_string = String::new(); - let og_primary_origin = message + let og_primary_path = message .groups .iter() .find_map(|group| { group.elements.iter().find_map(|s| match &s { Element::Cause(cause) => { if cause.markers.iter().any(|m| m.kind.is_primary()) { - Some(cause.origin) + Some(cause.path) } else { None } } Element::Origin(origin) => { if origin.primary { - Some(Some(origin.origin)) + Some(Some(origin.path)) } else { None } @@ -260,8 +260,8 @@ impl Renderer { .iter() .find_map(|group| { group.elements.iter().find_map(|s| match &s { - Element::Cause(cause) => Some(cause.origin), - Element::Origin(origin) => Some(Some(origin.origin)), + Element::Cause(cause) => Some(cause.path), + Element::Origin(origin) => Some(Some(origin.path)), _ => None, }) }) @@ -270,20 +270,20 @@ impl Renderer { let group_len = message.groups.len(); for (g, group) in message.groups.into_iter().enumerate() { let mut buffer = StyledBuffer::new(); - let primary_origin = group + let primary_path = group .elements .iter() .find_map(|s| match &s { Element::Cause(cause) => { if cause.markers.iter().any(|m| m.kind.is_primary()) { - Some(cause.origin) + Some(cause.path) } else { None } } Element::Origin(origin) => { if origin.primary { - Some(Some(origin.origin)) + Some(Some(origin.path)) } else { None } @@ -295,8 +295,8 @@ impl Renderer { .elements .iter() .find_map(|s| match &s { - Element::Cause(cause) => Some(cause.origin), - Element::Origin(origin) => Some(Some(origin.origin)), + Element::Cause(cause) => Some(cause.path), + Element::Origin(origin) => Some(Some(origin.path)), _ => None, }) .unwrap_or_default(), @@ -357,7 +357,7 @@ impl Renderer { &mut buffer, max_line_num_len, cause, - primary_origin, + primary_path, &source_map, &annotated_lines, max_depth, @@ -396,7 +396,7 @@ impl Renderer { suggestion, max_line_num_len, &source_map, - primary_origin.or(og_primary_origin), + primary_path.or(og_primary_path), last_was_suggestion, ); last_was_suggestion = true; @@ -490,8 +490,8 @@ impl Renderer { labels = Some(labels_inner); } - if let Some(origin) = cause.origin { - let mut origin = Origin::new(origin); + if let Some(path) = cause.path { + let mut origin = Origin::new(path); origin.primary = true; let source_map = SourceMap::new(cause.source, cause.line_start); @@ -764,10 +764,10 @@ impl Renderer { let str = match (&origin.line, &origin.char_column) { (Some(line), Some(col)) => { - format!("{}:{}:{}", origin.origin, line, col) + format!("{}:{}:{}", origin.path, line, col) } - (Some(line), None) => format!("{}:{}", origin.origin, line), - _ => origin.origin.to_owned(), + (Some(line), None) => format!("{}:{}", origin.path, line), + _ => origin.path.to_owned(), }; buffer.append(buffer_msg_line_offset, &str, ElementStyle::LineAndColumn); @@ -784,17 +784,17 @@ impl Renderer { buffer: &mut StyledBuffer, max_line_num_len: usize, snippet: &Snippet<'_, Annotation<'_>>, - primary_origin: Option<&str>, + primary_path: Option<&str>, sm: &SourceMap<'_>, annotated_lines: &[AnnotatedLineInfo<'_>], multiline_depth: usize, is_cont: bool, ) { - if let Some(origin) = snippet.origin { - let mut origin = Origin::new(origin); + if let Some(path) = snippet.path { + let mut origin = Origin::new(path); // print out the span location and spacer before we print the annotated source // to do this, we need to know if this span will be primary - let is_primary = primary_origin == Some(origin.origin); + let is_primary = primary_path == Some(origin.path); if is_primary { origin.primary = true; @@ -1648,7 +1648,7 @@ impl Renderer { suggestion: &Snippet<'_, Patch<'_>>, max_line_num_len: usize, sm: &SourceMap<'_>, - primary_origin: Option<&str>, + primary_path: Option<&str>, is_cont: bool, ) { let suggestions = sm.splice_lines(suggestion.markers.clone()); @@ -1671,14 +1671,14 @@ impl Renderer { ElementStyle::LineNumber, ); } - if suggestion.origin != primary_origin { - if let Some(origin) = suggestion.origin { + if suggestion.path != primary_path { + if let Some(path) = suggestion.path { let (loc, _) = sm.span_to_locations(parts[0].span.clone()); // --> file.rs:line:col // | let arrow = self.file_start(); buffer.puts(row_num - 1, 0, arrow, ElementStyle::LineNumber); - let message = format!("{}:{}:{}", origin, loc.line, loc.char + 1); + let message = format!("{}:{}:{}", path, loc.line, loc.char + 1); if is_cont { buffer.append(row_num - 1, &message, ElementStyle::LineAndColumn); } else { diff --git a/src/snippet.rs b/src/snippet.rs index 16f337ad..abdab118 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -164,7 +164,7 @@ pub struct Title<'a> { /// A source view [`Element`] in a [`Group`] #[derive(Clone, Debug)] pub struct Snippet<'a, T> { - pub(crate) origin: Option<&'a str>, + pub(crate) path: Option<&'a str>, pub(crate) line_start: usize, pub(crate) source: &'a str, pub(crate) markers: Vec, @@ -183,7 +183,7 @@ impl<'a, T: Clone> Snippet<'a, T> { /// pub fn source(source: &'a str) -> Self { Self { - origin: None, + path: None, line_start: 1, source, markers: vec![], @@ -207,8 +207,8 @@ impl<'a, T: Clone> Snippet<'a, T> { /// not allowed to be passed to this function. /// /// - pub fn origin(mut self, origin: &'a str) -> Self { - self.origin = Some(origin); + pub fn path(mut self, path: &'a str) -> Self { + self.path = Some(path); self } @@ -378,7 +378,7 @@ impl<'a> Patch<'a> { /// The location of the [`Snippet`] (e.g. a path) #[derive(Clone, Debug)] pub struct Origin<'a> { - pub(crate) origin: &'a str, + pub(crate) path: &'a str, pub(crate) line: Option, pub(crate) char_column: Option, pub(crate) primary: bool, @@ -392,9 +392,9 @@ impl<'a> Origin<'a> { /// not allowed to be passed to this function. /// /// - pub fn new(origin: &'a str) -> Self { + pub fn new(path: &'a str) -> Self { Self { - origin, + path, line: None, char_column: None, primary: false, diff --git a/tests/color/ann_eof.rs b/tests/color/ann_eof.rs index 00e34b16..ea0c95b8 100644 --- a/tests/color/ann_eof.rs +++ b/tests/color/ann_eof.rs @@ -7,7 +7,7 @@ fn case() { let input = Level::ERROR.header("expected `.`, `=`").group( Group::new().element( Snippet::source("asdf") - .origin("Cargo.toml") + .path("Cargo.toml") .line_start(1) .annotation(AnnotationKind::Primary.span(4..4).label("")), ), diff --git a/tests/color/ann_insertion.rs b/tests/color/ann_insertion.rs index 802a0c78..a0c538b8 100644 --- a/tests/color/ann_insertion.rs +++ b/tests/color/ann_insertion.rs @@ -7,7 +7,7 @@ fn case() { let input = Level::ERROR.header("expected `.`, `=`").group( Group::new().element( Snippet::source("asf") - .origin("Cargo.toml") + .path("Cargo.toml") .line_start(1) .annotation(AnnotationKind::Primary.span(2..2).label("'d' belongs here")), ), diff --git a/tests/color/ann_multiline.rs b/tests/color/ann_multiline.rs index 4b561ed3..127c462e 100644 --- a/tests/color/ann_multiline.rs +++ b/tests/color/ann_multiline.rs @@ -15,7 +15,7 @@ fn case() { .group( Group::new().element( Snippet::source(source) - .origin("src/display_list.rs") + .path("src/display_list.rs") .line_start(139) .fold(false) .annotation( diff --git a/tests/color/ann_multiline2.rs b/tests/color/ann_multiline2.rs index 9996fa97..b8e36197 100644 --- a/tests/color/ann_multiline2.rs +++ b/tests/color/ann_multiline2.rs @@ -15,7 +15,7 @@ to exactly one character on next line. .group( Group::new().element( Snippet::source(source) - .origin("foo.txt") + .path("foo.txt") .line_start(26) .fold(false) .annotation( diff --git a/tests/color/ann_removed_nl.rs b/tests/color/ann_removed_nl.rs index 45a64626..b4398c47 100644 --- a/tests/color/ann_removed_nl.rs +++ b/tests/color/ann_removed_nl.rs @@ -7,7 +7,7 @@ fn case() { let input = Level::ERROR.header("expected `.`, `=`").group( Group::new().element( Snippet::source("asdf") - .origin("Cargo.toml") + .path("Cargo.toml") .line_start(1) .annotation(AnnotationKind::Primary.span(4..5).label("")), ), diff --git a/tests/color/ensure_emoji_highlight_width.rs b/tests/color/ensure_emoji_highlight_width.rs index b2397845..59dcdaa2 100644 --- a/tests/color/ensure_emoji_highlight_width.rs +++ b/tests/color/ensure_emoji_highlight_width.rs @@ -12,7 +12,7 @@ fn case() { Group::new() .element( Snippet::source(source) - .origin("") + .path("") .line_start(7) .annotation(AnnotationKind::Primary.span(0..35).label("")) ) diff --git a/tests/color/fold_ann_multiline.rs b/tests/color/fold_ann_multiline.rs index 3995b686..b0ccdd55 100644 --- a/tests/color/fold_ann_multiline.rs +++ b/tests/color/fold_ann_multiline.rs @@ -31,7 +31,7 @@ fn case() { let input = Level::ERROR.header("mismatched types").id("E0308").group( Group::new().element( Snippet::source(source) - .origin("src/format.rs") + .path("src/format.rs") .line_start(51) .fold(true) .annotation(AnnotationKind::Context.span(5..19).label( diff --git a/tests/color/fold_bad_origin_line.rs b/tests/color/fold_bad_origin_line.rs index 1a21a5ef..852f9b54 100644 --- a/tests/color/fold_bad_origin_line.rs +++ b/tests/color/fold_bad_origin_line.rs @@ -12,7 +12,7 @@ invalid syntax let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) - .origin("path/to/error.rs") + .path("path/to/error.rs") .line_start(1) .fold(true) .annotation(AnnotationKind::Context.span(2..16).label("error here")), diff --git a/tests/color/fold_leading.rs b/tests/color/fold_leading.rs index 93ba4992..965741d5 100644 --- a/tests/color/fold_leading.rs +++ b/tests/color/fold_leading.rs @@ -23,7 +23,7 @@ workspace = 20 .group( Group::new().element( Snippet::source(source) - .origin("Cargo.toml") + .path("Cargo.toml") .line_start(1) .fold(true) .annotation(AnnotationKind::Primary.span(132..134).label("")), diff --git a/tests/color/fold_trailing.rs b/tests/color/fold_trailing.rs index f86ade78..bbcf5d80 100644 --- a/tests/color/fold_trailing.rs +++ b/tests/color/fold_trailing.rs @@ -22,7 +22,7 @@ edition = "2021" .group( Group::new().element( Snippet::source(source) - .origin("Cargo.toml") + .path("Cargo.toml") .line_start(1) .fold(true) .annotation(AnnotationKind::Primary.span(8..10).label("")), diff --git a/tests/color/issue_9.rs b/tests/color/issue_9.rs index 2accd2f2..36d13f44 100644 --- a/tests/color/issue_9.rs +++ b/tests/color/issue_9.rs @@ -9,7 +9,7 @@ fn case() { Group::new() .element( Snippet::source("let x = vec![1];") - .origin("/code/rust/src/test/ui/annotate-snippet/suggestion.rs") + .path("/code/rust/src/test/ui/annotate-snippet/suggestion.rs") .line_start(4) .annotation(AnnotationKind::Context.span(4..5).label("move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait")) ) diff --git a/tests/color/multiline_removal_suggestion.rs b/tests/color/multiline_removal_suggestion.rs index fbc47540..ced5e09d 100644 --- a/tests/color/multiline_removal_suggestion.rs +++ b/tests/color/multiline_removal_suggestion.rs @@ -71,7 +71,7 @@ fn main() {} Group::new() .element( Snippet::source(source) - .origin("$DIR/multiline-removal-suggestion.rs") + .path("$DIR/multiline-removal-suggestion.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -102,7 +102,7 @@ fn main() {} .element(Level::HELP.title("consider removing this method call, as the receiver has type `std::vec::IntoIter>` and `std::vec::IntoIter>: Iterator` trivially holds")) .element( Snippet::source(source) - .origin("$DIR/multiline-removal-suggestion.rs") + .path("$DIR/multiline-removal-suggestion.rs") .fold(true) .patch(Patch::new(708..768, "")), ), diff --git a/tests/color/simple.rs b/tests/color/simple.rs index 35e83d38..83834295 100644 --- a/tests/color/simple.rs +++ b/tests/color/simple.rs @@ -14,7 +14,7 @@ fn case() { .group( Group::new().element( Snippet::source(source) - .origin("src/format_color.rs") + .path("src/format_color.rs") .line_start(169) .annotation( AnnotationKind::Primary diff --git a/tests/color/strip_line.rs b/tests/color/strip_line.rs index fd1ba588..4b21f9a1 100644 --- a/tests/color/strip_line.rs +++ b/tests/color/strip_line.rs @@ -9,7 +9,7 @@ fn case() { let input = Level::ERROR.header("mismatched types").id("E0308").group( Group::new().element( Snippet::source(source) - .origin("$DIR/whitespace-trimming.rs") + .path("$DIR/whitespace-trimming.rs") .line_start(4) .annotation( AnnotationKind::Primary diff --git a/tests/color/strip_line_char.rs b/tests/color/strip_line_char.rs index df609e2f..f30d5e90 100644 --- a/tests/color/strip_line_char.rs +++ b/tests/color/strip_line_char.rs @@ -9,7 +9,7 @@ fn case() { let input = Level::ERROR.header("mismatched types").id("E0308").group( Group::new().element( Snippet::source(source) - .origin("$DIR/whitespace-trimming.rs") + .path("$DIR/whitespace-trimming.rs") .line_start(4) .annotation( AnnotationKind::Primary diff --git a/tests/color/strip_line_non_ws.rs b/tests/color/strip_line_non_ws.rs index f82d369b..a67d70d1 100644 --- a/tests/color/strip_line_non_ws.rs +++ b/tests/color/strip_line_non_ws.rs @@ -10,7 +10,7 @@ fn case() { let input = Level::ERROR.header("mismatched types").id("E0308").group( Group::new().element( Snippet::source(source) - .origin("$DIR/non-whitespace-trimming.rs") + .path("$DIR/non-whitespace-trimming.rs") .line_start(4) .annotation( AnnotationKind::Primary diff --git a/tests/formatter.rs b/tests/formatter.rs index b48d8f52..42886762 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -8,7 +8,7 @@ fn test_i_29() { let snippets = Level::ERROR.header("oops").group( Group::new().element( Snippet::source("First line\r\nSecond oops line") - .origin("") + .path("") .annotation(AnnotationKind::Primary.span(19..23).label("oops")) .fold(true), ), @@ -30,7 +30,7 @@ fn test_point_to_double_width_characters() { let snippets = Level::ERROR.header("").group( Group::new().element( Snippet::source("こんにちは、世界") - .origin("") + .path("") .annotation(AnnotationKind::Primary.span(18..24).label("world")), ), ); @@ -52,7 +52,7 @@ fn test_point_to_double_width_characters_across_lines() { let snippets = Level::ERROR.header("").group( Group::new().element( Snippet::source("おはよう\nございます") - .origin("") + .path("") .annotation(AnnotationKind::Primary.span(6..22).label("Good morning")), ), ); @@ -76,7 +76,7 @@ fn test_point_to_double_width_characters_multiple() { let snippets = Level::ERROR.header("").group( Group::new().element( Snippet::source("お寿司\n食べたい🍣") - .origin("") + .path("") .annotation(AnnotationKind::Primary.span(0..9).label("Sushi1")) .annotation(AnnotationKind::Context.span(16..22).label("Sushi2")), ), @@ -101,7 +101,7 @@ fn test_point_to_double_width_characters_mixed() { let snippets = Level::ERROR.header("").group( Group::new().element( Snippet::source("こんにちは、新しいWorld!") - .origin("") + .path("") .annotation(AnnotationKind::Primary.span(18..32).label("New world")), ), ); @@ -153,12 +153,12 @@ fn test_format_snippets_continuation() { .element( Snippet::>::source(src_0) .line_start(5402) - .origin("file1.rs"), + .path("file1.rs"), ) .element( Snippet::>::source(src_1) .line_start(2) - .origin("file2.rs"), + .path("file2.rs"), ), ); let expected = str![[r#" @@ -298,7 +298,7 @@ error: fn test_only_source() { let input = Level::ERROR .header("") - .group(Group::new().element(Snippet::>::source("").origin("file.rs"))); + .group(Group::new().element(Snippet::>::source("").path("file.rs"))); let expected = str![[r#" error: --> file.rs @@ -332,7 +332,7 @@ fn issue_130() { let input = Level::ERROR.header("dummy").group( Group::new().element( Snippet::source("foo\nbar\nbaz") - .origin("file/path") + .path("file/path") .line_start(3) .fold(true) .annotation(AnnotationKind::Primary.span(4..11)), @@ -360,7 +360,7 @@ a\" let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) - .origin("file/path") + .path("file/path") .line_start(3) .fold(true) .annotation(AnnotationKind::Primary.span(0..10)), @@ -384,7 +384,7 @@ fn char_and_nl_annotate_char() { let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) - .origin("file/path") + .path("file/path") .line_start(3) .annotation(AnnotationKind::Primary.span(0..2)), ), // a\r @@ -407,7 +407,7 @@ fn char_eol_annotate_char() { let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) - .origin("file/path") + .path("file/path") .line_start(3) .annotation(AnnotationKind::Primary.span(0..3)), ), // a\r\n @@ -429,7 +429,7 @@ fn char_eol_annotate_char_double_width() { let snippets = Level::ERROR.header("").group( Group::new().element( Snippet::source("こん\r\nにちは\r\n世界") - .origin("") + .path("") .annotation(AnnotationKind::Primary.span(3..8)), ), // ん\r\n ); @@ -455,7 +455,7 @@ fn annotate_eol() { let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) - .origin("file/path") + .path("file/path") .line_start(3) .annotation(AnnotationKind::Primary.span(1..2)), ), // \r @@ -478,7 +478,7 @@ fn annotate_eol2() { let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) - .origin("file/path") + .path("file/path") .line_start(3) .annotation(AnnotationKind::Primary.span(1..3)), ), // \r\n @@ -502,7 +502,7 @@ fn annotate_eol3() { let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) - .origin("file/path") + .path("file/path") .line_start(3) .annotation(AnnotationKind::Primary.span(2..3)), ), // \n @@ -526,7 +526,7 @@ fn annotate_eol4() { let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) - .origin("file/path") + .path("file/path") .line_start(3) .annotation(AnnotationKind::Primary.span(2..2)), ), // \n @@ -548,7 +548,7 @@ fn annotate_eol_double_width() { let snippets = Level::ERROR.header("").group( Group::new().element( Snippet::source("こん\r\nにちは\r\n世界") - .origin("") + .path("") .annotation(AnnotationKind::Primary.span(7..8)), ), // \n ); @@ -574,7 +574,7 @@ fn multiline_eol_start() { let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) - .origin("file/path") + .path("file/path") .line_start(3) .annotation(AnnotationKind::Primary.span(1..4)), ), // \r\nb @@ -598,7 +598,7 @@ fn multiline_eol_start2() { let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) - .origin("file/path") + .path("file/path") .line_start(3) .annotation(AnnotationKind::Primary.span(2..4)), ), // \nb @@ -622,7 +622,7 @@ fn multiline_eol_start3() { let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) - .origin("file/path") + .path("file/path") .line_start(3) .annotation(AnnotationKind::Primary.span(1..3)), ), // \nb @@ -645,7 +645,7 @@ fn multiline_eol_start_double_width() { let snippets = Level::ERROR.header("").group( Group::new().element( Snippet::source("こん\r\nにちは\r\n世界") - .origin("") + .path("") .annotation(AnnotationKind::Primary.span(7..11)), ), // \r\nに ); @@ -671,7 +671,7 @@ fn multiline_eol_start_eol_end() { let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) - .origin("file/path") + .path("file/path") .line_start(3) .annotation(AnnotationKind::Primary.span(1..4)), ), // \nb\n @@ -696,7 +696,7 @@ fn multiline_eol_start_eol_end2() { let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) - .origin("file/path") + .path("file/path") .line_start(3) .annotation(AnnotationKind::Primary.span(2..5)), ), // \nb\r @@ -721,7 +721,7 @@ fn multiline_eol_start_eol_end3() { let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) - .origin("file/path") + .path("file/path") .line_start(3) .annotation(AnnotationKind::Primary.span(2..6)), ), // \nb\r\n @@ -746,7 +746,7 @@ fn multiline_eol_start_eof_end() { let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) - .origin("file/path") + .path("file/path") .line_start(3) .annotation(AnnotationKind::Primary.span(1..5)), ), // \r\nb(EOF) @@ -770,7 +770,7 @@ fn multiline_eol_start_eof_end_double_width() { let input = Level::ERROR.header("").group( Group::new().element( Snippet::source(source) - .origin("file/path") + .path("file/path") .line_start(3) .annotation(AnnotationKind::Primary.span(3..9)), ), // \r\nに(EOF) @@ -794,7 +794,7 @@ fn two_single_line_same_line() { let input = Level::ERROR.header("unused optional dependency").group( Group::new().element( Snippet::source(source) - .origin("Cargo.toml") + .path("Cargo.toml") .line_start(4) .annotation( AnnotationKind::Primary @@ -969,7 +969,7 @@ fn origin_correct_start_line() { let input = Level::ERROR.header("title").group( Group::new().element( Snippet::source(source) - .origin("origin.txt") + .path("origin.txt") .fold(false) .annotation(AnnotationKind::Primary.span(8..8 + 3).label("annotation")), ), @@ -995,7 +995,7 @@ fn origin_correct_mid_line() { let input = Level::ERROR.header("title").group( Group::new().element( Snippet::source(source) - .origin("origin.txt") + .path("origin.txt") .fold(false) .annotation( AnnotationKind::Primary @@ -1565,7 +1565,7 @@ fn main() {}"#; .id("E0277") .group(Group::new().element(Snippet::source(source) .line_start(1) - .origin("$DIR/removal-of-multiline-trait-bound-in-where-clause.rs") + .path("$DIR/removal-of-multiline-trait-bound-in-where-clause.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -1583,7 +1583,7 @@ fn main() {}"#; ).element( Snippet::source(source) .line_start(1) - .origin("$DIR/removal-of-multiline-trait-bound-in-where-clause.rs") + .path("$DIR/removal-of-multiline-trait-bound-in-where-clause.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -1598,7 +1598,7 @@ fn main() {}"#; .element( Snippet::source(source) .line_start(1) - .origin("$DIR/removal-of-multiline-trait-bound-in-where-clause.rs") + .path("$DIR/removal-of-multiline-trait-bound-in-where-clause.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -1744,7 +1744,7 @@ fn main() { .id("E0271") .group(Group::new().element(Snippet::source(source) .line_start(4) - .origin("$DIR/E0271.rs") + .path("$DIR/E0271.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -1756,7 +1756,7 @@ fn main() { ).element( Snippet::source(source) .line_start(4) - .origin("$DIR/E0271.rs") + .path("$DIR/E0271.rs") .fold(true) .annotation(AnnotationKind::Primary.span(89..90)) ).element( @@ -1832,7 +1832,7 @@ fn main() { .id("E0271") .group(Group::new().element(Snippet::source(source) .line_start(4) - .origin("$DIR/E0271.rs") + .path("$DIR/E0271.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -1844,7 +1844,7 @@ fn main() { ).element( Snippet::source(source) .line_start(4) - .origin("$DIR/E0271.rs") + .path("$DIR/E0271.rs") .fold(true) .annotation(AnnotationKind::Primary.span(89..90)) ).element( @@ -1986,7 +1986,7 @@ fn main() { .group(Group::new().element( Snippet::source(source) .line_start(7) - .origin("$DIR/long-E0308.rs") + .path("$DIR/long-E0308.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -2071,7 +2071,7 @@ fn main() { .group(Group::new().element( Snippet::source(source) .line_start(7) - .origin("$DIR/unicode-output.rs") + .path("$DIR/unicode-output.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -2093,7 +2093,7 @@ fn main() { ).element( Snippet::source(source) .line_start(7) - .origin("$DIR/unicode-output.rs") + .path("$DIR/unicode-output.rs") .fold(true) .annotation(AnnotationKind::Primary.span(77..210)) .annotation(AnnotationKind::Context.span(71..76)), @@ -2299,7 +2299,7 @@ fn main() { let input = Level::ERROR.header("mismatched types").id("E0308").group( Group::new().element( Snippet::source(source) - .origin("$DIR/non-whitespace-trimming-unicode.rs") + .path("$DIR/non-whitespace-trimming-unicode.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -2359,7 +2359,7 @@ fn main() { Group::new() .element( Snippet::source(source) - .origin("$DIR/non-1-width-unicode-multiline-label.rs") + .path("$DIR/non-1-width-unicode-multiline-label.rs") .fold(true) .annotation(AnnotationKind::Context.span(970..984).label("&str")) .annotation(AnnotationKind::Context.span(987..1001).label("&str")) @@ -2379,7 +2379,7 @@ fn main() { .element(Level::HELP.title("create an owned `String` from a string reference")) .element( Snippet::source(source) - .origin("$DIR/non-1-width-unicode-multiline-label.rs") + .path("$DIR/non-1-width-unicode-multiline-label.rs") .fold(true) .patch(Patch::new(984..984, ".to_owned()")), ), @@ -2442,7 +2442,7 @@ fn foo() { .group( Group::new().element( Snippet::source(source) - .origin("$DIR/not-utf8.rs") + .path("$DIR/not-utf8.rs") .fold(true) .annotation(AnnotationKind::Primary.span(136..160)), ), @@ -2452,7 +2452,7 @@ fn foo() { .element(Level::NOTE.title("byte `193` is not valid utf-8")) .element( Snippet::source(bin_source) - .origin("$DIR/not-utf8.bin") + .path("$DIR/not-utf8.bin") .fold(true) .annotation(AnnotationKind::Primary.span(0..0)), ) diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index 23c178bf..c5e0602f 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -17,7 +17,7 @@ fn foo() { Group::new().element( Snippet::source(source) .line_start(1) - .origin("test.rs") + .path("test.rs") .fold(true) .annotation(AnnotationKind::Primary.span(10..13).label("test")), ), @@ -47,7 +47,7 @@ fn foo() { Group::new().element( Snippet::source(source) .line_start(1) - .origin("test.rs") + .path("test.rs") .fold(true) .annotation(AnnotationKind::Primary.span(10..17).label("test")), ), @@ -79,7 +79,7 @@ fn foo() { Group::new().element( Snippet::source(source) .line_start(1) - .origin("test.rs") + .path("test.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -122,7 +122,7 @@ fn foo() { Group::new().element( Snippet::source(source) .line_start(1) - .origin("test.rs") + .path("test.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -166,7 +166,7 @@ fn foo() { Group::new().element( Snippet::source(source) .line_start(1) - .origin("test.rs") + .path("test.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -210,7 +210,7 @@ fn foo() { Group::new().element( Snippet::source(source) .line_start(1) - .origin("test.rs") + .path("test.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -257,7 +257,7 @@ fn foo() { Group::new().element( Snippet::source(source) .line_start(1) - .origin("test.rs") + .path("test.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -305,7 +305,7 @@ fn foo() { Group::new().element( Snippet::source(source) .line_start(1) - .origin("test.rs") + .path("test.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -355,7 +355,7 @@ fn foo() { Group::new().element( Snippet::source(source) .line_start(1) - .origin("test.rs") + .path("test.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -399,7 +399,7 @@ fn foo() { Group::new().element( Snippet::source(source) .line_start(1) - .origin("test.rs") + .path("test.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -442,7 +442,7 @@ fn foo() { Group::new().element( Snippet::source(source) .line_start(1) - .origin("test.rs") + .path("test.rs") .fold(true) .annotation(AnnotationKind::Primary.span(18..25).label("")) .annotation( @@ -475,7 +475,7 @@ fn foo() { Group::new().element( Snippet::source(source) .line_start(1) - .origin("test.rs") + .path("test.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -507,7 +507,7 @@ fn foo() { Group::new().element( Snippet::source(source) .line_start(1) - .origin("test.rs") + .path("test.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -542,7 +542,7 @@ fn foo() { Group::new().element( Snippet::source(source) .line_start(1) - .origin("test.rs") + .path("test.rs") .fold(true) .annotation(AnnotationKind::Primary.span(14..27).label("")) .annotation( @@ -576,7 +576,7 @@ fn foo() { Group::new().element( Snippet::source(source) .line_start(1) - .origin("test.rs") + .path("test.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -610,7 +610,7 @@ fn foo() { Group::new().element( Snippet::source(source) .line_start(1) - .origin("test.rs") + .path("test.rs") .fold(true) .annotation(AnnotationKind::Primary.span(14..27).label("")) .annotation(AnnotationKind::Context.span(18..25).label("")), @@ -638,7 +638,7 @@ fn foo() { Group::new().element( Snippet::source(source) .line_start(1) - .origin("test.rs") + .path("test.rs") .fold(true) .annotation(AnnotationKind::Primary.span(18..25).label("")) .annotation(AnnotationKind::Context.span(14..27).label("")) @@ -667,7 +667,7 @@ fn foo() { Group::new().element( Snippet::source(source) .line_start(1) - .origin("test.rs") + .path("test.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -706,7 +706,7 @@ fn foo() { Group::new().element( Snippet::source(source) .line_start(1) - .origin("test.rs") + .path("test.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -737,7 +737,7 @@ fn foo() { Group::new().element( Snippet::source(source) .line_start(1) - .origin("test.rs") + .path("test.rs") .fold(true) .annotation(AnnotationKind::Primary.span(14..27).label("")), ), @@ -777,7 +777,7 @@ fn foo() { Group::new().element( Snippet::source(source) .line_start(1) - .origin("test.rs") + .path("test.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -837,7 +837,7 @@ fn foo() { Group::new().element( Snippet::source(source) .line_start(1) - .origin("test.rs") + .path("test.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -893,7 +893,7 @@ fn f(){||yield(((){), Group::new().element( Snippet::source(source) .line_start(1) - .origin("$DIR/issue-91334.rs") + .path("$DIR/issue-91334.rs") .fold(true) .annotation( AnnotationKind::Context @@ -965,7 +965,7 @@ fn main() { Group::new().element( Snippet::source(source) .line_start(1) - .origin("$DIR/issue-114529-illegal-break-with-value.rs") + .path("$DIR/issue-114529-illegal-break-with-value.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -988,7 +988,7 @@ fn main() { .element( Snippet::source(source) .line_start(1) - .origin("$DIR/issue-114529-illegal-break-with-value.rs") + .path("$DIR/issue-114529-illegal-break-with-value.rs") .fold(true) .annotation(AnnotationKind::Context.span(483..581).label("break")), ), @@ -1175,7 +1175,7 @@ fn nsize() { Group::new().element( Snippet::source(source) .line_start(1) - .origin("$DIR/primitive_reprs_should_have_correct_length.rs") + .path("$DIR/primitive_reprs_should_have_correct_length.rs") .fold(true) .annotation(AnnotationKind::Primary.span(4375..4381).label( "the size of `V0usize` is smaller than the size of `[usize; 2]`", @@ -1188,7 +1188,7 @@ fn nsize() { .element( Snippet::source(source) .line_start(1) - .origin("$DIR/primitive_reprs_should_have_correct_length.rs") + .path("$DIR/primitive_reprs_should_have_correct_length.rs") .fold(true) .annotation( AnnotationKind::Context @@ -1262,7 +1262,7 @@ fn main() { Snippet::source(source) .line_start(1) .fold(true) - .origin("$DIR/align-fail.rs") + .path("$DIR/align-fail.rs") .annotation( AnnotationKind::Primary .span(442..459) @@ -1330,7 +1330,7 @@ fn main() {} Group::new().element( Snippet::source(source) .line_start(1) - .origin("$DIR/missing-semicolon.rs") + .path("$DIR/missing-semicolon.rs") .fold(true) .annotation( AnnotationKind::Context @@ -1421,7 +1421,7 @@ outer_macro!(FirstStruct, FirstAttrStruct); .element( Snippet::source(aux_source) .line_start(1) - .origin("$DIR/auxiliary/nested-macro-rules.rs") + .path("$DIR/auxiliary/nested-macro-rules.rs") .fold(true) .annotation( AnnotationKind::Context @@ -1433,7 +1433,7 @@ outer_macro!(FirstStruct, FirstAttrStruct); .element( Snippet::source(source) .line_start(1) - .origin("$DIR/nested-macro-rules.rs") + .path("$DIR/nested-macro-rules.rs") .fold(true) .annotation( AnnotationKind::Context @@ -1456,7 +1456,7 @@ outer_macro!(FirstStruct, FirstAttrStruct); .element( Snippet::source(source) .line_start(1) - .origin("$DIR/nested-macro-rules.rs") + .path("$DIR/nested-macro-rules.rs") .fold(true) .annotation(AnnotationKind::Primary.span(224..245)), ), @@ -1554,7 +1554,7 @@ macro_rules! inline { Group::new().element( Snippet::source(source) .line_start(1) - .origin("$DIR/method-on-ambiguous-numeric-type.rs") + .path("$DIR/method-on-ambiguous-numeric-type.rs") .fold(true) .annotation(AnnotationKind::Primary.span(916..919)), ), @@ -1565,7 +1565,7 @@ macro_rules! inline { .element( Snippet::source(aux_source) .line_start(1) - .origin("$DIR/auxiliary/macro-in-other-crate.rs") + .path("$DIR/auxiliary/macro-in-other-crate.rs") .fold(true) .annotation(AnnotationKind::Context.span(69..69).label(": i32")), ), @@ -1618,7 +1618,7 @@ fn main() {} Group::new().element( Snippet::source(source) .line_start(1) - .origin("$DIR/issue-42234-unknown-receiver-type.rs") + .path("$DIR/issue-42234-unknown-receiver-type.rs") .fold(true) .annotation(AnnotationKind::Primary.span(536..539).label( "cannot infer type of the type parameter `S` declared on the method `sum`", @@ -1726,7 +1726,7 @@ fn main() {} Group::new().element( Snippet::source(source) .line_start(1) - .origin("$DIR/empty-match.rs") + .path("$DIR/empty-match.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -1741,7 +1741,7 @@ fn main() {} .element( Snippet::source(source) .line_start(1) - .origin("$DIR/empty-match.rs") + .path("$DIR/empty-match.rs") .fold(true) .annotation(AnnotationKind::Primary.span(818..831)) .annotation(AnnotationKind::Context.span(842..844).label("not covered")) @@ -1762,7 +1762,7 @@ fn main() {} .element( Snippet::source(source) .line_start(1) - .origin("$DIR/empty-match.rs") + .path("$DIR/empty-match.rs") .fold(true) .annotation(AnnotationKind::Context.span(485..485).label(",\n _ => todo!()")) ) @@ -1826,7 +1826,7 @@ fn main() { Group::new().element( Snippet::source(source) .line_start(1) - .origin("$DIR/object-fail.rs") + .path("$DIR/object-fail.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -1851,7 +1851,7 @@ fn main() { .element( Snippet::source(source) .line_start(1) - .origin("$DIR/object-fail.rs") + .path("$DIR/object-fail.rs") .fold(true) .annotation( AnnotationKind::Context @@ -1894,7 +1894,7 @@ fn main() {} let input = Level::ERROR.header("mismatched types").id("E0038").group( Group::new().element( Snippet::source(source) - .origin("$DIR/long-span.rs") + .path("$DIR/long-span.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -1928,7 +1928,7 @@ fn main() {} let input = Level::ERROR.header("mismatched types").id("E0038").group( Group::new().element( Snippet::source(source) - .origin("$DIR/long-span.rs") + .path("$DIR/long-span.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -1963,7 +1963,7 @@ fn main() {} let input = Level::ERROR.header("mismatched types").id("E0038").group( Group::new().element( Snippet::source(source) - .origin("$DIR/long-span.rs") + .path("$DIR/long-span.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -1998,7 +1998,7 @@ fn main() {} let input = Level::ERROR.header("mismatched types").id("E0038").group( Group::new().element( Snippet::source(source) - .origin("$DIR/long-span.rs") + .path("$DIR/long-span.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -2052,7 +2052,7 @@ fn main() { Group::new() .element( Snippet::source(source) - .origin("$DIR/lint_map_unit_fn.rs") + .path("$DIR/lint_map_unit_fn.rs") .fold(true) .annotation(AnnotationKind::Context.span(271..278).label( "this function returns `()`, which is likely not what you wanted", @@ -2077,7 +2077,7 @@ fn main() { .element(Level::HELP.title("you might have meant to use `Iterator::for_each`")) .element( Snippet::source(source) - .origin("$DIR/lint_map_unit_fn.rs") + .path("$DIR/lint_map_unit_fn.rs") .fold(true) .patch(Patch::new(267..270, r#"for_each"#)), ), @@ -2146,7 +2146,7 @@ fn main() { .group( Group::new().element( Snippet::source(source) - .origin("$DIR/bad-char-literals.rs") + .path("$DIR/bad-char-literals.rs") .fold(true) .annotation(AnnotationKind::Primary.span(204..205)), ), @@ -2156,7 +2156,7 @@ fn main() { .element(Level::HELP.title("escape the character")) .element( Snippet::source(source) - .origin("$DIR/bad-char-literals.rs") + .path("$DIR/bad-char-literals.rs") .line_start(1) .fold(true) .patch(Patch::new(204..205, r#"\n"#)), @@ -2201,7 +2201,7 @@ fn main() {} .group( Group::new().element( Snippet::source(source) - .origin("$DIR/unclosed-1.rs") + .path("$DIR/unclosed-1.rs") .fold(true) .annotation(AnnotationKind::Primary.span(0..221)), ), @@ -2211,7 +2211,7 @@ fn main() {} .element(Level::NOTE.title("frontmatter opening here was not closed")) .element( Snippet::source(source) - .origin("$DIR/unclosed-1.rs") + .path("$DIR/unclosed-1.rs") .fold(true) .annotation(AnnotationKind::Primary.span(0..4)), ), @@ -2261,7 +2261,7 @@ fn foo() -> &str { .group( Group::new().element( Snippet::source(source) - .origin("$DIR/unclosed-2.rs") + .path("$DIR/unclosed-2.rs") .fold(true) .annotation(AnnotationKind::Primary.span(0..377)), ), @@ -2271,7 +2271,7 @@ fn foo() -> &str { .element(Level::NOTE.title("frontmatter opening here was not closed")) .element( Snippet::source(source) - .origin("$DIR/unclosed-2.rs") + .path("$DIR/unclosed-2.rs") .fold(true) .annotation(AnnotationKind::Primary.span(0..4)), ), @@ -2323,7 +2323,7 @@ fn foo(x: i32) -> i32 { .group( Group::new().element( Snippet::source(source) - .origin("$DIR/unclosed-3.rs") + .path("$DIR/unclosed-3.rs") .fold(true) .annotation(AnnotationKind::Primary.span(302..310)), ), @@ -2335,7 +2335,7 @@ fn foo(x: i32) -> i32 { ) .element( Snippet::source(source) - .origin("$DIR/unclosed-3.rs") + .path("$DIR/unclosed-3.rs") .fold(true) .annotation(AnnotationKind::Primary.span(302..306)), ), @@ -2377,7 +2377,7 @@ fn main() {} .group( Group::new().element( Snippet::source(source) - .origin("$DIR/unclosed-4.rs") + .path("$DIR/unclosed-4.rs") .fold(true) .annotation(AnnotationKind::Primary.span(0..43)), ), @@ -2387,7 +2387,7 @@ fn main() {} .element(Level::NOTE.title("frontmatter opening here was not closed")) .element( Snippet::source(source) - .origin("$DIR/unclosed-4.rs") + .path("$DIR/unclosed-4.rs") .fold(true) .annotation(AnnotationKind::Primary.span(0..4)), ), @@ -2432,7 +2432,7 @@ fn main() {} .group( Group::new().element( Snippet::source(source) - .origin("$DIR/unclosed-5.rs") + .path("$DIR/unclosed-5.rs") .fold(true) .annotation(AnnotationKind::Primary.span(0..176)), ), @@ -2442,7 +2442,7 @@ fn main() {} .element(Level::NOTE.title("frontmatter opening here was not closed")) .element( Snippet::source(source) - .origin("$DIR/unclosed-5.rs") + .path("$DIR/unclosed-5.rs") .fold(true) .annotation(AnnotationKind::Primary.span(0..4)), ), @@ -2558,13 +2558,13 @@ pub enum E2 { Group::new() .element( Snippet::source(source) - .origin("$DIR/pat-tuple-field-count-cross.rs") + .path("$DIR/pat-tuple-field-count-cross.rs") .fold(true) .annotation(AnnotationKind::Primary.span(1760..1766)), ) .element( Snippet::source(source1) - .origin("$DIR/auxiliary/declarations-for-tuple-field-count-errors.rs") + .path("$DIR/auxiliary/declarations-for-tuple-field-count-errors.rs") .fold(true) .annotation( AnnotationKind::Context @@ -2583,7 +2583,7 @@ pub enum E2 { .element(Level::HELP.title("use the tuple variant pattern syntax instead")) .element( Snippet::source(source) - .origin("$DIR/pat-tuple-field-count-cross.rs") + .path("$DIR/pat-tuple-field-count-cross.rs") .fold(true) .patch(Patch::new(1760..1766, r#"E1::Z1()"#)), ), @@ -2593,7 +2593,7 @@ pub enum E2 { .element(Level::HELP.title("a unit variant with a similar name exists")) .element( Snippet::source(source) - .origin("$DIR/pat-tuple-field-count-cross.rs") + .path("$DIR/pat-tuple-field-count-cross.rs") .fold(true) .patch(Patch::new(1764..1766, r#"Z0"#)), ), @@ -2639,7 +2639,7 @@ fn unterminated_nested_comment() { let input = Level::ERROR.header("unterminated block comment").id("E0758").group( Group::new().element( Snippet::source(source) - .origin("$DIR/unterminated-nested-comment.rs") + .path("$DIR/unterminated-nested-comment.rs") .fold(true) .annotation( AnnotationKind::Context @@ -2698,7 +2698,7 @@ fn mismatched_types1() { Snippet::source(file_txt_source) .fold(true) .line_start(3) - .origin("$DIR/file.txt") + .path("$DIR/file.txt") .annotation( AnnotationKind::Primary .span(0..0) @@ -2707,7 +2707,7 @@ fn mismatched_types1() { ) .element( Snippet::source(rust_source) - .origin("$DIR/mismatched-types.rs") + .path("$DIR/mismatched-types.rs") .fold(true) .annotation( AnnotationKind::Context @@ -2759,7 +2759,7 @@ fn mismatched_types2() { Group::new() .element( Snippet::source(source) - .origin("$DIR/mismatched-types.rs") + .path("$DIR/mismatched-types.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -2815,7 +2815,7 @@ fn main() { .group( Group::new().element( Snippet::source(source) - .origin("$DIR/short-error-format.rs") + .path("$DIR/short-error-format.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -2834,7 +2834,7 @@ fn main() { .element(Level::NOTE.title("function defined here")) .element( Snippet::source(source) - .origin("$DIR/short-error-format.rs") + .path("$DIR/short-error-format.rs") .fold(true) .annotation(AnnotationKind::Context.span(48..54).label("")) .annotation(AnnotationKind::Primary.span(44..47)), @@ -2871,7 +2871,7 @@ fn main() { .group( Group::new().element( Snippet::source(source) - .origin("$DIR/short-error-format.rs") + .path("$DIR/short-error-format.rs") .fold(true) .annotation( AnnotationKind::Primary @@ -2909,7 +2909,7 @@ pub struct Foo; //~^ ERROR Group::new() .element( Snippet::source(source_0) - .origin("$DIR/diagnostic-width.rs") + .path("$DIR/diagnostic-width.rs") .fold(true) .annotation(AnnotationKind::Primary.span(111..126)), ) @@ -2923,7 +2923,7 @@ pub struct Foo; //~^ ERROR .element(Level::NOTE.title("the lint level is defined here")) .element( Snippet::source(source_0) - .origin("$DIR/diagnostic-width.rs") + .path("$DIR/diagnostic-width.rs") .fold(true) .annotation(AnnotationKind::Primary.span(49..67)), ), @@ -2933,7 +2933,7 @@ pub struct Foo; //~^ ERROR .element(Level::HELP.title("use an automatic link instead")) .element( Snippet::source(source_1) - .origin("$DIR/diagnostic-width.rs") + .path("$DIR/diagnostic-width.rs") .line_start(4) .fold(true) .patch(Patch::new(40..40, "<")) @@ -2985,7 +2985,7 @@ fn main() { Group::new() .element( Snippet::source(source1) - .origin("lint_example.rs") + .path("lint_example.rs") .fold(true) .annotation(AnnotationKind::Primary.span(40..49)), ) @@ -3000,7 +3000,7 @@ fn main() { ) .element( Snippet::source(source2) - .origin("lint_example.rs") + .path("lint_example.rs") .line_start(3) .fold(true) .patch(Patch::new(10..19, "iter")), @@ -3011,7 +3011,7 @@ fn main() { .element(Level::HELP.title(long_title3)) .element( Snippet::source(source2) - .origin("lint_example.rs") + .path("lint_example.rs") .line_start(3) .fold(true) .patch(Patch::new(0..0, "IntoIterator::into_iter(")) From 8df4d37c138d0fcc2e9127876d89bfbd1ba7a4cc Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Thu, 26 Jun 2025 14:34:06 -0600 Subject: [PATCH 231/293] chore: Improve docs arount Origin and Snippet --- src/snippet.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/snippet.rs b/src/snippet.rs index abdab118..f3c517bb 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -162,6 +162,8 @@ pub struct Title<'a> { } /// A source view [`Element`] in a [`Group`] +/// +/// If you do not have [source][Snippet::source] available, see instead [`Origin`] #[derive(Clone, Debug)] pub struct Snippet<'a, T> { pub(crate) path: Option<&'a str>, @@ -375,7 +377,9 @@ impl<'a> Patch<'a> { } } -/// The location of the [`Snippet`] (e.g. a path) +/// The referenced location (e.g. a path) +/// +/// If you have source available, see instead [`Snippet`] #[derive(Clone, Debug)] pub struct Origin<'a> { pub(crate) path: &'a str, @@ -412,6 +416,12 @@ impl<'a> Origin<'a> { /// Set the default column to display /// /// Otherwise this will be inferred from the primary [`Annotation`] + /// + ///
+ /// + /// `char_column` is only be respected if [`Origin::line`] is also set. + /// + ///
pub fn char_column(mut self, char_column: usize) -> Self { self.char_column = Some(char_column); self From 3f45b4d5fd89205054e112b97b4fa7940f1ca6d5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 26 Jun 2025 22:00:45 +0000 Subject: [PATCH 232/293] chore(deps): Update Rust Stable to v1.88 (#228) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d88caceb..b1f01275 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -104,7 +104,7 @@ jobs: - name: Install Rust uses: dtolnay/rust-toolchain@stable with: - toolchain: "1.87" # STABLE + toolchain: "1.88" # STABLE - uses: Swatinem/rust-cache@v2 - name: Check documentation env: @@ -119,7 +119,7 @@ jobs: - name: Install Rust uses: dtolnay/rust-toolchain@stable with: - toolchain: "1.87" # STABLE + toolchain: "1.88" # STABLE components: rustfmt - uses: Swatinem/rust-cache@v2 - name: Check formatting @@ -135,7 +135,7 @@ jobs: - name: Install Rust uses: dtolnay/rust-toolchain@stable with: - toolchain: "1.87" # STABLE + toolchain: "1.88" # STABLE components: clippy - uses: Swatinem/rust-cache@v2 - name: Install SARIF tools From a2595e2b381271ebfbb75f48787d150e9410e50b Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Thu, 12 Jun 2025 10:21:23 -0600 Subject: [PATCH 233/293] test: Secondary title alignment --- tests/formatter.rs | 93 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/tests/formatter.rs b/tests/formatter.rs index 42886762..edae0a62 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -2494,3 +2494,96 @@ LL │ �|�␂!5�cc␕␂�Ӻi��WWj�ȥ�'�}�␒�J�ȉ��W let renderer_unicode = renderer_ascii.theme(OutputTheme::Unicode); assert_data_eq!(renderer_unicode.render(input), expected_unicode); } + +#[test] +fn secondary_title_no_level_text() { + let source = r#"fn main() { + let b: &[u8] = include_str!("file.txt"); //~ ERROR mismatched types + let s: &str = include_bytes!("file.txt"); //~ ERROR mismatched types +}"#; + + let input = Level::ERROR.header("mismatched types").id("E0308").group( + Group::new() + .element( + Snippet::source(source) + .path("$DIR/mismatched-types.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(105..131) + .label("expected `&str`, found `&[u8; 0]`"), + ) + .annotation( + AnnotationKind::Context + .span(98..102) + .label("expected due to this"), + ), + ) + .element( + Level::NOTE + .text(None) + .title("expected reference `&str`\nfound reference `&'static [u8; 0]`"), + ), + ); + + let expected = str![[r#" +error[E0308]: mismatched types + --> $DIR/mismatched-types.rs:3:19 + | +LL | let s: &str = include_bytes!("file.txt"); //~ ERROR mismatched types + | ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&str`, found `&[u8; 0]` + | | + | expected due to this + expected reference `&str` + found reference `&'static [u8; 0]` +"#]]; + let renderer = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer.render(input), expected); +} + +#[test] +fn secondary_title_custom_level_text() { + let source = r#"fn main() { + let b: &[u8] = include_str!("file.txt"); //~ ERROR mismatched types + let s: &str = include_bytes!("file.txt"); //~ ERROR mismatched types +}"#; + + let input = Level::ERROR.header("mismatched types").id("E0308").group( + Group::new() + .element( + Snippet::source(source) + .path("$DIR/mismatched-types.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(105..131) + .label("expected `&str`, found `&[u8; 0]`"), + ) + .annotation( + AnnotationKind::Context + .span(98..102) + .label("expected due to this"), + ), + ) + .element( + Level::NOTE + .text(Some("custom")) + .title("expected reference `&str`\nfound reference `&'static [u8; 0]`"), + ), + ); + + let expected = str![[r#" +error[E0308]: mismatched types + --> $DIR/mismatched-types.rs:3:19 + | +LL | let s: &str = include_bytes!("file.txt"); //~ ERROR mismatched types + | ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&str`, found `&[u8; 0]` + | | + | expected due to this + | + = custom: expected reference `&str` + found reference `&'static [u8; 0]` +"#]]; + let renderer = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer.render(input), expected); +} From 2af175c609a42d914aaa084ed279f32883547d79 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Thu, 12 Jun 2025 10:27:56 -0600 Subject: [PATCH 234/293] fix: Add '=' before all secondary titles --- src/renderer/mod.rs | 13 +++++++------ tests/formatter.rs | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 93996075..732e5a86 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -555,13 +555,14 @@ impl Renderer { buffer.prepend(buffer_msg_line_offset, " ", ElementStyle::NoStyle); } + self.draw_note_separator( + buffer, + buffer_msg_line_offset, + max_line_num_len + 1, + is_cont, + ); + if title.level.name != Some(None) { - self.draw_note_separator( - buffer, - buffer_msg_line_offset, - max_line_num_len + 1, - is_cont, - ); buffer.append( buffer_msg_line_offset, title.level.as_str(), diff --git a/tests/formatter.rs b/tests/formatter.rs index edae0a62..f763f663 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -2534,7 +2534,7 @@ LL | let s: &str = include_bytes!("file.txt"); //~ ERROR mismatched types | ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&str`, found `&[u8; 0]` | | | expected due to this - expected reference `&str` + = expected reference `&str` found reference `&'static [u8; 0]` "#]]; let renderer = Renderer::plain().anonymized_line_numbers(true); From e7c3b6bc0b09170a50307190f4c3049c28dc5179 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Thu, 12 Jun 2025 10:27:56 -0600 Subject: [PATCH 235/293] fix: Align multi-line secondary titles by level text --- src/renderer/mod.rs | 47 ++++++++++++++++++++++++--------------------- tests/formatter.rs | 4 ++-- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 732e5a86..39c805b7 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -562,17 +562,37 @@ impl Renderer { is_cont, ); - if title.level.name != Some(None) { + let label_width = if title.level.name != Some(None) { buffer.append( buffer_msg_line_offset, title.level.as_str(), ElementStyle::MainHeaderMsg, ); buffer.append(buffer_msg_line_offset, ": ", ElementStyle::NoStyle); - } + title.level.as_str().len() + 2 + } else { + 0 + }; + // The extra 3 ` ` is padding that's always needed to align to the + // label i.e. `note: `: + // + // error: message + // --> file.rs:13:20 + // | + // 13 | + // | ^^^^ + // | + // = note: multiline + // message + // ++^^^------ + // | | | + // | | | + // | | width of label + // | magic `3` + // `max_line_num_len` + let padding = max_line_num_len + 3 + label_width; - let printed_lines = - self.msgs_to_buffer(buffer, title.title, max_line_num_len, "note", None); + let printed_lines = self.msgs_to_buffer(buffer, title.title, padding, None); if is_cont && matches!(self.theme, OutputTheme::Unicode) { // There's another note after this one, associated to the subwindow above. // We write additional vertical lines to join them: @@ -660,26 +680,9 @@ impl Renderer { buffer: &mut StyledBuffer, title: &str, padding: usize, - label: &str, override_style: Option, ) -> usize { - // The extra 5 ` ` is padding that's always needed to align to the `note: `: - // - // error: message - // --> file.rs:13:20 - // | - // 13 | - // | ^^^^ - // | - // = note: multiline - // message - // ++^^^----xx - // | | | | - // | | | magic `2` - // | | length of label - // | magic `3` - // `max_line_num_len` - let padding = " ".repeat(padding + label.len() + 5); + let padding = " ".repeat(padding); let mut line_number = buffer.num_lines().saturating_sub(1); diff --git a/tests/formatter.rs b/tests/formatter.rs index f763f663..fb671dfd 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -2535,7 +2535,7 @@ LL | let s: &str = include_bytes!("file.txt"); //~ ERROR mismatched types | | | expected due to this = expected reference `&str` - found reference `&'static [u8; 0]` + found reference `&'static [u8; 0]` "#]]; let renderer = Renderer::plain().anonymized_line_numbers(true); assert_data_eq!(renderer.render(input), expected); @@ -2582,7 +2582,7 @@ LL | let s: &str = include_bytes!("file.txt"); //~ ERROR mismatched types | expected due to this | = custom: expected reference `&str` - found reference `&'static [u8; 0]` + found reference `&'static [u8; 0]` "#]]; let renderer = Renderer::plain().anonymized_line_numbers(true); assert_data_eq!(renderer.render(input), expected); From 359a6ed10e5f2f065f8cd51a5f5f4164e6291d0b Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Tue, 10 Jun 2025 04:20:52 -0600 Subject: [PATCH 236/293] test: Add hyperlink test --- examples/id_hyperlink.rs | 32 +++++++++++++++++++++++++++++++ examples/id_hyperlink.svg | 40 +++++++++++++++++++++++++++++++++++++++ tests/examples.rs | 7 +++++++ 3 files changed, 79 insertions(+) create mode 100644 examples/id_hyperlink.rs create mode 100644 examples/id_hyperlink.svg diff --git a/examples/id_hyperlink.rs b/examples/id_hyperlink.rs new file mode 100644 index 00000000..7c3ace1e --- /dev/null +++ b/examples/id_hyperlink.rs @@ -0,0 +1,32 @@ +use annotate_snippets::renderer::OutputTheme; +use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; + +fn main() { + let source = r#"//@ compile-flags: -Zterminal-urls=yes +fn main() { + let () = 4; //~ ERROR +} +"#; + + let message = Level::ERROR.header("mismatched types").id("E0308").group( + Group::new().element( + Snippet::source(source) + .line_start(1) + .path("$DIR/terminal_urls.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(59..61) + .label("expected integer, found `()`"), + ) + .annotation( + AnnotationKind::Context + .span(64..65) + .label("this expression has type `{integer}`"), + ), + ), + ); + + let renderer = Renderer::styled().theme(OutputTheme::Unicode); + anstream::println!("{}", renderer.render(message)); +} diff --git a/examples/id_hyperlink.svg b/examples/id_hyperlink.svg new file mode 100644 index 00000000..64dbfe18 --- /dev/null +++ b/examples/id_hyperlink.svg @@ -0,0 +1,40 @@ + + + + + + + error[E0308]: mismatched types + + ╭▸ $DIR/terminal_urls.rs:3:9 + + + + 3 let () = 4; //~ ERROR + + ┯━ this expression has type `{integer}` + + + + ╰╴ expected integer, found `()` + + + + + + diff --git a/tests/examples.rs b/tests/examples.rs index 02e961c8..ec2643e9 100644 --- a/tests/examples.rs +++ b/tests/examples.rs @@ -49,6 +49,13 @@ fn highlight_title() { assert_example(target, expected); } +#[test] +fn id_hyperlink() { + let target = "id_hyperlink"; + let expected = snapbox::file!["../examples/id_hyperlink.svg": TermSvg]; + assert_example(target, expected); +} + #[test] fn multislice() { let target = "multislice"; From bff9dd5f88bcba80e8c4aa7ecc60a8f178e46137 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Thu, 5 Jun 2025 20:14:19 -0600 Subject: [PATCH 237/293] feat: Add support for ID hyperlinks --- Cargo.lock | 20 +++++++------------ examples/id_hyperlink.rs | 41 +++++++++++++++++++++------------------ examples/id_hyperlink.svg | 2 +- src/renderer/mod.rs | 19 ++++++++++++++++-- src/snippet.rs | 20 +++++++++++++++++-- 5 files changed, 65 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 532bb57a..8cfa6638 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,7 +12,7 @@ dependencies = [ "divan", "memchr", "snapbox", - "unicode-width 0.2.0", + "unicode-width", ] [[package]] @@ -47,9 +47,9 @@ dependencies = [ [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] @@ -65,15 +65,15 @@ dependencies = [ [[package]] name = "anstyle-svg" -version = "0.1.4" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbbf0bf947d663010f0b4132f28ca08da9151f3b9035fa7578a38de521c1d1aa" +checksum = "0a43964079ef399480603125d5afae2b219aceffb77478956e25f17b9bc3435c" dependencies = [ - "anstream", "anstyle", "anstyle-lossy", + "anstyle-parse", "html-escape", - "unicode-width 0.1.13", + "unicode-width", ] [[package]] @@ -418,12 +418,6 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" -[[package]] -name = "unicode-width" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" - [[package]] name = "unicode-width" version = "0.2.0" diff --git a/examples/id_hyperlink.rs b/examples/id_hyperlink.rs index 7c3ace1e..209fc15b 100644 --- a/examples/id_hyperlink.rs +++ b/examples/id_hyperlink.rs @@ -7,25 +7,28 @@ fn main() { let () = 4; //~ ERROR } "#; - - let message = Level::ERROR.header("mismatched types").id("E0308").group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .path("$DIR/terminal_urls.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(59..61) - .label("expected integer, found `()`"), - ) - .annotation( - AnnotationKind::Context - .span(64..65) - .label("this expression has type `{integer}`"), - ), - ), - ); + let message = Level::ERROR + .header("mismatched types") + .id("E0308") + .id_url("https://doc.rust-lang.org/error_codes/E0308.html") + .group( + Group::new().element( + Snippet::source(source) + .line_start(1) + .path("$DIR/terminal_urls.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(59..61) + .label("expected integer, found `()`"), + ) + .annotation( + AnnotationKind::Context + .span(64..65) + .label("this expression has type `{integer}`"), + ), + ), + ); let renderer = Renderer::styled().theme(OutputTheme::Unicode); anstream::println!("{}", renderer.render(message)); diff --git a/examples/id_hyperlink.svg b/examples/id_hyperlink.svg index 64dbfe18..5caa4114 100644 --- a/examples/id_hyperlink.svg +++ b/examples/id_hyperlink.svg @@ -19,7 +19,7 @@ - error[E0308]: mismatched types + error[E0308]: mismatched types ╭▸ $DIR/terminal_urls.rs:3:9 diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 39c805b7..a5459734 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -46,6 +46,7 @@ use crate::renderer::source_map::{ AnnotatedLineInfo, LineInfo, Loc, SourceMap, SubstitutionHighlight, }; use crate::renderer::styled_buffer::StyledBuffer; +use crate::snippet::Id; use crate::{Annotation, AnnotationKind, Element, Group, Message, Origin, Patch, Snippet, Title}; pub use anstyle::*; use margin::Margin; @@ -545,7 +546,7 @@ impl Renderer { title: &Title<'_>, max_line_num_len: usize, title_style: TitleStyle, - id: Option<&&str>, + id: Option<&Id<'_>>, is_cont: bool, buffer_msg_line_offset: usize, ) { @@ -620,17 +621,31 @@ impl Renderer { ); } label_width += title.level.as_str().len(); - if let Some(id) = id { + if let Some(Id { id: Some(id), url }) = id { buffer.append( buffer_msg_line_offset, "[", ElementStyle::Level(title.level.level), ); + if let Some(url) = url.as_ref() { + buffer.append( + buffer_msg_line_offset, + &format!("\x1B]8;;{url}\x1B\\"), + ElementStyle::Level(title.level.level), + ); + } buffer.append( buffer_msg_line_offset, id, ElementStyle::Level(title.level.level), ); + if url.is_some() { + buffer.append( + buffer_msg_line_offset, + "\x1B]8;;\x1B\\", + ElementStyle::Level(title.level.level), + ); + } buffer.append( buffer_msg_line_offset, "]", diff --git a/src/snippet.rs b/src/snippet.rs index f3c517bb..2d686a5e 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -13,7 +13,7 @@ pub(crate) const WARNING_TXT: &str = "warning"; /// Top-level user message #[derive(Clone, Debug)] pub struct Message<'a> { - pub(crate) id: Option<&'a str>, // for "correctness", could be sloppy and be on Title + pub(crate) id: Option>, // for "correctness", could be sloppy and be on Title pub(crate) groups: Vec>, } @@ -26,7 +26,17 @@ impl<'a> Message<'a> { /// /// pub fn id(mut self, id: &'a str) -> Self { - self.id = Some(id); + self.id.get_or_insert(Id::default()).id = Some(id); + self + } + + ///
+ /// + /// This is only relevant if the `id` present + /// + ///
+ pub fn id_url(https://github.com/mut%20self,%20url:%20&'a%20str) -> Self { + self.id.get_or_insert(Id::default()).url = Some(url); self } @@ -75,6 +85,12 @@ impl<'a> Message<'a> { } } +#[derive(Clone, Debug, Default)] +pub(crate) struct Id<'a> { + pub(crate) id: Option<&'a str>, + pub(crate) url: Option<&'a str>, +} + /// An [`Element`] container #[derive(Clone, Debug)] pub struct Group<'a> { From 0adeff8f8deb0914b0a0d7b089db32bab0c02ca0 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Thu, 12 Jun 2025 11:59:37 -0600 Subject: [PATCH 238/293] fix: Make pre-styled titles use their own fn --- examples/highlight_title.rs | 2 +- src/level.rs | 24 ++++++++++++++++++++++-- src/renderer/mod.rs | 22 +++++++++++++++++----- src/snippet.rs | 1 + 4 files changed, 41 insertions(+), 8 deletions(-) diff --git a/examples/highlight_title.rs b/examples/highlight_title.rs index 2f74a37b..f4e24627 100644 --- a/examples/highlight_title.rs +++ b/examples/highlight_title.rs @@ -61,7 +61,7 @@ fn main() { .label("arguments to this function are incorrect"), ), ) - .element(Level::NOTE.title(&title)), + .element(Level::NOTE.pre_styled_title(&title)), ) .group( Group::new() diff --git a/src/level.rs b/src/level.rs index eaa95600..fe746eca 100644 --- a/src/level.rs +++ b/src/level.rs @@ -78,10 +78,26 @@ impl<'a> Level<'a> { groups: vec![Group::new().element(Element::Title(Title { level: self, title: header, + is_pre_styled: false, }))], } } + ///
+ /// + /// Text passed to this function is considered "untrusted input", as such + /// all text is passed through a normalization function. Pre-styled text is + /// not allowed to be passed to this function. + /// + ///
+ pub fn title(self, title: &'a str) -> Title<'a> { + Title { + level: self, + title, + is_pre_styled: false, + } + } + ///
/// /// Text passed to this function is allowed to be pre-styled, as such all @@ -90,8 +106,12 @@ impl<'a> Level<'a> { /// used to normalize untrusted text before it is passed to this function. /// ///
- pub fn title(self, title: &'a str) -> Title<'a> { - Title { level: self, title } + pub fn pre_styled_title(self, title: &'a str) -> Title<'a> { + Title { + level: self, + title, + is_pre_styled: true, + } } pub(crate) fn as_str(&self) -> &'a str { diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index a5459734..8f279c62 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -593,7 +593,8 @@ impl Renderer { // `max_line_num_len` let padding = max_line_num_len + 3 + label_width; - let printed_lines = self.msgs_to_buffer(buffer, title.title, padding, None); + let printed_lines = + self.msgs_to_buffer(buffer, title.title, padding, None, title.is_pre_styled); if is_cont && matches!(self.theme, OutputTheme::Unicode) { // There's another note after this one, associated to the subwindow above. // We write additional vertical lines to join them: @@ -669,7 +670,12 @@ impl Renderer { label_width += 2; } if !title.title.is_empty() { - for (line, text) in normalize_whitespace(title.title).lines().enumerate() { + let (title_str, style) = if title.is_pre_styled { + (title.title.to_owned(), ElementStyle::NoStyle) + } else { + (normalize_whitespace(title.title), header_style) + }; + for (line, text) in title_str.lines().enumerate() { buffer.append( buffer_msg_line_offset + line, &format!( @@ -681,7 +687,7 @@ impl Renderer { }, text ), - header_style, + style, ); } } @@ -696,6 +702,7 @@ impl Renderer { title: &str, padding: usize, override_style: Option, + is_pre_styled: bool, ) -> usize { let padding = " ".repeat(padding); @@ -725,7 +732,12 @@ impl Renderer { } else { ElementStyle::NoStyle }; - let lines = title.split('\n').collect::>(); + let title_str = if is_pre_styled { + title.to_owned() + } else { + normalize_whitespace(title) + }; + let lines = title_str.split('\n').collect::>(); if lines.len() > 1 { for (i, line) in lines.iter().enumerate() { if i != 0 { @@ -735,7 +747,7 @@ impl Renderer { buffer.append(line_number, line, style); } } else { - buffer.append(line_number, title, style); + buffer.append(line_number, &title_str, style); } line_number } diff --git a/src/snippet.rs b/src/snippet.rs index 2d686a5e..5f35e582 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -175,6 +175,7 @@ pub struct Padding; pub struct Title<'a> { pub(crate) level: Level<'a>, pub(crate) title: &'a str, + pub(crate) is_pre_styled: bool, } /// A source view [`Element`] in a [`Group`] From e72952b5436e9af52db0f6dfa3822894797831d6 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Thu, 12 Jun 2025 10:50:33 -0600 Subject: [PATCH 239/293] refactor: Unify render_title logic --- src/renderer/mod.rs | 253 ++++++++++++++------------------------------ 1 file changed, 80 insertions(+), 173 deletions(-) diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 8f279c62..148c2c56 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -550,30 +550,59 @@ impl Renderer { is_cont: bool, buffer_msg_line_offset: usize, ) { - if title_style == TitleStyle::Secondary { - // This is a secondary message with no span info - for _ in 0..max_line_num_len { - buffer.prepend(buffer_msg_line_offset, " ", ElementStyle::NoStyle); - } - - self.draw_note_separator( - buffer, - buffer_msg_line_offset, - max_line_num_len + 1, - is_cont, - ); + let (label_style, title_element_style) = match title_style { + TitleStyle::MainHeader => ( + ElementStyle::Level(title.level.level), + if self.short_message { + ElementStyle::NoStyle + } else { + ElementStyle::MainHeaderMsg + }, + ), + TitleStyle::Header => ( + ElementStyle::Level(title.level.level), + ElementStyle::HeaderMsg, + ), + TitleStyle::Secondary => { + for _ in 0..max_line_num_len { + buffer.prepend(buffer_msg_line_offset, " ", ElementStyle::NoStyle); + } - let label_width = if title.level.name != Some(None) { - buffer.append( + self.draw_note_separator( + buffer, buffer_msg_line_offset, - title.level.as_str(), - ElementStyle::MainHeaderMsg, + max_line_num_len + 1, + is_cont, ); - buffer.append(buffer_msg_line_offset, ": ", ElementStyle::NoStyle); - title.level.as_str().len() + 2 - } else { - 0 - }; + (ElementStyle::MainHeaderMsg, ElementStyle::NoStyle) + } + }; + let mut label_width = 0; + + if title.level.name != Some(None) { + buffer.append(buffer_msg_line_offset, title.level.as_str(), label_style); + label_width += title.level.as_str().len(); + if let Some(Id { id: Some(id), url }) = id { + buffer.append(buffer_msg_line_offset, "[", label_style); + if let Some(url) = url.as_ref() { + buffer.append( + buffer_msg_line_offset, + &format!("\x1B]8;;{url}\x1B\\"), + label_style, + ); + } + buffer.append(buffer_msg_line_offset, id, label_style); + if url.is_some() { + buffer.append(buffer_msg_line_offset, "\x1B]8;;\x1B\\", label_style); + } + buffer.append(buffer_msg_line_offset, "]", label_style); + label_width += 2 + id.len(); + } + buffer.append(buffer_msg_line_offset, ": ", title_element_style); + label_width += 2; + } + + let padding = " ".repeat(if title_style == TitleStyle::Secondary { // The extra 3 ` ` is padding that's always needed to align to the // label i.e. `note: `: // @@ -591,165 +620,43 @@ impl Renderer { // | | width of label // | magic `3` // `max_line_num_len` - let padding = max_line_num_len + 3 + label_width; - - let printed_lines = - self.msgs_to_buffer(buffer, title.title, padding, None, title.is_pre_styled); - if is_cont && matches!(self.theme, OutputTheme::Unicode) { - // There's another note after this one, associated to the subwindow above. - // We write additional vertical lines to join them: - // ╭▸ test.rs:3:3 - // │ - // 3 │ code - // │ ━━━━ - // │ - // ├ note: foo - // │ bar - // ╰ note: foo - // bar - for i in buffer_msg_line_offset + 1..=printed_lines { - self.draw_col_separator_no_space(buffer, i, max_line_num_len + 1); - } - } + max_line_num_len + 3 + label_width } else { - let mut label_width = 0; - - if title.level.name != Some(None) { - buffer.append( - buffer_msg_line_offset, - title.level.as_str(), - ElementStyle::Level(title.level.level), - ); - } - label_width += title.level.as_str().len(); - if let Some(Id { id: Some(id), url }) = id { - buffer.append( - buffer_msg_line_offset, - "[", - ElementStyle::Level(title.level.level), - ); - if let Some(url) = url.as_ref() { - buffer.append( - buffer_msg_line_offset, - &format!("\x1B]8;;{url}\x1B\\"), - ElementStyle::Level(title.level.level), - ); - } - buffer.append( - buffer_msg_line_offset, - id, - ElementStyle::Level(title.level.level), - ); - if url.is_some() { - buffer.append( - buffer_msg_line_offset, - "\x1B]8;;\x1B\\", - ElementStyle::Level(title.level.level), - ); - } - buffer.append( - buffer_msg_line_offset, - "]", - ElementStyle::Level(title.level.level), - ); - label_width += 2 + id.len(); - } - let header_style = match title_style { - TitleStyle::MainHeader => { - if self.short_message { - ElementStyle::NoStyle - } else { - ElementStyle::MainHeaderMsg - } - } - TitleStyle::Header => ElementStyle::HeaderMsg, - TitleStyle::Secondary => unreachable!(), - }; - if title.level.name != Some(None) { - buffer.append(buffer_msg_line_offset, ": ", header_style); - label_width += 2; - } - if !title.title.is_empty() { - let (title_str, style) = if title.is_pre_styled { - (title.title.to_owned(), ElementStyle::NoStyle) - } else { - (normalize_whitespace(title.title), header_style) - }; - for (line, text) in title_str.lines().enumerate() { - buffer.append( - buffer_msg_line_offset + line, - &format!( - "{}{}", - if line == 0 { - String::new() - } else { - " ".repeat(label_width) - }, - text - ), - style, - ); - } - } - } - } - - /// Adds a left margin to every line but the first, given a padding length and the label being - /// displayed, keeping the provided highlighting. - fn msgs_to_buffer( - &self, - buffer: &mut StyledBuffer, - title: &str, - padding: usize, - override_style: Option, - is_pre_styled: bool, - ) -> usize { - let padding = " ".repeat(padding); - - let mut line_number = buffer.num_lines().saturating_sub(1); + label_width + }); - // Provided the following diagnostic message: - // - // let msgs = vec![ - // (" - // ("highlighted multiline\nstring to\nsee how it ", Style::NoStyle), - // ("looks", Style::Highlight), - // ("with\nvery ", Style::NoStyle), - // ("weird", Style::Highlight), - // (" formats\n", Style::NoStyle), - // ("see?", Style::Highlight), - // ]; - // - // the expected output on a note is (* surround the highlighted text) - // - // = note: highlighted multiline - // string to - // see how it *looks* with - // very *weird* formats - // see? - let style = if let Some(override_style) = override_style { - override_style - } else { - ElementStyle::NoStyle - }; - let title_str = if is_pre_styled { - title.to_owned() + let (title_str, style) = if title.is_pre_styled { + (title.title.to_owned(), ElementStyle::NoStyle) } else { - normalize_whitespace(title) + (normalize_whitespace(title.title), title_element_style) }; - let lines = title_str.split('\n').collect::>(); - if lines.len() > 1 { - for (i, line) in lines.iter().enumerate() { - if i != 0 { - line_number += 1; - buffer.append(line_number, &padding, ElementStyle::NoStyle); + for (i, text) in title_str.lines().enumerate() { + if i != 0 { + buffer.append(buffer_msg_line_offset + i, &padding, ElementStyle::NoStyle); + if title_style == TitleStyle::Secondary + && is_cont + && matches!(self.theme, OutputTheme::Unicode) + { + // There's another note after this one, associated to the subwindow above. + // We write additional vertical lines to join them: + // ╭▸ test.rs:3:3 + // │ + // 3 │ code + // │ ━━━━ + // │ + // ├ note: foo + // │ bar + // ╰ note: foo + // bar + self.draw_col_separator_no_space( + buffer, + buffer_msg_line_offset + i, + max_line_num_len + 1, + ); } - buffer.append(line_number, line, style); } - } else { - buffer.append(line_number, &title_str, style); + buffer.append(buffer_msg_line_offset + i, text, style); } - line_number } fn render_origin( From 5cee9d38993d049b986ed1223c197e74dbc64cfc Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Thu, 12 Jun 2025 08:44:03 -0600 Subject: [PATCH 240/293] test: Add a test for id on any Title --- tests/formatter.rs | 112 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/tests/formatter.rs b/tests/formatter.rs index fb671dfd..daa03e4b 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -2587,3 +2587,115 @@ LL | let s: &str = include_bytes!("file.txt"); //~ ERROR mismatched types let renderer = Renderer::plain().anonymized_line_numbers(true); assert_data_eq!(renderer.render(input), expected); } + +#[test] +fn id_on_title() { + let source = r#"// Regression test for issue #114529 +// Tests that we do not ICE during const eval for a +// break-with-value in contexts where it is illegal + +#[allow(while_true)] +fn main() { + [(); { + while true { + break 9; //~ ERROR `break` with value from a `while` loop + }; + 51 + }]; + + [(); { + while let Some(v) = Some(9) { + break v; //~ ERROR `break` with value from a `while` loop + }; + 51 + }]; + + while true { + break (|| { //~ ERROR `break` with value from a `while` loop + let local = 9; + }); + } +} +"#; + let input = Level::ERROR + .header("`break` with value from a `while` loop") + .id("E0571") + .group( + Group::new().element( + Snippet::source(source) + .line_start(1) + .path("$DIR/issue-114529-illegal-break-with-value.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(483..581) + .label("can only break with a value inside `loop` or breakable block"), + ) + .annotation( + AnnotationKind::Context + .span(462..472) + .label("you can't `break` with a value in a `while` loop"), + ), + ), + ) + .group( + Group::new() + .element( + Level::HELP + .text(Some("suggestion[S0123]")) + .title("use `break` on its own without a value inside this `while` loop"), + ) + .element( + Snippet::source(source) + .line_start(1) + .path("$DIR/issue-114529-illegal-break-with-value.rs") + .fold(true) + .patch(Patch::new(483..581, "break")), + ), + ); + + let expected_ascii = str![[r#" +error[E0571]: `break` with value from a `while` loop + --> $DIR/issue-114529-illegal-break-with-value.rs:22:9 + | +LL | while true { + | ---------- you can't `break` with a value in a `while` loop +LL | / break (|| { //~ ERROR `break` with value from a `while` loop +LL | | let local = 9; +LL | | }); + | |__________^ can only break with a value inside `loop` or breakable block + | +suggestion[S0123]: use `break` on its own without a value inside this `while` loop + | +LL - break (|| { //~ ERROR `break` with value from a `while` loop +LL - let local = 9; +LL - }); +LL + break; + | +"#]]; + + let renderer_ascii = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer_ascii.render(input.clone()), expected_ascii); + + let expected_unicode = str![[r#" +error[E0571]: `break` with value from a `while` loop + ╭▸ $DIR/issue-114529-illegal-break-with-value.rs:22:9 + │ +LL │ while true { + │ ────────── you can't `break` with a value in a `while` loop +LL │ ┏ break (|| { //~ ERROR `break` with value from a `while` loop +LL │ ┃ let local = 9; +LL │ ┃ }); + │ ┗━━━━━━━━━━┛ can only break with a value inside `loop` or breakable block + ╰╴ +suggestion[S0123]: use `break` on its own without a value inside this `while` loop + ╭╴ +LL - break (|| { //~ ERROR `break` with value from a `while` loop +LL - let local = 9; +LL - }); +LL + break; + ╰╴ +"#]]; + let renderer_unicode = renderer_ascii.theme(OutputTheme::Unicode); + assert_data_eq!(renderer_unicode.render(input), expected_unicode); +} From 9024488ea0fdad67d09b016b7608cb64c1e41bdb Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Thu, 12 Jun 2025 09:42:56 -0600 Subject: [PATCH 241/293] feat: Allow all titles to have IDs --- src/level.rs | 4 +++- src/renderer/mod.rs | 11 +--------- src/snippet.rs | 52 ++++++++++++++++++++++++++++++++++++++++++--- tests/formatter.rs | 5 +++-- 4 files changed, 56 insertions(+), 16 deletions(-) diff --git a/src/level.rs b/src/level.rs index fe746eca..4a8e8347 100644 --- a/src/level.rs +++ b/src/level.rs @@ -74,9 +74,9 @@ impl<'a> Level<'a> { /// pub fn header(self, header: &'a str) -> Message<'a> { Message { - id: None, groups: vec![Group::new().element(Element::Title(Title { level: self, + id: None, title: header, is_pre_styled: false, }))], @@ -93,6 +93,7 @@ impl<'a> Level<'a> { pub fn title(self, title: &'a str) -> Title<'a> { Title { level: self, + id: None, title, is_pre_styled: false, } @@ -109,6 +110,7 @@ impl<'a> Level<'a> { pub fn pre_styled_title(self, title: &'a str) -> Title<'a> { Title { level: self, + id: None, title, is_pre_styled: true, } diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 148c2c56..5084b631 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -338,13 +338,6 @@ impl Renderer { title, max_line_num_len, title_style, - message.id.as_ref().and_then(|id| { - if g == 0 && i == 0 { - Some(id) - } else { - None - } - }), matches!(peek, Some(Element::Title(_))), buffer_msg_line_offset, ); @@ -524,7 +517,6 @@ impl Renderer { &title, 0, // No line numbers in short messages TitleStyle::MainHeader, - message.id.as_ref(), false, 0, ); @@ -546,7 +538,6 @@ impl Renderer { title: &Title<'_>, max_line_num_len: usize, title_style: TitleStyle, - id: Option<&Id<'_>>, is_cont: bool, buffer_msg_line_offset: usize, ) { @@ -582,7 +573,7 @@ impl Renderer { if title.level.name != Some(None) { buffer.append(buffer_msg_line_offset, title.level.as_str(), label_style); label_width += title.level.as_str().len(); - if let Some(Id { id: Some(id), url }) = id { + if let Some(Id { id: Some(id), url }) = title.id { buffer.append(buffer_msg_line_offset, "[", label_style); if let Some(url) = url.as_ref() { buffer.append( diff --git a/src/snippet.rs b/src/snippet.rs index 5f35e582..e5080a4c 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -13,7 +13,6 @@ pub(crate) const WARNING_TXT: &str = "warning"; /// Top-level user message #[derive(Clone, Debug)] pub struct Message<'a> { - pub(crate) id: Option>, // for "correctness", could be sloppy and be on Title pub(crate) groups: Vec>, } @@ -26,7 +25,15 @@ impl<'a> Message<'a> { /// /// pub fn id(mut self, id: &'a str) -> Self { - self.id.get_or_insert(Id::default()).id = Some(id); + let Some(Element::Title(title)) = + self.groups.get_mut(0).and_then(|g| g.elements.first_mut()) + else { + panic!( + "Expected first element to be a Title, got: {:?}", + self.groups + ); + }; + title.id.get_or_insert(Id::default()).id = Some(id); self } @@ -36,7 +43,15 @@ impl<'a> Message<'a> { /// /// pub fn id_url(https://github.com/mut%20self,%20url:%20&'a%20str) -> Self { - self.id.get_or_insert(Id::default()).url = Some(url); + let Some(Element::Title(title)) = + self.groups.get_mut(0).and_then(|g| g.elements.first_mut()) + else { + panic!( + "Expected first element to be a Title, got: {:?}", + self.groups + ); + }; + title.id.get_or_insert(Id::default()).url = Some(url); self } @@ -174,10 +189,41 @@ pub struct Padding; #[derive(Clone, Debug)] pub struct Title<'a> { pub(crate) level: Level<'a>, + pub(crate) id: Option>, pub(crate) title: &'a str, pub(crate) is_pre_styled: bool, } +impl<'a> Title<'a> { + ///
+ /// + /// This is only relevant if the title is the first element of a group. + /// + ///
+ ///
+ /// + /// Text passed to this function is considered "untrusted input", as such + /// all text is passed through a normalization function. Pre-styled text is + /// not allowed to be passed to this function. + /// + ///
+ pub fn id(mut self, id: &'a str) -> Self { + self.id.get_or_insert(Id::default()).id = Some(id); + self + } + + ///
+ /// + /// This is only relevant if the title is the first element of a group and + /// `id` present + /// + ///
+ pub fn id_url(https://github.com/mut%20self,%20url:%20&'a%20str) -> Self { + self.id.get_or_insert(Id::default()).url = Some(url); + self + } +} + /// A source view [`Element`] in a [`Group`] /// /// If you do not have [source][Snippet::source] available, see instead [`Origin`] diff --git a/tests/formatter.rs b/tests/formatter.rs index daa03e4b..7e431215 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -2642,8 +2642,9 @@ fn main() { Group::new() .element( Level::HELP - .text(Some("suggestion[S0123]")) - .title("use `break` on its own without a value inside this `while` loop"), + .text(Some("suggestion")) + .title("use `break` on its own without a value inside this `while` loop") + .id("S0123"), ) .element( Snippet::source(source) From 99b68cbb8dc55422c3a2fadc453085cabab0588a Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Thu, 12 Jun 2025 11:51:22 -0600 Subject: [PATCH 242/293] fix!: Remove Message in favor of Group --- benches/bench.rs | 16 +- examples/custom_error.rs | 33 +- examples/custom_level.rs | 43 +- examples/expected_type.rs | 8 +- examples/footer.rs | 15 +- examples/format.rs | 8 +- examples/highlight_source.rs | 35 +- examples/highlight_title.rs | 62 +- examples/id_hyperlink.rs | 45 +- examples/multislice.rs | 25 +- src/level.rs | 22 +- src/lib.rs | 18 - src/renderer/mod.rs | 487 ++++--- src/renderer/styled_buffer.rs | 4 +- src/snippet.rs | 106 +- tests/color/ann_eof.rs | 8 +- tests/color/ann_insertion.rs | 8 +- tests/color/ann_multiline.rs | 33 +- tests/color/ann_multiline2.rs | 29 +- tests/color/ann_removed_nl.rs | 8 +- tests/color/ensure_emoji_highlight_width.rs | 19 +- tests/color/fold_ann_multiline.rs | 8 +- tests/color/fold_bad_origin_line.rs | 16 +- tests/color/fold_leading.rs | 25 +- tests/color/fold_trailing.rs | 25 +- tests/color/issue_9.rs | 39 +- tests/color/multiline_removal_suggestion.rs | 81 +- tests/color/multiple_annotations.rs | 40 +- tests/color/simple.rs | 36 +- tests/color/strip_line.rs | 8 +- tests/color/strip_line_char.rs | 8 +- tests/color/strip_line_non_ws.rs | 8 +- tests/formatter.rs | 1164 +++++++-------- tests/rustc_tests.rs | 1451 +++++++++---------- 34 files changed, 1806 insertions(+), 2135 deletions(-) diff --git a/benches/bench.rs b/benches/bench.rs index 32b67c3f..6390628f 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -24,8 +24,9 @@ fn simple() -> String { _ => continue, } }"#; - let message = Level::ERROR.header("mismatched types").id("E0308").group( - Group::new().element( + let message = &[Group::new() + .element(Level::ERROR.title("mismatched types").id("E0308")) + .element( Snippet::source(source) .line_start(51) .path("src/format.rs") @@ -39,8 +40,7 @@ fn simple() -> String { .span(26..724) .label("expected enum `std::option::Option`"), ), - ), - ); + )]; let renderer = Renderer::plain(); let rendered = renderer.render(message); @@ -69,8 +69,9 @@ fn fold(bencher: divan::Bencher<'_, '_>, context: usize) { (input, span) }) .bench_values(|(input, span)| { - let message = Level::ERROR.header("mismatched types").id("E0308").group( - Group::new().element( + let message = &[Group::new() + .element(Level::ERROR.title("mismatched types").id("E0308")) + .element( Snippet::source(&input) .fold(true) .path("src/format.rs") @@ -79,8 +80,7 @@ fn fold(bencher: divan::Bencher<'_, '_>, context: usize) { .span(span) .label("expected `Option` because of return type"), ), - ), - ); + )]; let renderer = Renderer::plain(); let rendered = renderer.render(message); diff --git a/examples/custom_error.rs b/examples/custom_error.rs index dfb8fc6c..e80b1466 100644 --- a/examples/custom_error.rs +++ b/examples/custom_error.rs @@ -15,22 +15,23 @@ fn main() { pub static C: u32 = 0 - 1; //~^ ERROR could not evaluate static initializer "#; - let message = Level::ERROR - .text(Some("error: internal compiler error")) - .header("could not evaluate static initializer") - .id("E0080") - .group( - Group::new().element( - Snippet::source(source) - .path("$DIR/err.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(386..391) - .label("attempt to compute `0_u32 - 1_u32`, which would overflow"), - ), - ), - ); + let message = &[Group::new() + .element( + Level::ERROR + .text(Some("error: internal compiler error")) + .title("could not evaluate static initializer") + .id("E0080"), + ) + .element( + Snippet::source(source) + .path("$DIR/err.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(386..391) + .label("attempt to compute `0_u32 - 1_u32`, which would overflow"), + ), + )]; let renderer = Renderer::styled().theme(OutputTheme::Unicode); anstream::println!("{}", renderer.render(message)); diff --git a/examples/custom_level.rs b/examples/custom_level.rs index 57f2fb5a..b500c063 100644 --- a/examples/custom_level.rs +++ b/examples/custom_level.rs @@ -29,11 +29,14 @@ fn main() { } } "#; - let message = Level::ERROR - .header("`break` with value from a `while` loop") - .id("E0571") - .group( - Group::new().element( + let message = &[ + Group::new() + .element( + Level::ERROR + .title("`break` with value from a `while` loop") + .id("E0571"), + ) + .element( Snippet::source(source) .line_start(1) .path("$DIR/issue-114529-illegal-break-with-value.rs") @@ -49,22 +52,20 @@ fn main() { .label("you can't `break` with a value in a `while` loop"), ), ), - ) - .group( - Group::new() - .element( - Level::HELP - .text(Some("suggestion")) - .title("use `break` on its own without a value inside this `while` loop"), - ) - .element( - Snippet::source(source) - .line_start(1) - .path("$DIR/issue-114529-illegal-break-with-value.rs") - .fold(true) - .patch(Patch::new(483..581, "break")), - ), - ); + Group::new() + .element( + Level::HELP + .text(Some("suggestion")) + .title("use `break` on its own without a value inside this `while` loop"), + ) + .element( + Snippet::source(source) + .line_start(1) + .path("$DIR/issue-114529-illegal-break-with-value.rs") + .fold(true) + .patch(Patch::new(483..581, "break")), + ), + ]; let renderer = Renderer::styled().theme(OutputTheme::Unicode); anstream::println!("{}", renderer.render(message)); diff --git a/examples/expected_type.rs b/examples/expected_type.rs index 440c64c3..0fce9938 100644 --- a/examples/expected_type.rs +++ b/examples/expected_type.rs @@ -6,8 +6,9 @@ fn main() { , range: <22, 25>,"#; let message = - Level::ERROR.header("expected type, found `22`").group( - Group::new().element( + &[Group::new() + .element(Level::ERROR.title("expected type, found `22`")) + .element( Snippet::source(source) .line_start(26) .path("examples/footer.rs") @@ -20,8 +21,7 @@ fn main() { .span(34..50) .label("while parsing this struct"), ), - ), - ); + )]; let renderer = Renderer::styled(); anstream::println!("{}", renderer.render(message)); diff --git a/examples/footer.rs b/examples/footer.rs index 36173350..aa9b784f 100644 --- a/examples/footer.rs +++ b/examples/footer.rs @@ -1,11 +1,10 @@ use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; fn main() { - let message = Level::ERROR - .header("mismatched types") - .id("E0308") - .group( - Group::new().element( + let message = &[ + Group::new() + .element(Level::ERROR.title("mismatched types").id("E0308")) + .element( Snippet::source(" slices: vec![\"A\",") .line_start(13) .path("src/multislice.rs") @@ -13,10 +12,10 @@ fn main() { "expected struct `annotate_snippets::snippet::Slice`, found reference", )), ), - ) - .group(Group::new().element(Level::NOTE.title( + Group::new().element(Level::NOTE.title( "expected type: `snippet::Annotation`\n found type: `__&__snippet::Annotation`", - ))); + )), + ]; let renderer = Renderer::styled(); anstream::println!("{}", renderer.render(message)); diff --git a/examples/format.rs b/examples/format.rs index 4268e315..ae603259 100644 --- a/examples/format.rs +++ b/examples/format.rs @@ -23,8 +23,9 @@ fn main() { _ => continue, } }"#; - let message = Level::ERROR.header("mismatched types").id("E0308").group( - Group::new().element( + let message = &[Group::new() + .element(Level::ERROR.title("mismatched types").id("E0308")) + .element( Snippet::source(source) .line_start(51) .path("src/format.rs") @@ -38,8 +39,7 @@ fn main() { .span(26..724) .label("expected enum `std::option::Option`"), ), - ), - ); + )]; let renderer = Renderer::styled(); anstream::println!("{}", renderer.render(message)); diff --git a/examples/highlight_source.rs b/examples/highlight_source.rs index f5871453..f897a3f5 100644 --- a/examples/highlight_source.rs +++ b/examples/highlight_source.rs @@ -9,26 +9,23 @@ const CON: Vec = vec![1, 2, 3]; //~ ERROR E0010 //~| ERROR cannot call non-const method fn main() {} "#; - let message = Level::ERROR - .header("allocations are not allowed in constants") - .id("E0010") - .group( - Group::new() - .element( - Snippet::source(source) - .fold(true) - .path("$DIR/E0010-teach.rs") - .annotation( - AnnotationKind::Primary - .span(72..85) - .label("allocation not allowed in constants") - .highlight_source(true), - ), - ) - .element( - Level::NOTE.title("The runtime heap is not yet available at compile-time, so no runtime heap allocations can be created."), + let message = &[Group::new().element(Level::ERROR.title("allocations are not allowed in constants") + .id("E0010")) + .element( + Snippet::source(source) + .fold(true) + .path("$DIR/E0010-teach.rs") + .annotation( + AnnotationKind::Primary + .span(72..85) + .label("allocation not allowed in constants") + .highlight_source(true), ), - ); + ) + .element( + Level::NOTE.title("The runtime heap is not yet available at compile-time, so no runtime heap allocations can be created."), + + )]; let renderer = Renderer::styled().anonymized_line_numbers(true); anstream::println!("{}", renderer.render(message)); diff --git a/examples/highlight_title.rs b/examples/highlight_title.rs index f4e24627..6ed3817f 100644 --- a/examples/highlight_title.rs +++ b/examples/highlight_title.rs @@ -41,39 +41,35 @@ fn main() { magenta.render_reset() ); - let message = Level::ERROR - .header("mismatched types") - .id("E0308") - .group( - Group::new() - .element( - Snippet::source(source) - .fold(true) - .path("$DIR/highlighting.rs") - .annotation( - AnnotationKind::Primary - .span(553..563) - .label("one type is more general than the other"), - ) - .annotation( - AnnotationKind::Context - .span(547..552) - .label("arguments to this function are incorrect"), - ), - ) - .element(Level::NOTE.pre_styled_title(&title)), - ) - .group( - Group::new() - .element(Level::NOTE.title("function defined here")) - .element( - Snippet::source(source) - .fold(true) - .path("$DIR/highlighting.rs") - .annotation(AnnotationKind::Context.span(200..333).label("")) - .annotation(AnnotationKind::Primary.span(194..199)), - ), - ); + let message = &[ + Group::new() + .element(Level::ERROR.title("mismatched types").id("E0308")) + .element( + Snippet::source(source) + .fold(true) + .path("$DIR/highlighting.rs") + .annotation( + AnnotationKind::Primary + .span(553..563) + .label("one type is more general than the other"), + ) + .annotation( + AnnotationKind::Context + .span(547..552) + .label("arguments to this function are incorrect"), + ), + ) + .element(Level::NOTE.pre_styled_title(&title)), + Group::new() + .element(Level::NOTE.title("function defined here")) + .element( + Snippet::source(source) + .fold(true) + .path("$DIR/highlighting.rs") + .annotation(AnnotationKind::Context.span(200..333).label("")) + .annotation(AnnotationKind::Primary.span(194..199)), + ), + ]; let renderer = Renderer::styled().anonymized_line_numbers(true); anstream::println!("{}", renderer.render(message)); diff --git a/examples/id_hyperlink.rs b/examples/id_hyperlink.rs index 209fc15b..2d49b275 100644 --- a/examples/id_hyperlink.rs +++ b/examples/id_hyperlink.rs @@ -7,28 +7,29 @@ fn main() { let () = 4; //~ ERROR } "#; - let message = Level::ERROR - .header("mismatched types") - .id("E0308") - .id_url("https://doc.rust-lang.org/error_codes/E0308.html") - .group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .path("$DIR/terminal_urls.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(59..61) - .label("expected integer, found `()`"), - ) - .annotation( - AnnotationKind::Context - .span(64..65) - .label("this expression has type `{integer}`"), - ), - ), - ); + let message = &[Group::new() + .element( + Level::ERROR + .title("mismatched types") + .id("E0308") + .id_url("https://doc.rust-lang.org/error_codes/E0308.html"), + ) + .element( + Snippet::source(source) + .line_start(1) + .path("$DIR/terminal_urls.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(59..61) + .label("expected integer, found `()`"), + ) + .annotation( + AnnotationKind::Context + .span(64..65) + .label("this expression has type `{integer}`"), + ), + )]; let renderer = Renderer::styled().theme(OutputTheme::Unicode); anstream::println!("{}", renderer.render(message)); diff --git a/examples/multislice.rs b/examples/multislice.rs index b8b4ac74..9393aadb 100644 --- a/examples/multislice.rs +++ b/examples/multislice.rs @@ -1,19 +1,18 @@ use annotate_snippets::{Annotation, Group, Level, Renderer, Snippet}; fn main() { - let message = Level::ERROR.header("mismatched types").group( - Group::new() - .element( - Snippet::>::source("Foo") - .line_start(51) - .path("src/format.rs"), - ) - .element( - Snippet::>::source("Faa") - .line_start(129) - .path("src/display.rs"), - ), - ); + let message = &[Group::new() + .element(Level::ERROR.title("mismatched types")) + .element( + Snippet::>::source("Foo") + .line_start(51) + .path("src/format.rs"), + ) + .element( + Snippet::>::source("Faa") + .line_start(129) + .path("src/display.rs"), + )]; let renderer = Renderer::styled(); anstream::println!("{}", renderer.render(message)); diff --git a/src/level.rs b/src/level.rs index 4a8e8347..d3db1814 100644 --- a/src/level.rs +++ b/src/level.rs @@ -2,7 +2,7 @@ use crate::renderer::stylesheet::Stylesheet; use crate::snippet::{ERROR_TXT, HELP_TXT, INFO_TXT, NOTE_TXT, WARNING_TXT}; -use crate::{Element, Group, Message, Title}; +use crate::Title; use anstyle::Style; /// Default `error:` [`Level`] @@ -35,7 +35,7 @@ pub const HELP: Level<'_> = Level { level: LevelInner::Help, }; -/// [`Message`] or [`Title`] severity level +/// [`Title`] severity level #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct Level<'a> { pub(crate) name: Option>, @@ -65,24 +65,6 @@ impl<'a> Level<'a> { } impl<'a> Level<'a> { - ///
- /// - /// Text passed to this function is considered "untrusted input", as such - /// all text is passed through a normalization function. Pre-styled text is - /// not allowed to be passed to this function. - /// - ///
- pub fn header(self, header: &'a str) -> Message<'a> { - Message { - groups: vec![Group::new().element(Element::Title(Title { - level: self, - id: None, - title: header, - is_pre_styled: false, - }))], - } - } - ///
/// /// Text passed to this function is considered "untrusted input", as such diff --git a/src/lib.rs b/src/lib.rs index bf5a720e..74f116aa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,24 +12,6 @@ //! #![doc = include_str!("../examples/expected_type.svg")] //! -//! The crate uses a three stage process with two conversions between states: -//! -//! ```text -//! Message --> Renderer --> impl Display -//! ``` -//! -//! The input type - [Message] is a structure designed -//! to align with likely output from any parser whose code snippet is to be -//! annotated. -//! -//! The middle structure - [Renderer] is a structure designed -//! to convert a snippet into an internal structure that is designed to store -//! the snippet data in a way that is easy to format. -//! [Renderer] also handles the user-configurable formatting -//! options, such as color, or margins. -//! -//! Finally, `impl Display` into a final `String` output. -//! //! # features //! - `testing-colors` - Makes [Renderer::styled] colors OS independent, which //! allows for easier testing when testing colored output. It should be added as diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 5084b631..12139c38 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -1,6 +1,6 @@ // Most of this file is adapted from https://github.com/rust-lang/rust/blob/160905b6253f42967ed4aef4b98002944c7df24c/compiler/rustc_errors/src/emitter.rs -//! The renderer for [`Message`]s +//! The renderer for [`Group`]s //! //! # Example //! ``` @@ -18,21 +18,24 @@ //! bar(); //! } //! "#; -//! Level::ERROR -//! .header("unresolved import `baz::zed`") -//! .id("E0432") -//! .group( -//! Group::new().element( -//! Snippet::source(source) -//! .path("temp.rs") -//! .line_start(1) -//! .fold(true) -//! .annotation( -//! AnnotationKind::Primary -//! .span(10..13) -//! .label("could not find `zed` in `baz`"), -//! ) -//! ) +//! +//! +//! Group::new() +//! .element( +//! Level::ERROR +//! .title("unresolved import `baz::zed`") +//! .id("E0432") +//! ) +//! .element( +//! Snippet::source(source) +//! .path("temp.rs") +//! .line_start(1) +//! .fold(true) +//! .annotation( +//! AnnotationKind::Primary +//! .span(10..13) +//! .label("could not find `zed` in `baz`"), +//! ) //! ); //! ``` @@ -47,7 +50,7 @@ use crate::renderer::source_map::{ }; use crate::renderer::styled_buffer::StyledBuffer; use crate::snippet::Id; -use crate::{Annotation, AnnotationKind, Element, Group, Message, Origin, Patch, Snippet, Title}; +use crate::{Annotation, AnnotationKind, Element, Group, Origin, Patch, Snippet, Title}; pub use anstyle::*; use margin::Margin; use std::borrow::Cow; @@ -60,7 +63,7 @@ use stylesheet::Stylesheet; const ANONYMIZED_LINE_NUM: &str = "LL"; pub const DEFAULT_TERM_WIDTH: usize = 140; -/// A renderer for [`Message`]s +/// A renderer for [`Group`]s #[derive(Clone, Debug)] pub struct Renderer { anonymized_line_numbers: bool, @@ -206,265 +209,220 @@ impl Renderer { } impl Renderer { - pub fn render(&self, mut message: Message<'_>) -> String { + pub fn render(&self, groups: &[Group<'_>]) -> String { if self.short_message { - self.render_short_message(message).unwrap() + self.render_short_message(groups).unwrap() } else { let max_line_num_len = if self.anonymized_line_numbers { ANONYMIZED_LINE_NUM.len() } else { - let n = message.max_line_number(); - num_decimal_digits(n) + num_decimal_digits(max_line_number(groups)) }; - let title = message.groups.remove(0).elements.remove(0); - if let Some(first) = message.groups.first_mut() { - first.elements.insert(0, title); - } else { - message.groups.push(Group::new().element(title)); - } - self.render_message(message, max_line_num_len).unwrap() - } - } - - fn render_message( - &self, - message: Message<'_>, - max_line_num_len: usize, - ) -> Result { - let mut out_string = String::new(); - - let og_primary_path = message - .groups - .iter() - .find_map(|group| { - group.elements.iter().find_map(|s| match &s { - Element::Cause(cause) => { - if cause.markers.iter().any(|m| m.kind.is_primary()) { - Some(cause.path) - } else { - None + let mut out_string = String::new(); + let group_len = groups.len(); + let mut og_primary_path = None; + for (g, group) in groups.iter().enumerate() { + let mut buffer = StyledBuffer::new(); + let primary_path = group + .elements + .iter() + .find_map(|s| match &s { + Element::Cause(cause) => { + if cause.markers.iter().any(|m| m.kind.is_primary()) { + Some(cause.path) + } else { + None + } } - } - Element::Origin(origin) => { - if origin.primary { - Some(Some(origin.path)) - } else { - None + Element::Origin(origin) => { + if origin.primary { + Some(Some(origin.path)) + } else { + None + } } - } - _ => None, - }) - }) - .unwrap_or( - message - .groups + _ => None, + }) + .unwrap_or( + group + .elements + .iter() + .find_map(|s| match &s { + Element::Cause(cause) => Some(cause.path), + Element::Origin(origin) => Some(Some(origin.path)), + _ => None, + }) + .unwrap_or_default(), + ); + if og_primary_path.is_none() && primary_path.is_some() { + og_primary_path = primary_path; + } + let level = group + .elements .iter() - .find_map(|group| { - group.elements.iter().find_map(|s| match &s { - Element::Cause(cause) => Some(cause.path), - Element::Origin(origin) => Some(Some(origin.path)), - _ => None, - }) + .find_map(|s| match &s { + Element::Title(title) => Some(title.level.clone()), + _ => None, }) - .unwrap_or_default(), - ); - let group_len = message.groups.len(); - for (g, group) in message.groups.into_iter().enumerate() { - let mut buffer = StyledBuffer::new(); - let primary_path = group - .elements - .iter() - .find_map(|s| match &s { - Element::Cause(cause) => { - if cause.markers.iter().any(|m| m.kind.is_primary()) { - Some(cause.path) - } else { - None - } + .unwrap_or(Level::ERROR); + let mut source_map_annotated_lines = VecDeque::new(); + let mut max_depth = 0; + for e in &group.elements { + if let Element::Cause(cause) = e { + let source_map = SourceMap::new(cause.source, cause.line_start); + let (depth, annotated_lines) = + source_map.annotated_lines(cause.markers.clone(), cause.fold); + max_depth = max(max_depth, depth); + source_map_annotated_lines.push_back((source_map, annotated_lines)); } - Element::Origin(origin) => { - if origin.primary { - Some(Some(origin.path)) - } else { - None - } - } - _ => None, - }) - .unwrap_or( - group - .elements - .iter() - .find_map(|s| match &s { - Element::Cause(cause) => Some(cause.path), - Element::Origin(origin) => Some(Some(origin.path)), - _ => None, - }) - .unwrap_or_default(), - ); - let level = group - .elements - .iter() - .find_map(|s| match &s { - Element::Title(title) => Some(title.level.clone()), - _ => None, - }) - .unwrap_or(Level::ERROR); - let mut source_map_annotated_lines = VecDeque::new(); - let mut max_depth = 0; - for e in &group.elements { - if let Element::Cause(cause) = e { - let source_map = SourceMap::new(cause.source, cause.line_start); - let (depth, annotated_lines) = - source_map.annotated_lines(cause.markers.clone(), cause.fold); - max_depth = max(max_depth, depth); - source_map_annotated_lines.push_back((source_map, annotated_lines)); } - } - let mut message_iter = group.elements.iter().enumerate().peekable(); - let mut last_was_suggestion = false; - while let Some((i, section)) = message_iter.next() { - let peek = message_iter.peek().map(|(_, s)| s).copied(); - match §ion { - Element::Title(title) => { - let title_style = match (i == 0, g == 0) { - (true, true) => TitleStyle::MainHeader, - (true, false) => TitleStyle::Header, - (false, _) => TitleStyle::Secondary, - }; - let buffer_msg_line_offset = buffer.num_lines(); - self.render_title( - &mut buffer, - title, - max_line_num_len, - title_style, - matches!(peek, Some(Element::Title(_))), - buffer_msg_line_offset, - ); - last_was_suggestion = false; - } - Element::Cause(cause) => { - if let Some((source_map, annotated_lines)) = - source_map_annotated_lines.pop_front() - { - self.render_snippet_annotations( + let mut message_iter = group.elements.iter().enumerate().peekable(); + let mut last_was_suggestion = false; + while let Some((i, section)) = message_iter.next() { + let peek = message_iter.peek().map(|(_, s)| s).copied(); + match §ion { + Element::Title(title) => { + let title_style = match (i == 0, g == 0) { + (true, true) => TitleStyle::MainHeader, + (true, false) => TitleStyle::Header, + (false, _) => TitleStyle::Secondary, + }; + let buffer_msg_line_offset = buffer.num_lines(); + self.render_title( &mut buffer, + title, max_line_num_len, - cause, - primary_path, - &source_map, - &annotated_lines, - max_depth, - peek.is_some() || (g == 0 && group_len > 1), + title_style, + matches!(peek, Some(Element::Title(_))), + buffer_msg_line_offset, ); + last_was_suggestion = false; + } + Element::Cause(cause) => { + if let Some((source_map, annotated_lines)) = + source_map_annotated_lines.pop_front() + { + self.render_snippet_annotations( + &mut buffer, + max_line_num_len, + cause, + primary_path, + &source_map, + &annotated_lines, + max_depth, + peek.is_some() || (g == 0 && group_len > 1), + ); - if g == 0 { - let current_line = buffer.num_lines(); - match peek { - Some(Element::Title(level)) - if level.level.name != Some(None) => - { - self.draw_col_separator_no_space( + if g == 0 { + let current_line = buffer.num_lines(); + match peek { + Some(Element::Title(level)) + if level.level.name != Some(None) => + { + self.draw_col_separator_no_space( + &mut buffer, + current_line, + max_line_num_len + 1, + ); + } + + None if group_len > 1 => self.draw_col_separator_end( &mut buffer, current_line, max_line_num_len + 1, - ); + ), + _ => {} } - - None if group_len > 1 => self.draw_col_separator_end( - &mut buffer, - current_line, - max_line_num_len + 1, - ), - _ => {} } } - } - last_was_suggestion = false; - } - Element::Suggestion(suggestion) => { - let source_map = SourceMap::new(suggestion.source, suggestion.line_start); - self.emit_suggestion_default( - &mut buffer, - suggestion, - max_line_num_len, - &source_map, - primary_path.or(og_primary_path), - last_was_suggestion, - ); - last_was_suggestion = true; - } + last_was_suggestion = false; + } + Element::Suggestion(suggestion) => { + let source_map = + SourceMap::new(suggestion.source, suggestion.line_start); + self.emit_suggestion_default( + &mut buffer, + suggestion, + max_line_num_len, + &source_map, + primary_path.or(og_primary_path), + last_was_suggestion, + ); + last_was_suggestion = true; + } - Element::Origin(origin) => { - let buffer_msg_line_offset = buffer.num_lines(); - self.render_origin( - &mut buffer, - max_line_num_len, - origin, - buffer_msg_line_offset, - ); - last_was_suggestion = false; - } - Element::Padding(_) => { - let current_line = buffer.num_lines(); - self.draw_col_separator_no_space( - &mut buffer, - current_line, - max_line_num_len + 1, - ); + Element::Origin(origin) => { + let buffer_msg_line_offset = buffer.num_lines(); + self.render_origin( + &mut buffer, + max_line_num_len, + origin, + buffer_msg_line_offset, + ); + last_was_suggestion = false; + } + Element::Padding(_) => { + let current_line = buffer.num_lines(); + self.draw_col_separator_no_space( + &mut buffer, + current_line, + max_line_num_len + 1, + ); + } } - } - if g == 0 - && (matches!(section, Element::Origin(_)) - || (matches!(section, Element::Title(_)) && i == 0) - || matches!(section, Element::Title(level) if level.level.name == Some(None))) - { - let current_line = buffer.num_lines(); - if peek.is_none() && group_len > 1 { - self.draw_col_separator_end( - &mut buffer, - current_line, - max_line_num_len + 1, - ); - } else if matches!(peek, Some(Element::Title(level)) if level.level.name != Some(None)) + if g == 0 + && (matches!(section, Element::Origin(_)) + || (matches!(section, Element::Title(_)) && i == 0) + || matches!(section, Element::Title(level) if level.level.name == Some(None))) { - self.draw_col_separator_no_space( - &mut buffer, - current_line, - max_line_num_len + 1, - ); + let current_line = buffer.num_lines(); + if peek.is_none() && group_len > 1 { + self.draw_col_separator_end( + &mut buffer, + current_line, + max_line_num_len + 1, + ); + } else if matches!(peek, Some(Element::Title(level)) if level.level.name != Some(None)) + { + self.draw_col_separator_no_space( + &mut buffer, + current_line, + max_line_num_len + 1, + ); + } } } - } - buffer.render(level, &self.stylesheet, &mut out_string)?; - if g != group_len - 1 { - use std::fmt::Write; + buffer + .render(&level, &self.stylesheet, &mut out_string) + .unwrap(); + if g != group_len - 1 { + use std::fmt::Write; - writeln!(out_string)?; + writeln!(out_string).unwrap(); + } } + out_string } - Ok(out_string) } - fn render_short_message(&self, mut message: Message<'_>) -> Result { + fn render_short_message(&self, groups: &[Group<'_>]) -> Result { let mut buffer = StyledBuffer::new(); + let mut labels = None; + let group = groups.first().expect("Expected at least one group"); - let Element::Title(title) = message.groups.remove(0).elements.remove(0) else { + let Some(Element::Title(title)) = group.elements.first() else { panic!( "Expected first element to be a Title, got: {:?}", - message.groups + group.elements.first() ); }; - let mut labels = None; - - if let Some(Element::Cause(cause)) = message.groups.first().and_then(|group| { - group - .elements - .iter() - .find(|e| matches!(e, Element::Cause(_))) - }) { + if let Some(Element::Cause(cause)) = group + .elements + .iter() + .find(|e| matches!(e, Element::Cause(_))) + { let labels_inner = cause .markers .iter() @@ -514,7 +472,7 @@ impl Renderer { self.render_title( &mut buffer, - &title, + title, 0, // No line numbers in short messages TitleStyle::MainHeader, false, @@ -526,7 +484,7 @@ impl Renderer { } let mut out_string = String::new(); - buffer.render(title.level, &self.stylesheet, &mut out_string)?; + buffer.render(&title.level, &self.stylesheet, &mut out_string)?; Ok(out_string) } @@ -2871,6 +2829,57 @@ enum TitleStyle { Secondary, } +fn max_line_number(groups: &[Group<'_>]) -> usize { + groups + .iter() + .map(|v| { + v.elements + .iter() + .map(|s| match s { + Element::Title(_) | Element::Origin(_) | Element::Padding(_) => 0, + Element::Cause(cause) => { + let end = cause + .markers + .iter() + .map(|a| a.span.end) + .max() + .unwrap_or(cause.source.len()) + .min(cause.source.len()); + + cause.line_start + newline_count(&cause.source[..end]) + } + Element::Suggestion(suggestion) => { + let end = suggestion + .markers + .iter() + .map(|a| a.span.end) + .max() + .unwrap_or(suggestion.source.len()) + .min(suggestion.source.len()); + + suggestion.line_start + newline_count(&suggestion.source[..end]) + } + }) + .max() + .unwrap_or(1) + }) + .max() + .unwrap_or(1) +} + +fn newline_count(body: &str) -> usize { + #[cfg(feature = "simd")] + { + memchr::memchr_iter(b'\n', body.as_bytes()) + .count() + .saturating_sub(1) + } + #[cfg(not(feature = "simd"))] + { + body.lines().count().saturating_sub(1) + } +} + #[cfg(test)] mod test { use super::OUTPUT_REPLACEMENTS; diff --git a/src/renderer/styled_buffer.rs b/src/renderer/styled_buffer.rs index f72c58c6..de3d0815 100644 --- a/src/renderer/styled_buffer.rs +++ b/src/renderer/styled_buffer.rs @@ -41,14 +41,14 @@ impl StyledBuffer { pub(crate) fn render( &self, - level: Level<'_>, + level: &Level<'_>, stylesheet: &Stylesheet, str: &mut String, ) -> Result<(), fmt::Error> { for (i, line) in self.lines.iter().enumerate() { let mut current_style = stylesheet.none; for StyledChar { ch, style } in line { - let ch_style = style.color_spec(&level, stylesheet); + let ch_style = style.color_spec(level, stylesheet); if ch_style != current_style { if !line.is_empty() { write!(str, "{}", current_style.render_reset())?; diff --git a/src/snippet.rs b/src/snippet.rs index e5080a4c..6e9a78c7 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -10,96 +10,6 @@ pub(crate) const INFO_TXT: &str = "info"; pub(crate) const NOTE_TXT: &str = "note"; pub(crate) const WARNING_TXT: &str = "warning"; -/// Top-level user message -#[derive(Clone, Debug)] -pub struct Message<'a> { - pub(crate) groups: Vec>, -} - -impl<'a> Message<'a> { - ///
- /// - /// Text passed to this function is considered "untrusted input", as such - /// all text is passed through a normalization function. Pre-styled text is - /// not allowed to be passed to this function. - /// - ///
- pub fn id(mut self, id: &'a str) -> Self { - let Some(Element::Title(title)) = - self.groups.get_mut(0).and_then(|g| g.elements.first_mut()) - else { - panic!( - "Expected first element to be a Title, got: {:?}", - self.groups - ); - }; - title.id.get_or_insert(Id::default()).id = Some(id); - self - } - - ///
- /// - /// This is only relevant if the `id` present - /// - ///
- pub fn id_url(https://github.com/mut%20self,%20url:%20&'a%20str) -> Self { - let Some(Element::Title(title)) = - self.groups.get_mut(0).and_then(|g| g.elements.first_mut()) - else { - panic!( - "Expected first element to be a Title, got: {:?}", - self.groups - ); - }; - title.id.get_or_insert(Id::default()).url = Some(url); - self - } - - /// Add an [`Element`] container - pub fn group(mut self, group: Group<'a>) -> Self { - self.groups.push(group); - self - } - - pub(crate) fn max_line_number(&self) -> usize { - self.groups - .iter() - .map(|v| { - v.elements - .iter() - .map(|s| match s { - Element::Title(_) | Element::Origin(_) | Element::Padding(_) => 0, - Element::Cause(cause) => { - let end = cause - .markers - .iter() - .map(|a| a.span.end) - .max() - .unwrap_or(cause.source.len()) - .min(cause.source.len()); - - cause.line_start + newline_count(&cause.source[..end]) - } - Element::Suggestion(suggestion) => { - let end = suggestion - .markers - .iter() - .map(|a| a.span.end) - .max() - .unwrap_or(suggestion.source.len()) - .min(suggestion.source.len()); - - suggestion.line_start + newline_count(&suggestion.source[..end]) - } - }) - .max() - .unwrap_or(1) - }) - .max() - .unwrap_or(1) - } -} - #[derive(Clone, Debug, Default)] pub(crate) struct Id<'a> { pub(crate) id: Option<&'a str>, @@ -350,7 +260,8 @@ impl<'a> Annotation<'a> { /// The category of the [`Annotation`] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum AnnotationKind { - /// Color to [`Message`]'s [`Level`] + /// Color to the [`Level`] the first [`Title`] in [`Group`]. If no [`Title`] + /// is present, it will default to `error`. Primary, /// "secondary"; fixed color Context, @@ -496,19 +407,6 @@ impl<'a> Origin<'a> { } } -fn newline_count(body: &str) -> usize { - #[cfg(feature = "simd")] - { - memchr::memchr_iter(b'\n', body.as_bytes()) - .count() - .saturating_sub(1) - } - #[cfg(not(feature = "simd"))] - { - body.lines().count().saturating_sub(1) - } -} - /// Given an original string like `AACC`, and a suggestion like `AABBCC`, try to detect /// the case where a substring of the suggestion is "sandwiched" in the original, like /// `BB` is. Return the length of the prefix, the "trimmed" suggestion, and the length diff --git a/tests/color/ann_eof.rs b/tests/color/ann_eof.rs index ea0c95b8..e550ba55 100644 --- a/tests/color/ann_eof.rs +++ b/tests/color/ann_eof.rs @@ -4,14 +4,14 @@ use snapbox::{assert_data_eq, file}; #[test] fn case() { - let input = Level::ERROR.header("expected `.`, `=`").group( - Group::new().element( + let input = &[Group::new() + .element(Level::ERROR.title("expected `.`, `=`")) + .element( Snippet::source("asdf") .path("Cargo.toml") .line_start(1) .annotation(AnnotationKind::Primary.span(4..4).label("")), - ), - ); + )]; let expected = file!["ann_eof.term.svg"]; let renderer = Renderer::styled(); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/color/ann_insertion.rs b/tests/color/ann_insertion.rs index a0c538b8..73dd7d80 100644 --- a/tests/color/ann_insertion.rs +++ b/tests/color/ann_insertion.rs @@ -4,14 +4,14 @@ use snapbox::{assert_data_eq, file}; #[test] fn case() { - let input = Level::ERROR.header("expected `.`, `=`").group( - Group::new().element( + let input = &[Group::new() + .element(Level::ERROR.title("expected `.`, `=`")) + .element( Snippet::source("asf") .path("Cargo.toml") .line_start(1) .annotation(AnnotationKind::Primary.span(2..2).label("'d' belongs here")), - ), - ); + )]; let expected = file!["ann_insertion.term.svg"]; let renderer = Renderer::styled(); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/color/ann_multiline.rs b/tests/color/ann_multiline.rs index 127c462e..29d4c309 100644 --- a/tests/color/ann_multiline.rs +++ b/tests/color/ann_multiline.rs @@ -9,22 +9,23 @@ fn case() { } = body[body_idx] "#; - let input = Level::ERROR - .header("pattern does not mention fields `lineno`, `content`") - .id("E0027") - .group( - Group::new().element( - Snippet::source(source) - .path("src/display_list.rs") - .line_start(139) - .fold(false) - .annotation( - AnnotationKind::Primary - .span(31..128) - .label("missing fields `lineno`, `content`"), - ), - ), - ); + let input = &[Group::new() + .element( + Level::ERROR + .title("pattern does not mention fields `lineno`, `content`") + .id("E0027"), + ) + .element( + Snippet::source(source) + .path("src/display_list.rs") + .line_start(139) + .fold(false) + .annotation( + AnnotationKind::Primary + .span(31..128) + .label("missing fields `lineno`, `content`"), + ), + )]; let expected = file!["ann_multiline.term.svg"]; let renderer = Renderer::styled(); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/color/ann_multiline2.rs b/tests/color/ann_multiline2.rs index b8e36197..cf21e5ea 100644 --- a/tests/color/ann_multiline2.rs +++ b/tests/color/ann_multiline2.rs @@ -9,22 +9,19 @@ of an edge case of an annotation overflowing to exactly one character on next line. "#; - let input = Level::ERROR - .header("spacing error found") - .id("E####") - .group( - Group::new().element( - Snippet::source(source) - .path("foo.txt") - .line_start(26) - .fold(false) - .annotation( - AnnotationKind::Primary - .span(11..19) - .label("this should not be on separate lines"), - ), - ), - ); + let input = &[Group::new() + .element(Level::ERROR.title("spacing error found").id("E####")) + .element( + Snippet::source(source) + .path("foo.txt") + .line_start(26) + .fold(false) + .annotation( + AnnotationKind::Primary + .span(11..19) + .label("this should not be on separate lines"), + ), + )]; let expected = file!["ann_multiline2.term.svg"]; let renderer = Renderer::styled(); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/color/ann_removed_nl.rs b/tests/color/ann_removed_nl.rs index b4398c47..68ec8326 100644 --- a/tests/color/ann_removed_nl.rs +++ b/tests/color/ann_removed_nl.rs @@ -4,14 +4,14 @@ use snapbox::{assert_data_eq, file}; #[test] fn case() { - let input = Level::ERROR.header("expected `.`, `=`").group( - Group::new().element( + let input = &[Group::new() + .element(Level::ERROR.title("expected `.`, `=`")) + .element( Snippet::source("asdf") .path("Cargo.toml") .line_start(1) .annotation(AnnotationKind::Primary.span(4..5).label("")), - ), - ); + )]; let expected = file!["ann_removed_nl.term.svg"]; let renderer = Renderer::styled(); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/color/ensure_emoji_highlight_width.rs b/tests/color/ensure_emoji_highlight_width.rs index 59dcdaa2..bc22f9ab 100644 --- a/tests/color/ensure_emoji_highlight_width.rs +++ b/tests/color/ensure_emoji_highlight_width.rs @@ -7,17 +7,14 @@ fn case() { let source = r#""haha this isn't a valid name 🐛" = { package = "libc", version = "0.1" } "#; - let input = Level::ERROR.header("invalid character ` ` in package name: `haha this isn't a valid name 🐛`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters)") - .group( - Group::new() - .element( - Snippet::source(source) - .path("") - .line_start(7) - .annotation(AnnotationKind::Primary.span(0..35).label("")) - ) - ) -; + let input = &[Group::new() + .element(Level::ERROR.title("invalid character ` ` in package name: `haha this isn't a valid name 🐛`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters)")) + .element( + Snippet::source(source) + .path("") + .line_start(7) + .annotation(AnnotationKind::Primary.span(0..35).label("")) + )]; let expected = file!["ensure_emoji_highlight_width.term.svg"]; let renderer = Renderer::styled(); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/color/fold_ann_multiline.rs b/tests/color/fold_ann_multiline.rs index b0ccdd55..1c035f41 100644 --- a/tests/color/fold_ann_multiline.rs +++ b/tests/color/fold_ann_multiline.rs @@ -28,8 +28,9 @@ fn case() { } "#; - let input = Level::ERROR.header("mismatched types").id("E0308").group( - Group::new().element( + let input = &[Group::new() + .element(Level::ERROR.title("mismatched types").id("E0308")) + .element( Snippet::source(source) .path("src/format.rs") .line_start(51) @@ -42,8 +43,7 @@ fn case() { .span(22..766) .label("expected enum `std::option::Option`, found ()"), ), - ), - ); + )]; let expected = file!["fold_ann_multiline.term.svg"]; let renderer = Renderer::styled(); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/color/fold_bad_origin_line.rs b/tests/color/fold_bad_origin_line.rs index 852f9b54..9e4c5c0c 100644 --- a/tests/color/fold_bad_origin_line.rs +++ b/tests/color/fold_bad_origin_line.rs @@ -9,15 +9,13 @@ fn case() { invalid syntax "#; - let input = Level::ERROR.header("").group( - Group::new().element( - Snippet::source(source) - .path("path/to/error.rs") - .line_start(1) - .fold(true) - .annotation(AnnotationKind::Context.span(2..16).label("error here")), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source(source) + .path("path/to/error.rs") + .line_start(1) + .fold(true) + .annotation(AnnotationKind::Context.span(2..16).label("error here")), + )]; let expected = file!["fold_bad_origin_line.term.svg"]; let renderer = Renderer::styled(); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/color/fold_leading.rs b/tests/color/fold_leading.rs index 965741d5..0e4ae61d 100644 --- a/tests/color/fold_leading.rs +++ b/tests/color/fold_leading.rs @@ -17,18 +17,19 @@ edition = "2021" workspace = 20 "#; - let input = Level::ERROR - .header("invalid type: integer `20`, expected a bool") - .id("E0308") - .group( - Group::new().element( - Snippet::source(source) - .path("Cargo.toml") - .line_start(1) - .fold(true) - .annotation(AnnotationKind::Primary.span(132..134).label("")), - ), - ); + let input = &[Group::new() + .element( + Level::ERROR + .title("invalid type: integer `20`, expected a bool") + .id("E0308"), + ) + .element( + Snippet::source(source) + .path("Cargo.toml") + .line_start(1) + .fold(true) + .annotation(AnnotationKind::Primary.span(132..134).label("")), + )]; let expected = file!["fold_leading.term.svg"]; let renderer = Renderer::styled(); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/color/fold_trailing.rs b/tests/color/fold_trailing.rs index bbcf5d80..6421dd45 100644 --- a/tests/color/fold_trailing.rs +++ b/tests/color/fold_trailing.rs @@ -16,18 +16,19 @@ rust-version = "1.70" edition = "2021" "#; - let input = Level::ERROR - .header("invalid type: integer `20`, expected a lints table") - .id("E0308") - .group( - Group::new().element( - Snippet::source(source) - .path("Cargo.toml") - .line_start(1) - .fold(true) - .annotation(AnnotationKind::Primary.span(8..10).label("")), - ), - ); + let input = &[Group::new() + .element( + Level::ERROR + .title("invalid type: integer `20`, expected a lints table") + .id("E0308"), + ) + .element( + Snippet::source(source) + .path("Cargo.toml") + .line_start(1) + .fold(true) + .annotation(AnnotationKind::Primary.span(8..10).label("")), + )]; let expected = file!["fold_trailing.term.svg"]; let renderer = Renderer::styled(); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/color/issue_9.rs b/tests/color/issue_9.rs index 36d13f44..f42c30b9 100644 --- a/tests/color/issue_9.rs +++ b/tests/color/issue_9.rs @@ -4,27 +4,24 @@ use snapbox::{assert_data_eq, file}; #[test] fn case() { - let input = Level::ERROR.header("expected one of `.`, `;`, `?`, or an operator, found `for`") - .group( - Group::new() - .element( - Snippet::source("let x = vec![1];") - .path("/code/rust/src/test/ui/annotate-snippet/suggestion.rs") - .line_start(4) - .annotation(AnnotationKind::Context.span(4..5).label("move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait")) - ) - .element( - Snippet::source("let y = x;") - .line_start(7) - .annotation(AnnotationKind::Context.span(8..9).label("value moved here")) - ) - .element( - Snippet::source("x;") - .line_start(9) - .annotation(AnnotationKind::Primary.span(0..1).label("value used here after move")) - ) - ) -; + let input = &[Group::new().element(Level::ERROR.title("expected one of `.`, `;`, `?`, or an operator, found `for`")) + .element( + Snippet::source("let x = vec![1];") + .path("/code/rust/src/test/ui/annotate-snippet/suggestion.rs") + .line_start(4) + .annotation(AnnotationKind::Context.span(4..5).label("move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait")) + ) + .element( + Snippet::source("let y = x;") + .line_start(7) + .annotation(AnnotationKind::Context.span(8..9).label("value moved here")) + ) + .element( + Snippet::source("x;") + .line_start(9) + .annotation(AnnotationKind::Primary.span(0..1).label("value used here after move")) + ) + ]; let expected = file!["issue_9.term.svg"]; let renderer = Renderer::styled(); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/color/multiline_removal_suggestion.rs b/tests/color/multiline_removal_suggestion.rs index ced5e09d..fbaf4fff 100644 --- a/tests/color/multiline_removal_suggestion.rs +++ b/tests/color/multiline_removal_suggestion.rs @@ -64,49 +64,44 @@ fn bay() -> Vec<(bool, HashSet)> { fn main() {} "#; - let input = Level::ERROR - .header("`(bool, HashSet)` is not an iterator") - .id("E0277") - .group( - Group::new() - .element( - Snippet::source(source) - .path("$DIR/multiline-removal-suggestion.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(769..776) - .label("`(bool, HashSet)` is not an iterator"), - ), - ) - .element( - Level::HELP - .title("the trait `Iterator` is not implemented for `(bool, HashSet)`"), - ) - .element( - Level::NOTE - .title("required for `(bool, HashSet)` to implement `IntoIterator`"), - ), - ) - .group( - Group::new() - .element(Level::NOTE.title("required by a bound in `flatten`")) - .element( - Origin::new("/rustc/FAKE_PREFIX/library/core/src/iter/traits/iterator.rs") - .line(1556) - .char_column(4), - ), - ) - .group( - Group::new() - .element(Level::HELP.title("consider removing this method call, as the receiver has type `std::vec::IntoIter>` and `std::vec::IntoIter>: Iterator` trivially holds")) - .element( - Snippet::source(source) - .path("$DIR/multiline-removal-suggestion.rs") - .fold(true) - .patch(Patch::new(708..768, "")), - ), - ); + let input = &[ + Group::new() + .element( + Level::ERROR + .title("`(bool, HashSet)` is not an iterator") + .id("E0277"), + ) + .element( + Snippet::source(source) + .path("$DIR/multiline-removal-suggestion.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(769..776) + .label("`(bool, HashSet)` is not an iterator"), + ), + ) + .element( + Level::HELP + .title("the trait `Iterator` is not implemented for `(bool, HashSet)`"), + ) + .element( + Level::NOTE.title("required for `(bool, HashSet)` to implement `IntoIterator`"), + ), + Group::new() + .element(Level::NOTE.title("required by a bound in `flatten`")) + .element( + Origin::new("/rustc/FAKE_PREFIX/library/core/src/iter/traits/iterator.rs") + .line(1556) + .char_column(4), + ), + Group::new().element(Level::HELP.title("consider removing this method call, as the receiver has type `std::vec::IntoIter>` and `std::vec::IntoIter>: Iterator` trivially holds")).element( + Snippet::source(source) + .path("$DIR/multiline-removal-suggestion.rs") + .fold(true) + .patch(Patch::new(708..768, "")), + ), + ]; let expected = file!["multiline_removal_suggestion.term.svg"]; let renderer = Renderer::styled(); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/color/multiple_annotations.rs b/tests/color/multiple_annotations.rs index b568b919..464d7672 100644 --- a/tests/color/multiple_annotations.rs +++ b/tests/color/multiple_annotations.rs @@ -15,27 +15,25 @@ fn case() { } "#; - let input = Level::ERROR.header("").group( - Group::new().element( - Snippet::source(source) - .line_start(96) - .annotation( - AnnotationKind::Primary - .span(100..110) - .label("Variable defined here"), - ) - .annotation( - AnnotationKind::Primary - .span(184..194) - .label("Referenced here"), - ) - .annotation( - AnnotationKind::Primary - .span(243..253) - .label("Referenced again here"), - ), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source(source) + .line_start(96) + .annotation( + AnnotationKind::Primary + .span(100..110) + .label("Variable defined here"), + ) + .annotation( + AnnotationKind::Primary + .span(184..194) + .label("Referenced here"), + ) + .annotation( + AnnotationKind::Primary + .span(243..253) + .label("Referenced again here"), + ), + )]; let expected = file!["multiple_annotations.term.svg"]; let renderer = Renderer::styled(); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/color/simple.rs b/tests/color/simple.rs index 83834295..17287d94 100644 --- a/tests/color/simple.rs +++ b/tests/color/simple.rs @@ -9,25 +9,23 @@ fn case() { for line in &self.body { "#; - let input = Level::ERROR - .header("expected one of `.`, `;`, `?`, or an operator, found `for`") - .group( - Group::new().element( - Snippet::source(source) - .path("src/format_color.rs") - .line_start(169) - .annotation( - AnnotationKind::Primary - .span(20..23) - .label("unexpected token"), - ) - .annotation( - AnnotationKind::Context - .span(10..11) - .label("expected one of `.`, `;`, `?`, or an operator here"), - ), - ), - ); + let input = &[Group::new() + .element(Level::ERROR.title("expected one of `.`, `;`, `?`, or an operator, found `for`")) + .element( + Snippet::source(source) + .path("src/format_color.rs") + .line_start(169) + .annotation( + AnnotationKind::Primary + .span(20..23) + .label("unexpected token"), + ) + .annotation( + AnnotationKind::Context + .span(10..11) + .label("expected one of `.`, `;`, `?`, or an operator here"), + ), + )]; let expected = file!["simple.term.svg"]; let renderer = Renderer::styled(); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/color/strip_line.rs b/tests/color/strip_line.rs index 4b21f9a1..fbb72506 100644 --- a/tests/color/strip_line.rs +++ b/tests/color/strip_line.rs @@ -6,8 +6,9 @@ use snapbox::{assert_data_eq, file}; fn case() { let source = r#" let _: () = 42;"#; - let input = Level::ERROR.header("mismatched types").id("E0308").group( - Group::new().element( + let input = &[Group::new() + .element(Level::ERROR.title("mismatched types").id("E0308")) + .element( Snippet::source(source) .path("$DIR/whitespace-trimming.rs") .line_start(4) @@ -16,8 +17,7 @@ fn case() { .span(192..194) .label("expected (), found integer"), ), - ), - ); + )]; let expected = file!["strip_line.term.svg"]; let renderer = Renderer::styled().anonymized_line_numbers(true); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/color/strip_line_char.rs b/tests/color/strip_line_char.rs index f30d5e90..090e1dba 100644 --- a/tests/color/strip_line_char.rs +++ b/tests/color/strip_line_char.rs @@ -6,8 +6,9 @@ use snapbox::{assert_data_eq, file}; fn case() { let source = r#" let _: () = 42ñ"#; - let input = Level::ERROR.header("mismatched types").id("E0308").group( - Group::new().element( + let input = &[Group::new() + .element(Level::ERROR.title("mismatched types").id("E0308")) + .element( Snippet::source(source) .path("$DIR/whitespace-trimming.rs") .line_start(4) @@ -16,8 +17,7 @@ fn case() { .span(192..194) .label("expected (), found integer"), ), - ), - ); + )]; let expected = file!["strip_line_char.term.svg"]; let renderer = Renderer::styled().anonymized_line_numbers(true); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/color/strip_line_non_ws.rs b/tests/color/strip_line_non_ws.rs index a67d70d1..da65e6a3 100644 --- a/tests/color/strip_line_non_ws.rs +++ b/tests/color/strip_line_non_ws.rs @@ -7,8 +7,9 @@ fn case() { let source = r#" let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = 42; let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); "#; - let input = Level::ERROR.header("mismatched types").id("E0308").group( - Group::new().element( + let input = &[Group::new() + .element(Level::ERROR.title("mismatched types").id("E0308")) + .element( Snippet::source(source) .path("$DIR/non-whitespace-trimming.rs") .line_start(4) @@ -22,8 +23,7 @@ fn case() { .span(232..234) .label("expected due to this"), ), - ), - ); + )]; let expected = file!["strip_line_non_ws.term.svg"]; let renderer = Renderer::styled().anonymized_line_numbers(true); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/formatter.rs b/tests/formatter.rs index 7e431215..34c40bf8 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -5,14 +5,12 @@ use snapbox::{assert_data_eq, str}; #[test] fn test_i_29() { - let snippets = Level::ERROR.header("oops").group( - Group::new().element( - Snippet::source("First line\r\nSecond oops line") - .path("") - .annotation(AnnotationKind::Primary.span(19..23).label("oops")) - .fold(true), - ), - ); + let snippets = &[Group::new().element(Level::ERROR.title("oops")).element( + Snippet::source("First line\r\nSecond oops line") + .path("") + .annotation(AnnotationKind::Primary.span(19..23).label("oops")) + .fold(true), + )]; let expected = str![[r#" error: oops --> :2:8 @@ -27,13 +25,11 @@ error: oops #[test] fn test_point_to_double_width_characters() { - let snippets = Level::ERROR.header("").group( - Group::new().element( - Snippet::source("こんにちは、世界") - .path("") - .annotation(AnnotationKind::Primary.span(18..24).label("world")), - ), - ); + let snippets = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source("こんにちは、世界") + .path("") + .annotation(AnnotationKind::Primary.span(18..24).label("world")), + )]; let expected = str![[r#" error: @@ -49,13 +45,11 @@ error: #[test] fn test_point_to_double_width_characters_across_lines() { - let snippets = Level::ERROR.header("").group( - Group::new().element( - Snippet::source("おはよう\nございます") - .path("") - .annotation(AnnotationKind::Primary.span(6..22).label("Good morning")), - ), - ); + let snippets = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source("おはよう\nございます") + .path("") + .annotation(AnnotationKind::Primary.span(6..22).label("Good morning")), + )]; let expected = str![[r#" error: @@ -73,14 +67,12 @@ error: #[test] fn test_point_to_double_width_characters_multiple() { - let snippets = Level::ERROR.header("").group( - Group::new().element( - Snippet::source("お寿司\n食べたい🍣") - .path("") - .annotation(AnnotationKind::Primary.span(0..9).label("Sushi1")) - .annotation(AnnotationKind::Context.span(16..22).label("Sushi2")), - ), - ); + let snippets = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source("お寿司\n食べたい🍣") + .path("") + .annotation(AnnotationKind::Primary.span(0..9).label("Sushi1")) + .annotation(AnnotationKind::Context.span(16..22).label("Sushi2")), + )]; let expected = str![[r#" error: @@ -98,13 +90,11 @@ error: #[test] fn test_point_to_double_width_characters_mixed() { - let snippets = Level::ERROR.header("").group( - Group::new().element( - Snippet::source("こんにちは、新しいWorld!") - .path("") - .annotation(AnnotationKind::Primary.span(18..32).label("New world")), - ), - ); + let snippets = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source("こんにちは、新しいWorld!") + .path("") + .annotation(AnnotationKind::Primary.span(18..32).label("New world")), + )]; let expected = str![[r#" error: @@ -120,7 +110,7 @@ error: #[test] fn test_format_title() { - let input = Level::ERROR.header("This is a title").id("E0001"); + let input = &[Group::new().element(Level::ERROR.title("This is a title").id("E0001"))]; let expected = str![r#"error[E0001]: This is a title"#]; let renderer = Renderer::plain(); @@ -130,9 +120,9 @@ fn test_format_title() { #[test] fn test_format_snippet_only() { let source = "This is line 1\nThis is line 2"; - let input = Level::ERROR - .header("") - .group(Group::new().element(Snippet::>::source(source).line_start(5402))); + let input = &[Group::new() + .element(Level::ERROR.title("")) + .element(Snippet::>::source(source).line_start(5402))]; let expected = str![[r#" error: @@ -148,19 +138,18 @@ error: fn test_format_snippets_continuation() { let src_0 = "This is slice 1"; let src_1 = "This is slice 2"; - let input = Level::ERROR.header("").group( - Group::new() - .element( - Snippet::>::source(src_0) - .line_start(5402) - .path("file1.rs"), - ) - .element( - Snippet::>::source(src_1) - .line_start(2) - .path("file2.rs"), - ), - ); + let input = &[Group::new() + .element(Level::ERROR.title("")) + .element( + Snippet::>::source(src_0) + .line_start(5402) + .path("file1.rs"), + ) + .element( + Snippet::>::source(src_1) + .line_start(2) + .path("file2.rs"), + )]; let expected = str![[r#" error: --> file1.rs @@ -182,15 +171,13 @@ fn test_format_snippet_annotation_standalone() { let source = [line_1, line_2].join("\n"); // In line 2 let range = 22..24; - let input = Level::ERROR.header("").group( - Group::new().element( - Snippet::source(&source).line_start(5402).annotation( - AnnotationKind::Context - .span(range.clone()) - .label("Test annotation"), - ), + let input = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source(&source).line_start(5402).annotation( + AnnotationKind::Context + .span(range.clone()) + .label("Test annotation"), ), - ); + )]; let expected = str![[r#" error: | @@ -204,9 +191,9 @@ error: #[test] fn test_format_footer_title() { - let input = Level::ERROR - .header("") - .group(Group::new().element(Level::ERROR.title("This __is__ a title"))); + let input = &[Group::new() + .element(Level::ERROR.title("")) + .element(Level::ERROR.title("This __is__ a title"))]; let expected = str![[r#" error: | @@ -221,15 +208,13 @@ error: fn test_i26() { let source = "short"; let label = "label"; - let input = Level::ERROR.header("").group( - Group::new().element( - Snippet::source(source).line_start(0).annotation( - AnnotationKind::Primary - .span(0..source.len() + 2) - .label(label), - ), + let input = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source(source).line_start(0).annotation( + AnnotationKind::Primary + .span(0..source.len() + 2) + .label(label), ), - ); + )]; let renderer = Renderer::plain(); let _ = renderer.render(input); } @@ -237,9 +222,9 @@ fn test_i26() { #[test] fn test_source_content() { let source = "This is an example\nof content lines"; - let input = Level::ERROR - .header("") - .group(Group::new().element(Snippet::>::source(source).line_start(56))); + let input = &[Group::new() + .element(Level::ERROR.title("")) + .element(Snippet::>::source(source).line_start(56))]; let expected = str![[r#" error: | @@ -253,13 +238,11 @@ error: #[test] fn test_source_annotation_standalone_singleline() { let source = "tests"; - let input = Level::ERROR.header("").group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .annotation(AnnotationKind::Context.span(0..5).label("Example string")), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source(source) + .line_start(1) + .annotation(AnnotationKind::Context.span(0..5).label("Example string")), + )]; let expected = str![[r#" error: | @@ -273,14 +256,12 @@ error: #[test] fn test_source_annotation_standalone_multiline() { let source = "tests"; - let input = Level::ERROR.header("").group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .annotation(AnnotationKind::Context.span(0..5).label("Example string")) - .annotation(AnnotationKind::Context.span(0..5).label("Second line")), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source(source) + .line_start(1) + .annotation(AnnotationKind::Context.span(0..5).label("Example string")) + .annotation(AnnotationKind::Context.span(0..5).label("Second line")), + )]; let expected = str![[r#" error: | @@ -296,9 +277,9 @@ error: #[test] fn test_only_source() { - let input = Level::ERROR - .header("") - .group(Group::new().element(Snippet::>::source("").path("file.rs"))); + let input = &[Group::new() + .element(Level::ERROR.title("")) + .element(Snippet::>::source("").path("file.rs"))]; let expected = str![[r#" error: --> file.rs @@ -312,9 +293,9 @@ error: #[test] fn test_anon_lines() { let source = "This is an example\nof content lines\n\nabc"; - let input = Level::ERROR - .header("") - .group(Group::new().element(Snippet::>::source(source).line_start(56))); + let input = &[Group::new() + .element(Level::ERROR.title("")) + .element(Snippet::>::source(source).line_start(56))]; let expected = str![[r#" error: | @@ -329,15 +310,14 @@ LL | abc #[test] fn issue_130() { - let input = Level::ERROR.header("dummy").group( - Group::new().element( - Snippet::source("foo\nbar\nbaz") - .path("file/path") - .line_start(3) - .fold(true) - .annotation(AnnotationKind::Primary.span(4..11)), - ), // bar\nbaz - ); + let input = &[Group::new().element(Level::ERROR.title("dummy")).element( + Snippet::source("foo\nbar\nbaz") + .path("file/path") + .line_start(3) + .fold(true) + .annotation(AnnotationKind::Primary.span(4..11)), + // bar\nbaz + )]; let expected = str![[r#" error: dummy @@ -357,15 +337,14 @@ fn unterminated_string_multiline() { a\" // ... "; - let input = Level::ERROR.header("").group( - Group::new().element( - Snippet::source(source) - .path("file/path") - .line_start(3) - .fold(true) - .annotation(AnnotationKind::Primary.span(0..10)), - ), // 1..10 works - ); + let input = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source(source) + .path("file/path") + .line_start(3) + .fold(true) + .annotation(AnnotationKind::Primary.span(0..10)), + // 1..10 works + )]; let expected = str![[r#" error: --> file/path:3:1 @@ -381,14 +360,13 @@ error: #[test] fn char_and_nl_annotate_char() { let source = "a\r\nb"; - let input = Level::ERROR.header("").group( - Group::new().element( - Snippet::source(source) - .path("file/path") - .line_start(3) - .annotation(AnnotationKind::Primary.span(0..2)), - ), // a\r - ); + let input = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source(source) + .path("file/path") + .line_start(3) + .annotation(AnnotationKind::Primary.span(0..2)), + // a\r + )]; let expected = str![[r#" error: --> file/path:3:1 @@ -404,14 +382,13 @@ error: #[test] fn char_eol_annotate_char() { let source = "a\r\nb"; - let input = Level::ERROR.header("").group( - Group::new().element( - Snippet::source(source) - .path("file/path") - .line_start(3) - .annotation(AnnotationKind::Primary.span(0..3)), - ), // a\r\n - ); + let input = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source(source) + .path("file/path") + .line_start(3) + .annotation(AnnotationKind::Primary.span(0..3)), + // a\r\n + )]; let expected = str![[r#" error: --> file/path:3:1 @@ -426,13 +403,12 @@ error: #[test] fn char_eol_annotate_char_double_width() { - let snippets = Level::ERROR.header("").group( - Group::new().element( - Snippet::source("こん\r\nにちは\r\n世界") - .path("") - .annotation(AnnotationKind::Primary.span(3..8)), - ), // ん\r\n - ); + let snippets = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source("こん\r\nにちは\r\n世界") + .path("") + .annotation(AnnotationKind::Primary.span(3..8)), + // ん\r\n + )]; let expected = str![[r#" error: @@ -452,14 +428,13 @@ error: #[test] fn annotate_eol() { let source = "a\r\nb"; - let input = Level::ERROR.header("").group( - Group::new().element( - Snippet::source(source) - .path("file/path") - .line_start(3) - .annotation(AnnotationKind::Primary.span(1..2)), - ), // \r - ); + let input = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source(source) + .path("file/path") + .line_start(3) + .annotation(AnnotationKind::Primary.span(1..2)), + // \r + )]; let expected = str![[r#" error: --> file/path:3:2 @@ -475,14 +450,13 @@ error: #[test] fn annotate_eol2() { let source = "a\r\nb"; - let input = Level::ERROR.header("").group( - Group::new().element( - Snippet::source(source) - .path("file/path") - .line_start(3) - .annotation(AnnotationKind::Primary.span(1..3)), - ), // \r\n - ); + let input = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source(source) + .path("file/path") + .line_start(3) + .annotation(AnnotationKind::Primary.span(1..3)), + // \r\n + )]; let expected = str![[r#" error: --> file/path:3:2 @@ -499,14 +473,13 @@ error: #[test] fn annotate_eol3() { let source = "a\r\nb"; - let input = Level::ERROR.header("").group( - Group::new().element( - Snippet::source(source) - .path("file/path") - .line_start(3) - .annotation(AnnotationKind::Primary.span(2..3)), - ), // \n - ); + let input = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source(source) + .path("file/path") + .line_start(3) + .annotation(AnnotationKind::Primary.span(2..3)), + // \n + )]; let expected = str![[r#" error: --> file/path:3:3 @@ -523,14 +496,13 @@ error: #[test] fn annotate_eol4() { let source = "a\r\nb"; - let input = Level::ERROR.header("").group( - Group::new().element( - Snippet::source(source) - .path("file/path") - .line_start(3) - .annotation(AnnotationKind::Primary.span(2..2)), - ), // \n - ); + let input = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source(source) + .path("file/path") + .line_start(3) + .annotation(AnnotationKind::Primary.span(2..2)), + // \n + )]; let expected = str![[r#" error: --> file/path:3:3 @@ -545,13 +517,12 @@ error: #[test] fn annotate_eol_double_width() { - let snippets = Level::ERROR.header("").group( - Group::new().element( - Snippet::source("こん\r\nにちは\r\n世界") - .path("") - .annotation(AnnotationKind::Primary.span(7..8)), - ), // \n - ); + let snippets = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source("こん\r\nにちは\r\n世界") + .path("") + .annotation(AnnotationKind::Primary.span(7..8)), + // \n + )]; let expected = str![[r#" error: @@ -571,14 +542,13 @@ error: #[test] fn multiline_eol_start() { let source = "a\r\nb"; - let input = Level::ERROR.header("").group( - Group::new().element( - Snippet::source(source) - .path("file/path") - .line_start(3) - .annotation(AnnotationKind::Primary.span(1..4)), - ), // \r\nb - ); + let input = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source(source) + .path("file/path") + .line_start(3) + .annotation(AnnotationKind::Primary.span(1..4)), + // \r\nb + )]; let expected = str![[r#" error: --> file/path:3:2 @@ -595,14 +565,13 @@ error: #[test] fn multiline_eol_start2() { let source = "a\r\nb"; - let input = Level::ERROR.header("").group( - Group::new().element( - Snippet::source(source) - .path("file/path") - .line_start(3) - .annotation(AnnotationKind::Primary.span(2..4)), - ), // \nb - ); + let input = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source(source) + .path("file/path") + .line_start(3) + .annotation(AnnotationKind::Primary.span(2..4)), + // \nb + )]; let expected = str![[r#" error: --> file/path:3:3 @@ -619,14 +588,13 @@ error: #[test] fn multiline_eol_start3() { let source = "a\nb"; - let input = Level::ERROR.header("").group( - Group::new().element( - Snippet::source(source) - .path("file/path") - .line_start(3) - .annotation(AnnotationKind::Primary.span(1..3)), - ), // \nb - ); + let input = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source(source) + .path("file/path") + .line_start(3) + .annotation(AnnotationKind::Primary.span(1..3)), + // \nb + )]; let expected = str![[r#" error: --> file/path:3:2 @@ -642,13 +610,12 @@ error: #[test] fn multiline_eol_start_double_width() { - let snippets = Level::ERROR.header("").group( - Group::new().element( - Snippet::source("こん\r\nにちは\r\n世界") - .path("") - .annotation(AnnotationKind::Primary.span(7..11)), - ), // \r\nに - ); + let snippets = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source("こん\r\nにちは\r\n世界") + .path("") + .annotation(AnnotationKind::Primary.span(7..11)), + // \r\nに + )]; let expected = str![[r#" error: @@ -668,14 +635,13 @@ error: #[test] fn multiline_eol_start_eol_end() { let source = "a\nb\nc"; - let input = Level::ERROR.header("").group( - Group::new().element( - Snippet::source(source) - .path("file/path") - .line_start(3) - .annotation(AnnotationKind::Primary.span(1..4)), - ), // \nb\n - ); + let input = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source(source) + .path("file/path") + .line_start(3) + .annotation(AnnotationKind::Primary.span(1..4)), + // \nb\n + )]; let expected = str![[r#" error: --> file/path:3:2 @@ -693,14 +659,13 @@ error: #[test] fn multiline_eol_start_eol_end2() { let source = "a\r\nb\r\nc"; - let input = Level::ERROR.header("").group( - Group::new().element( - Snippet::source(source) - .path("file/path") - .line_start(3) - .annotation(AnnotationKind::Primary.span(2..5)), - ), // \nb\r - ); + let input = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source(source) + .path("file/path") + .line_start(3) + .annotation(AnnotationKind::Primary.span(2..5)), + // \nb\r + )]; let expected = str![[r#" error: --> file/path:3:3 @@ -718,14 +683,13 @@ error: #[test] fn multiline_eol_start_eol_end3() { let source = "a\r\nb\r\nc"; - let input = Level::ERROR.header("").group( - Group::new().element( - Snippet::source(source) - .path("file/path") - .line_start(3) - .annotation(AnnotationKind::Primary.span(2..6)), - ), // \nb\r\n - ); + let input = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source(source) + .path("file/path") + .line_start(3) + .annotation(AnnotationKind::Primary.span(2..6)), + // \nb\r\n + )]; let expected = str![[r#" error: --> file/path:3:3 @@ -743,14 +707,13 @@ error: #[test] fn multiline_eol_start_eof_end() { let source = "a\r\nb"; - let input = Level::ERROR.header("").group( - Group::new().element( - Snippet::source(source) - .path("file/path") - .line_start(3) - .annotation(AnnotationKind::Primary.span(1..5)), - ), // \r\nb(EOF) - ); + let input = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source(source) + .path("file/path") + .line_start(3) + .annotation(AnnotationKind::Primary.span(1..5)), + // \r\nb(EOF) + )]; let expected = str![[r#" error: --> file/path:3:2 @@ -767,14 +730,13 @@ error: #[test] fn multiline_eol_start_eof_end_double_width() { let source = "ん\r\nに"; - let input = Level::ERROR.header("").group( - Group::new().element( - Snippet::source(source) - .path("file/path") - .line_start(3) - .annotation(AnnotationKind::Primary.span(3..9)), - ), // \r\nに(EOF) - ); + let input = &[Group::new().element(Level::ERROR.title("")).element( + Snippet::source(source) + .path("file/path") + .line_start(3) + .annotation(AnnotationKind::Primary.span(3..9)), + // \r\nに(EOF) + )]; let expected = str![[r#" error: --> file/path:3:2 @@ -791,8 +753,9 @@ error: #[test] fn two_single_line_same_line() { let source = r#"bar = { version = "0.1.0", optional = true }"#; - let input = Level::ERROR.header("unused optional dependency").group( - Group::new().element( + let input = &[Group::new() + .element(Level::ERROR.title("unused optional dependency")) + .element( Snippet::source(source) .path("Cargo.toml") .line_start(4) @@ -806,8 +769,7 @@ fn two_single_line_same_line() { .span(27..42) .label("This should also be long but not too long"), ), - ), - ); + )]; let expected = str![[r#" error: unused optional dependency --> Cargo.toml:4:1 @@ -828,8 +790,9 @@ this is another line so is this bar = { version = "0.1.0", optional = true } "#; - let input = Level::ERROR.header("unused optional dependency").group( - Group::new().element( + let input = &[Group::new() + .element(Level::ERROR.title("unused optional dependency")) + .element( Snippet::source(source) .line_start(4) .annotation( @@ -842,8 +805,7 @@ bar = { version = "0.1.0", optional = true } .span(27..42) .label("This should also be long but not too long"), ), - ), - ); + )]; let expected = str![[r#" error: unused optional dependency | @@ -867,8 +829,9 @@ this is another line so is this bar = { version = "0.1.0", optional = true } "#; - let input = Level::ERROR.header("unused optional dependency").group( - Group::new().element( + let input = &[Group::new() + .element(Level::ERROR.title("unused optional dependency")) + .element( Snippet::source(source) .line_start(4) .annotation( @@ -886,8 +849,7 @@ bar = { version = "0.1.0", optional = true } .span(27..42) .label("This should also be long but not too long"), ), - ), - ); + )]; let expected = str![[r#" error: unused optional dependency | @@ -915,8 +877,9 @@ so is this bar = { version = "0.1.0", optional = true } this is another line "#; - let input = Level::ERROR.header("unused optional dependency").group( - Group::new().element( + let input = &[Group::new() + .element(Level::ERROR.title("unused optional dependency")) + .element( Snippet::source(source) .line_start(4) .annotation( @@ -939,8 +902,7 @@ this is another line .span(27..42) .label("This should also be long but not too long"), ), - ), - ); + )]; let expected = str![[r#" error: unused optional dependency | @@ -966,14 +928,12 @@ error: unused optional dependency #[test] fn origin_correct_start_line() { let source = "aaa\nbbb\nccc\nddd\n"; - let input = Level::ERROR.header("title").group( - Group::new().element( - Snippet::source(source) - .path("origin.txt") - .fold(false) - .annotation(AnnotationKind::Primary.span(8..8 + 3).label("annotation")), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("title")).element( + Snippet::source(source) + .path("origin.txt") + .fold(false) + .annotation(AnnotationKind::Primary.span(8..8 + 3).label("annotation")), + )]; let expected = str![[r#" error: title @@ -992,18 +952,16 @@ error: title #[test] fn origin_correct_mid_line() { let source = "aaa\nbbb\nccc\nddd\n"; - let input = Level::ERROR.header("title").group( - Group::new().element( - Snippet::source(source) - .path("origin.txt") - .fold(false) - .annotation( - AnnotationKind::Primary - .span(8 + 1..8 + 3) - .label("annotation"), - ), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("title")).element( + Snippet::source(source) + .path("origin.txt") + .fold(false) + .annotation( + AnnotationKind::Primary + .span(8 + 1..8 + 3) + .label("annotation"), + ), + )]; let expected = str![[r#" error: title @@ -1022,33 +980,33 @@ error: title #[test] fn two_suggestions_same_span() { let source = r#" A.foo();"#; - let input_new = Level::ERROR - .header("expected value, found enum `A`") - .id("E0423") - .group( - Group::new().element( + let input_new = &[ + Group::new() + .element( + Level::ERROR + .title("expected value, found enum `A`") + .id("E0423"), + ) + .element( Snippet::source(source) .fold(true) .annotation(AnnotationKind::Primary.span(4..5)), ), - ) - .group( - Group::new() - .element( - Level::HELP - .title("you might have meant to use one of the following enum variants"), - ) - .element( - Snippet::source(source) - .fold(true) - .patch(Patch::new(4..5, "(A::Tuple())")), - ) - .element( - Snippet::source(source) - .fold(true) - .patch(Patch::new(4..5, "A::Unit")), - ), - ); + Group::new() + .element( + Level::HELP.title("you might have meant to use one of the following enum variants"), + ) + .element( + Snippet::source(source) + .fold(true) + .patch(Patch::new(4..5, "(A::Tuple())")), + ) + .element( + Snippet::source(source) + .fold(true) + .patch(Patch::new(4..5, "A::Unit")), + ), + ]; let expected = str![[r#" error[E0423]: expected value, found enum `A` @@ -1090,11 +1048,9 @@ fn main() { banana::Chaenomeles.pick() }"#; let input_new = - Level::ERROR - .header("no method named `pick` found for struct `Chaenomeles` in the current scope") - .id("E0599") - .group( - Group::new().element( + &[Group::new().element(Level::ERROR + .title("no method named `pick` found for struct `Chaenomeles` in the current scope") + .id("E0599")).element( Snippet::source(source) .line_start(1) .fold(true) @@ -1109,8 +1065,6 @@ fn main() { .label("method not found in `Chaenomeles`"), ), ), - ) - .group( Group::new() .element(Level::HELP.title( "the following traits which provide `pick` are implemented but not in scope; perhaps you want to import one of them", @@ -1124,8 +1078,7 @@ fn main() { Snippet::source(source) .fold(true) .patch(Patch::new(1..1, "use banana::Peach;\n")), - ), - ); + )]; let expected = str![[r#" error[E0599]: no method named `pick` found for struct `Chaenomeles` in the current scope | @@ -1150,28 +1103,29 @@ LL + use banana::Peach; fn single_line_non_overlapping_suggestions() { let source = r#" A.foo();"#; - let input_new = Level::ERROR - .header("expected value, found enum `A`") - .id("E0423") - .group( - Group::new().element( + let input_new = &[ + Group::new() + .element( + Level::ERROR + .title("expected value, found enum `A`") + .id("E0423"), + ) + .element( Snippet::source(source) .fold(true) .line_start(1) .annotation(AnnotationKind::Primary.span(4..5)), ), - ) - .group( - Group::new() - .element(Level::HELP.title("make these changes and things will work")) - .element( - Snippet::source(source) - .fold(true) - .fold(true) - .patch(Patch::new(4..5, "(A::Tuple())")) - .patch(Patch::new(6..9, "bar")), - ), - ); + Group::new() + .element(Level::HELP.title("make these changes and things will work")) + .element( + Snippet::source(source) + .fold(true) + .fold(true) + .patch(Patch::new(4..5, "(A::Tuple())")) + .patch(Patch::new(6..9, "bar")), + ), + ]; let expected = str![[r#" error[E0423]: expected value, found enum `A` @@ -1192,28 +1146,25 @@ LL + (A::Tuple()).bar(); #[test] fn single_line_non_overlapping_suggestions2() { let source = r#" ThisIsVeryLong.foo();"#; - let input_new = Level::ERROR - .header("Found `ThisIsVeryLong`") - .id("E0423") - .group( - Group::new().element( + let input_new = &[ + Group::new() + .element(Level::ERROR.title("Found `ThisIsVeryLong`").id("E0423")) + .element( Snippet::source(source) .fold(true) .line_start(1) .annotation(AnnotationKind::Primary.span(4..18)), ), - ) - .group( - Group::new() - .element(Level::HELP.title("make these changes and things will work")) - .element( - Snippet::source(source) - .fold(true) - .fold(true) - .patch(Patch::new(4..18, "(A::Tuple())")) - .patch(Patch::new(19..22, "bar")), - ), - ); + Group::new() + .element(Level::HELP.title("make these changes and things will work")) + .element( + Snippet::source(source) + .fold(true) + .fold(true) + .patch(Patch::new(4..18, "(A::Tuple())")) + .patch(Patch::new(19..22, "bar")), + ), + ]; let expected = str![[r#" error[E0423]: Found `ThisIsVeryLong` @@ -1241,11 +1192,16 @@ fn multiple_replacements() { y(); "#; - let input_new = Level::ERROR - .header("cannot borrow `*self` as mutable because it is also borrowed as immutable") - .id("E0502") - .group( - Group::new().element( + let input_new = &[ + Group::new() + .element( + Level::ERROR + .title( + "cannot borrow `*self` as mutable because it is also borrowed as immutable", + ) + .id("E0502"), + ) + .element( Snippet::source(source) .line_start(1) .fold(true) @@ -1270,21 +1226,18 @@ fn multiple_replacements() { .label("immutable borrow later used here"), ), ), - ) - .group( - Group::new() - .element( - Level::HELP - .title("try explicitly pass `&Self` into the Closure as an argument"), - ) - .element( - Snippet::source(source) - .fold(true) - .patch(Patch::new(14..14, "this: &Self")) - .patch(Patch::new(26..30, "this")) - .patch(Patch::new(66..68, "(self)")), - ), - ); + Group::new() + .element( + Level::HELP.title("try explicitly pass `&Self` into the Closure as an argument"), + ) + .element( + Snippet::source(source) + .fold(true) + .patch(Patch::new(14..14, "this: &Self")) + .patch(Patch::new(26..30, "this")) + .patch(Patch::new(66..68, "(self)")), + ), + ]; let expected = str![[r#" error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable | @@ -1325,11 +1278,9 @@ fn main() { test1(); }"#; - let input_new = Level::ERROR - .header("cannot borrow `chars` as mutable more than once at a time") - .id("E0499") - .group( - Group::new().element( + let input_new = &[Group::new().element(Level::ERROR + .title("cannot borrow `chars` as mutable more than once at a time") + .id("E0499")).element( Snippet::source(source) .line_start(1) .fold(true) @@ -1349,8 +1300,6 @@ fn main() { .label("first borrow later used here"), ), ), - ) - .group( Group::new() .element( Level::HELP @@ -1365,8 +1314,7 @@ fn main() { )) .patch(Patch::new(61..79, ") = iter.next()")) .patch(Patch::new(90..95, "iter")), - ), - ); + )]; let expected = str![[r#" error[E0499]: cannot borrow `chars` as mutable more than once at a time @@ -1409,45 +1357,42 @@ struct Foo { fn main() {}"#; - let input_new = Level::ERROR - .header("failed to resolve: use of undeclared crate or module `st`") - .id("E0433") - .group( - Group::new().element( + let input_new = &[ + Group::new() + .element( + Level::ERROR + .title("failed to resolve: use of undeclared crate or module `st`") + .id("E0433"), + ) + .element( Snippet::source(source).line_start(1).fold(true).annotation( AnnotationKind::Primary .span(122..124) .label("use of undeclared crate or module `st`"), ), ), - ) - .group( - Group::new() - .element(Level::HELP.title("there is a crate or module with a similar name")) - .element( - Snippet::source(source) - .fold(true) - .patch(Patch::new(122..124, "std")), - ), - ) - .group( - Group::new() - .element(Level::HELP.title("consider importing this module")) - .element( - Snippet::source(source) - .fold(true) - .patch(Patch::new(1..1, "use std::cell;\n")), - ), - ) - .group( - Group::new() - .element(Level::HELP.title("if you import `cell`, refer to it directly")) - .element( - Snippet::source(source) - .fold(true) - .patch(Patch::new(122..126, "")), - ), - ); + Group::new() + .element(Level::HELP.title("there is a crate or module with a similar name")) + .element( + Snippet::source(source) + .fold(true) + .patch(Patch::new(122..124, "std")), + ), + Group::new() + .element(Level::HELP.title("consider importing this module")) + .element( + Snippet::source(source) + .fold(true) + .patch(Patch::new(1..1, "use std::cell;\n")), + ), + Group::new() + .element(Level::HELP.title("if you import `cell`, refer to it directly")) + .element( + Snippet::source(source) + .fold(true) + .patch(Patch::new(122..126, "")), + ), + ]; let expected = str![[r#" error[E0433]: failed to resolve: use of undeclared crate or module `st` | @@ -1491,11 +1436,14 @@ where fn main() {}"#; - let input_new = Level::ERROR - .header("the size for values of type `T` cannot be known at compilation time") - .id("E0277") - .group( - Group::new().element( + let input_new = &[ + Group::new() + .element( + Level::ERROR + .title("the size for values of type `T` cannot be known at compilation time") + .id("E0277"), + ) + .element( Snippet::source(source) .line_start(1) .fold(true) @@ -1510,18 +1458,18 @@ fn main() {}"#; .label("this type parameter needs to be `Sized`"), ), ), - ) - .group( - Group::new() - .element(Level::HELP.title( + Group::new() + .element( + Level::HELP.title( "consider removing the `?Sized` bound to make the type parameter `Sized`", - )) - .element( - Snippet::source(source) - .fold(true) - .patch(Patch::new(52..85, "")), ), - ); + ) + .element( + Snippet::source(source) + .fold(true) + .patch(Patch::new(52..85, "")), + ), + ]; let expected = str![[r#" error[E0277]: the size for values of type `T` cannot be known at compilation time | @@ -1560,10 +1508,9 @@ and where } fn main() {}"#; - let input_new = Level::ERROR - .header("the size for values of type `T` cannot be known at compilation time") - .id("E0277") - .group(Group::new().element(Snippet::source(source) + let input_new = &[Group::new().element(Level::ERROR + .title("the size for values of type `T` cannot be known at compilation time") + .id("E0277")).element(Snippet::source(source) .line_start(1) .path("$DIR/removal-of-multiline-trait-bound-in-where-clause.rs") .fold(true) @@ -1576,8 +1523,8 @@ fn main() {}"#; AnnotationKind::Context .span(31..32) .label("this type parameter needs to be `Sized`"), - ))) - .group(Group::new().element( + )) + ,Group::new().element( Level::NOTE .title("required by an implicit `Sized` bound in `Wrapper`") ).element( @@ -1590,8 +1537,7 @@ fn main() {}"#; .span(16..17) .label("required by the implicit `Sized` requirement on this type parameter in `Wrapper`"), ) - )) - .group(Group::new().element( + ), Group::new().element( Level::HELP .title("you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box`") ) @@ -1611,8 +1557,7 @@ fn main() {}"#; .label("...if indirection were used here: `Box`"), ) - )) - .group(Group::new().element( + ),Group::new().element( Level::HELP .title("consider removing the `?Sized` bound to make the type parameter `Sized`") ).element( @@ -1621,7 +1566,7 @@ fn main() {}"#; .patch(Patch::new(56..89, "")) .patch(Patch::new(89..89, "+ Send")) , - )); + )]; let expected = str![[r#" error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/removal-of-multiline-trait-bound-in-where-clause.rs:4:16 @@ -1669,12 +1614,14 @@ quack zappy "#; - let input_new = Level::ERROR - .header("the size for values of type `T` cannot be known at compilation time") - .id("E0277") - // We need an empty group here to ensure the HELP line is rendered correctly - .group(Group::new()) - .group( + let input_new = + &[ + Group::new().element( + Level::ERROR + .title("the size for values of type `T` cannot be known at compilation time") + .id("E0277"), + ), + // We need an empty group here to ensure the HELP line is rendered correctly Group::new() .element(Level::HELP.title( "consider removing the `?Sized` bound to make the type parameter `Sized`", @@ -1686,7 +1633,7 @@ zappy .patch(Patch::new(3..21, "")) .patch(Patch::new(22..40, "")), ), - ); + ]; let expected = str![[r#" error[E0277]: the size for values of type `T` cannot be known at compilation time | @@ -1739,10 +1686,9 @@ fn main() { } "#; - let input_new = Level::ERROR - .header("type mismatch resolving `>, ...>>, ...>>, ...> as Future>::Error == Foo`") - .id("E0271") - .group(Group::new().element(Snippet::source(source) + let input_new = &[Group::new().element(Level::ERROR + .title("type mismatch resolving `>, ...>>, ...>>, ...> as Future>::Error == Foo`") + .id("E0271")).element(Snippet::source(source) .line_start(4) .path("$DIR/E0271.rs") .fold(true) @@ -1750,8 +1696,7 @@ fn main() { AnnotationKind::Primary .span(208..510) .label("type mismatch resolving `, ...>>, ...> as Future>::Error == Foo`"), - ))) - .group(Group::new().element( + )),Group::new().element( Level::NOTE.title("expected this to be `Foo`") ).element( Snippet::source(source) @@ -1763,7 +1708,7 @@ fn main() { Level::NOTE .title("required for the cast from `Box>, ()>>, ()>>, ()>>` to `Box<(dyn Future + 'static)>`") , - )); + )]; let expected = str![[r#" error[E0271]: type mismatch resolving `>, ...>>, ...>>, ...> as Future>::Error == Foo` @@ -1827,10 +1772,9 @@ fn main() { } "#; - let input_new = Level::ERROR - .header("type mismatch resolving `>, ...>>, ...>>, ...> as Future>::Error == Foo`") - .id("E0271") - .group(Group::new().element(Snippet::source(source) + let input_new = &[Group::new().element(Level::ERROR + .title("type mismatch resolving `>, ...>>, ...>>, ...> as Future>::Error == Foo`") + .id("E0271")).element(Snippet::source(source) .line_start(4) .path("$DIR/E0271.rs") .fold(true) @@ -1838,8 +1782,7 @@ fn main() { AnnotationKind::Primary .span(208..510) .label("type mismatch resolving `, ...>>, ...> as Future>::Error == Foo`"), - ))) - .group(Group::new().element( + )),Group::new().element( Level::NOTE.title("expected this to be `Foo`") ).element( Snippet::source(source) @@ -1852,7 +1795,7 @@ fn main() { .title("required for the cast from `Box>, ()>>, ()>>, ()>>` to `Box<(dyn Future + 'static)>`") ).element( Level::NOTE.title("a second note"), - )); + )]; let expected = str![[r#" error[E0271]: type mismatch resolving `>, ...>>, ...>>, ...> as Future>::Error == Foo` @@ -1928,7 +1871,7 @@ fn main() { Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok( Ok("") )))))))))))))))))))))))))))))) - )))))))))))))))))))))))))))))); + )))))))))))))))))))))))))))))]; //~^^^^^ ERROR E0308 let _ = Some(Ok(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some(Some( @@ -1941,7 +1884,7 @@ fn main() { Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok( Ok(Ok(Ok(Ok(Ok(Ok(Ok(""))))))) )))))))))))))))))))))))))))))) - )))))))))))))))))))))))); + )))))))))))))))))))))))]; //~^^^^^ ERROR E0308 let x: Atype< @@ -1975,15 +1918,14 @@ fn main() { Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok( Ok(Ok(Ok(Ok(Ok(Ok(Ok(""))))))) )))))))))))))))))))))))))))))) - )))))))))))))))))))))))); + )))))))))))))))))))))))]; //~^^^^^ ERROR E0308 } "#; - let input_new = Level::ERROR - .header("mismatched types") - .id("E0308") - .group(Group::new().element( + let input_new = &[Group::new().element(Level::ERROR + .title("mismatched types") + .id("E0308")).element( Snippet::source(source) .line_start(7) .path("$DIR/long-E0308.rs") @@ -2008,7 +1950,7 @@ fn main() { Level::NOTE .title("consider using `--verbose` to print the full type name to the console") , - )); + )]; let expected = str![[r#" error[E0308]: mismatched types @@ -2028,7 +1970,7 @@ LL │ │ > = Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(O… LL │ ┃ Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(O… LL │ ┃ Ok("") LL │ ┃ )))))))))))))))))))))))))))))) -LL │ ┃ )))))))))))))))))))))))))))))); +LL │ ┃ )))))))))))))))))))))))))))))]; │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `Atype, i32>, i32>`, found `Result, _>, _>` │ ├ note: expected struct `Atype, i32>` @@ -2065,10 +2007,9 @@ fn main() { } "#; - let input_new = Level::ERROR - .header("mismatched types") - .id("E0308") - .group(Group::new().element( + let input_new = &[Group::new().element(Level::ERROR + .title("mismatched types") + .id("E0308")).element( Snippet::source(source) .line_start(7) .path("$DIR/unicode-output.rs") @@ -2087,8 +2028,7 @@ fn main() { Level::NOTE .title("expected fn pointer `for<'a> fn(Box<(dyn Any + Send + 'a)>) -> Pin<_>`\n found fn item `fn(Box<(dyn Any + Send + 'static)>) -> Pin<_> {wrapped_fn}`") , - )) - .group(Group::new().element( + ),Group::new().element( Level::NOTE.title("function defined here"), ).element( Snippet::source(source) @@ -2097,7 +2037,7 @@ fn main() { .fold(true) .annotation(AnnotationKind::Primary.span(77..210)) .annotation(AnnotationKind::Context.span(71..76)), - )); + )]; let expected = str![[r#" error[E0308]: mismatched types @@ -2134,13 +2074,11 @@ LL │ ┃ )>>) {} #[test] fn unicode_cut_handling() { let source = "version = \"0.1.0\"\n# Ensure that the spans from toml handle utf-8 correctly\nauthors = [\n { name = \"Z\u{351}\u{36b}\u{343}\u{36a}\u{302}\u{36b}\u{33d}\u{34f}\u{334}\u{319}\u{324}\u{31e}\u{349}\u{35a}\u{32f}\u{31e}\u{320}\u{34d}A\u{36b}\u{357}\u{334}\u{362}\u{335}\u{31c}\u{330}\u{354}L\u{368}\u{367}\u{369}\u{358}\u{320}G\u{311}\u{357}\u{30e}\u{305}\u{35b}\u{341}\u{334}\u{33b}\u{348}\u{34d}\u{354}\u{339}O\u{342}\u{30c}\u{30c}\u{358}\u{328}\u{335}\u{339}\u{33b}\u{31d}\u{333}\", email = 1 }\n]\n"; - let input = Level::ERROR.header("title").group( - Group::new().element( - Snippet::source(source) - .fold(false) - .annotation(AnnotationKind::Primary.span(85..228).label("annotation")), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("title")).element( + Snippet::source(source) + .fold(false) + .annotation(AnnotationKind::Primary.span(85..228).label("annotation")), + )]; let expected_ascii = str![[r#" error: title | @@ -2153,7 +2091,7 @@ error: title | |_^ annotation "#]]; let renderer_ascii = Renderer::plain(); - assert_data_eq!(renderer_ascii.render(input.clone()), expected_ascii); + assert_data_eq!(renderer_ascii.render(input), expected_ascii); let expected_unicode = str![[r#" error: title @@ -2173,17 +2111,15 @@ error: title #[test] fn unicode_cut_handling2() { let source = "/*这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。*/?"; - let input = Level::ERROR - .header("expected item, found `?`") - .group( - Group::new().element( + let input = &[Group::new().element(Level::ERROR + .title("expected item, found `?`")).element( Snippet::source(source) .fold(false) .annotation(AnnotationKind::Primary.span(499..500).label("expected item")) ).element( Level::NOTE.title("for a full list of items that can appear in modules, see ") - ) - ); + + )]; let expected_ascii = str![[r#" error: expected item, found `?` @@ -2195,7 +2131,7 @@ error: expected item, found `?` "#]]; let renderer_ascii = Renderer::plain(); - assert_data_eq!(renderer_ascii.render(input.clone()), expected_ascii); + assert_data_eq!(renderer_ascii.render(input), expected_ascii); let expected_unicode = str![[r#" error: expected item, found `?` @@ -2212,17 +2148,15 @@ error: expected item, found `?` #[test] fn unicode_cut_handling3() { let source = "/*这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。*/?"; - let input = Level::ERROR - .header("expected item, found `?`") - .group( - Group::new().element( + let input = &[Group::new().element(Level::ERROR + .title("expected item, found `?`")).element( Snippet::source(source) .fold(false) .annotation(AnnotationKind::Primary.span(251..254).label("expected item")) ).element( Level::NOTE.title("for a full list of items that can appear in modules, see ") - ) - ); + + )]; let expected_ascii = str![[r#" error: expected item, found `?` @@ -2234,7 +2168,7 @@ error: expected item, found `?` "#]]; let renderer_ascii = Renderer::plain().term_width(43); - assert_data_eq!(renderer_ascii.render(input.clone()), expected_ascii); + assert_data_eq!(renderer_ascii.render(input), expected_ascii); let expected_unicode = str![[r#" error: expected item, found `?` @@ -2251,17 +2185,15 @@ error: expected item, found `?` #[test] fn unicode_cut_handling4() { let source = "/*aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa*/?"; - let input = Level::ERROR - .header("expected item, found `?`") - .group( - Group::new().element( + let input = &[Group::new().element(Level::ERROR + .title("expected item, found `?`")).element( Snippet::source(source) .fold(false) .annotation(AnnotationKind::Primary.span(334..335).label("expected item")) ).element( Level::NOTE.title("for a full list of items that can appear in modules, see ") - ) - ); + + )]; let expected_ascii = str![[r#" error: expected item, found `?` @@ -2273,7 +2205,7 @@ error: expected item, found `?` "#]]; let renderer_ascii = Renderer::plain(); - assert_data_eq!(renderer_ascii.render(input.clone()), expected_ascii); + assert_data_eq!(renderer_ascii.render(input), expected_ascii); let expected_unicode = str![[r#" error: expected item, found `?` @@ -2296,8 +2228,9 @@ fn main() { //~^ ERROR mismatched types } "##; - let input = Level::ERROR.header("mismatched types").id("E0308").group( - Group::new().element( + let input = &[Group::new() + .element(Level::ERROR.title("mismatched types").id("E0308")) + .element( Snippet::source(source) .path("$DIR/non-whitespace-trimming-unicode.rs") .fold(true) @@ -2311,8 +2244,7 @@ fn main() { .span(1202..1204) .label("expected due to this"), ), - ), - ); + )]; let expected_ascii = str![[r#" error[E0308]: mismatched types @@ -2325,7 +2257,7 @@ LL | ...♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾ "#]]; let renderer_ascii = Renderer::plain().anonymized_line_numbers(true); - assert_data_eq!(renderer_ascii.render(input.clone()), expected_ascii); + assert_data_eq!(renderer_ascii.render(input), expected_ascii); let expected_unicode = str![[r#" error[E0308]: mismatched types @@ -2352,38 +2284,37 @@ fn main() { //[ascii]~^ ERROR cannot add `&str` to `&str` } "##; - let input = Level::ERROR - .header("cannot add `&str` to `&str`") - .id("E0369") - .group( - Group::new() - .element( - Snippet::source(source) - .path("$DIR/non-1-width-unicode-multiline-label.rs") - .fold(true) - .annotation(AnnotationKind::Context.span(970..984).label("&str")) - .annotation(AnnotationKind::Context.span(987..1001).label("&str")) - .annotation( - AnnotationKind::Primary - .span(985..986) - .label("`+` cannot be used to concatenate two `&str` strings"), - ), - ) - .element( - Level::NOTE - .title("string concatenation requires an owned `String` on the left"), - ), - ) - .group( - Group::new() - .element(Level::HELP.title("create an owned `String` from a string reference")) - .element( - Snippet::source(source) - .path("$DIR/non-1-width-unicode-multiline-label.rs") - .fold(true) - .patch(Patch::new(984..984, ".to_owned()")), - ), - ); + let input = &[ + Group::new() + .element( + Level::ERROR + .title("cannot add `&str` to `&str`") + .id("E0369"), + ) + .element( + Snippet::source(source) + .path("$DIR/non-1-width-unicode-multiline-label.rs") + .fold(true) + .annotation(AnnotationKind::Context.span(970..984).label("&str")) + .annotation(AnnotationKind::Context.span(987..1001).label("&str")) + .annotation( + AnnotationKind::Primary + .span(985..986) + .label("`+` cannot be used to concatenate two `&str` strings"), + ), + ) + .element( + Level::NOTE.title("string concatenation requires an owned `String` on the left"), + ), + Group::new() + .element(Level::HELP.title("create an owned `String` from a string reference")) + .element( + Snippet::source(source) + .path("$DIR/non-1-width-unicode-multiline-label.rs") + .fold(true) + .patch(Patch::new(984..984, ".to_owned()")), + ), + ]; let expected_ascii = str![[r#" error[E0369]: cannot add `&str` to `&str` @@ -2403,7 +2334,7 @@ LL | let _ = "ༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓ "#]]; let renderer_ascii = Renderer::plain().anonymized_line_numbers(true); - assert_data_eq!(renderer_ascii.render(input.clone()), expected_ascii); + assert_data_eq!(renderer_ascii.render(input), expected_ascii); let expected_unicode = str![[r#" error[E0369]: cannot add `&str` to `&str` @@ -2437,17 +2368,13 @@ fn foo() { } "##; let bin_source = "�|�\u{0002}!5�cc\u{0015}\u{0002}�Ӻi��WWj�ȥ�'�}�\u{0012}�J�ȉ��W�\u{001e}O�@����\u{001c}w�V���LO����\u{0014}[ \u{0003}_�'���SQ�~ذ��ų&��-\t��lN~��!@␌ _#���kQ��h�\u{001d}�:�\u{001c}\u{0007}�"; - let input = Level::ERROR - .header("couldn't read `$DIR/not-utf8.bin`: stream did not contain valid UTF-8") - .group( - Group::new().element( + let input = &[Group::new().element(Level::ERROR + .title("couldn't read `$DIR/not-utf8.bin`: stream did not contain valid UTF-8")).element( Snippet::source(source) .path("$DIR/not-utf8.rs") .fold(true) .annotation(AnnotationKind::Primary.span(136..160)), ), - ) - .group( Group::new() .element(Level::NOTE.title("byte `193` is not valid utf-8")) .element( @@ -2457,7 +2384,7 @@ fn foo() { .annotation(AnnotationKind::Primary.span(0..0)), ) .element(Level::NOTE.title("this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)")), - ); + ]; let expected_ascii = str![[r#" error: couldn't read `$DIR/not-utf8.bin`: stream did not contain valid UTF-8 @@ -2475,7 +2402,7 @@ LL | �|�␂!5�cc␕␂�Ӻi��WWj�ȥ�'�}�␒�J�ȉ��W "#]]; let renderer_ascii = Renderer::plain().anonymized_line_numbers(true); - assert_data_eq!(renderer_ascii.render(input.clone()), expected_ascii); + assert_data_eq!(renderer_ascii.render(input), expected_ascii); let expected_unicode = str![[r#" error: couldn't read `$DIR/not-utf8.bin`: stream did not contain valid UTF-8 @@ -2502,29 +2429,28 @@ fn secondary_title_no_level_text() { let s: &str = include_bytes!("file.txt"); //~ ERROR mismatched types }"#; - let input = Level::ERROR.header("mismatched types").id("E0308").group( - Group::new() - .element( - Snippet::source(source) - .path("$DIR/mismatched-types.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(105..131) - .label("expected `&str`, found `&[u8; 0]`"), - ) - .annotation( - AnnotationKind::Context - .span(98..102) - .label("expected due to this"), - ), - ) - .element( - Level::NOTE - .text(None) - .title("expected reference `&str`\nfound reference `&'static [u8; 0]`"), - ), - ); + let input = &[Group::new() + .element(Level::ERROR.title("mismatched types").id("E0308")) + .element( + Snippet::source(source) + .path("$DIR/mismatched-types.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(105..131) + .label("expected `&str`, found `&[u8; 0]`"), + ) + .annotation( + AnnotationKind::Context + .span(98..102) + .label("expected due to this"), + ), + ) + .element( + Level::NOTE + .text(None) + .title("expected reference `&str`\nfound reference `&'static [u8; 0]`"), + )]; let expected = str![[r#" error[E0308]: mismatched types @@ -2548,29 +2474,28 @@ fn secondary_title_custom_level_text() { let s: &str = include_bytes!("file.txt"); //~ ERROR mismatched types }"#; - let input = Level::ERROR.header("mismatched types").id("E0308").group( - Group::new() - .element( - Snippet::source(source) - .path("$DIR/mismatched-types.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(105..131) - .label("expected `&str`, found `&[u8; 0]`"), - ) - .annotation( - AnnotationKind::Context - .span(98..102) - .label("expected due to this"), - ), - ) - .element( - Level::NOTE - .text(Some("custom")) - .title("expected reference `&str`\nfound reference `&'static [u8; 0]`"), - ), - ); + let input = &[Group::new() + .element(Level::ERROR.title("mismatched types").id("E0308")) + .element( + Snippet::source(source) + .path("$DIR/mismatched-types.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(105..131) + .label("expected `&str`, found `&[u8; 0]`"), + ) + .annotation( + AnnotationKind::Context + .span(98..102) + .label("expected due to this"), + ), + ) + .element( + Level::NOTE + .text(Some("custom")) + .title("expected reference `&str`\nfound reference `&'static [u8; 0]`"), + )]; let expected = str![[r#" error[E0308]: mismatched types @@ -2617,11 +2542,14 @@ fn main() { } } "#; - let input = Level::ERROR - .header("`break` with value from a `while` loop") - .id("E0571") - .group( - Group::new().element( + let input = &[ + Group::new() + .element( + Level::ERROR + .title("`break` with value from a `while` loop") + .id("E0571"), + ) + .element( Snippet::source(source) .line_start(1) .path("$DIR/issue-114529-illegal-break-with-value.rs") @@ -2637,23 +2565,21 @@ fn main() { .label("you can't `break` with a value in a `while` loop"), ), ), - ) - .group( - Group::new() - .element( - Level::HELP - .text(Some("suggestion")) - .title("use `break` on its own without a value inside this `while` loop") - .id("S0123"), - ) - .element( - Snippet::source(source) - .line_start(1) - .path("$DIR/issue-114529-illegal-break-with-value.rs") - .fold(true) - .patch(Patch::new(483..581, "break")), - ), - ); + Group::new() + .element( + Level::HELP + .text(Some("suggestion")) + .title("use `break` on its own without a value inside this `while` loop") + .id("S0123"), + ) + .element( + Snippet::source(source) + .line_start(1) + .path("$DIR/issue-114529-illegal-break-with-value.rs") + .fold(true) + .patch(Patch::new(483..581, "break")), + ), + ]; let expected_ascii = str![[r#" error[E0571]: `break` with value from a `while` loop @@ -2676,7 +2602,7 @@ LL + break; "#]]; let renderer_ascii = Renderer::plain().anonymized_line_numbers(true); - assert_data_eq!(renderer_ascii.render(input.clone()), expected_ascii); + assert_data_eq!(renderer_ascii.render(input), expected_ascii); let expected_unicode = str![[r#" error[E0571]: `break` with value from a `while` loop diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index c5e0602f..de5f615f 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -13,15 +13,13 @@ fn ends_on_col0() { fn foo() { } "#; - let input = Level::ERROR.header("foo").group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .path("test.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(10..13).label("test")), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("foo")).element( + Snippet::source(source) + .line_start(1) + .path("test.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(10..13).label("test")), + )]; let expected = str![[r#" error: foo @@ -43,16 +41,13 @@ fn foo() { } "#; - let input = Level::ERROR.header("foo").group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .path("test.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(10..17).label("test")), - ), - ); - + let input = &[Group::new().element(Level::ERROR.title("foo")).element( + Snippet::source(source) + .line_start(1) + .path("test.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(10..17).label("test")), + )]; let expected = str![[r#" error: foo --> test.rs:2:10 @@ -75,24 +70,22 @@ fn foo() { X2 Y2 } "#; - let input = Level::ERROR.header("foo").group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .path("test.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(14..32) - .label("`X` is a good letter"), - ) - .annotation( - AnnotationKind::Context - .span(17..35) - .label("`Y` is a good letter too"), - ), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("foo")).element( + Snippet::source(source) + .line_start(1) + .path("test.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(14..32) + .label("`X` is a good letter"), + ) + .annotation( + AnnotationKind::Context + .span(17..35) + .label("`Y` is a good letter too"), + ), + )]; let expected = str![[r#" error: foo @@ -118,24 +111,22 @@ fn foo() { Y1 X1 } "#; - let input = Level::ERROR.header("foo").group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .path("test.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(14..27) - .label("`X` is a good letter"), - ) - .annotation( - AnnotationKind::Context - .span(17..24) - .label("`Y` is a good letter too"), - ), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("foo")).element( + Snippet::source(source) + .line_start(1) + .path("test.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(14..27) + .label("`X` is a good letter"), + ) + .annotation( + AnnotationKind::Context + .span(17..24) + .label("`Y` is a good letter too"), + ), + )]; let expected = str![[r#" error: foo @@ -162,24 +153,22 @@ fn foo() { X3 Y3 Z3 } "#; - let input = Level::ERROR.header("foo").group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .path("test.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(17..38) - .label("`X` is a good letter"), - ) - .annotation( - AnnotationKind::Context - .span(31..49) - .label("`Y` is a good letter too"), - ), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("foo")).element( + Snippet::source(source) + .line_start(1) + .path("test.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(17..38) + .label("`X` is a good letter"), + ) + .annotation( + AnnotationKind::Context + .span(31..49) + .label("`Y` is a good letter too"), + ), + )]; let expected = str![[r#" error: foo @@ -206,25 +195,23 @@ fn foo() { X2 Y2 Z2 } "#; - let input = Level::ERROR.header("foo").group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .path("test.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(14..38) - .label("`X` is a good letter"), - ) - .annotation( - AnnotationKind::Context - .span(17..41) - .label("`Y` is a good letter too"), - ) - .annotation(AnnotationKind::Context.span(20..44).label("`Z` label")), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("foo")).element( + Snippet::source(source) + .line_start(1) + .path("test.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(14..38) + .label("`X` is a good letter"), + ) + .annotation( + AnnotationKind::Context + .span(17..41) + .label("`Y` is a good letter too"), + ) + .annotation(AnnotationKind::Context.span(20..44).label("`Z` label")), + )]; let expected = str![[r#" error: foo @@ -253,25 +240,23 @@ fn foo() { X2 Y2 Z2 } "#; - let input = Level::ERROR.header("foo").group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .path("test.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(14..38) - .label("`X` is a good letter"), - ) - .annotation( - AnnotationKind::Context - .span(14..38) - .label("`Y` is a good letter too"), - ) - .annotation(AnnotationKind::Context.span(14..38).label("`Z` label")), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("foo")).element( + Snippet::source(source) + .line_start(1) + .path("test.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(14..38) + .label("`X` is a good letter"), + ) + .annotation( + AnnotationKind::Context + .span(14..38) + .label("`Y` is a good letter too"), + ) + .annotation(AnnotationKind::Context.span(14..38).label("`Z` label")), + )]; // This should have a `^` but we currently don't support the idea of a // "primary" annotation, which would solve this @@ -301,25 +286,23 @@ fn foo() { X3 Y3 Z3 } "#; - let input = Level::ERROR.header("foo").group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .path("test.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(17..27) - .label("`X` is a good letter"), - ) - .annotation( - AnnotationKind::Context - .span(28..44) - .label("`Y` is a good letter too"), - ) - .annotation(AnnotationKind::Context.span(36..52).label("`Z`")), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("foo")).element( + Snippet::source(source) + .line_start(1) + .path("test.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(17..27) + .label("`X` is a good letter"), + ) + .annotation( + AnnotationKind::Context + .span(28..44) + .label("`Y` is a good letter too"), + ) + .annotation(AnnotationKind::Context.span(36..52).label("`Z`")), + )]; let expected = str![[r#" error: foo @@ -351,24 +334,22 @@ fn foo() { X3 Y3 Z3 } "#; - let input = Level::ERROR.header("foo").group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .path("test.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(14..27) - .label("`X` is a good letter"), - ) - .annotation( - AnnotationKind::Context - .span(39..55) - .label("`Y` is a good letter too"), - ), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("foo")).element( + Snippet::source(source) + .line_start(1) + .path("test.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(14..27) + .label("`X` is a good letter"), + ) + .annotation( + AnnotationKind::Context + .span(39..55) + .label("`Y` is a good letter too"), + ), + )]; let expected = str![[r#" error: foo @@ -395,24 +376,22 @@ fn foo() { X3 Y3 Z3 } "#; - let input = Level::ERROR.header("foo").group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .path("test.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(17..27) - .label("`X` is a good letter"), - ) - .annotation( - AnnotationKind::Context - .span(31..55) - .label("`Y` is a good letter too"), - ), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("foo")).element( + Snippet::source(source) + .line_start(1) + .path("test.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(17..27) + .label("`X` is a good letter"), + ) + .annotation( + AnnotationKind::Context + .span(31..55) + .label("`Y` is a good letter too"), + ), + )]; let expected = str![[r#" error: foo @@ -438,21 +417,19 @@ fn foo() { a { b { c } d } } "#; - let input = Level::ERROR.header("foo").group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .path("test.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(18..25).label("")) - .annotation( - AnnotationKind::Context - .span(14..27) - .label("`a` is a good letter"), - ) - .annotation(AnnotationKind::Context.span(22..23).label("")), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("foo")).element( + Snippet::source(source) + .line_start(1) + .path("test.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(18..25).label("")) + .annotation( + AnnotationKind::Context + .span(14..27) + .label("`a` is a good letter"), + ) + .annotation(AnnotationKind::Context.span(22..23).label("")), + )]; let expected = str![[r#" error: foo @@ -471,20 +448,18 @@ fn foo() { a { b { c } d } } "#; - let input = Level::ERROR.header("foo").group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .path("test.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(14..27) - .label("`a` is a good letter"), - ) - .annotation(AnnotationKind::Context.span(18..25).label("")), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("foo")).element( + Snippet::source(source) + .line_start(1) + .path("test.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(14..27) + .label("`a` is a good letter"), + ) + .annotation(AnnotationKind::Context.span(18..25).label("")), + )]; let expected = str![[r#" error: foo @@ -503,21 +478,19 @@ fn foo() { a { b { c } d } } "#; - let input = Level::ERROR.header("foo").group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .path("test.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(18..25) - .label("`b` is a good letter"), - ) - .annotation(AnnotationKind::Context.span(14..27).label("")) - .annotation(AnnotationKind::Context.span(22..23).label("")), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("foo")).element( + Snippet::source(source) + .line_start(1) + .path("test.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(18..25) + .label("`b` is a good letter"), + ) + .annotation(AnnotationKind::Context.span(14..27).label("")) + .annotation(AnnotationKind::Context.span(22..23).label("")), + )]; let expected = str![[r#" error: foo @@ -538,20 +511,18 @@ fn foo() { a { b { c } d } } "#; - let input = Level::ERROR.header("foo").group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .path("test.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(14..27).label("")) - .annotation( - AnnotationKind::Context - .span(18..25) - .label("`b` is a good letter"), - ), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("foo")).element( + Snippet::source(source) + .line_start(1) + .path("test.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(14..27).label("")) + .annotation( + AnnotationKind::Context + .span(18..25) + .label("`b` is a good letter"), + ), + )]; let expected = str![[r#" error: foo @@ -572,20 +543,18 @@ fn foo() { a bc d } "#; - let input = Level::ERROR.header("foo").group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .path("test.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(14..18) - .label("`a` is a good letter"), - ) - .annotation(AnnotationKind::Context.span(18..22).label("")), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("foo")).element( + Snippet::source(source) + .line_start(1) + .path("test.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(14..18) + .label("`a` is a good letter"), + ) + .annotation(AnnotationKind::Context.span(18..22).label("")), + )]; let expected = str![[r#" error: foo @@ -606,16 +575,14 @@ fn foo() { a { b { c } d } } "#; - let input = Level::ERROR.header("foo").group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .path("test.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(14..27).label("")) - .annotation(AnnotationKind::Context.span(18..25).label("")), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("foo")).element( + Snippet::source(source) + .line_start(1) + .path("test.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(14..27).label("")) + .annotation(AnnotationKind::Context.span(18..25).label("")), + )]; let expected = str![[r#" error: foo @@ -634,17 +601,15 @@ fn foo() { a { b { c } d } } "#; - let input = Level::ERROR.header("foo").group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .path("test.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(18..25).label("")) - .annotation(AnnotationKind::Context.span(14..27).label("")) - .annotation(AnnotationKind::Context.span(22..23).label("")), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("foo")).element( + Snippet::source(source) + .line_start(1) + .path("test.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(18..25).label("")) + .annotation(AnnotationKind::Context.span(14..27).label("")) + .annotation(AnnotationKind::Context.span(22..23).label("")), + )]; let expected = str![[r#" error: foo @@ -663,24 +628,22 @@ fn foo() { a { b { c } d } } "#; - let input = Level::ERROR.header("foo").group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .path("test.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(14..27) - .label("`a` is a good letter"), - ) - .annotation( - AnnotationKind::Context - .span(18..25) - .label("`b` is a good letter"), - ), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("foo")).element( + Snippet::source(source) + .line_start(1) + .path("test.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(14..27) + .label("`a` is a good letter"), + ) + .annotation( + AnnotationKind::Context + .span(18..25) + .label("`b` is a good letter"), + ), + )]; let expected = str![[r#" error: foo @@ -702,19 +665,17 @@ fn foo() { a { b { c } d } } "#; - let input = Level::ERROR.header("foo").group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .path("test.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(14..27) - .label("`a` is a good letter"), - ), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("foo")).element( + Snippet::source(source) + .line_start(1) + .path("test.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(14..27) + .label("`a` is a good letter"), + ), + )]; let expected = str![[r#" error: foo @@ -733,15 +694,13 @@ fn foo() { a { b { c } d } } "#; - let input = Level::ERROR.header("foo").group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .path("test.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(14..27).label("")), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("foo")).element( + Snippet::source(source) + .line_start(1) + .path("test.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(14..27).label("")), + )]; let expected = str![[r#" error: foo @@ -773,24 +732,22 @@ fn foo() { X3 Y3 Z3 } "#; - let input = Level::ERROR.header("foo").group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .path("test.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(17..27) - .label("`X` is a good letter"), - ) - .annotation( - AnnotationKind::Context - .span(31..76) - .label("`Y` is a good letter too"), - ), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("foo")).element( + Snippet::source(source) + .line_start(1) + .path("test.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(17..27) + .label("`X` is a good letter"), + ) + .annotation( + AnnotationKind::Context + .span(31..76) + .label("`Y` is a good letter too"), + ), + )]; let expected = str![[r#" error: foo @@ -833,24 +790,22 @@ fn foo() { X3 Y3 Z3 } "#; - let input = Level::ERROR.header("foo").group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .path("test.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(17..73) - .label("`Y` is a good letter"), - ) - .annotation( - AnnotationKind::Context - .span(37..56) - .label("`Z` is a good letter too"), - ), - ), - ); + let input = &[Group::new().element(Level::ERROR.title("foo")).element( + Snippet::source(source) + .line_start(1) + .path("test.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(17..73) + .label("`Y` is a good letter"), + ) + .annotation( + AnnotationKind::Context + .span(37..56) + .label("`Z` is a good letter too"), + ), + )]; let expected = str![[r#" error: foo @@ -887,32 +842,30 @@ fn issue_91334() { fn f(){||yield(((){), "#; - let input = Level::ERROR - .header("this file contains an unclosed delimiter") - .group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .path("$DIR/issue-91334.rs") - .fold(true) - .annotation( - AnnotationKind::Context - .span(151..152) - .label("unclosed delimiter"), - ) - .annotation( - AnnotationKind::Context - .span(159..160) - .label("unclosed delimiter"), - ) - .annotation( - AnnotationKind::Context - .span(164..164) - .label("missing open `(` for this delimiter"), - ) - .annotation(AnnotationKind::Primary.span(167..167)), - ), - ); + let input = &[Group::new() + .element(Level::ERROR.title("this file contains an unclosed delimiter")) + .element( + Snippet::source(source) + .line_start(1) + .path("$DIR/issue-91334.rs") + .fold(true) + .annotation( + AnnotationKind::Context + .span(151..152) + .label("unclosed delimiter"), + ) + .annotation( + AnnotationKind::Context + .span(159..160) + .label("unclosed delimiter"), + ) + .annotation( + AnnotationKind::Context + .span(164..164) + .label("missing open `(` for this delimiter"), + ) + .annotation(AnnotationKind::Primary.span(167..167)), + )]; let expected = str![[r#" error: this file contains an unclosed delimiter --> $DIR/issue-91334.rs:7:23 @@ -958,11 +911,14 @@ fn main() { } } "#; - let input = Level::ERROR - .header("`break` with value from a `while` loop") - .id("E0571") - .group( - Group::new().element( + let input = &[ + Group::new() + .element( + Level::ERROR + .title("`break` with value from a `while` loop") + .id("E0571"), + ) + .element( Snippet::source(source) .line_start(1) .path("$DIR/issue-114529-illegal-break-with-value.rs") @@ -978,21 +934,19 @@ fn main() { .label("you can't `break` with a value in a `while` loop"), ), ), - ) - .group( - Group::new() - .element( - Level::HELP - .title("use `break` on its own without a value inside this `while` loop"), - ) - .element( - Snippet::source(source) - .line_start(1) - .path("$DIR/issue-114529-illegal-break-with-value.rs") - .fold(true) - .annotation(AnnotationKind::Context.span(483..581).label("break")), - ), - ); + Group::new() + .element( + Level::HELP + .title("use `break` on its own without a value inside this `while` loop"), + ) + .element( + Snippet::source(source) + .line_start(1) + .path("$DIR/issue-114529-illegal-break-with-value.rs") + .fold(true) + .annotation(AnnotationKind::Context.span(483..581).label("break")), + ), + ]; let expected = str![[r#" error[E0571]: `break` with value from a `while` loop --> $DIR/issue-114529-illegal-break-with-value.rs:22:9 @@ -1168,11 +1122,14 @@ fn nsize() { } "#; let input = - Level::ERROR - .header("`V0usize` cannot be safely transmuted into `[usize; 2]`") - .id("E0277") - .group( - Group::new().element( + &[ + Group::new() + .element( + Level::ERROR + .title("`V0usize` cannot be safely transmuted into `[usize; 2]`") + .id("E0277"), + ) + .element( Snippet::source(source) .line_start(1) .path("$DIR/primitive_reprs_should_have_correct_length.rs") @@ -1181,27 +1138,25 @@ fn nsize() { "the size of `V0usize` is smaller than the size of `[usize; 2]`", )), ), - ) - .group( - Group::new() - .element(Level::NOTE.title("required by a bound in `is_transmutable`")) - .element( - Snippet::source(source) - .line_start(1) - .path("$DIR/primitive_reprs_should_have_correct_length.rs") - .fold(true) - .annotation( - AnnotationKind::Context - .span(225..240) - .label("required by a bound in this function"), - ) - .annotation( - AnnotationKind::Primary - .span(276..470) - .label("required by this bound in `is_transmutable`"), - ), - ), - ); + Group::new() + .element(Level::NOTE.title("required by a bound in `is_transmutable`")) + .element( + Snippet::source(source) + .line_start(1) + .path("$DIR/primitive_reprs_should_have_correct_length.rs") + .fold(true) + .annotation( + AnnotationKind::Context + .span(225..240) + .label("required by a bound in this function"), + ) + .annotation( + AnnotationKind::Primary + .span(276..470) + .label("required by this bound in `is_transmutable`"), + ), + ), + ]; let expected = str![[r#" error[E0277]: `V0usize` cannot be safely transmuted into `[usize; 2]` --> $DIR/primitive_reprs_should_have_correct_length.rs:144:44 @@ -1254,11 +1209,9 @@ fn main() { assert::is_maybe_transmutable::<&'static [u8; 0], &'static [u16; 0]>(); //~ ERROR `&[u8; 0]` cannot be safely transmuted into `&[u16; 0]` } "#; - let input = Level::ERROR - .header("`&[u8; 0]` cannot be safely transmuted into `&[u16; 0]`") - .id("E027s7") - .group( - Group::new().element( + let input = &[Group::new().element(Level::ERROR + .title("`&[u8; 0]` cannot be safely transmuted into `&[u16; 0]`") + .id("E027s7")).element( Snippet::source(source) .line_start(1) .fold(true) @@ -1268,8 +1221,7 @@ fn main() { .span(442..459) .label("the minimum alignment of `&[u8; 0]` (1) should be greater than that of `&[u16; 0]` (2)") ), - ), - ); + )]; let expected = str![[r#" error[E027s7]: `&[u8; 0]` cannot be safely transmuted into `&[u16; 0]` --> $DIR/align-fail.rs:21:55 @@ -1323,11 +1275,14 @@ fn g() { } fn main() {} "#; - let input = Level::ERROR - .header("expected function, found `{integer}`") - .id("E0618") - .group( - Group::new().element( + let input = + &[Group::new() + .element( + Level::ERROR + .title("expected function, found `{integer}`") + .id("E0618"), + ) + .element( Snippet::source(source) .line_start(1) .path("$DIR/missing-semicolon.rs") @@ -1346,8 +1301,7 @@ fn main() {} "help: consider using a semicolon here to finish the statement: `;`", )) .annotation(AnnotationKind::Primary.span(108..109)), - ), - ); + )]; let expected = str![[r#" error[E0618]: expected function, found `{integer}` --> $DIR/missing-semicolon.rs:5:13 @@ -1414,10 +1368,9 @@ macro_rules! outer_macro { outer_macro!(FirstStruct, FirstAttrStruct); "#; - let input = Level::WARNING - .header("non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module") - .group( - Group::new() + let input = + &[ Group::new().element(Level::WARNING + .title("non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module")) .element( Snippet::source(aux_source) .line_start(1) @@ -1449,8 +1402,6 @@ outer_macro!(FirstStruct, FirstAttrStruct); Level::NOTE .title("a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute") ), - ) - .group( Group::new() .element(Level::NOTE.title("the lint level is defined here")) .element( @@ -1459,8 +1410,7 @@ outer_macro!(FirstStruct, FirstAttrStruct); .path("$DIR/nested-macro-rules.rs") .fold(true) .annotation(AnnotationKind::Primary.span(224..245)), - ), - ); + )]; let expected = str![[r#" warning: non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module --> $DIR/auxiliary/nested-macro-rules.rs:7:9 @@ -1547,29 +1497,30 @@ macro_rules! inline { () => () } "#; - let input = Level::ERROR - .header("can't call method `pow` on ambiguous numeric type `{integer}`") - .id("E0689") - .group( - Group::new().element( + let input = &[ + Group::new() + .element( + Level::ERROR + .title("can't call method `pow` on ambiguous numeric type `{integer}`") + .id("E0689"), + ) + .element( Snippet::source(source) .line_start(1) .path("$DIR/method-on-ambiguous-numeric-type.rs") .fold(true) .annotation(AnnotationKind::Primary.span(916..919)), ), - ) - .group( - Group::new() - .element(Level::HELP.title("you must specify a type for this binding, like `i32`")) - .element( - Snippet::source(aux_source) - .line_start(1) - .path("$DIR/auxiliary/macro-in-other-crate.rs") - .fold(true) - .annotation(AnnotationKind::Context.span(69..69).label(": i32")), - ), - ); + Group::new() + .element(Level::HELP.title("you must specify a type for this binding, like `i32`")) + .element( + Snippet::source(aux_source) + .line_start(1) + .path("$DIR/auxiliary/macro-in-other-crate.rs") + .fold(true) + .annotation(AnnotationKind::Context.span(69..69).label(": i32")), + ), + ]; let expected = str![[r#" error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}` --> $DIR/method-on-ambiguous-numeric-type.rs:37:9 @@ -1611,20 +1562,17 @@ fn courier_to_des_moines_and_points_west(data: &[u32]) -> String { fn main() {} "#; - let input = Level::ERROR - .header("type annotations needed") - .id("E0282") - .group( - Group::new().element( - Snippet::source(source) - .line_start(1) - .path("$DIR/issue-42234-unknown-receiver-type.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(536..539).label( - "cannot infer type of the type parameter `S` declared on the method `sum`", - )), - ), - ); + let input = &[Group::new() + .element(Level::ERROR.title("type annotations needed").id("E0282")) + .element( + Snippet::source(source) + .line_start(1) + .path("$DIR/issue-42234-unknown-receiver-type.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(536..539).label( + "cannot infer type of the type parameter `S` declared on the method `sum`", + )), + )]; let expected = str![[r#" error[E0282]: type annotations needed --> $DIR/issue-42234-unknown-receiver-type.rs:15:10 @@ -1717,13 +1665,12 @@ fn nonempty(arrayN_of_empty: [!; N]) { fn main() {} "##; - let input = Level::ERROR - .header( - "non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered" - ) - .id("E0004") - .group( - Group::new().element( + let input = + &[ Group::new().element( Level::ERROR + .title( + "non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered" + ) + .id("E0004")).element( Snippet::source(source) .line_start(1) .path("$DIR/empty-match.rs") @@ -1734,8 +1681,6 @@ fn main() {} .label("patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered") ), ), - ) - .group( Group::new() .element(Level::NOTE.title("`NonEmptyEnum5` defined here")) .element( @@ -1751,9 +1696,8 @@ fn main() {} .annotation(AnnotationKind::Context.span(890..892).label("not covered")) ) .element(Level::NOTE.title("the matched value is of type `NonEmptyEnum5`")) - .element(Level::NOTE.title("match arms with guards don't count towards exhaustivity")) - ) - .group( + .element(Level::NOTE.title("match arms with guards don't count towards exhaustivity") + ), Group::new() .element( Level::HELP @@ -1765,8 +1709,8 @@ fn main() {} .path("$DIR/empty-match.rs") .fold(true) .annotation(AnnotationKind::Context.span(485..485).label(",\n _ => todo!()")) - ) - ); + + )]; let expected = str![[r#" error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered --> $DIR/empty-match.rs:71:24 @@ -1819,11 +1763,9 @@ fn main() { //~^ ERROR must be specified } "#; - let input = Level::ERROR - .header("the trait alias `EqAlias` is not dyn compatible") - .id("E0038") - .group( - Group::new().element( + let input = &[Group::new().element(Level::ERROR + .title("the trait alias `EqAlias` is not dyn compatible") + .id("E0038")).element( Snippet::source(source) .line_start(1) .path("$DIR/object-fail.rs") @@ -1834,8 +1776,6 @@ fn main() { .label("`EqAlias` is not dyn compatible"), ), ), - ) - .group( Group::new() .element( Level::NOTE @@ -1858,8 +1798,7 @@ fn main() { .span(32..39) .label("this trait is not dyn compatible..."), ), - ), - ); + )]; let expected = str![[r#" error[E0038]: the trait alias `EqAlias` is not dyn compatible --> $DIR/object-fail.rs:7:17 @@ -1891,8 +1830,9 @@ const C: u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, fn main() {} "#; - let input = Level::ERROR.header("mismatched types").id("E0038").group( - Group::new().element( + let input = &[Group::new() + .element(Level::ERROR.title("mismatched types").id("E0038")) + .element( Snippet::source(source) .path("$DIR/long-span.rs") .fold(true) @@ -1901,8 +1841,7 @@ fn main() {} .span(15..5055) .label("expected `u8`, found `[{integer}; 1680]`"), ), - ), - ); + )]; let expected = str![[r#" error[E0038]: mismatched types --> $DIR/long-span.rs:2:15 @@ -1925,8 +1864,9 @@ const C: u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, fn main() {} "#; - let input = Level::ERROR.header("mismatched types").id("E0038").group( - Group::new().element( + let input = &[Group::new() + .element(Level::ERROR.title("mismatched types").id("E0038")) + .element( Snippet::source(source) .path("$DIR/long-span.rs") .fold(true) @@ -1935,8 +1875,7 @@ fn main() {} .span(15..5055) .label("expected `u8`, found `[{integer}; 1680]`"), ), - ), - ); + )]; let expected = str![[r#" error[E0038]: mismatched types ╭▸ $DIR/long-span.rs:2:15 @@ -1960,8 +1899,9 @@ const C: u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, fn main() {} "#; - let input = Level::ERROR.header("mismatched types").id("E0038").group( - Group::new().element( + let input = &[Group::new() + .element(Level::ERROR.title("mismatched types").id("E0038")) + .element( Snippet::source(source) .path("$DIR/long-span.rs") .fold(true) @@ -1970,8 +1910,7 @@ fn main() {} .span(15..5055) .label("expected `u8`, found `[{integer}; 1680]`"), ), - ), - ); + )]; let expected = str![[r#" error[E0038]: mismatched types ╭▸ $DIR/long-span.rs:2:15 @@ -1995,8 +1934,9 @@ const C: u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, fn main() {} "#; - let input = Level::ERROR.header("mismatched types").id("E0038").group( - Group::new().element( + let input = &[Group::new() + .element(Level::ERROR.title("mismatched types").id("E0038")) + .element( Snippet::source(source) .path("$DIR/long-span.rs") .fold(true) @@ -2005,8 +1945,7 @@ fn main() {} .span(15..5055) .label("expected `u8`, found `[{integer}; 1680]`"), ), - ), - ); + )]; let expected = str![[r#" error[E0038]: mismatched types --> $DIR/long-span.rs:2:15 @@ -2046,10 +1985,8 @@ fn main() { } "#; - let input = Level::ERROR - .header("`Iterator::map` call that discard the iterator's values") - .group( - Group::new() + let input = &[Group::new().element(Level::ERROR + .title("`Iterator::map` call that discard the iterator's values")) .element( Snippet::source(source) .path("$DIR/lint_map_unit_fn.rs") @@ -2071,8 +2008,6 @@ fn main() { ) .element( Level::NOTE.title("`Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated")), - ) - .group( Group::new() .element(Level::HELP.title("you might have meant to use `Iterator::for_each`")) .element( @@ -2080,8 +2015,7 @@ fn main() { .path("$DIR/lint_map_unit_fn.rs") .fold(true) .patch(Patch::new(267..270, r#"for_each"#)), - ), - ); + )]; let expected = str![[r#" error: `Iterator::map` call that discard the iterator's values @@ -2141,27 +2075,25 @@ fn main() { } "#; - let input = Level::ERROR - .header("character constant must be escaped: `\\n`") - .group( - Group::new().element( + let input = &[ + Group::new() + .element(Level::ERROR.title("character constant must be escaped: `\\n`")) + .element( Snippet::source(source) .path("$DIR/bad-char-literals.rs") .fold(true) .annotation(AnnotationKind::Primary.span(204..205)), ), - ) - .group( - Group::new() - .element(Level::HELP.title("escape the character")) - .element( - Snippet::source(source) - .path("$DIR/bad-char-literals.rs") - .line_start(1) - .fold(true) - .patch(Patch::new(204..205, r#"\n"#)), - ), - ); + Group::new() + .element(Level::HELP.title("escape the character")) + .element( + Snippet::source(source) + .path("$DIR/bad-char-literals.rs") + .line_start(1) + .fold(true) + .patch(Patch::new(204..205, r#"\n"#)), + ), + ]; let expected = str![[r#" error: character constant must be escaped: `/n` --> $DIR/bad-char-literals.rs:10:6 @@ -2196,26 +2128,24 @@ fn unclosed_1() { fn main() {} "#; - let input = Level::ERROR - .header("unclosed frontmatter") - .group( - Group::new().element( + let input = &[ + Group::new() + .element(Level::ERROR.title("unclosed frontmatter")) + .element( Snippet::source(source) .path("$DIR/unclosed-1.rs") .fold(true) .annotation(AnnotationKind::Primary.span(0..221)), ), - ) - .group( - Group::new() - .element(Level::NOTE.title("frontmatter opening here was not closed")) - .element( - Snippet::source(source) - .path("$DIR/unclosed-1.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(0..4)), - ), - ); + Group::new() + .element(Level::NOTE.title("frontmatter opening here was not closed")) + .element( + Snippet::source(source) + .path("$DIR/unclosed-1.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(0..4)), + ), + ]; let expected = str![[r#" error: unclosed frontmatter --> $DIR/unclosed-1.rs:1:1 @@ -2256,26 +2186,24 @@ fn foo() -> &str { } "#; - let input = Level::ERROR - .header("unclosed frontmatter") - .group( - Group::new().element( + let input = &[ + Group::new() + .element(Level::ERROR.title("unclosed frontmatter")) + .element( Snippet::source(source) .path("$DIR/unclosed-2.rs") .fold(true) .annotation(AnnotationKind::Primary.span(0..377)), ), - ) - .group( - Group::new() - .element(Level::NOTE.title("frontmatter opening here was not closed")) - .element( - Snippet::source(source) - .path("$DIR/unclosed-2.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(0..4)), - ), - ); + Group::new() + .element(Level::NOTE.title("frontmatter opening here was not closed")) + .element( + Snippet::source(source) + .path("$DIR/unclosed-2.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(0..4)), + ), + ]; let expected = str![[r#" error: unclosed frontmatter --> $DIR/unclosed-2.rs:1:1 @@ -2318,28 +2246,24 @@ fn foo(x: i32) -> i32 { //~^ ERROR: unexpected closing delimiter: `}` "#; - let input = Level::ERROR - .header("invalid preceding whitespace for frontmatter close") - .group( - Group::new().element( + let input = &[ + Group::new() + .element(Level::ERROR.title("invalid preceding whitespace for frontmatter close")) + .element( Snippet::source(source) .path("$DIR/unclosed-3.rs") .fold(true) .annotation(AnnotationKind::Primary.span(302..310)), ), - ) - .group( - Group::new() - .element( - Level::NOTE.title("frontmatter close should not be preceded by whitespace"), - ) - .element( - Snippet::source(source) - .path("$DIR/unclosed-3.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(302..306)), - ), - ); + Group::new() + .element(Level::NOTE.title("frontmatter close should not be preceded by whitespace")) + .element( + Snippet::source(source) + .path("$DIR/unclosed-3.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(302..306)), + ), + ]; let expected = str![[r#" error: invalid preceding whitespace for frontmatter close --> $DIR/unclosed-3.rs:12:1 @@ -2372,26 +2296,24 @@ fn unclosed_4() { fn main() {} "#; - let input = Level::ERROR - .header("unclosed frontmatter") - .group( - Group::new().element( + let input = &[ + Group::new() + .element(Level::ERROR.title("unclosed frontmatter")) + .element( Snippet::source(source) .path("$DIR/unclosed-4.rs") .fold(true) .annotation(AnnotationKind::Primary.span(0..43)), ), - ) - .group( - Group::new() - .element(Level::NOTE.title("frontmatter opening here was not closed")) - .element( - Snippet::source(source) - .path("$DIR/unclosed-4.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(0..4)), - ), - ); + Group::new() + .element(Level::NOTE.title("frontmatter opening here was not closed")) + .element( + Snippet::source(source) + .path("$DIR/unclosed-4.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(0..4)), + ), + ]; let expected = str![[r#" error: unclosed frontmatter --> $DIR/unclosed-4.rs:1:1 @@ -2427,26 +2349,24 @@ use std::env; fn main() {} "#; - let input = Level::ERROR - .header("unclosed frontmatter") - .group( - Group::new().element( + let input = &[ + Group::new() + .element(Level::ERROR.title("unclosed frontmatter")) + .element( Snippet::source(source) .path("$DIR/unclosed-5.rs") .fold(true) .annotation(AnnotationKind::Primary.span(0..176)), ), - ) - .group( - Group::new() - .element(Level::NOTE.title("frontmatter opening here was not closed")) - .element( - Snippet::source(source) - .path("$DIR/unclosed-5.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(0..4)), - ), - ); + Group::new() + .element(Level::NOTE.title("frontmatter opening here was not closed")) + .element( + Snippet::source(source) + .path("$DIR/unclosed-5.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(0..4)), + ), + ]; let expected = str![[r#" error: unclosed frontmatter @@ -2551,11 +2471,9 @@ pub enum E2 { } "#; - let input = Level::ERROR - .header("expected unit struct, unit variant or constant, found tuple variant `E1::Z1`") - .id(r#"E0532"#) - .group( - Group::new() + let input = &[Group::new().element(Level::ERROR + .title("expected unit struct, unit variant or constant, found tuple variant `E1::Z1`") + .id(r#"E0532"#)) .element( Snippet::source(source) .path("$DIR/pat-tuple-field-count-cross.rs") @@ -2577,8 +2495,6 @@ pub enum E2 { .label("similarly named unit variant `Z0` defined here"), ), ), - ) - .group( Group::new() .element(Level::HELP.title("use the tuple variant pattern syntax instead")) .element( @@ -2587,8 +2503,6 @@ pub enum E2 { .fold(true) .patch(Patch::new(1760..1766, r#"E1::Z1()"#)), ), - ) - .group( Group::new() .element(Level::HELP.title("a unit variant with a similar name exists")) .element( @@ -2596,8 +2510,7 @@ pub enum E2 { .path("$DIR/pat-tuple-field-count-cross.rs") .fold(true) .patch(Patch::new(1764..1766, r#"Z0"#)), - ), - ); + )]; let expected = str![[r#" error[E0532]: expected unit struct, unit variant or constant, found tuple variant `E1::Z1` --> $DIR/pat-tuple-field-count-cross.rs:35:9 @@ -2636,8 +2549,9 @@ fn unterminated_nested_comment() { */ "#; - let input = Level::ERROR.header("unterminated block comment").id("E0758").group( - Group::new().element( + let input = &[Group::new() + .element(Level::ERROR.title("unterminated block comment").id("E0758")) + .element( Snippet::source(source) .path("$DIR/unterminated-nested-comment.rs") .fold(true) @@ -2655,8 +2569,7 @@ fn unterminated_nested_comment() { .label("...and last nested comment terminates here."), ) .annotation(AnnotationKind::Primary.span(0..31)), - ), - ); + )]; let expected = str![[r#" error[E0758]: unterminated block comment @@ -2692,38 +2605,37 @@ fn mismatched_types1() { let s: &str = include_bytes!("file.txt"); //~ ERROR mismatched types }"#; - let input = Level::ERROR.header("mismatched types").id("E0308").group( - Group::new() - .element( - Snippet::source(file_txt_source) - .fold(true) - .line_start(3) - .path("$DIR/file.txt") - .annotation( - AnnotationKind::Primary - .span(0..0) - .label("expected `&[u8]`, found `&str`"), - ), - ) - .element( - Snippet::source(rust_source) - .path("$DIR/mismatched-types.rs") - .fold(true) - .annotation( - AnnotationKind::Context - .span(23..28) - .label("expected due to this"), - ) - .annotation( - AnnotationKind::Context - .span(31..55) - .label("in this macro invocation"), - ), - ) - .element( - Level::NOTE.title("expected reference `&[u8]`\n found reference `&'static str`"), - ), - ); + let input = &[Group::new() + .element(Level::ERROR.title("mismatched types").id("E0308")) + .element( + Snippet::source(file_txt_source) + .fold(true) + .line_start(3) + .path("$DIR/file.txt") + .annotation( + AnnotationKind::Primary + .span(0..0) + .label("expected `&[u8]`, found `&str`"), + ), + ) + .element( + Snippet::source(rust_source) + .path("$DIR/mismatched-types.rs") + .fold(true) + .annotation( + AnnotationKind::Context + .span(23..28) + .label("expected due to this"), + ) + .annotation( + AnnotationKind::Context + .span(31..55) + .label("in this macro invocation"), + ), + ) + .element( + Level::NOTE.title("expected reference `&[u8]`\n found reference `&'static str`"), + )]; let expected = str![[r#" error[E0308]: mismatched types @@ -2755,28 +2667,26 @@ fn mismatched_types2() { let s: &str = include_bytes!("file.txt"); //~ ERROR mismatched types }"#; - let input = Level::ERROR.header("mismatched types").id("E0308").group( - Group::new() - .element( - Snippet::source(source) - .path("$DIR/mismatched-types.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(105..131) - .label("expected `&str`, found `&[u8; 0]`"), - ) - .annotation( - AnnotationKind::Context - .span(98..102) - .label("expected due to this"), - ), - ) - .element( - Level::NOTE - .title("expected reference `&str`\n found reference `&'static [u8; 0]`"), - ), - ); + let input = &[Group::new() + .element(Level::ERROR.title("mismatched types").id("E0308")) + .element( + Snippet::source(source) + .path("$DIR/mismatched-types.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(105..131) + .label("expected `&str`, found `&[u8; 0]`"), + ) + .annotation( + AnnotationKind::Context + .span(98..102) + .label("expected due to this"), + ), + ) + .element( + Level::NOTE.title("expected reference `&str`\n found reference `&'static [u8; 0]`"), + )]; let expected = str![[r#" error[E0308]: mismatched types @@ -2809,11 +2719,10 @@ fn main() { } "#; - let input = Level::ERROR - .header("mismatched types") - .id("E0308") - .group( - Group::new().element( + let input = &[ + Group::new() + .element(Level::ERROR.title("mismatched types").id("E0308")) + .element( Snippet::source(source) .path("$DIR/short-error-format.rs") .fold(true) @@ -2828,18 +2737,16 @@ fn main() { .label("arguments to this function are incorrect"), ), ), - ) - .group( - Group::new() - .element(Level::NOTE.title("function defined here")) - .element( - Snippet::source(source) - .path("$DIR/short-error-format.rs") - .fold(true) - .annotation(AnnotationKind::Context.span(48..54).label("")) - .annotation(AnnotationKind::Primary.span(44..47)), - ), - ); + Group::new() + .element(Level::NOTE.title("function defined here")) + .element( + Snippet::source(source) + .path("$DIR/short-error-format.rs") + .fold(true) + .annotation(AnnotationKind::Context.span(48..54).label("")) + .annotation(AnnotationKind::Primary.span(44..47)), + ), + ]; let expected = str![[r#" $DIR/short-error-format.rs:6:9: error[E0308]: mismatched types: expected `u32`, found `String` @@ -2865,21 +2772,22 @@ fn main() { } "#; - let input = Level::ERROR - .header("no method named `salut` found for type `u32` in the current scope") - .id("E0599") - .group( - Group::new().element( - Snippet::source(source) - .path("$DIR/short-error-format.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(127..132) - .label("method not found in `u32`"), - ), - ), - ); + let input = &[Group::new() + .element( + Level::ERROR + .title("no method named `salut` found for type `u32` in the current scope") + .id("E0599"), + ) + .element( + Snippet::source(source) + .path("$DIR/short-error-format.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(127..132) + .label("method not found in `u32`"), + ), + )]; let expected = str![[r#" $DIR/short-error-format.rs:8:7: error[E0599]: no method named `salut` found for type `u32` in the current scope: method not found in `u32` @@ -2903,43 +2811,37 @@ pub struct Foo; //~^ ERROR let source_1 = r#"/// This is a long line that contains a http://link.com "#; - let input = Level::ERROR - .header("this URL is not a hyperlink") - .group( - Group::new() - .element( - Snippet::source(source_0) - .path("$DIR/diagnostic-width.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(111..126)), - ) - .element( - Level::NOTE - .title("bare URLs are not automatically turned into clickable links"), - ), - ) - .group( - Group::new() - .element(Level::NOTE.title("the lint level is defined here")) - .element( - Snippet::source(source_0) - .path("$DIR/diagnostic-width.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(49..67)), - ), - ) - .group( - Group::new() - .element(Level::HELP.title("use an automatic link instead")) - .element( - Snippet::source(source_1) - .path("$DIR/diagnostic-width.rs") - .line_start(4) - .fold(true) - .patch(Patch::new(40..40, "<")) - .patch(Patch::new(55..55, ">")), - ), - ); + let input = &[ + Group::new() + .element(Level::ERROR.title("this URL is not a hyperlink")) + .element( + Snippet::source(source_0) + .path("$DIR/diagnostic-width.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(111..126)), + ) + .element( + Level::NOTE.title("bare URLs are not automatically turned into clickable links"), + ), + Group::new() + .element(Level::NOTE.title("the lint level is defined here")) + .element( + Snippet::source(source_0) + .path("$DIR/diagnostic-width.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(49..67)), + ), + Group::new() + .element(Level::HELP.title("use an automatic link instead")) + .element( + Snippet::source(source_1) + .path("$DIR/diagnostic-width.rs") + .line_start(4) + .fold(true) + .patch(Patch::new(40..40, "<")) + .patch(Patch::new(55..55, ">")), + ), + ]; let expected = str![[r#" error: this URL is not a hyperlink @@ -2979,45 +2881,40 @@ fn main() { let long_title2 = "for more information, see "; let long_title3 = "or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value"; - let input = Level::WARNING - .header(long_title1) - .group( - Group::new() - .element( - Snippet::source(source1) - .path("lint_example.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(40..49)), - ) - .element(Level::WARNING.title("this changes meaning in Rust 2021")) - .element(Level::NOTE.title(long_title2)) - .element(Level::NOTE.title("`#[warn(array_into_iter)]` on by default")), - ) - .group( - Group::new() - .element( - Level::HELP.title("use `.iter()` instead of `.into_iter()` to avoid ambiguity"), - ) - .element( - Snippet::source(source2) - .path("lint_example.rs") - .line_start(3) - .fold(true) - .patch(Patch::new(10..19, "iter")), - ), - ) - .group( - Group::new() - .element(Level::HELP.title(long_title3)) - .element( - Snippet::source(source2) - .path("lint_example.rs") - .line_start(3) - .fold(true) - .patch(Patch::new(0..0, "IntoIterator::into_iter(")) - .patch(Patch::new(9..21, ")")), - ), - ); + let input = &[ + Group::new() + .element(Level::WARNING.title(long_title1)) + .element( + Snippet::source(source1) + .path("lint_example.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(40..49)), + ) + .element(Level::WARNING.title("this changes meaning in Rust 2021")) + .element(Level::NOTE.title(long_title2)) + .element(Level::NOTE.title("`#[warn(array_into_iter)]` on by default")), + Group::new() + .element( + Level::HELP.title("use `.iter()` instead of `.into_iter()` to avoid ambiguity"), + ) + .element( + Snippet::source(source2) + .path("lint_example.rs") + .line_start(3) + .fold(true) + .patch(Patch::new(10..19, "iter")), + ), + Group::new() + .element(Level::HELP.title(long_title3)) + .element( + Snippet::source(source2) + .path("lint_example.rs") + .line_start(3) + .fold(true) + .patch(Patch::new(0..0, "IntoIterator::into_iter(")) + .patch(Patch::new(9..21, ")")), + ), + ]; let expected = str![[r#" warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 From 37542efce234d5dd9c192ead275f7944a8872773 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Tue, 24 Jun 2025 03:30:20 -0600 Subject: [PATCH 243/293] fix: Take Into instead of &str --- src/level.rs | 23 ++++----- src/renderer/mod.rs | 56 +++++++++++----------- src/renderer/source_map.rs | 11 +++-- src/snippet.rs | 96 ++++++++++++++++++++++++++++---------- tests/formatter.rs | 2 +- 5 files changed, 119 insertions(+), 69 deletions(-) diff --git a/src/level.rs b/src/level.rs index d3db1814..5934a280 100644 --- a/src/level.rs +++ b/src/level.rs @@ -2,8 +2,9 @@ use crate::renderer::stylesheet::Stylesheet; use crate::snippet::{ERROR_TXT, HELP_TXT, INFO_TXT, NOTE_TXT, WARNING_TXT}; -use crate::Title; +use crate::{OptionCow, Title}; use anstyle::Style; +use std::borrow::Cow; /// Default `error:` [`Level`] pub const ERROR: Level<'_> = Level { @@ -38,7 +39,7 @@ pub const HELP: Level<'_> = Level { /// [`Title`] severity level #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct Level<'a> { - pub(crate) name: Option>, + pub(crate) name: Option>>, pub(crate) level: LevelInner, } @@ -56,9 +57,9 @@ impl<'a> Level<'a> { /// not allowed to be passed to this function. /// ///
- pub fn text(self, text: Option<&'a str>) -> Level<'a> { + pub fn text(self, text: impl Into>) -> Level<'a> { Level { - name: Some(text), + name: Some(text.into().0), level: self.level, } } @@ -72,11 +73,11 @@ impl<'a> Level<'a> { /// not allowed to be passed to this function. /// /// - pub fn title(self, title: &'a str) -> Title<'a> { + pub fn title(self, title: impl Into>) -> Title<'a> { Title { level: self, id: None, - title, + title: title.into(), is_pre_styled: false, } } @@ -89,18 +90,18 @@ impl<'a> Level<'a> { /// used to normalize untrusted text before it is passed to this function. /// /// - pub fn pre_styled_title(self, title: &'a str) -> Title<'a> { + pub fn pre_styled_title(self, title: impl Into>) -> Title<'a> { Title { level: self, id: None, - title, + title: title.into(), is_pre_styled: true, } } - pub(crate) fn as_str(&self) -> &'a str { - match (self.name, self.level) { - (Some(Some(name)), _) => name, + pub(crate) fn as_str(&'a self) -> &'a str { + match (&self.name, self.level) { + (Some(Some(name)), _) => name.as_ref(), (Some(None), _) => "", (None, LevelInner::Error) => ERROR_TXT, (None, LevelInner::Warning) => WARNING_TXT, diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 12139c38..0cc43d26 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -229,14 +229,14 @@ impl Renderer { .find_map(|s| match &s { Element::Cause(cause) => { if cause.markers.iter().any(|m| m.kind.is_primary()) { - Some(cause.path) + Some(cause.path.as_ref()) } else { None } } Element::Origin(origin) => { if origin.primary { - Some(Some(origin.path)) + Some(Some(&origin.path)) } else { None } @@ -248,8 +248,8 @@ impl Renderer { .elements .iter() .find_map(|s| match &s { - Element::Cause(cause) => Some(cause.path), - Element::Origin(origin) => Some(Some(origin.path)), + Element::Cause(cause) => Some(cause.path.as_ref()), + Element::Origin(origin) => Some(Some(&origin.path)), _ => None, }) .unwrap_or_default(), @@ -269,7 +269,7 @@ impl Renderer { let mut max_depth = 0; for e in &group.elements { if let Element::Cause(cause) = e { - let source_map = SourceMap::new(cause.source, cause.line_start); + let source_map = SourceMap::new(&cause.source, cause.line_start); let (depth, annotated_lines) = source_map.annotated_lines(cause.markers.clone(), cause.fold); max_depth = max(max_depth, depth); @@ -340,7 +340,7 @@ impl Renderer { } Element::Suggestion(suggestion) => { let source_map = - SourceMap::new(suggestion.source, suggestion.line_start); + SourceMap::new(&suggestion.source, suggestion.line_start); self.emit_suggestion_default( &mut buffer, suggestion, @@ -426,10 +426,10 @@ impl Renderer { let labels_inner = cause .markers .iter() - .filter_map(|ann| match ann.label { + .filter_map(|ann| match &ann.label { Some(msg) if ann.kind.is_primary() => { if !msg.trim().is_empty() { - Some(msg.to_owned()) + Some(msg.to_string()) } else { None } @@ -442,11 +442,11 @@ impl Renderer { labels = Some(labels_inner); } - if let Some(path) = cause.path { - let mut origin = Origin::new(path); + if let Some(path) = &cause.path { + let mut origin = Origin::new(path.as_ref()); origin.primary = true; - let source_map = SourceMap::new(cause.source, cause.line_start); + let source_map = SourceMap::new(&cause.source, cause.line_start); let (_depth, annotated_lines) = source_map.annotated_lines(cause.markers.clone(), cause.fold); @@ -531,7 +531,7 @@ impl Renderer { if title.level.name != Some(None) { buffer.append(buffer_msg_line_offset, title.level.as_str(), label_style); label_width += title.level.as_str().len(); - if let Some(Id { id: Some(id), url }) = title.id { + if let Some(Id { id: Some(id), url }) = &title.id { buffer.append(buffer_msg_line_offset, "[", label_style); if let Some(url) = url.as_ref() { buffer.append( @@ -575,9 +575,9 @@ impl Renderer { }); let (title_str, style) = if title.is_pre_styled { - (title.title.to_owned(), ElementStyle::NoStyle) + (title.title.to_string(), ElementStyle::NoStyle) } else { - (normalize_whitespace(title.title), title_element_style) + (normalize_whitespace(&title.title), title_element_style) }; for (i, text) in title_str.lines().enumerate() { if i != 0 { @@ -654,7 +654,7 @@ impl Renderer { format!("{}:{}:{}", origin.path, line, col) } (Some(line), None) => format!("{}:{}", origin.path, line), - _ => origin.path.to_owned(), + _ => origin.path.to_string(), }; buffer.append(buffer_msg_line_offset, &str, ElementStyle::LineAndColumn); @@ -671,17 +671,17 @@ impl Renderer { buffer: &mut StyledBuffer, max_line_num_len: usize, snippet: &Snippet<'_, Annotation<'_>>, - primary_path: Option<&str>, + primary_path: Option<&Cow<'_, str>>, sm: &SourceMap<'_>, annotated_lines: &[AnnotatedLineInfo<'_>], multiline_depth: usize, is_cont: bool, ) { - if let Some(path) = snippet.path { - let mut origin = Origin::new(path); + if let Some(path) = &snippet.path { + let mut origin = Origin::new(path.as_ref()); // print out the span location and spacer before we print the annotated source // to do this, we need to know if this span will be primary - let is_primary = primary_path == Some(origin.path); + let is_primary = primary_path == Some(&origin.path); if is_primary { origin.primary = true; @@ -1394,7 +1394,7 @@ impl Renderer { } else { (pos + 2, annotation.start.display.saturating_sub(left)) }; - if let Some(label) = annotation.label { + if let Some(label) = &annotation.label { buffer.puts(line_offset + pos, code_offset + col, label, style); } } @@ -1535,7 +1535,7 @@ impl Renderer { suggestion: &Snippet<'_, Patch<'_>>, max_line_num_len: usize, sm: &SourceMap<'_>, - primary_path: Option<&str>, + primary_path: Option<&Cow<'_, str>>, is_cont: bool, ) { let suggestions = sm.splice_lines(suggestion.markers.clone()); @@ -1558,8 +1558,8 @@ impl Renderer { ElementStyle::LineNumber, ); } - if suggestion.path != primary_path { - if let Some(path) = suggestion.path { + if suggestion.path.as_ref() != primary_path { + if let Some(path) = suggestion.path.as_ref() { let (loc, _) = sm.span_to_locations(parts[0].span.clone()); // --> file.rs:line:col // | @@ -1781,7 +1781,7 @@ impl Renderer { // ...or trailing spaces. Account for substitutions containing unicode // characters. let sub_len: usize = str_width(if is_whitespace_addition { - part.replacement + &part.replacement } else { part.replacement.trim() }); @@ -1802,7 +1802,7 @@ impl Renderer { let padding: usize = max_line_num_len + 3; for p in underline_start..underline_end { if matches!(show_code_change, DisplaySuggestion::Underline) - && is_different(sm, part.replacement, part.span.clone()) + && is_different(sm, &part.replacement, part.span.clone()) { // If this is a replacement, underline with `~`, if this is an addition // underline with `+`. @@ -1903,7 +1903,7 @@ impl Renderer { } // length of the code after substitution - let full_sub_len = str_width(part.replacement) as isize; + let full_sub_len = str_width(&part.replacement) as isize; // length of the code to be substituted let snippet_len = span_end_pos as isize - span_start_pos as isize; @@ -2631,7 +2631,7 @@ pub(crate) struct LineAnnotation<'a> { pub kind: AnnotationKind, /// Optional label to display adjacent to the annotation. - pub label: Option<&'a str>, + pub label: Option>, /// Is this a single line, multiline or multiline span minimized down to a /// smaller span. @@ -2658,7 +2658,7 @@ impl LineAnnotation<'_> { } pub(crate) fn has_label(&self) -> bool { - if let Some(label) = self.label { + if let Some(label) = &self.label { // Consider labels with no text as effectively not being there // to avoid weird output with unnecessary vertical lines, like: // diff --git a/src/renderer/source_map.rs b/src/renderer/source_map.rs index 026b2a42..e2e4b61c 100644 --- a/src/renderer/source_map.rs +++ b/src/renderer/source_map.rs @@ -1,5 +1,6 @@ use crate::renderer::{char_width, is_different, num_overlap, LineAnnotation, LineAnnotationType}; use crate::{Annotation, AnnotationKind, Patch}; +use std::borrow::Cow; use std::cmp::{max, min}; use std::ops::Range; @@ -453,14 +454,14 @@ impl<'a> SourceMap<'a> { .replacement .split('\n') .next() - .unwrap_or(part.replacement) + .unwrap_or(&part.replacement) .chars() .map(|c| match c { '\t' => 4, _ => 1, }) .sum(); - if !is_different(self, part.replacement, part.span.clone()) { + if !is_different(self, &part.replacement, part.span.clone()) { // Account for cases where we are suggesting the same code that's already // there. This shouldn't happen often, but in some cases for multipart // suggestions it's much easier to handle it here than in the origin. @@ -470,7 +471,7 @@ impl<'a> SourceMap<'a> { end: (cur_lo.char as isize + acc + len) as usize, }); } - buf.push_str(part.replacement); + buf.push_str(&part.replacement); // Account for the difference between the width of the current code and the // snippet being suggested, so that the *later* suggestions are correctly // aligned on the screen. Note that cur_hi and cur_lo can be on different @@ -514,7 +515,7 @@ pub(crate) struct MultilineAnnotation<'a> { pub start: Loc, pub end: Loc, pub kind: AnnotationKind, - pub label: Option<&'a str>, + pub label: Option>, pub overlaps_exactly: bool, pub highlight_source: bool, } @@ -555,7 +556,7 @@ impl<'a> MultilineAnnotation<'a> { }, end: self.end, kind: self.kind, - label: self.label, + label: self.label.clone(), annotation_type: LineAnnotationType::MultilineEnd(self.depth), highlight_source: self.highlight_source, } diff --git a/src/snippet.rs b/src/snippet.rs index 6e9a78c7..f8b243fb 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -2,6 +2,7 @@ use crate::renderer::source_map::SourceMap; use crate::Level; +use std::borrow::Cow; use std::ops::Range; pub(crate) const ERROR_TXT: &str = "error"; @@ -12,8 +13,8 @@ pub(crate) const WARNING_TXT: &str = "warning"; #[derive(Clone, Debug, Default)] pub(crate) struct Id<'a> { - pub(crate) id: Option<&'a str>, - pub(crate) url: Option<&'a str>, + pub(crate) id: Option>, + pub(crate) url: Option>, } /// An [`Element`] container @@ -100,7 +101,7 @@ pub struct Padding; pub struct Title<'a> { pub(crate) level: Level<'a>, pub(crate) id: Option>, - pub(crate) title: &'a str, + pub(crate) title: Cow<'a, str>, pub(crate) is_pre_styled: bool, } @@ -117,8 +118,8 @@ impl<'a> Title<'a> { /// not allowed to be passed to this function. /// /// - pub fn id(mut self, id: &'a str) -> Self { - self.id.get_or_insert(Id::default()).id = Some(id); + pub fn id(mut self, id: impl Into>) -> Self { + self.id.get_or_insert(Id::default()).id = Some(id.into()); self } @@ -128,8 +129,8 @@ impl<'a> Title<'a> { /// `id` present /// /// - pub fn id_url(https://github.com/mut%20self,%20url:%20&'a%20str) -> Self { - self.id.get_or_insert(Id::default()).url = Some(url); + pub fn id_url(https://github.com/mut%20self,%20url:%20impl%20Into%3CCow%3C'a,%20str%3E%3E) -> Self { + self.id.get_or_insert(Id::default()).url = Some(url.into()); self } } @@ -139,9 +140,9 @@ impl<'a> Title<'a> { /// If you do not have [source][Snippet::source] available, see instead [`Origin`] #[derive(Clone, Debug)] pub struct Snippet<'a, T> { - pub(crate) path: Option<&'a str>, + pub(crate) path: Option>, pub(crate) line_start: usize, - pub(crate) source: &'a str, + pub(crate) source: Cow<'a, str>, pub(crate) markers: Vec, pub(crate) fold: bool, } @@ -156,11 +157,11 @@ impl<'a, T: Clone> Snippet<'a, T> { /// not allowed to be passed to this function. /// /// - pub fn source(source: &'a str) -> Self { + pub fn source(source: impl Into>) -> Self { Self { path: None, line_start: 1, - source, + source: source.into(), markers: vec![], fold: false, } @@ -182,8 +183,8 @@ impl<'a, T: Clone> Snippet<'a, T> { /// not allowed to be passed to this function. /// /// - pub fn path(mut self, path: &'a str) -> Self { - self.path = Some(path); + pub fn path(mut self, path: impl Into>) -> Self { + self.path = path.into().0; self } @@ -228,7 +229,7 @@ impl<'a> Snippet<'a, Patch<'a>> { #[derive(Clone, Debug)] pub struct Annotation<'a> { pub(crate) span: Range, - pub(crate) label: Option<&'a str>, + pub(crate) label: Option>, pub(crate) kind: AnnotationKind, pub(crate) highlight_source: bool, } @@ -245,8 +246,8 @@ impl<'a> Annotation<'a> { /// not allowed to be passed to this function. /// /// - pub fn label(mut self, label: &'a str) -> Self { - self.label = Some(label); + pub fn label(mut self, label: impl Into>) -> Self { + self.label = label.into().0; self } @@ -286,7 +287,7 @@ impl AnnotationKind { #[derive(Clone, Debug)] pub struct Patch<'a> { pub(crate) span: Range, - pub(crate) replacement: &'a str, + pub(crate) replacement: Cow<'a, str>, } impl<'a> Patch<'a> { @@ -299,8 +300,11 @@ impl<'a> Patch<'a> { /// not allowed to be passed to this function. /// /// - pub fn new(span: Range, replacement: &'a str) -> Self { - Self { span, replacement } + pub fn new(span: Range, replacement: impl Into>) -> Self { + Self { + span, + replacement: replacement.into(), + } } pub(crate) fn is_addition(&self, sm: &SourceMap<'_>) -> bool { @@ -344,9 +348,9 @@ impl<'a> Patch<'a> { return; }; - if let Some((prefix, substr, suffix)) = as_substr(snippet, self.replacement) { + if let Some((prefix, substr, suffix)) = as_substr(snippet, &self.replacement) { self.span = self.span.start + prefix..self.span.end.saturating_sub(suffix); - self.replacement = substr; + self.replacement = Cow::Owned(substr.to_owned()); } } } @@ -356,7 +360,7 @@ impl<'a> Patch<'a> { /// If you have source available, see instead [`Snippet`] #[derive(Clone, Debug)] pub struct Origin<'a> { - pub(crate) path: &'a str, + pub(crate) path: Cow<'a, str>, pub(crate) line: Option, pub(crate) char_column: Option, pub(crate) primary: bool, @@ -370,9 +374,9 @@ impl<'a> Origin<'a> { /// not allowed to be passed to this function. /// /// - pub fn new(path: &'a str) -> Self { + pub fn new(path: impl Into>) -> Self { Self { - path, + path: path.into(), line: None, char_column: None, primary: false, @@ -407,6 +411,50 @@ impl<'a> Origin<'a> { } } +impl<'a> From> for Origin<'a> { + fn from(origin: Cow<'a, str>) -> Self { + Self::new(origin) + } +} + +#[derive(Debug)] +pub struct OptionCow<'a>(pub(crate) Option>); + +impl<'a, T: Into>> From> for OptionCow<'a> { + fn from(value: Option) -> Self { + Self(value.map(Into::into)) + } +} + +impl<'a> From<&'a Cow<'a, str>> for OptionCow<'a> { + fn from(value: &'a Cow<'a, str>) -> Self { + Self(Some(Cow::Borrowed(value))) + } +} + +impl<'a> From> for OptionCow<'a> { + fn from(value: Cow<'a, str>) -> Self { + Self(Some(value)) + } +} + +impl<'a> From<&'a str> for OptionCow<'a> { + fn from(value: &'a str) -> Self { + Self(Some(Cow::Borrowed(value))) + } +} +impl<'a> From for OptionCow<'a> { + fn from(value: String) -> Self { + Self(Some(Cow::Owned(value))) + } +} + +impl<'a> From<&'a String> for OptionCow<'a> { + fn from(value: &'a String) -> Self { + Self(Some(Cow::Borrowed(value.as_str()))) + } +} + /// Given an original string like `AACC`, and a suggestion like `AABBCC`, try to detect /// the case where a substring of the suggestion is "sandwiched" in the original, like /// `BB` is. Return the length of the prefix, the "trimmed" suggestion, and the length diff --git a/tests/formatter.rs b/tests/formatter.rs index 34c40bf8..c538a9e8 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -2448,7 +2448,7 @@ fn secondary_title_no_level_text() { ) .element( Level::NOTE - .text(None) + .text(None::<&str>) .title("expected reference `&str`\nfound reference `&'static [u8; 0]`"), )]; From 1b950821f4ed792578490f1cd0e9cb8b3780c140 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 30 Jun 2025 10:27:22 -0500 Subject: [PATCH 244/293] fix!: Make AnnotationKind non-exhaustive This will allow adding more cases in the future. --- src/snippet.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/snippet.rs b/src/snippet.rs index 6e9a78c7..2cbf3d7c 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -259,6 +259,7 @@ impl<'a> Annotation<'a> { /// The category of the [`Annotation`] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[non_exhaustive] pub enum AnnotationKind { /// Color to the [`Level`] the first [`Title`] in [`Group`]. If no [`Title`] /// is present, it will default to `error`. From ac0fcf34fb3e160dc76e21db14cd6148d586e4a2 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Mon, 30 Jun 2025 11:39:59 -0600 Subject: [PATCH 245/293] fix: Add missing functions for setting stylesheet colors --- src/renderer/mod.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 0cc43d26..85bdf628 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -206,6 +206,24 @@ impl Renderer { self.stylesheet.none = style; self } + + /// Set the output style for [`AnnotationKind::Context`] + pub const fn context(mut self, style: Style) -> Self { + self.stylesheet.context = style; + self + } + + /// Set the output style for additions + pub const fn addition(mut self, style: Style) -> Self { + self.stylesheet.addition = style; + self + } + + /// Set the output style for removals + pub const fn removal(mut self, style: Style) -> Self { + self.stylesheet.removal = style; + self + } } impl Renderer { From 4e70f5649ed6fd623c00252e1b3023d5d7b14aac Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Mon, 30 Jun 2025 18:10:46 -0600 Subject: [PATCH 246/293] docs: More accuratly describe AnnotationKind variants --- src/snippet.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/snippet.rs b/src/snippet.rs index c2ed5c77..8c213260 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -262,10 +262,14 @@ impl<'a> Annotation<'a> { #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] #[non_exhaustive] pub enum AnnotationKind { - /// Color to the [`Level`] the first [`Title`] in [`Group`]. If no [`Title`] - /// is present, it will default to `error`. + /// Match the primary [`Level`] of the group. Primary, - /// "secondary"; fixed color + /// Additional context to explain the [`Primary`][Self::Primary] + /// [`Annotation`] + /// + /// See also [`Renderer::context`]. + /// + /// [`Renderer::context`]: crate::renderer::Renderer Context, } From 52fd5df0e0c3f3faf5ddc1ea3fdf3c88a500ddeb Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Tue, 24 Jun 2025 03:30:20 -0600 Subject: [PATCH 247/293] test: Add a test for a group with no Title --- examples/elide_header.rs | 21 +++++++++++++++++++ examples/elide_header.svg | 44 +++++++++++++++++++++++++++++++++++++++ tests/examples.rs | 7 +++++++ 3 files changed, 72 insertions(+) create mode 100644 examples/elide_header.rs create mode 100644 examples/elide_header.svg diff --git a/examples/elide_header.rs b/examples/elide_header.rs new file mode 100644 index 00000000..716f8e56 --- /dev/null +++ b/examples/elide_header.rs @@ -0,0 +1,21 @@ +use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; + +fn main() { + let source = r#"# Docstring followed by a newline + +def foobar(door, bar={}): + """ + """ +"#; + + let message = &[Group::new() + .element( + Snippet::source(source) + .fold(false) + .annotation(AnnotationKind::Primary.span(56..58).label("B006")), + ) + .element(Level::HELP.title("Replace with `None`; initialize within function"))]; + + let renderer = Renderer::styled(); + anstream::println!("{}", renderer.render(message)); +} diff --git a/examples/elide_header.svg b/examples/elide_header.svg new file mode 100644 index 00000000..cd4eead7 --- /dev/null +++ b/examples/elide_header.svg @@ -0,0 +1,44 @@ + + + + + + + | + + 1 | # Docstring followed by a newline + + 2 | + + 3 | def foobar(door, bar={}): + + | ^^ B006 + + 4 | """ + + 5 | """ + + | + + = help: Replace with `None`; initialize within function + + + + + + diff --git a/tests/examples.rs b/tests/examples.rs index ec2643e9..db00bc1f 100644 --- a/tests/examples.rs +++ b/tests/examples.rs @@ -14,6 +14,13 @@ fn custom_level() { assert_example(target, expected); } +#[test] +fn elide_header() { + let target = "elide_header"; + let expected = snapbox::file!["../examples/elide_header.svg": TermSvg]; + assert_example(target, expected); +} + #[test] fn expected_type() { let target = "expected_type"; From 74cc62b1e7f2dd93aba78057707714598671486c Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Mon, 30 Jun 2025 17:56:38 -0600 Subject: [PATCH 248/293] fix: Only the first element in a Group can set Level --- examples/elide_header.svg | 4 ++-- src/renderer/mod.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/elide_header.svg b/examples/elide_header.svg index cd4eead7..080837d6 100644 --- a/examples/elide_header.svg +++ b/examples/elide_header.svg @@ -3,7 +3,7 @@ .fg { fill: #AAAAAA } .bg { background: #000000 } .fg-bright-blue { fill: #5555FF } - .fg-bright-cyan { fill: #55FFFF } + .fg-bright-red { fill: #FF5555 } .container { padding: 0 10px; line-height: 18px; @@ -27,7 +27,7 @@
3 | def foobar(door, bar={}): - | ^^ B006 + | ^^ B006 4 | """ diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 85bdf628..9912d52c 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -277,8 +277,8 @@ impl Renderer { } let level = group .elements - .iter() - .find_map(|s| match &s { + .first() + .and_then(|s| match &s { Element::Title(title) => Some(title.level.clone()), _ => None, }) From 5f0b4252f744ba2e02e5dadadc2c2837074a7eaf Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Tue, 24 Jun 2025 03:30:20 -0600 Subject: [PATCH 249/293] feat: Allow setting the primary level for a group --- examples/elide_header.rs | 1 + examples/elide_header.svg | 4 ++-- src/renderer/mod.rs | 18 ++++++++++-------- src/snippet.rs | 17 ++++++++++++++++- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/examples/elide_header.rs b/examples/elide_header.rs index 716f8e56..a280616c 100644 --- a/examples/elide_header.rs +++ b/examples/elide_header.rs @@ -9,6 +9,7 @@ def foobar(door, bar={}): "#; let message = &[Group::new() + .primary_level(Level::NOTE) .element( Snippet::source(source) .fold(false) diff --git a/examples/elide_header.svg b/examples/elide_header.svg index 080837d6..ccec3e10 100644 --- a/examples/elide_header.svg +++ b/examples/elide_header.svg @@ -3,7 +3,7 @@ .fg { fill: #AAAAAA } .bg { background: #000000 } .fg-bright-blue { fill: #5555FF } - .fg-bright-red { fill: #FF5555 } + .fg-bright-green { fill: #55FF55 } .container { padding: 0 10px; line-height: 18px; @@ -27,7 +27,7 @@ 3 | def foobar(door, bar={}): - | ^^ B006 + | ^^ B006 4 | """ diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 9912d52c..9d89026c 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -275,14 +275,16 @@ impl Renderer { if og_primary_path.is_none() && primary_path.is_some() { og_primary_path = primary_path; } - let level = group - .elements - .first() - .and_then(|s| match &s { - Element::Title(title) => Some(title.level.clone()), - _ => None, - }) - .unwrap_or(Level::ERROR); + let level = group.primary_level.clone().unwrap_or_else(|| { + group + .elements + .first() + .and_then(|s| match &s { + Element::Title(title) => Some(title.level.clone()), + _ => None, + }) + .unwrap_or(Level::ERROR) + }); let mut source_map_annotated_lines = VecDeque::new(); let mut max_depth = 0; for e in &group.elements { diff --git a/src/snippet.rs b/src/snippet.rs index 8c213260..8206f600 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -20,6 +20,7 @@ pub(crate) struct Id<'a> { /// An [`Element`] container #[derive(Clone, Debug)] pub struct Group<'a> { + pub(crate) primary_level: Option>, pub(crate) elements: Vec>, } @@ -31,7 +32,10 @@ impl Default for Group<'_> { impl<'a> Group<'a> { pub fn new() -> Self { - Self { elements: vec![] } + Self { + primary_level: None, + elements: vec![], + } } pub fn element(mut self, section: impl Into>) -> Self { @@ -44,6 +48,15 @@ impl<'a> Group<'a> { self } + /// Set the primary [`Level`] for this [`Group`]. + /// + /// If not specified, use the [`Level`] of the first element in a [`Group`] + /// if it is a [`Title`]. If not it will default to [`Level::ERROR`]. + pub fn primary_level(mut self, level: Level<'a>) -> Self { + self.primary_level = Some(level); + self + } + pub fn is_empty(&self) -> bool { self.elements.is_empty() } @@ -263,6 +276,8 @@ impl<'a> Annotation<'a> { #[non_exhaustive] pub enum AnnotationKind { /// Match the primary [`Level`] of the group. + /// + /// See [`Group::primary_level`] for details about how this is determined Primary, /// Additional context to explain the [`Primary`][Self::Primary] /// [`Annotation`] From 08e68a37dc92370a0763097a3cb209ad7194bb87 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 02:00:09 +0000 Subject: [PATCH 250/293] chore(deps): Update Rust crate anstream to v0.6.19 (#236) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8cfa6638..d44cfe5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,9 +17,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.18" +version = "0.6.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" dependencies = [ "anstyle", "anstyle-parse", From 49322a7599e21ce5b7b251eff2a297ff522eefa8 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 1 Jul 2025 16:23:45 -0500 Subject: [PATCH 251/293] fix: Force group levels to be explicitly given Moved from `Group::new().primary_level(level)` to `Group::with_level(level)`. As a convenience for titled-groups, we have `Group::with_title(title)`. I had considered `child`/`children` methods on `Title` to make a group but that didn't work out well for title-only groups and I feel like this design is more consistent / easier to discover. --- benches/bench.rs | 16 +- examples/custom_error.rs | 33 +- examples/custom_level.rs | 68 +- examples/elide_header.rs | 3 +- examples/expected_type.rs | 8 +- examples/footer.rs | 15 +- examples/format.rs | 8 +- examples/highlight_source.rs | 2 +- examples/highlight_title.rs | 19 +- examples/id_hyperlink.rs | 45 +- examples/multislice.rs | 3 +- src/renderer/mod.rs | 44 +- src/snippet.rs | 28 +- tests/color/ann_eof.rs | 8 +- tests/color/ann_insertion.rs | 8 +- tests/color/ann_multiline.rs | 33 +- tests/color/ann_multiline2.rs | 8 +- tests/color/ann_removed_nl.rs | 8 +- tests/color/ensure_emoji_highlight_width.rs | 3 +- tests/color/fold_ann_multiline.rs | 8 +- tests/color/fold_bad_origin_line.rs | 2 +- tests/color/fold_leading.rs | 25 +- tests/color/fold_trailing.rs | 25 +- tests/color/issue_9.rs | 2 +- tests/color/multiline_removal_suggestion.rs | 8 +- tests/color/multiple_annotations.rs | 2 +- tests/color/simple.rs | 35 +- tests/color/strip_line.rs | 8 +- tests/color/strip_line_char.rs | 8 +- tests/color/strip_line_non_ws.rs | 8 +- tests/formatter.rs | 788 +++++++++-------- tests/rustc_tests.rs | 896 ++++++++++---------- 32 files changed, 1038 insertions(+), 1137 deletions(-) diff --git a/benches/bench.rs b/benches/bench.rs index 6390628f..4e03ae8c 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -24,9 +24,8 @@ fn simple() -> String { _ => continue, } }"#; - let message = &[Group::new() - .element(Level::ERROR.title("mismatched types").id("E0308")) - .element( + let message = &[ + Group::with_title(Level::ERROR.title("mismatched types").id("E0308")).element( Snippet::source(source) .line_start(51) .path("src/format.rs") @@ -40,7 +39,8 @@ fn simple() -> String { .span(26..724) .label("expected enum `std::option::Option`"), ), - )]; + ), + ]; let renderer = Renderer::plain(); let rendered = renderer.render(message); @@ -69,9 +69,8 @@ fn fold(bencher: divan::Bencher<'_, '_>, context: usize) { (input, span) }) .bench_values(|(input, span)| { - let message = &[Group::new() - .element(Level::ERROR.title("mismatched types").id("E0308")) - .element( + let message = &[ + Group::with_title(Level::ERROR.title("mismatched types").id("E0308")).element( Snippet::source(&input) .fold(true) .path("src/format.rs") @@ -80,7 +79,8 @@ fn fold(bencher: divan::Bencher<'_, '_>, context: usize) { .span(span) .label("expected `Option` because of return type"), ), - )]; + ), + ]; let renderer = Renderer::plain(); let rendered = renderer.render(message); diff --git a/examples/custom_error.rs b/examples/custom_error.rs index e80b1466..a26dc4af 100644 --- a/examples/custom_error.rs +++ b/examples/custom_error.rs @@ -15,23 +15,22 @@ fn main() { pub static C: u32 = 0 - 1; //~^ ERROR could not evaluate static initializer "#; - let message = &[Group::new() - .element( - Level::ERROR - .text(Some("error: internal compiler error")) - .title("could not evaluate static initializer") - .id("E0080"), - ) - .element( - Snippet::source(source) - .path("$DIR/err.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(386..391) - .label("attempt to compute `0_u32 - 1_u32`, which would overflow"), - ), - )]; + let message = &[Group::with_title( + Level::ERROR + .text(Some("error: internal compiler error")) + .title("could not evaluate static initializer") + .id("E0080"), + ) + .element( + Snippet::source(source) + .path("$DIR/err.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(386..391) + .label("attempt to compute `0_u32 - 1_u32`, which would overflow"), + ), + )]; let renderer = Renderer::styled().theme(OutputTheme::Unicode); anstream::println!("{}", renderer.render(message)); diff --git a/examples/custom_level.rs b/examples/custom_level.rs index b500c063..3cf475d0 100644 --- a/examples/custom_level.rs +++ b/examples/custom_level.rs @@ -30,41 +30,39 @@ fn main() { } "#; let message = &[ - Group::new() - .element( - Level::ERROR - .title("`break` with value from a `while` loop") - .id("E0571"), - ) - .element( - Snippet::source(source) - .line_start(1) - .path("$DIR/issue-114529-illegal-break-with-value.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(483..581) - .label("can only break with a value inside `loop` or breakable block"), - ) - .annotation( - AnnotationKind::Context - .span(462..472) - .label("you can't `break` with a value in a `while` loop"), - ), - ), - Group::new() - .element( - Level::HELP - .text(Some("suggestion")) - .title("use `break` on its own without a value inside this `while` loop"), - ) - .element( - Snippet::source(source) - .line_start(1) - .path("$DIR/issue-114529-illegal-break-with-value.rs") - .fold(true) - .patch(Patch::new(483..581, "break")), - ), + Group::with_title( + Level::ERROR + .title("`break` with value from a `while` loop") + .id("E0571"), + ) + .element( + Snippet::source(source) + .line_start(1) + .path("$DIR/issue-114529-illegal-break-with-value.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(483..581) + .label("can only break with a value inside `loop` or breakable block"), + ) + .annotation( + AnnotationKind::Context + .span(462..472) + .label("you can't `break` with a value in a `while` loop"), + ), + ), + Group::with_title( + Level::HELP + .text(Some("suggestion")) + .title("use `break` on its own without a value inside this `while` loop"), + ) + .element( + Snippet::source(source) + .line_start(1) + .path("$DIR/issue-114529-illegal-break-with-value.rs") + .fold(true) + .patch(Patch::new(483..581, "break")), + ), ]; let renderer = Renderer::styled().theme(OutputTheme::Unicode); diff --git a/examples/elide_header.rs b/examples/elide_header.rs index a280616c..436bb25e 100644 --- a/examples/elide_header.rs +++ b/examples/elide_header.rs @@ -8,8 +8,7 @@ def foobar(door, bar={}): """ "#; - let message = &[Group::new() - .primary_level(Level::NOTE) + let message = &[Group::with_level(Level::NOTE) .element( Snippet::source(source) .fold(false) diff --git a/examples/expected_type.rs b/examples/expected_type.rs index 0fce9938..6bbf0812 100644 --- a/examples/expected_type.rs +++ b/examples/expected_type.rs @@ -6,9 +6,8 @@ fn main() { , range: <22, 25>,"#; let message = - &[Group::new() - .element(Level::ERROR.title("expected type, found `22`")) - .element( + &[ + Group::with_title(Level::ERROR.title("expected type, found `22`")).element( Snippet::source(source) .line_start(26) .path("examples/footer.rs") @@ -21,7 +20,8 @@ fn main() { .span(34..50) .label("while parsing this struct"), ), - )]; + ), + ]; let renderer = Renderer::styled(); anstream::println!("{}", renderer.render(message)); diff --git a/examples/footer.rs b/examples/footer.rs index aa9b784f..e9d6b7ee 100644 --- a/examples/footer.rs +++ b/examples/footer.rs @@ -1,10 +1,9 @@ use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; fn main() { - let message = &[ - Group::new() - .element(Level::ERROR.title("mismatched types").id("E0308")) - .element( + let message = + &[ + Group::with_title(Level::ERROR.title("mismatched types").id("E0308")).element( Snippet::source(" slices: vec![\"A\",") .line_start(13) .path("src/multislice.rs") @@ -12,10 +11,10 @@ fn main() { "expected struct `annotate_snippets::snippet::Slice`, found reference", )), ), - Group::new().element(Level::NOTE.title( - "expected type: `snippet::Annotation`\n found type: `__&__snippet::Annotation`", - )), - ]; + Group::with_title(Level::NOTE.title( + "expected type: `snippet::Annotation`\n found type: `__&__snippet::Annotation`", + )), + ]; let renderer = Renderer::styled(); anstream::println!("{}", renderer.render(message)); diff --git a/examples/format.rs b/examples/format.rs index ae603259..384453b2 100644 --- a/examples/format.rs +++ b/examples/format.rs @@ -23,9 +23,8 @@ fn main() { _ => continue, } }"#; - let message = &[Group::new() - .element(Level::ERROR.title("mismatched types").id("E0308")) - .element( + let message = &[ + Group::with_title(Level::ERROR.title("mismatched types").id("E0308")).element( Snippet::source(source) .line_start(51) .path("src/format.rs") @@ -39,7 +38,8 @@ fn main() { .span(26..724) .label("expected enum `std::option::Option`"), ), - )]; + ), + ]; let renderer = Renderer::styled(); anstream::println!("{}", renderer.render(message)); diff --git a/examples/highlight_source.rs b/examples/highlight_source.rs index f897a3f5..297ad871 100644 --- a/examples/highlight_source.rs +++ b/examples/highlight_source.rs @@ -9,7 +9,7 @@ const CON: Vec = vec![1, 2, 3]; //~ ERROR E0010 //~| ERROR cannot call non-const method fn main() {} "#; - let message = &[Group::new().element(Level::ERROR.title("allocations are not allowed in constants") + let message = &[Group::with_title(Level::ERROR.title("allocations are not allowed in constants") .id("E0010")) .element( Snippet::source(source) diff --git a/examples/highlight_title.rs b/examples/highlight_title.rs index 6ed3817f..7f6ccb77 100644 --- a/examples/highlight_title.rs +++ b/examples/highlight_title.rs @@ -42,8 +42,7 @@ fn main() { ); let message = &[ - Group::new() - .element(Level::ERROR.title("mismatched types").id("E0308")) + Group::with_title(Level::ERROR.title("mismatched types").id("E0308")) .element( Snippet::source(source) .fold(true) @@ -60,15 +59,13 @@ fn main() { ), ) .element(Level::NOTE.pre_styled_title(&title)), - Group::new() - .element(Level::NOTE.title("function defined here")) - .element( - Snippet::source(source) - .fold(true) - .path("$DIR/highlighting.rs") - .annotation(AnnotationKind::Context.span(200..333).label("")) - .annotation(AnnotationKind::Primary.span(194..199)), - ), + Group::with_title(Level::NOTE.title("function defined here")).element( + Snippet::source(source) + .fold(true) + .path("$DIR/highlighting.rs") + .annotation(AnnotationKind::Context.span(200..333).label("")) + .annotation(AnnotationKind::Primary.span(194..199)), + ), ]; let renderer = Renderer::styled().anonymized_line_numbers(true); diff --git a/examples/id_hyperlink.rs b/examples/id_hyperlink.rs index 2d49b275..6259e4d1 100644 --- a/examples/id_hyperlink.rs +++ b/examples/id_hyperlink.rs @@ -7,29 +7,28 @@ fn main() { let () = 4; //~ ERROR } "#; - let message = &[Group::new() - .element( - Level::ERROR - .title("mismatched types") - .id("E0308") - .id_url("https://doc.rust-lang.org/error_codes/E0308.html"), - ) - .element( - Snippet::source(source) - .line_start(1) - .path("$DIR/terminal_urls.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(59..61) - .label("expected integer, found `()`"), - ) - .annotation( - AnnotationKind::Context - .span(64..65) - .label("this expression has type `{integer}`"), - ), - )]; + let message = &[Group::with_title( + Level::ERROR + .title("mismatched types") + .id("E0308") + .id_url("https://doc.rust-lang.org/error_codes/E0308.html"), + ) + .element( + Snippet::source(source) + .line_start(1) + .path("$DIR/terminal_urls.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(59..61) + .label("expected integer, found `()`"), + ) + .annotation( + AnnotationKind::Context + .span(64..65) + .label("this expression has type `{integer}`"), + ), + )]; let renderer = Renderer::styled().theme(OutputTheme::Unicode); anstream::println!("{}", renderer.render(message)); diff --git a/examples/multislice.rs b/examples/multislice.rs index 9393aadb..35b745c1 100644 --- a/examples/multislice.rs +++ b/examples/multislice.rs @@ -1,8 +1,7 @@ use annotate_snippets::{Annotation, Group, Level, Renderer, Snippet}; fn main() { - let message = &[Group::new() - .element(Level::ERROR.title("mismatched types")) + let message = &[Group::with_title(Level::ERROR.title("mismatched types")) .element( Snippet::>::source("Foo") .line_start(51) diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 9d89026c..fe29822f 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -20,23 +20,22 @@ //! "#; //! //! -//! Group::new() -//! .element( -//! Level::ERROR -//! .title("unresolved import `baz::zed`") -//! .id("E0432") -//! ) -//! .element( -//! Snippet::source(source) -//! .path("temp.rs") -//! .line_start(1) -//! .fold(true) -//! .annotation( -//! AnnotationKind::Primary -//! .span(10..13) -//! .label("could not find `zed` in `baz`"), -//! ) -//! ); +//! Group::with_title( +//! Level::ERROR +//! .title("unresolved import `baz::zed`") +//! .id("E0432") +//! ) +//! .element( +//! Snippet::source(source) +//! .path("temp.rs") +//! .line_start(1) +//! .fold(true) +//! .annotation( +//! AnnotationKind::Primary +//! .span(10..13) +//! .label("could not find `zed` in `baz`"), +//! ) +//! ); //! ``` mod margin; @@ -275,16 +274,7 @@ impl Renderer { if og_primary_path.is_none() && primary_path.is_some() { og_primary_path = primary_path; } - let level = group.primary_level.clone().unwrap_or_else(|| { - group - .elements - .first() - .and_then(|s| match &s { - Element::Title(title) => Some(title.level.clone()), - _ => None, - }) - .unwrap_or(Level::ERROR) - }); + let level = group.primary_level.clone(); let mut source_map_annotated_lines = VecDeque::new(); let mut max_depth = 0; for e in &group.elements { diff --git a/src/snippet.rs b/src/snippet.rs index 8206f600..3045b2a7 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -20,20 +20,21 @@ pub(crate) struct Id<'a> { /// An [`Element`] container #[derive(Clone, Debug)] pub struct Group<'a> { - pub(crate) primary_level: Option>, + pub(crate) primary_level: Level<'a>, pub(crate) elements: Vec>, } -impl Default for Group<'_> { - fn default() -> Self { - Self::new() +impl<'a> Group<'a> { + /// Create group with a title, deriving the primary [`Level`] for [`Annotation`]s from it + pub fn with_title(title: Title<'a>) -> Self { + let level = title.level.clone(); + Self::with_level(level).element(title) } -} -impl<'a> Group<'a> { - pub fn new() -> Self { + /// Create a title-less group with a primary [`Level`] for [`Annotation`]s + pub fn with_level(level: Level<'a>) -> Self { Self { - primary_level: None, + primary_level: level, elements: vec![], } } @@ -48,15 +49,6 @@ impl<'a> Group<'a> { self } - /// Set the primary [`Level`] for this [`Group`]. - /// - /// If not specified, use the [`Level`] of the first element in a [`Group`] - /// if it is a [`Title`]. If not it will default to [`Level::ERROR`]. - pub fn primary_level(mut self, level: Level<'a>) -> Self { - self.primary_level = Some(level); - self - } - pub fn is_empty(&self) -> bool { self.elements.is_empty() } @@ -277,7 +269,7 @@ impl<'a> Annotation<'a> { pub enum AnnotationKind { /// Match the primary [`Level`] of the group. /// - /// See [`Group::primary_level`] for details about how this is determined + /// See [`Group::with_level`] for details about how this is determined Primary, /// Additional context to explain the [`Primary`][Self::Primary] /// [`Annotation`] diff --git a/tests/color/ann_eof.rs b/tests/color/ann_eof.rs index e550ba55..d188fd1a 100644 --- a/tests/color/ann_eof.rs +++ b/tests/color/ann_eof.rs @@ -4,14 +4,14 @@ use snapbox::{assert_data_eq, file}; #[test] fn case() { - let input = &[Group::new() - .element(Level::ERROR.title("expected `.`, `=`")) - .element( + let input = &[ + Group::with_title(Level::ERROR.title("expected `.`, `=`")).element( Snippet::source("asdf") .path("Cargo.toml") .line_start(1) .annotation(AnnotationKind::Primary.span(4..4).label("")), - )]; + ), + ]; let expected = file!["ann_eof.term.svg"]; let renderer = Renderer::styled(); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/color/ann_insertion.rs b/tests/color/ann_insertion.rs index 73dd7d80..a0748e59 100644 --- a/tests/color/ann_insertion.rs +++ b/tests/color/ann_insertion.rs @@ -4,14 +4,14 @@ use snapbox::{assert_data_eq, file}; #[test] fn case() { - let input = &[Group::new() - .element(Level::ERROR.title("expected `.`, `=`")) - .element( + let input = &[ + Group::with_title(Level::ERROR.title("expected `.`, `=`")).element( Snippet::source("asf") .path("Cargo.toml") .line_start(1) .annotation(AnnotationKind::Primary.span(2..2).label("'d' belongs here")), - )]; + ), + ]; let expected = file!["ann_insertion.term.svg"]; let renderer = Renderer::styled(); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/color/ann_multiline.rs b/tests/color/ann_multiline.rs index 29d4c309..1801c3bc 100644 --- a/tests/color/ann_multiline.rs +++ b/tests/color/ann_multiline.rs @@ -9,23 +9,22 @@ fn case() { } = body[body_idx] "#; - let input = &[Group::new() - .element( - Level::ERROR - .title("pattern does not mention fields `lineno`, `content`") - .id("E0027"), - ) - .element( - Snippet::source(source) - .path("src/display_list.rs") - .line_start(139) - .fold(false) - .annotation( - AnnotationKind::Primary - .span(31..128) - .label("missing fields `lineno`, `content`"), - ), - )]; + let input = &[Group::with_title( + Level::ERROR + .title("pattern does not mention fields `lineno`, `content`") + .id("E0027"), + ) + .element( + Snippet::source(source) + .path("src/display_list.rs") + .line_start(139) + .fold(false) + .annotation( + AnnotationKind::Primary + .span(31..128) + .label("missing fields `lineno`, `content`"), + ), + )]; let expected = file!["ann_multiline.term.svg"]; let renderer = Renderer::styled(); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/color/ann_multiline2.rs b/tests/color/ann_multiline2.rs index cf21e5ea..b8fa6152 100644 --- a/tests/color/ann_multiline2.rs +++ b/tests/color/ann_multiline2.rs @@ -9,9 +9,8 @@ of an edge case of an annotation overflowing to exactly one character on next line. "#; - let input = &[Group::new() - .element(Level::ERROR.title("spacing error found").id("E####")) - .element( + let input = &[ + Group::with_title(Level::ERROR.title("spacing error found").id("E####")).element( Snippet::source(source) .path("foo.txt") .line_start(26) @@ -21,7 +20,8 @@ to exactly one character on next line. .span(11..19) .label("this should not be on separate lines"), ), - )]; + ), + ]; let expected = file!["ann_multiline2.term.svg"]; let renderer = Renderer::styled(); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/color/ann_removed_nl.rs b/tests/color/ann_removed_nl.rs index 68ec8326..e13b4bd5 100644 --- a/tests/color/ann_removed_nl.rs +++ b/tests/color/ann_removed_nl.rs @@ -4,14 +4,14 @@ use snapbox::{assert_data_eq, file}; #[test] fn case() { - let input = &[Group::new() - .element(Level::ERROR.title("expected `.`, `=`")) - .element( + let input = &[ + Group::with_title(Level::ERROR.title("expected `.`, `=`")).element( Snippet::source("asdf") .path("Cargo.toml") .line_start(1) .annotation(AnnotationKind::Primary.span(4..5).label("")), - )]; + ), + ]; let expected = file!["ann_removed_nl.term.svg"]; let renderer = Renderer::styled(); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/color/ensure_emoji_highlight_width.rs b/tests/color/ensure_emoji_highlight_width.rs index bc22f9ab..c454e238 100644 --- a/tests/color/ensure_emoji_highlight_width.rs +++ b/tests/color/ensure_emoji_highlight_width.rs @@ -7,8 +7,7 @@ fn case() { let source = r#""haha this isn't a valid name 🐛" = { package = "libc", version = "0.1" } "#; - let input = &[Group::new() - .element(Level::ERROR.title("invalid character ` ` in package name: `haha this isn't a valid name 🐛`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters)")) + let input = &[Group::with_title(Level::ERROR.title("invalid character ` ` in package name: `haha this isn't a valid name 🐛`, characters must be Unicode XID characters (numbers, `-`, `_`, or most letters)")) .element( Snippet::source(source) .path("") diff --git a/tests/color/fold_ann_multiline.rs b/tests/color/fold_ann_multiline.rs index 1c035f41..68fd4f1b 100644 --- a/tests/color/fold_ann_multiline.rs +++ b/tests/color/fold_ann_multiline.rs @@ -28,9 +28,8 @@ fn case() { } "#; - let input = &[Group::new() - .element(Level::ERROR.title("mismatched types").id("E0308")) - .element( + let input = &[ + Group::with_title(Level::ERROR.title("mismatched types").id("E0308")).element( Snippet::source(source) .path("src/format.rs") .line_start(51) @@ -43,7 +42,8 @@ fn case() { .span(22..766) .label("expected enum `std::option::Option`, found ()"), ), - )]; + ), + ]; let expected = file!["fold_ann_multiline.term.svg"]; let renderer = Renderer::styled(); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/color/fold_bad_origin_line.rs b/tests/color/fold_bad_origin_line.rs index 9e4c5c0c..99da3c5d 100644 --- a/tests/color/fold_bad_origin_line.rs +++ b/tests/color/fold_bad_origin_line.rs @@ -9,7 +9,7 @@ fn case() { invalid syntax "#; - let input = &[Group::new().element(Level::ERROR.title("")).element( + let input = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source(source) .path("path/to/error.rs") .line_start(1) diff --git a/tests/color/fold_leading.rs b/tests/color/fold_leading.rs index 0e4ae61d..e941c805 100644 --- a/tests/color/fold_leading.rs +++ b/tests/color/fold_leading.rs @@ -17,19 +17,18 @@ edition = "2021" workspace = 20 "#; - let input = &[Group::new() - .element( - Level::ERROR - .title("invalid type: integer `20`, expected a bool") - .id("E0308"), - ) - .element( - Snippet::source(source) - .path("Cargo.toml") - .line_start(1) - .fold(true) - .annotation(AnnotationKind::Primary.span(132..134).label("")), - )]; + let input = &[Group::with_title( + Level::ERROR + .title("invalid type: integer `20`, expected a bool") + .id("E0308"), + ) + .element( + Snippet::source(source) + .path("Cargo.toml") + .line_start(1) + .fold(true) + .annotation(AnnotationKind::Primary.span(132..134).label("")), + )]; let expected = file!["fold_leading.term.svg"]; let renderer = Renderer::styled(); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/color/fold_trailing.rs b/tests/color/fold_trailing.rs index 6421dd45..9c85d873 100644 --- a/tests/color/fold_trailing.rs +++ b/tests/color/fold_trailing.rs @@ -16,19 +16,18 @@ rust-version = "1.70" edition = "2021" "#; - let input = &[Group::new() - .element( - Level::ERROR - .title("invalid type: integer `20`, expected a lints table") - .id("E0308"), - ) - .element( - Snippet::source(source) - .path("Cargo.toml") - .line_start(1) - .fold(true) - .annotation(AnnotationKind::Primary.span(8..10).label("")), - )]; + let input = &[Group::with_title( + Level::ERROR + .title("invalid type: integer `20`, expected a lints table") + .id("E0308"), + ) + .element( + Snippet::source(source) + .path("Cargo.toml") + .line_start(1) + .fold(true) + .annotation(AnnotationKind::Primary.span(8..10).label("")), + )]; let expected = file!["fold_trailing.term.svg"]; let renderer = Renderer::styled(); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/color/issue_9.rs b/tests/color/issue_9.rs index f42c30b9..0ac5d4de 100644 --- a/tests/color/issue_9.rs +++ b/tests/color/issue_9.rs @@ -4,7 +4,7 @@ use snapbox::{assert_data_eq, file}; #[test] fn case() { - let input = &[Group::new().element(Level::ERROR.title("expected one of `.`, `;`, `?`, or an operator, found `for`")) + let input = &[Group::with_title(Level::ERROR.title("expected one of `.`, `;`, `?`, or an operator, found `for`")) .element( Snippet::source("let x = vec![1];") .path("/code/rust/src/test/ui/annotate-snippet/suggestion.rs") diff --git a/tests/color/multiline_removal_suggestion.rs b/tests/color/multiline_removal_suggestion.rs index fbaf4fff..6a98ec40 100644 --- a/tests/color/multiline_removal_suggestion.rs +++ b/tests/color/multiline_removal_suggestion.rs @@ -65,8 +65,7 @@ fn main() {} "#; let input = &[ - Group::new() - .element( + Group::with_title( Level::ERROR .title("`(bool, HashSet)` is not an iterator") .id("E0277"), @@ -88,14 +87,13 @@ fn main() {} .element( Level::NOTE.title("required for `(bool, HashSet)` to implement `IntoIterator`"), ), - Group::new() - .element(Level::NOTE.title("required by a bound in `flatten`")) + Group::with_title(Level::NOTE.title("required by a bound in `flatten`")) .element( Origin::new("/rustc/FAKE_PREFIX/library/core/src/iter/traits/iterator.rs") .line(1556) .char_column(4), ), - Group::new().element(Level::HELP.title("consider removing this method call, as the receiver has type `std::vec::IntoIter>` and `std::vec::IntoIter>: Iterator` trivially holds")).element( + Group::with_title(Level::HELP.title("consider removing this method call, as the receiver has type `std::vec::IntoIter>` and `std::vec::IntoIter>: Iterator` trivially holds")).element( Snippet::source(source) .path("$DIR/multiline-removal-suggestion.rs") .fold(true) diff --git a/tests/color/multiple_annotations.rs b/tests/color/multiple_annotations.rs index 464d7672..4533019a 100644 --- a/tests/color/multiple_annotations.rs +++ b/tests/color/multiple_annotations.rs @@ -15,7 +15,7 @@ fn case() { } "#; - let input = &[Group::new().element(Level::ERROR.title("")).element( + let input = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source(source) .line_start(96) .annotation( diff --git a/tests/color/simple.rs b/tests/color/simple.rs index 17287d94..9e35cf58 100644 --- a/tests/color/simple.rs +++ b/tests/color/simple.rs @@ -9,23 +9,24 @@ fn case() { for line in &self.body { "#; - let input = &[Group::new() - .element(Level::ERROR.title("expected one of `.`, `;`, `?`, or an operator, found `for`")) - .element( - Snippet::source(source) - .path("src/format_color.rs") - .line_start(169) - .annotation( - AnnotationKind::Primary - .span(20..23) - .label("unexpected token"), - ) - .annotation( - AnnotationKind::Context - .span(10..11) - .label("expected one of `.`, `;`, `?`, or an operator here"), - ), - )]; + let input = &[Group::with_title( + Level::ERROR.title("expected one of `.`, `;`, `?`, or an operator, found `for`"), + ) + .element( + Snippet::source(source) + .path("src/format_color.rs") + .line_start(169) + .annotation( + AnnotationKind::Primary + .span(20..23) + .label("unexpected token"), + ) + .annotation( + AnnotationKind::Context + .span(10..11) + .label("expected one of `.`, `;`, `?`, or an operator here"), + ), + )]; let expected = file!["simple.term.svg"]; let renderer = Renderer::styled(); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/color/strip_line.rs b/tests/color/strip_line.rs index fbb72506..8e30ac4e 100644 --- a/tests/color/strip_line.rs +++ b/tests/color/strip_line.rs @@ -6,9 +6,8 @@ use snapbox::{assert_data_eq, file}; fn case() { let source = r#" let _: () = 42;"#; - let input = &[Group::new() - .element(Level::ERROR.title("mismatched types").id("E0308")) - .element( + let input = &[ + Group::with_title(Level::ERROR.title("mismatched types").id("E0308")).element( Snippet::source(source) .path("$DIR/whitespace-trimming.rs") .line_start(4) @@ -17,7 +16,8 @@ fn case() { .span(192..194) .label("expected (), found integer"), ), - )]; + ), + ]; let expected = file!["strip_line.term.svg"]; let renderer = Renderer::styled().anonymized_line_numbers(true); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/color/strip_line_char.rs b/tests/color/strip_line_char.rs index 090e1dba..e78b530b 100644 --- a/tests/color/strip_line_char.rs +++ b/tests/color/strip_line_char.rs @@ -6,9 +6,8 @@ use snapbox::{assert_data_eq, file}; fn case() { let source = r#" let _: () = 42ñ"#; - let input = &[Group::new() - .element(Level::ERROR.title("mismatched types").id("E0308")) - .element( + let input = &[ + Group::with_title(Level::ERROR.title("mismatched types").id("E0308")).element( Snippet::source(source) .path("$DIR/whitespace-trimming.rs") .line_start(4) @@ -17,7 +16,8 @@ fn case() { .span(192..194) .label("expected (), found integer"), ), - )]; + ), + ]; let expected = file!["strip_line_char.term.svg"]; let renderer = Renderer::styled().anonymized_line_numbers(true); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/color/strip_line_non_ws.rs b/tests/color/strip_line_non_ws.rs index da65e6a3..7ef3ad57 100644 --- a/tests/color/strip_line_non_ws.rs +++ b/tests/color/strip_line_non_ws.rs @@ -7,9 +7,8 @@ fn case() { let source = r#" let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = 42; let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); let _: () = (); "#; - let input = &[Group::new() - .element(Level::ERROR.title("mismatched types").id("E0308")) - .element( + let input = &[ + Group::with_title(Level::ERROR.title("mismatched types").id("E0308")).element( Snippet::source(source) .path("$DIR/non-whitespace-trimming.rs") .line_start(4) @@ -23,7 +22,8 @@ fn case() { .span(232..234) .label("expected due to this"), ), - )]; + ), + ]; let expected = file!["strip_line_non_ws.term.svg"]; let renderer = Renderer::styled().anonymized_line_numbers(true); assert_data_eq!(renderer.render(input), expected); diff --git a/tests/formatter.rs b/tests/formatter.rs index c538a9e8..a4c6f6ff 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -5,7 +5,7 @@ use snapbox::{assert_data_eq, str}; #[test] fn test_i_29() { - let snippets = &[Group::new().element(Level::ERROR.title("oops")).element( + let snippets = &[Group::with_title(Level::ERROR.title("oops")).element( Snippet::source("First line\r\nSecond oops line") .path("") .annotation(AnnotationKind::Primary.span(19..23).label("oops")) @@ -25,7 +25,7 @@ error: oops #[test] fn test_point_to_double_width_characters() { - let snippets = &[Group::new().element(Level::ERROR.title("")).element( + let snippets = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source("こんにちは、世界") .path("") .annotation(AnnotationKind::Primary.span(18..24).label("world")), @@ -45,7 +45,7 @@ error: #[test] fn test_point_to_double_width_characters_across_lines() { - let snippets = &[Group::new().element(Level::ERROR.title("")).element( + let snippets = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source("おはよう\nございます") .path("") .annotation(AnnotationKind::Primary.span(6..22).label("Good morning")), @@ -67,7 +67,7 @@ error: #[test] fn test_point_to_double_width_characters_multiple() { - let snippets = &[Group::new().element(Level::ERROR.title("")).element( + let snippets = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source("お寿司\n食べたい🍣") .path("") .annotation(AnnotationKind::Primary.span(0..9).label("Sushi1")) @@ -90,7 +90,7 @@ error: #[test] fn test_point_to_double_width_characters_mixed() { - let snippets = &[Group::new().element(Level::ERROR.title("")).element( + let snippets = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source("こんにちは、新しいWorld!") .path("") .annotation(AnnotationKind::Primary.span(18..32).label("New world")), @@ -110,7 +110,9 @@ error: #[test] fn test_format_title() { - let input = &[Group::new().element(Level::ERROR.title("This is a title").id("E0001"))]; + let input = &[Group::with_title( + Level::ERROR.title("This is a title").id("E0001"), + )]; let expected = str![r#"error[E0001]: This is a title"#]; let renderer = Renderer::plain(); @@ -120,8 +122,7 @@ fn test_format_title() { #[test] fn test_format_snippet_only() { let source = "This is line 1\nThis is line 2"; - let input = &[Group::new() - .element(Level::ERROR.title("")) + let input = &[Group::with_title(Level::ERROR.title("")) .element(Snippet::>::source(source).line_start(5402))]; let expected = str![[r#" @@ -138,8 +139,7 @@ error: fn test_format_snippets_continuation() { let src_0 = "This is slice 1"; let src_1 = "This is slice 2"; - let input = &[Group::new() - .element(Level::ERROR.title("")) + let input = &[Group::with_title(Level::ERROR.title("")) .element( Snippet::>::source(src_0) .line_start(5402) @@ -171,7 +171,7 @@ fn test_format_snippet_annotation_standalone() { let source = [line_1, line_2].join("\n"); // In line 2 let range = 22..24; - let input = &[Group::new().element(Level::ERROR.title("")).element( + let input = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source(&source).line_start(5402).annotation( AnnotationKind::Context .span(range.clone()) @@ -191,8 +191,7 @@ error: #[test] fn test_format_footer_title() { - let input = &[Group::new() - .element(Level::ERROR.title("")) + let input = &[Group::with_title(Level::ERROR.title("")) .element(Level::ERROR.title("This __is__ a title"))]; let expected = str![[r#" error: @@ -208,7 +207,7 @@ error: fn test_i26() { let source = "short"; let label = "label"; - let input = &[Group::new().element(Level::ERROR.title("")).element( + let input = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source(source).line_start(0).annotation( AnnotationKind::Primary .span(0..source.len() + 2) @@ -222,8 +221,7 @@ fn test_i26() { #[test] fn test_source_content() { let source = "This is an example\nof content lines"; - let input = &[Group::new() - .element(Level::ERROR.title("")) + let input = &[Group::with_title(Level::ERROR.title("")) .element(Snippet::>::source(source).line_start(56))]; let expected = str![[r#" error: @@ -238,7 +236,7 @@ error: #[test] fn test_source_annotation_standalone_singleline() { let source = "tests"; - let input = &[Group::new().element(Level::ERROR.title("")).element( + let input = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source(source) .line_start(1) .annotation(AnnotationKind::Context.span(0..5).label("Example string")), @@ -256,7 +254,7 @@ error: #[test] fn test_source_annotation_standalone_multiline() { let source = "tests"; - let input = &[Group::new().element(Level::ERROR.title("")).element( + let input = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source(source) .line_start(1) .annotation(AnnotationKind::Context.span(0..5).label("Example string")) @@ -277,8 +275,7 @@ error: #[test] fn test_only_source() { - let input = &[Group::new() - .element(Level::ERROR.title("")) + let input = &[Group::with_title(Level::ERROR.title("")) .element(Snippet::>::source("").path("file.rs"))]; let expected = str![[r#" error: @@ -293,8 +290,7 @@ error: #[test] fn test_anon_lines() { let source = "This is an example\nof content lines\n\nabc"; - let input = &[Group::new() - .element(Level::ERROR.title("")) + let input = &[Group::with_title(Level::ERROR.title("")) .element(Snippet::>::source(source).line_start(56))]; let expected = str![[r#" error: @@ -310,7 +306,7 @@ LL | abc #[test] fn issue_130() { - let input = &[Group::new().element(Level::ERROR.title("dummy")).element( + let input = &[Group::with_title(Level::ERROR.title("dummy")).element( Snippet::source("foo\nbar\nbaz") .path("file/path") .line_start(3) @@ -337,7 +333,7 @@ fn unterminated_string_multiline() { a\" // ... "; - let input = &[Group::new().element(Level::ERROR.title("")).element( + let input = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source(source) .path("file/path") .line_start(3) @@ -360,7 +356,7 @@ error: #[test] fn char_and_nl_annotate_char() { let source = "a\r\nb"; - let input = &[Group::new().element(Level::ERROR.title("")).element( + let input = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source(source) .path("file/path") .line_start(3) @@ -382,7 +378,7 @@ error: #[test] fn char_eol_annotate_char() { let source = "a\r\nb"; - let input = &[Group::new().element(Level::ERROR.title("")).element( + let input = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source(source) .path("file/path") .line_start(3) @@ -403,7 +399,7 @@ error: #[test] fn char_eol_annotate_char_double_width() { - let snippets = &[Group::new().element(Level::ERROR.title("")).element( + let snippets = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source("こん\r\nにちは\r\n世界") .path("") .annotation(AnnotationKind::Primary.span(3..8)), @@ -428,7 +424,7 @@ error: #[test] fn annotate_eol() { let source = "a\r\nb"; - let input = &[Group::new().element(Level::ERROR.title("")).element( + let input = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source(source) .path("file/path") .line_start(3) @@ -450,7 +446,7 @@ error: #[test] fn annotate_eol2() { let source = "a\r\nb"; - let input = &[Group::new().element(Level::ERROR.title("")).element( + let input = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source(source) .path("file/path") .line_start(3) @@ -473,7 +469,7 @@ error: #[test] fn annotate_eol3() { let source = "a\r\nb"; - let input = &[Group::new().element(Level::ERROR.title("")).element( + let input = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source(source) .path("file/path") .line_start(3) @@ -496,7 +492,7 @@ error: #[test] fn annotate_eol4() { let source = "a\r\nb"; - let input = &[Group::new().element(Level::ERROR.title("")).element( + let input = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source(source) .path("file/path") .line_start(3) @@ -517,7 +513,7 @@ error: #[test] fn annotate_eol_double_width() { - let snippets = &[Group::new().element(Level::ERROR.title("")).element( + let snippets = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source("こん\r\nにちは\r\n世界") .path("") .annotation(AnnotationKind::Primary.span(7..8)), @@ -542,7 +538,7 @@ error: #[test] fn multiline_eol_start() { let source = "a\r\nb"; - let input = &[Group::new().element(Level::ERROR.title("")).element( + let input = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source(source) .path("file/path") .line_start(3) @@ -565,7 +561,7 @@ error: #[test] fn multiline_eol_start2() { let source = "a\r\nb"; - let input = &[Group::new().element(Level::ERROR.title("")).element( + let input = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source(source) .path("file/path") .line_start(3) @@ -588,7 +584,7 @@ error: #[test] fn multiline_eol_start3() { let source = "a\nb"; - let input = &[Group::new().element(Level::ERROR.title("")).element( + let input = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source(source) .path("file/path") .line_start(3) @@ -610,7 +606,7 @@ error: #[test] fn multiline_eol_start_double_width() { - let snippets = &[Group::new().element(Level::ERROR.title("")).element( + let snippets = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source("こん\r\nにちは\r\n世界") .path("") .annotation(AnnotationKind::Primary.span(7..11)), @@ -635,7 +631,7 @@ error: #[test] fn multiline_eol_start_eol_end() { let source = "a\nb\nc"; - let input = &[Group::new().element(Level::ERROR.title("")).element( + let input = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source(source) .path("file/path") .line_start(3) @@ -659,7 +655,7 @@ error: #[test] fn multiline_eol_start_eol_end2() { let source = "a\r\nb\r\nc"; - let input = &[Group::new().element(Level::ERROR.title("")).element( + let input = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source(source) .path("file/path") .line_start(3) @@ -683,7 +679,7 @@ error: #[test] fn multiline_eol_start_eol_end3() { let source = "a\r\nb\r\nc"; - let input = &[Group::new().element(Level::ERROR.title("")).element( + let input = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source(source) .path("file/path") .line_start(3) @@ -707,7 +703,7 @@ error: #[test] fn multiline_eol_start_eof_end() { let source = "a\r\nb"; - let input = &[Group::new().element(Level::ERROR.title("")).element( + let input = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source(source) .path("file/path") .line_start(3) @@ -730,7 +726,7 @@ error: #[test] fn multiline_eol_start_eof_end_double_width() { let source = "ん\r\nに"; - let input = &[Group::new().element(Level::ERROR.title("")).element( + let input = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source(source) .path("file/path") .line_start(3) @@ -753,9 +749,8 @@ error: #[test] fn two_single_line_same_line() { let source = r#"bar = { version = "0.1.0", optional = true }"#; - let input = &[Group::new() - .element(Level::ERROR.title("unused optional dependency")) - .element( + let input = &[ + Group::with_title(Level::ERROR.title("unused optional dependency")).element( Snippet::source(source) .path("Cargo.toml") .line_start(4) @@ -769,7 +764,8 @@ fn two_single_line_same_line() { .span(27..42) .label("This should also be long but not too long"), ), - )]; + ), + ]; let expected = str![[r#" error: unused optional dependency --> Cargo.toml:4:1 @@ -790,9 +786,8 @@ this is another line so is this bar = { version = "0.1.0", optional = true } "#; - let input = &[Group::new() - .element(Level::ERROR.title("unused optional dependency")) - .element( + let input = &[ + Group::with_title(Level::ERROR.title("unused optional dependency")).element( Snippet::source(source) .line_start(4) .annotation( @@ -805,7 +800,8 @@ bar = { version = "0.1.0", optional = true } .span(27..42) .label("This should also be long but not too long"), ), - )]; + ), + ]; let expected = str![[r#" error: unused optional dependency | @@ -829,9 +825,8 @@ this is another line so is this bar = { version = "0.1.0", optional = true } "#; - let input = &[Group::new() - .element(Level::ERROR.title("unused optional dependency")) - .element( + let input = &[ + Group::with_title(Level::ERROR.title("unused optional dependency")).element( Snippet::source(source) .line_start(4) .annotation( @@ -849,7 +844,8 @@ bar = { version = "0.1.0", optional = true } .span(27..42) .label("This should also be long but not too long"), ), - )]; + ), + ]; let expected = str![[r#" error: unused optional dependency | @@ -877,9 +873,8 @@ so is this bar = { version = "0.1.0", optional = true } this is another line "#; - let input = &[Group::new() - .element(Level::ERROR.title("unused optional dependency")) - .element( + let input = &[ + Group::with_title(Level::ERROR.title("unused optional dependency")).element( Snippet::source(source) .line_start(4) .annotation( @@ -902,7 +897,8 @@ this is another line .span(27..42) .label("This should also be long but not too long"), ), - )]; + ), + ]; let expected = str![[r#" error: unused optional dependency | @@ -928,7 +924,7 @@ error: unused optional dependency #[test] fn origin_correct_start_line() { let source = "aaa\nbbb\nccc\nddd\n"; - let input = &[Group::new().element(Level::ERROR.title("title")).element( + let input = &[Group::with_title(Level::ERROR.title("title")).element( Snippet::source(source) .path("origin.txt") .fold(false) @@ -952,7 +948,7 @@ error: title #[test] fn origin_correct_mid_line() { let source = "aaa\nbbb\nccc\nddd\n"; - let input = &[Group::new().element(Level::ERROR.title("title")).element( + let input = &[Group::with_title(Level::ERROR.title("title")).element( Snippet::source(source) .path("origin.txt") .fold(false) @@ -981,31 +977,29 @@ error: title fn two_suggestions_same_span() { let source = r#" A.foo();"#; let input_new = &[ - Group::new() - .element( - Level::ERROR - .title("expected value, found enum `A`") - .id("E0423"), - ) - .element( - Snippet::source(source) - .fold(true) - .annotation(AnnotationKind::Primary.span(4..5)), - ), - Group::new() - .element( - Level::HELP.title("you might have meant to use one of the following enum variants"), - ) - .element( - Snippet::source(source) - .fold(true) - .patch(Patch::new(4..5, "(A::Tuple())")), - ) - .element( - Snippet::source(source) - .fold(true) - .patch(Patch::new(4..5, "A::Unit")), - ), + Group::with_title( + Level::ERROR + .title("expected value, found enum `A`") + .id("E0423"), + ) + .element( + Snippet::source(source) + .fold(true) + .annotation(AnnotationKind::Primary.span(4..5)), + ), + Group::with_title( + Level::HELP.title("you might have meant to use one of the following enum variants"), + ) + .element( + Snippet::source(source) + .fold(true) + .patch(Patch::new(4..5, "(A::Tuple())")), + ) + .element( + Snippet::source(source) + .fold(true) + .patch(Patch::new(4..5, "A::Unit")), + ), ]; let expected = str![[r#" @@ -1048,7 +1042,7 @@ fn main() { banana::Chaenomeles.pick() }"#; let input_new = - &[Group::new().element(Level::ERROR + &[Group::with_title(Level::ERROR .title("no method named `pick` found for struct `Chaenomeles` in the current scope") .id("E0599")).element( Snippet::source(source) @@ -1065,8 +1059,7 @@ fn main() { .label("method not found in `Chaenomeles`"), ), ), - Group::new() - .element(Level::HELP.title( + Group::with_title(Level::HELP.title( "the following traits which provide `pick` are implemented but not in scope; perhaps you want to import one of them", )) .element( @@ -1104,27 +1097,24 @@ fn single_line_non_overlapping_suggestions() { let source = r#" A.foo();"#; let input_new = &[ - Group::new() - .element( - Level::ERROR - .title("expected value, found enum `A`") - .id("E0423"), - ) - .element( - Snippet::source(source) - .fold(true) - .line_start(1) - .annotation(AnnotationKind::Primary.span(4..5)), - ), - Group::new() - .element(Level::HELP.title("make these changes and things will work")) - .element( - Snippet::source(source) - .fold(true) - .fold(true) - .patch(Patch::new(4..5, "(A::Tuple())")) - .patch(Patch::new(6..9, "bar")), - ), + Group::with_title( + Level::ERROR + .title("expected value, found enum `A`") + .id("E0423"), + ) + .element( + Snippet::source(source) + .fold(true) + .line_start(1) + .annotation(AnnotationKind::Primary.span(4..5)), + ), + Group::with_title(Level::HELP.title("make these changes and things will work")).element( + Snippet::source(source) + .fold(true) + .fold(true) + .patch(Patch::new(4..5, "(A::Tuple())")) + .patch(Patch::new(6..9, "bar")), + ), ]; let expected = str![[r#" @@ -1147,23 +1137,19 @@ LL + (A::Tuple()).bar(); fn single_line_non_overlapping_suggestions2() { let source = r#" ThisIsVeryLong.foo();"#; let input_new = &[ - Group::new() - .element(Level::ERROR.title("Found `ThisIsVeryLong`").id("E0423")) - .element( - Snippet::source(source) - .fold(true) - .line_start(1) - .annotation(AnnotationKind::Primary.span(4..18)), - ), - Group::new() - .element(Level::HELP.title("make these changes and things will work")) - .element( - Snippet::source(source) - .fold(true) - .fold(true) - .patch(Patch::new(4..18, "(A::Tuple())")) - .patch(Patch::new(19..22, "bar")), - ), + Group::with_title(Level::ERROR.title("Found `ThisIsVeryLong`").id("E0423")).element( + Snippet::source(source) + .fold(true) + .line_start(1) + .annotation(AnnotationKind::Primary.span(4..18)), + ), + Group::with_title(Level::HELP.title("make these changes and things will work")).element( + Snippet::source(source) + .fold(true) + .fold(true) + .patch(Patch::new(4..18, "(A::Tuple())")) + .patch(Patch::new(19..22, "bar")), + ), ]; let expected = str![[r#" @@ -1193,50 +1179,46 @@ fn multiple_replacements() { "#; let input_new = &[ - Group::new() - .element( - Level::ERROR - .title( - "cannot borrow `*self` as mutable because it is also borrowed as immutable", - ) - .id("E0502"), - ) - .element( - Snippet::source(source) - .line_start(1) - .fold(true) - .annotation( - AnnotationKind::Primary - .span(49..59) - .label("mutable borrow occurs here"), - ) - .annotation( - AnnotationKind::Primary - .span(13..15) - .label("immutable borrow occurs here"), - ) - .annotation( - AnnotationKind::Primary - .span(26..30) - .label("first borrow occurs due to use of `*self` in closure"), - ) - .annotation( - AnnotationKind::Primary - .span(65..66) - .label("immutable borrow later used here"), - ), - ), - Group::new() - .element( - Level::HELP.title("try explicitly pass `&Self` into the Closure as an argument"), - ) - .element( - Snippet::source(source) - .fold(true) - .patch(Patch::new(14..14, "this: &Self")) - .patch(Patch::new(26..30, "this")) - .patch(Patch::new(66..68, "(self)")), - ), + Group::with_title( + Level::ERROR + .title("cannot borrow `*self` as mutable because it is also borrowed as immutable") + .id("E0502"), + ) + .element( + Snippet::source(source) + .line_start(1) + .fold(true) + .annotation( + AnnotationKind::Primary + .span(49..59) + .label("mutable borrow occurs here"), + ) + .annotation( + AnnotationKind::Primary + .span(13..15) + .label("immutable borrow occurs here"), + ) + .annotation( + AnnotationKind::Primary + .span(26..30) + .label("first borrow occurs due to use of `*self` in closure"), + ) + .annotation( + AnnotationKind::Primary + .span(65..66) + .label("immutable borrow later used here"), + ), + ), + Group::with_title( + Level::HELP.title("try explicitly pass `&Self` into the Closure as an argument"), + ) + .element( + Snippet::source(source) + .fold(true) + .patch(Patch::new(14..14, "this: &Self")) + .patch(Patch::new(26..30, "this")) + .patch(Patch::new(66..68, "(self)")), + ), ]; let expected = str![[r#" error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable @@ -1278,43 +1260,46 @@ fn main() { test1(); }"#; - let input_new = &[Group::new().element(Level::ERROR - .title("cannot borrow `chars` as mutable more than once at a time") - .id("E0499")).element( - Snippet::source(source) - .line_start(1) - .fold(true) - .annotation( - AnnotationKind::Context - .span(65..70) - .label("first mutable borrow occurs here"), - ) - .annotation( - AnnotationKind::Primary - .span(90..95) - .label("second mutable borrow occurs here"), - ) - .annotation( - AnnotationKind::Context - .span(65..79) - .label("first borrow later used here"), - ), - ), - Group::new() - .element( - Level::HELP - .title("if you want to call `next` on a iterator within the loop, consider using `while let`") + let input_new = &[ + Group::with_title( + Level::ERROR + .title("cannot borrow `chars` as mutable more than once at a time") + .id("E0499"), + ) + .element( + Snippet::source(source) + .line_start(1) + .fold(true) + .annotation( + AnnotationKind::Context + .span(65..70) + .label("first mutable borrow occurs here"), ) - .element( - Snippet::source(source) - .fold(true) - .patch(Patch::new( - 55..59, - "let iter = chars.by_ref();\n while let Some(", - )) - .patch(Patch::new(61..79, ") = iter.next()")) - .patch(Patch::new(90..95, "iter")), - )]; + .annotation( + AnnotationKind::Primary + .span(90..95) + .label("second mutable borrow occurs here"), + ) + .annotation( + AnnotationKind::Context + .span(65..79) + .label("first borrow later used here"), + ), + ), + Group::with_title(Level::HELP.title( + "if you want to call `next` on a iterator within the loop, consider using `while let`", + )) + .element( + Snippet::source(source) + .fold(true) + .patch(Patch::new( + 55..59, + "let iter = chars.by_ref();\n while let Some(", + )) + .patch(Patch::new(61..79, ") = iter.next()")) + .patch(Patch::new(90..95, "iter")), + ), + ]; let expected = str![[r#" error[E0499]: cannot borrow `chars` as mutable more than once at a time @@ -1358,40 +1343,34 @@ struct Foo { fn main() {}"#; let input_new = &[ - Group::new() - .element( - Level::ERROR - .title("failed to resolve: use of undeclared crate or module `st`") - .id("E0433"), - ) - .element( - Snippet::source(source).line_start(1).fold(true).annotation( - AnnotationKind::Primary - .span(122..124) - .label("use of undeclared crate or module `st`"), - ), + Group::with_title( + Level::ERROR + .title("failed to resolve: use of undeclared crate or module `st`") + .id("E0433"), + ) + .element( + Snippet::source(source).line_start(1).fold(true).annotation( + AnnotationKind::Primary + .span(122..124) + .label("use of undeclared crate or module `st`"), ), - Group::new() - .element(Level::HELP.title("there is a crate or module with a similar name")) + ), + Group::with_title(Level::HELP.title("there is a crate or module with a similar name")) .element( Snippet::source(source) .fold(true) .patch(Patch::new(122..124, "std")), ), - Group::new() - .element(Level::HELP.title("consider importing this module")) - .element( - Snippet::source(source) - .fold(true) - .patch(Patch::new(1..1, "use std::cell;\n")), - ), - Group::new() - .element(Level::HELP.title("if you import `cell`, refer to it directly")) - .element( - Snippet::source(source) - .fold(true) - .patch(Patch::new(122..126, "")), - ), + Group::with_title(Level::HELP.title("consider importing this module")).element( + Snippet::source(source) + .fold(true) + .patch(Patch::new(1..1, "use std::cell;\n")), + ), + Group::with_title(Level::HELP.title("if you import `cell`, refer to it directly")).element( + Snippet::source(source) + .fold(true) + .patch(Patch::new(122..126, "")), + ), ]; let expected = str![[r#" error[E0433]: failed to resolve: use of undeclared crate or module `st` @@ -1437,38 +1416,35 @@ where fn main() {}"#; let input_new = &[ - Group::new() - .element( - Level::ERROR - .title("the size for values of type `T` cannot be known at compilation time") - .id("E0277"), - ) - .element( - Snippet::source(source) - .line_start(1) - .fold(true) - .annotation( - AnnotationKind::Primary - .span(39..49) - .label("doesn't have a size known at compile-time"), - ) - .annotation( - AnnotationKind::Context - .span(31..32) - .label("this type parameter needs to be `Sized`"), - ), - ), - Group::new() - .element( - Level::HELP.title( - "consider removing the `?Sized` bound to make the type parameter `Sized`", + Group::with_title( + Level::ERROR + .title("the size for values of type `T` cannot be known at compilation time") + .id("E0277"), + ) + .element( + Snippet::source(source) + .line_start(1) + .fold(true) + .annotation( + AnnotationKind::Primary + .span(39..49) + .label("doesn't have a size known at compile-time"), + ) + .annotation( + AnnotationKind::Context + .span(31..32) + .label("this type parameter needs to be `Sized`"), ), - ) - .element( - Snippet::source(source) - .fold(true) - .patch(Patch::new(52..85, "")), - ), + ), + Group::with_title( + Level::HELP + .title("consider removing the `?Sized` bound to make the type parameter `Sized`"), + ) + .element( + Snippet::source(source) + .fold(true) + .patch(Patch::new(52..85, "")), + ), ]; let expected = str![[r#" error[E0277]: the size for values of type `T` cannot be known at compilation time @@ -1508,7 +1484,7 @@ and where } fn main() {}"#; - let input_new = &[Group::new().element(Level::ERROR + let input_new = &[Group::with_title(Level::ERROR .title("the size for values of type `T` cannot be known at compilation time") .id("E0277")).element(Snippet::source(source) .line_start(1) @@ -1524,7 +1500,7 @@ fn main() {}"#; .span(31..32) .label("this type parameter needs to be `Sized`"), )) - ,Group::new().element( + ,Group::with_title( Level::NOTE .title("required by an implicit `Sized` bound in `Wrapper`") ).element( @@ -1537,7 +1513,7 @@ fn main() {}"#; .span(16..17) .label("required by the implicit `Sized` requirement on this type parameter in `Wrapper`"), ) - ), Group::new().element( + ), Group::with_title( Level::HELP .title("you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box`") ) @@ -1557,7 +1533,7 @@ fn main() {}"#; .label("...if indirection were used here: `Box`"), ) - ),Group::new().element( + ),Group::with_title( Level::HELP .title("consider removing the `?Sized` bound to make the type parameter `Sized`") ).element( @@ -1614,26 +1590,25 @@ quack zappy "#; - let input_new = - &[ - Group::new().element( - Level::ERROR - .title("the size for values of type `T` cannot be known at compilation time") - .id("E0277"), - ), - // We need an empty group here to ensure the HELP line is rendered correctly - Group::new() - .element(Level::HELP.title( - "consider removing the `?Sized` bound to make the type parameter `Sized`", - )) - .element( - Snippet::source(source) - .line_start(7) - .fold(true) - .patch(Patch::new(3..21, "")) - .patch(Patch::new(22..40, "")), - ), - ]; + let input_new = &[ + Group::with_title( + Level::ERROR + .title("the size for values of type `T` cannot be known at compilation time") + .id("E0277"), + ), + // We need an empty group here to ensure the HELP line is rendered correctly + Group::with_title( + Level::HELP + .title("consider removing the `?Sized` bound to make the type parameter `Sized`"), + ) + .element( + Snippet::source(source) + .line_start(7) + .fold(true) + .patch(Patch::new(3..21, "")) + .patch(Patch::new(22..40, "")), + ), + ]; let expected = str![[r#" error[E0277]: the size for values of type `T` cannot be known at compilation time | @@ -1686,7 +1661,7 @@ fn main() { } "#; - let input_new = &[Group::new().element(Level::ERROR + let input_new = &[Group::with_title(Level::ERROR .title("type mismatch resolving `>, ...>>, ...>>, ...> as Future>::Error == Foo`") .id("E0271")).element(Snippet::source(source) .line_start(4) @@ -1696,7 +1671,7 @@ fn main() { AnnotationKind::Primary .span(208..510) .label("type mismatch resolving `, ...>>, ...> as Future>::Error == Foo`"), - )),Group::new().element( + )),Group::with_title( Level::NOTE.title("expected this to be `Foo`") ).element( Snippet::source(source) @@ -1772,7 +1747,7 @@ fn main() { } "#; - let input_new = &[Group::new().element(Level::ERROR + let input_new = &[Group::with_title(Level::ERROR .title("type mismatch resolving `>, ...>>, ...>>, ...> as Future>::Error == Foo`") .id("E0271")).element(Snippet::source(source) .line_start(4) @@ -1782,7 +1757,7 @@ fn main() { AnnotationKind::Primary .span(208..510) .label("type mismatch resolving `, ...>>, ...> as Future>::Error == Foo`"), - )),Group::new().element( + )),Group::with_title( Level::NOTE.title("expected this to be `Foo`") ).element( Snippet::source(source) @@ -1923,7 +1898,7 @@ fn main() { } "#; - let input_new = &[Group::new().element(Level::ERROR + let input_new = &[Group::with_title(Level::ERROR .title("mismatched types") .id("E0308")).element( Snippet::source(source) @@ -2007,7 +1982,7 @@ fn main() { } "#; - let input_new = &[Group::new().element(Level::ERROR + let input_new = &[Group::with_title(Level::ERROR .title("mismatched types") .id("E0308")).element( Snippet::source(source) @@ -2028,7 +2003,7 @@ fn main() { Level::NOTE .title("expected fn pointer `for<'a> fn(Box<(dyn Any + Send + 'a)>) -> Pin<_>`\n found fn item `fn(Box<(dyn Any + Send + 'static)>) -> Pin<_> {wrapped_fn}`") , - ),Group::new().element( + ),Group::with_title( Level::NOTE.title("function defined here"), ).element( Snippet::source(source) @@ -2074,7 +2049,7 @@ LL │ ┃ )>>) {} #[test] fn unicode_cut_handling() { let source = "version = \"0.1.0\"\n# Ensure that the spans from toml handle utf-8 correctly\nauthors = [\n { name = \"Z\u{351}\u{36b}\u{343}\u{36a}\u{302}\u{36b}\u{33d}\u{34f}\u{334}\u{319}\u{324}\u{31e}\u{349}\u{35a}\u{32f}\u{31e}\u{320}\u{34d}A\u{36b}\u{357}\u{334}\u{362}\u{335}\u{31c}\u{330}\u{354}L\u{368}\u{367}\u{369}\u{358}\u{320}G\u{311}\u{357}\u{30e}\u{305}\u{35b}\u{341}\u{334}\u{33b}\u{348}\u{34d}\u{354}\u{339}O\u{342}\u{30c}\u{30c}\u{358}\u{328}\u{335}\u{339}\u{33b}\u{31d}\u{333}\", email = 1 }\n]\n"; - let input = &[Group::new().element(Level::ERROR.title("title")).element( + let input = &[Group::with_title(Level::ERROR.title("title")).element( Snippet::source(source) .fold(false) .annotation(AnnotationKind::Primary.span(85..228).label("annotation")), @@ -2111,7 +2086,7 @@ error: title #[test] fn unicode_cut_handling2() { let source = "/*这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。*/?"; - let input = &[Group::new().element(Level::ERROR + let input = &[Group::with_title(Level::ERROR .title("expected item, found `?`")).element( Snippet::source(source) .fold(false) @@ -2148,7 +2123,7 @@ error: expected item, found `?` #[test] fn unicode_cut_handling3() { let source = "/*这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。*/?"; - let input = &[Group::new().element(Level::ERROR + let input = &[Group::with_title(Level::ERROR .title("expected item, found `?`")).element( Snippet::source(source) .fold(false) @@ -2185,7 +2160,7 @@ error: expected item, found `?` #[test] fn unicode_cut_handling4() { let source = "/*aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa*/?"; - let input = &[Group::new().element(Level::ERROR + let input = &[Group::with_title(Level::ERROR .title("expected item, found `?`")).element( Snippet::source(source) .fold(false) @@ -2228,9 +2203,8 @@ fn main() { //~^ ERROR mismatched types } "##; - let input = &[Group::new() - .element(Level::ERROR.title("mismatched types").id("E0308")) - .element( + let input = &[ + Group::with_title(Level::ERROR.title("mismatched types").id("E0308")).element( Snippet::source(source) .path("$DIR/non-whitespace-trimming-unicode.rs") .fold(true) @@ -2244,7 +2218,8 @@ fn main() { .span(1202..1204) .label("expected due to this"), ), - )]; + ), + ]; let expected_ascii = str![[r#" error[E0308]: mismatched types @@ -2285,29 +2260,25 @@ fn main() { } "##; let input = &[ - Group::new() - .element( - Level::ERROR - .title("cannot add `&str` to `&str`") - .id("E0369"), - ) - .element( - Snippet::source(source) - .path("$DIR/non-1-width-unicode-multiline-label.rs") - .fold(true) - .annotation(AnnotationKind::Context.span(970..984).label("&str")) - .annotation(AnnotationKind::Context.span(987..1001).label("&str")) - .annotation( - AnnotationKind::Primary - .span(985..986) - .label("`+` cannot be used to concatenate two `&str` strings"), - ), - ) - .element( - Level::NOTE.title("string concatenation requires an owned `String` on the left"), - ), - Group::new() - .element(Level::HELP.title("create an owned `String` from a string reference")) + Group::with_title( + Level::ERROR + .title("cannot add `&str` to `&str`") + .id("E0369"), + ) + .element( + Snippet::source(source) + .path("$DIR/non-1-width-unicode-multiline-label.rs") + .fold(true) + .annotation(AnnotationKind::Context.span(970..984).label("&str")) + .annotation(AnnotationKind::Context.span(987..1001).label("&str")) + .annotation( + AnnotationKind::Primary + .span(985..986) + .label("`+` cannot be used to concatenate two `&str` strings"), + ), + ) + .element(Level::NOTE.title("string concatenation requires an owned `String` on the left")), + Group::with_title(Level::HELP.title("create an owned `String` from a string reference")) .element( Snippet::source(source) .path("$DIR/non-1-width-unicode-multiline-label.rs") @@ -2368,15 +2339,14 @@ fn foo() { } "##; let bin_source = "�|�\u{0002}!5�cc\u{0015}\u{0002}�Ӻi��WWj�ȥ�'�}�\u{0012}�J�ȉ��W�\u{001e}O�@����\u{001c}w�V���LO����\u{0014}[ \u{0003}_�'���SQ�~ذ��ų&��-\t��lN~��!@␌ _#���kQ��h�\u{001d}�:�\u{001c}\u{0007}�"; - let input = &[Group::new().element(Level::ERROR + let input = &[Group::with_title(Level::ERROR .title("couldn't read `$DIR/not-utf8.bin`: stream did not contain valid UTF-8")).element( Snippet::source(source) .path("$DIR/not-utf8.rs") .fold(true) .annotation(AnnotationKind::Primary.span(136..160)), ), - Group::new() - .element(Level::NOTE.title("byte `193` is not valid utf-8")) + Group::with_title(Level::NOTE.title("byte `193` is not valid utf-8")) .element( Snippet::source(bin_source) .path("$DIR/not-utf8.bin") @@ -2429,28 +2399,29 @@ fn secondary_title_no_level_text() { let s: &str = include_bytes!("file.txt"); //~ ERROR mismatched types }"#; - let input = &[Group::new() - .element(Level::ERROR.title("mismatched types").id("E0308")) - .element( - Snippet::source(source) - .path("$DIR/mismatched-types.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(105..131) - .label("expected `&str`, found `&[u8; 0]`"), - ) - .annotation( - AnnotationKind::Context - .span(98..102) - .label("expected due to this"), - ), - ) - .element( - Level::NOTE - .text(None::<&str>) - .title("expected reference `&str`\nfound reference `&'static [u8; 0]`"), - )]; + let input = &[ + Group::with_title(Level::ERROR.title("mismatched types").id("E0308")) + .element( + Snippet::source(source) + .path("$DIR/mismatched-types.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(105..131) + .label("expected `&str`, found `&[u8; 0]`"), + ) + .annotation( + AnnotationKind::Context + .span(98..102) + .label("expected due to this"), + ), + ) + .element( + Level::NOTE + .text(None::<&str>) + .title("expected reference `&str`\nfound reference `&'static [u8; 0]`"), + ), + ]; let expected = str![[r#" error[E0308]: mismatched types @@ -2474,28 +2445,29 @@ fn secondary_title_custom_level_text() { let s: &str = include_bytes!("file.txt"); //~ ERROR mismatched types }"#; - let input = &[Group::new() - .element(Level::ERROR.title("mismatched types").id("E0308")) - .element( - Snippet::source(source) - .path("$DIR/mismatched-types.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(105..131) - .label("expected `&str`, found `&[u8; 0]`"), - ) - .annotation( - AnnotationKind::Context - .span(98..102) - .label("expected due to this"), - ), - ) - .element( - Level::NOTE - .text(Some("custom")) - .title("expected reference `&str`\nfound reference `&'static [u8; 0]`"), - )]; + let input = &[ + Group::with_title(Level::ERROR.title("mismatched types").id("E0308")) + .element( + Snippet::source(source) + .path("$DIR/mismatched-types.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(105..131) + .label("expected `&str`, found `&[u8; 0]`"), + ) + .annotation( + AnnotationKind::Context + .span(98..102) + .label("expected due to this"), + ), + ) + .element( + Level::NOTE + .text(Some("custom")) + .title("expected reference `&str`\nfound reference `&'static [u8; 0]`"), + ), + ]; let expected = str![[r#" error[E0308]: mismatched types @@ -2543,42 +2515,40 @@ fn main() { } "#; let input = &[ - Group::new() - .element( - Level::ERROR - .title("`break` with value from a `while` loop") - .id("E0571"), - ) - .element( - Snippet::source(source) - .line_start(1) - .path("$DIR/issue-114529-illegal-break-with-value.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(483..581) - .label("can only break with a value inside `loop` or breakable block"), - ) - .annotation( - AnnotationKind::Context - .span(462..472) - .label("you can't `break` with a value in a `while` loop"), - ), - ), - Group::new() - .element( - Level::HELP - .text(Some("suggestion")) - .title("use `break` on its own without a value inside this `while` loop") - .id("S0123"), - ) - .element( - Snippet::source(source) - .line_start(1) - .path("$DIR/issue-114529-illegal-break-with-value.rs") - .fold(true) - .patch(Patch::new(483..581, "break")), - ), + Group::with_title( + Level::ERROR + .title("`break` with value from a `while` loop") + .id("E0571"), + ) + .element( + Snippet::source(source) + .line_start(1) + .path("$DIR/issue-114529-illegal-break-with-value.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(483..581) + .label("can only break with a value inside `loop` or breakable block"), + ) + .annotation( + AnnotationKind::Context + .span(462..472) + .label("you can't `break` with a value in a `while` loop"), + ), + ), + Group::with_title( + Level::HELP + .text(Some("suggestion")) + .title("use `break` on its own without a value inside this `while` loop") + .id("S0123"), + ) + .element( + Snippet::source(source) + .line_start(1) + .path("$DIR/issue-114529-illegal-break-with-value.rs") + .fold(true) + .patch(Patch::new(483..581, "break")), + ), ]; let expected_ascii = str![[r#" diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index de5f615f..29b84006 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -13,7 +13,7 @@ fn ends_on_col0() { fn foo() { } "#; - let input = &[Group::new().element(Level::ERROR.title("foo")).element( + let input = &[Group::with_title(Level::ERROR.title("foo")).element( Snippet::source(source) .line_start(1) .path("test.rs") @@ -41,7 +41,7 @@ fn foo() { } "#; - let input = &[Group::new().element(Level::ERROR.title("foo")).element( + let input = &[Group::with_title(Level::ERROR.title("foo")).element( Snippet::source(source) .line_start(1) .path("test.rs") @@ -70,7 +70,7 @@ fn foo() { X2 Y2 } "#; - let input = &[Group::new().element(Level::ERROR.title("foo")).element( + let input = &[Group::with_title(Level::ERROR.title("foo")).element( Snippet::source(source) .line_start(1) .path("test.rs") @@ -111,7 +111,7 @@ fn foo() { Y1 X1 } "#; - let input = &[Group::new().element(Level::ERROR.title("foo")).element( + let input = &[Group::with_title(Level::ERROR.title("foo")).element( Snippet::source(source) .line_start(1) .path("test.rs") @@ -153,7 +153,7 @@ fn foo() { X3 Y3 Z3 } "#; - let input = &[Group::new().element(Level::ERROR.title("foo")).element( + let input = &[Group::with_title(Level::ERROR.title("foo")).element( Snippet::source(source) .line_start(1) .path("test.rs") @@ -195,7 +195,7 @@ fn foo() { X2 Y2 Z2 } "#; - let input = &[Group::new().element(Level::ERROR.title("foo")).element( + let input = &[Group::with_title(Level::ERROR.title("foo")).element( Snippet::source(source) .line_start(1) .path("test.rs") @@ -240,7 +240,7 @@ fn foo() { X2 Y2 Z2 } "#; - let input = &[Group::new().element(Level::ERROR.title("foo")).element( + let input = &[Group::with_title(Level::ERROR.title("foo")).element( Snippet::source(source) .line_start(1) .path("test.rs") @@ -286,7 +286,7 @@ fn foo() { X3 Y3 Z3 } "#; - let input = &[Group::new().element(Level::ERROR.title("foo")).element( + let input = &[Group::with_title(Level::ERROR.title("foo")).element( Snippet::source(source) .line_start(1) .path("test.rs") @@ -334,7 +334,7 @@ fn foo() { X3 Y3 Z3 } "#; - let input = &[Group::new().element(Level::ERROR.title("foo")).element( + let input = &[Group::with_title(Level::ERROR.title("foo")).element( Snippet::source(source) .line_start(1) .path("test.rs") @@ -376,7 +376,7 @@ fn foo() { X3 Y3 Z3 } "#; - let input = &[Group::new().element(Level::ERROR.title("foo")).element( + let input = &[Group::with_title(Level::ERROR.title("foo")).element( Snippet::source(source) .line_start(1) .path("test.rs") @@ -417,7 +417,7 @@ fn foo() { a { b { c } d } } "#; - let input = &[Group::new().element(Level::ERROR.title("foo")).element( + let input = &[Group::with_title(Level::ERROR.title("foo")).element( Snippet::source(source) .line_start(1) .path("test.rs") @@ -448,7 +448,7 @@ fn foo() { a { b { c } d } } "#; - let input = &[Group::new().element(Level::ERROR.title("foo")).element( + let input = &[Group::with_title(Level::ERROR.title("foo")).element( Snippet::source(source) .line_start(1) .path("test.rs") @@ -478,7 +478,7 @@ fn foo() { a { b { c } d } } "#; - let input = &[Group::new().element(Level::ERROR.title("foo")).element( + let input = &[Group::with_title(Level::ERROR.title("foo")).element( Snippet::source(source) .line_start(1) .path("test.rs") @@ -511,7 +511,7 @@ fn foo() { a { b { c } d } } "#; - let input = &[Group::new().element(Level::ERROR.title("foo")).element( + let input = &[Group::with_title(Level::ERROR.title("foo")).element( Snippet::source(source) .line_start(1) .path("test.rs") @@ -543,7 +543,7 @@ fn foo() { a bc d } "#; - let input = &[Group::new().element(Level::ERROR.title("foo")).element( + let input = &[Group::with_title(Level::ERROR.title("foo")).element( Snippet::source(source) .line_start(1) .path("test.rs") @@ -575,7 +575,7 @@ fn foo() { a { b { c } d } } "#; - let input = &[Group::new().element(Level::ERROR.title("foo")).element( + let input = &[Group::with_title(Level::ERROR.title("foo")).element( Snippet::source(source) .line_start(1) .path("test.rs") @@ -601,7 +601,7 @@ fn foo() { a { b { c } d } } "#; - let input = &[Group::new().element(Level::ERROR.title("foo")).element( + let input = &[Group::with_title(Level::ERROR.title("foo")).element( Snippet::source(source) .line_start(1) .path("test.rs") @@ -628,7 +628,7 @@ fn foo() { a { b { c } d } } "#; - let input = &[Group::new().element(Level::ERROR.title("foo")).element( + let input = &[Group::with_title(Level::ERROR.title("foo")).element( Snippet::source(source) .line_start(1) .path("test.rs") @@ -665,7 +665,7 @@ fn foo() { a { b { c } d } } "#; - let input = &[Group::new().element(Level::ERROR.title("foo")).element( + let input = &[Group::with_title(Level::ERROR.title("foo")).element( Snippet::source(source) .line_start(1) .path("test.rs") @@ -694,7 +694,7 @@ fn foo() { a { b { c } d } } "#; - let input = &[Group::new().element(Level::ERROR.title("foo")).element( + let input = &[Group::with_title(Level::ERROR.title("foo")).element( Snippet::source(source) .line_start(1) .path("test.rs") @@ -732,7 +732,7 @@ fn foo() { X3 Y3 Z3 } "#; - let input = &[Group::new().element(Level::ERROR.title("foo")).element( + let input = &[Group::with_title(Level::ERROR.title("foo")).element( Snippet::source(source) .line_start(1) .path("test.rs") @@ -790,7 +790,7 @@ fn foo() { X3 Y3 Z3 } "#; - let input = &[Group::new().element(Level::ERROR.title("foo")).element( + let input = &[Group::with_title(Level::ERROR.title("foo")).element( Snippet::source(source) .line_start(1) .path("test.rs") @@ -842,30 +842,32 @@ fn issue_91334() { fn f(){||yield(((){), "#; - let input = &[Group::new() - .element(Level::ERROR.title("this file contains an unclosed delimiter")) - .element( - Snippet::source(source) - .line_start(1) - .path("$DIR/issue-91334.rs") - .fold(true) - .annotation( - AnnotationKind::Context - .span(151..152) - .label("unclosed delimiter"), - ) - .annotation( - AnnotationKind::Context - .span(159..160) - .label("unclosed delimiter"), - ) - .annotation( - AnnotationKind::Context - .span(164..164) - .label("missing open `(` for this delimiter"), - ) - .annotation(AnnotationKind::Primary.span(167..167)), - )]; + let input = + &[ + Group::with_title(Level::ERROR.title("this file contains an unclosed delimiter")) + .element( + Snippet::source(source) + .line_start(1) + .path("$DIR/issue-91334.rs") + .fold(true) + .annotation( + AnnotationKind::Context + .span(151..152) + .label("unclosed delimiter"), + ) + .annotation( + AnnotationKind::Context + .span(159..160) + .label("unclosed delimiter"), + ) + .annotation( + AnnotationKind::Context + .span(164..164) + .label("missing open `(` for this delimiter"), + ) + .annotation(AnnotationKind::Primary.span(167..167)), + ), + ]; let expected = str![[r#" error: this file contains an unclosed delimiter --> $DIR/issue-91334.rs:7:23 @@ -912,40 +914,37 @@ fn main() { } "#; let input = &[ - Group::new() - .element( - Level::ERROR - .title("`break` with value from a `while` loop") - .id("E0571"), - ) - .element( - Snippet::source(source) - .line_start(1) - .path("$DIR/issue-114529-illegal-break-with-value.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(483..581) - .label("can only break with a value inside `loop` or breakable block"), - ) - .annotation( - AnnotationKind::Context - .span(462..472) - .label("you can't `break` with a value in a `while` loop"), - ), - ), - Group::new() - .element( - Level::HELP - .title("use `break` on its own without a value inside this `while` loop"), - ) - .element( - Snippet::source(source) - .line_start(1) - .path("$DIR/issue-114529-illegal-break-with-value.rs") - .fold(true) - .annotation(AnnotationKind::Context.span(483..581).label("break")), - ), + Group::with_title( + Level::ERROR + .title("`break` with value from a `while` loop") + .id("E0571"), + ) + .element( + Snippet::source(source) + .line_start(1) + .path("$DIR/issue-114529-illegal-break-with-value.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(483..581) + .label("can only break with a value inside `loop` or breakable block"), + ) + .annotation( + AnnotationKind::Context + .span(462..472) + .label("you can't `break` with a value in a `while` loop"), + ), + ), + Group::with_title( + Level::HELP.title("use `break` on its own without a value inside this `while` loop"), + ) + .element( + Snippet::source(source) + .line_start(1) + .path("$DIR/issue-114529-illegal-break-with-value.rs") + .fold(true) + .annotation(AnnotationKind::Context.span(483..581).label("break")), + ), ]; let expected = str![[r#" error[E0571]: `break` with value from a `while` loop @@ -1121,42 +1120,40 @@ fn nsize() { } } "#; - let input = - &[ - Group::new() - .element( - Level::ERROR - .title("`V0usize` cannot be safely transmuted into `[usize; 2]`") - .id("E0277"), - ) - .element( - Snippet::source(source) - .line_start(1) - .path("$DIR/primitive_reprs_should_have_correct_length.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(4375..4381).label( - "the size of `V0usize` is smaller than the size of `[usize; 2]`", - )), + let input = &[ + Group::with_title( + Level::ERROR + .title("`V0usize` cannot be safely transmuted into `[usize; 2]`") + .id("E0277"), + ) + .element( + Snippet::source(source) + .line_start(1) + .path("$DIR/primitive_reprs_should_have_correct_length.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(4375..4381) + .label("the size of `V0usize` is smaller than the size of `[usize; 2]`"), ), - Group::new() - .element(Level::NOTE.title("required by a bound in `is_transmutable`")) - .element( - Snippet::source(source) - .line_start(1) - .path("$DIR/primitive_reprs_should_have_correct_length.rs") - .fold(true) - .annotation( - AnnotationKind::Context - .span(225..240) - .label("required by a bound in this function"), - ) - .annotation( - AnnotationKind::Primary - .span(276..470) - .label("required by this bound in `is_transmutable`"), - ), + ), + Group::with_title(Level::NOTE.title("required by a bound in `is_transmutable`")).element( + Snippet::source(source) + .line_start(1) + .path("$DIR/primitive_reprs_should_have_correct_length.rs") + .fold(true) + .annotation( + AnnotationKind::Context + .span(225..240) + .label("required by a bound in this function"), + ) + .annotation( + AnnotationKind::Primary + .span(276..470) + .label("required by this bound in `is_transmutable`"), ), - ]; + ), + ]; let expected = str![[r#" error[E0277]: `V0usize` cannot be safely transmuted into `[usize; 2]` --> $DIR/primitive_reprs_should_have_correct_length.rs:144:44 @@ -1209,7 +1206,7 @@ fn main() { assert::is_maybe_transmutable::<&'static [u8; 0], &'static [u16; 0]>(); //~ ERROR `&[u8; 0]` cannot be safely transmuted into `&[u16; 0]` } "#; - let input = &[Group::new().element(Level::ERROR + let input = &[Group::with_title(Level::ERROR .title("`&[u8; 0]` cannot be safely transmuted into `&[u16; 0]`") .id("E027s7")).element( Snippet::source(source) @@ -1275,33 +1272,33 @@ fn g() { } fn main() {} "#; - let input = - &[Group::new() - .element( - Level::ERROR - .title("expected function, found `{integer}`") - .id("E0618"), + let input = &[Group::with_title( + Level::ERROR + .title("expected function, found `{integer}`") + .id("E0618"), + ) + .element( + Snippet::source(source) + .line_start(1) + .path("$DIR/missing-semicolon.rs") + .fold(true) + .annotation( + AnnotationKind::Context + .span(108..144) + .label("call expression requires function"), ) - .element( - Snippet::source(source) - .line_start(1) - .path("$DIR/missing-semicolon.rs") - .fold(true) - .annotation( - AnnotationKind::Context - .span(108..144) - .label("call expression requires function"), - ) - .annotation( - AnnotationKind::Context - .span(89..90) - .label("`x` has type `{integer}`"), - ) - .annotation(AnnotationKind::Context.span(109..109).label( - "help: consider using a semicolon here to finish the statement: `;`", - )) - .annotation(AnnotationKind::Primary.span(108..109)), - )]; + .annotation( + AnnotationKind::Context + .span(89..90) + .label("`x` has type `{integer}`"), + ) + .annotation( + AnnotationKind::Context + .span(109..109) + .label("help: consider using a semicolon here to finish the statement: `;`"), + ) + .annotation(AnnotationKind::Primary.span(108..109)), + )]; let expected = str![[r#" error[E0618]: expected function, found `{integer}` --> $DIR/missing-semicolon.rs:5:13 @@ -1369,7 +1366,7 @@ macro_rules! outer_macro { outer_macro!(FirstStruct, FirstAttrStruct); "#; let input = - &[ Group::new().element(Level::WARNING + &[ Group::with_title(Level::WARNING .title("non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module")) .element( Snippet::source(aux_source) @@ -1402,8 +1399,7 @@ outer_macro!(FirstStruct, FirstAttrStruct); Level::NOTE .title("a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute") ), - Group::new() - .element(Level::NOTE.title("the lint level is defined here")) + Group::with_title(Level::NOTE.title("the lint level is defined here")) .element( Snippet::source(source) .line_start(1) @@ -1498,28 +1494,28 @@ macro_rules! inline { } "#; let input = &[ - Group::new() - .element( - Level::ERROR - .title("can't call method `pow` on ambiguous numeric type `{integer}`") - .id("E0689"), - ) - .element( - Snippet::source(source) - .line_start(1) - .path("$DIR/method-on-ambiguous-numeric-type.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(916..919)), - ), - Group::new() - .element(Level::HELP.title("you must specify a type for this binding, like `i32`")) - .element( - Snippet::source(aux_source) - .line_start(1) - .path("$DIR/auxiliary/macro-in-other-crate.rs") - .fold(true) - .annotation(AnnotationKind::Context.span(69..69).label(": i32")), - ), + Group::with_title( + Level::ERROR + .title("can't call method `pow` on ambiguous numeric type `{integer}`") + .id("E0689"), + ) + .element( + Snippet::source(source) + .line_start(1) + .path("$DIR/method-on-ambiguous-numeric-type.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(916..919)), + ), + Group::with_title( + Level::HELP.title("you must specify a type for this binding, like `i32`"), + ) + .element( + Snippet::source(aux_source) + .line_start(1) + .path("$DIR/auxiliary/macro-in-other-crate.rs") + .fold(true) + .annotation(AnnotationKind::Context.span(69..69).label(": i32")), + ), ]; let expected = str![[r#" error[E0689]: can't call method `pow` on ambiguous numeric type `{integer}` @@ -1562,9 +1558,8 @@ fn courier_to_des_moines_and_points_west(data: &[u32]) -> String { fn main() {} "#; - let input = &[Group::new() - .element(Level::ERROR.title("type annotations needed").id("E0282")) - .element( + let input = &[ + Group::with_title(Level::ERROR.title("type annotations needed").id("E0282")).element( Snippet::source(source) .line_start(1) .path("$DIR/issue-42234-unknown-receiver-type.rs") @@ -1572,7 +1567,8 @@ fn main() {} .annotation(AnnotationKind::Primary.span(536..539).label( "cannot infer type of the type parameter `S` declared on the method `sum`", )), - )]; + ), + ]; let expected = str![[r#" error[E0282]: type annotations needed --> $DIR/issue-42234-unknown-receiver-type.rs:15:10 @@ -1666,7 +1662,7 @@ fn main() {} "##; let input = - &[ Group::new().element( Level::ERROR + &[ Group::with_title( Level::ERROR .title( "non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered" ) @@ -1681,8 +1677,7 @@ fn main() {} .label("patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered") ), ), - Group::new() - .element(Level::NOTE.title("`NonEmptyEnum5` defined here")) + Group::with_title(Level::NOTE.title("`NonEmptyEnum5` defined here")) .element( Snippet::source(source) .line_start(1) @@ -1698,8 +1693,7 @@ fn main() {} .element(Level::NOTE.title("the matched value is of type `NonEmptyEnum5`")) .element(Level::NOTE.title("match arms with guards don't count towards exhaustivity") ), - Group::new() - .element( + Group::with_title( Level::HELP .title("ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms") ) @@ -1763,7 +1757,7 @@ fn main() { //~^ ERROR must be specified } "#; - let input = &[Group::new().element(Level::ERROR + let input = &[Group::with_title(Level::ERROR .title("the trait alias `EqAlias` is not dyn compatible") .id("E0038")).element( Snippet::source(source) @@ -1776,8 +1770,7 @@ fn main() { .label("`EqAlias` is not dyn compatible"), ), ), - Group::new() - .element( + Group::with_title( Level::NOTE .title("for a trait to be dyn compatible it needs to allow building a vtable\nfor more information, visit ")) .element( @@ -1830,9 +1823,8 @@ const C: u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, fn main() {} "#; - let input = &[Group::new() - .element(Level::ERROR.title("mismatched types").id("E0038")) - .element( + let input = &[ + Group::with_title(Level::ERROR.title("mismatched types").id("E0038")).element( Snippet::source(source) .path("$DIR/long-span.rs") .fold(true) @@ -1841,7 +1833,8 @@ fn main() {} .span(15..5055) .label("expected `u8`, found `[{integer}; 1680]`"), ), - )]; + ), + ]; let expected = str![[r#" error[E0038]: mismatched types --> $DIR/long-span.rs:2:15 @@ -1864,9 +1857,8 @@ const C: u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, fn main() {} "#; - let input = &[Group::new() - .element(Level::ERROR.title("mismatched types").id("E0038")) - .element( + let input = &[ + Group::with_title(Level::ERROR.title("mismatched types").id("E0038")).element( Snippet::source(source) .path("$DIR/long-span.rs") .fold(true) @@ -1875,7 +1867,8 @@ fn main() {} .span(15..5055) .label("expected `u8`, found `[{integer}; 1680]`"), ), - )]; + ), + ]; let expected = str![[r#" error[E0038]: mismatched types ╭▸ $DIR/long-span.rs:2:15 @@ -1899,9 +1892,8 @@ const C: u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, fn main() {} "#; - let input = &[Group::new() - .element(Level::ERROR.title("mismatched types").id("E0038")) - .element( + let input = &[ + Group::with_title(Level::ERROR.title("mismatched types").id("E0038")).element( Snippet::source(source) .path("$DIR/long-span.rs") .fold(true) @@ -1910,7 +1902,8 @@ fn main() {} .span(15..5055) .label("expected `u8`, found `[{integer}; 1680]`"), ), - )]; + ), + ]; let expected = str![[r#" error[E0038]: mismatched types ╭▸ $DIR/long-span.rs:2:15 @@ -1934,9 +1927,8 @@ const C: u8 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, fn main() {} "#; - let input = &[Group::new() - .element(Level::ERROR.title("mismatched types").id("E0038")) - .element( + let input = &[ + Group::with_title(Level::ERROR.title("mismatched types").id("E0038")).element( Snippet::source(source) .path("$DIR/long-span.rs") .fold(true) @@ -1945,7 +1937,8 @@ fn main() {} .span(15..5055) .label("expected `u8`, found `[{integer}; 1680]`"), ), - )]; + ), + ]; let expected = str![[r#" error[E0038]: mismatched types --> $DIR/long-span.rs:2:15 @@ -1985,7 +1978,7 @@ fn main() { } "#; - let input = &[Group::new().element(Level::ERROR + let input = &[Group::with_title(Level::ERROR .title("`Iterator::map` call that discard the iterator's values")) .element( Snippet::source(source) @@ -2008,8 +2001,7 @@ fn main() { ) .element( Level::NOTE.title("`Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated")), - Group::new() - .element(Level::HELP.title("you might have meant to use `Iterator::for_each`")) + Group::with_title(Level::HELP.title("you might have meant to use `Iterator::for_each`")) .element( Snippet::source(source) .path("$DIR/lint_map_unit_fn.rs") @@ -2076,23 +2068,19 @@ fn main() { "#; let input = &[ - Group::new() - .element(Level::ERROR.title("character constant must be escaped: `\\n`")) - .element( - Snippet::source(source) - .path("$DIR/bad-char-literals.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(204..205)), - ), - Group::new() - .element(Level::HELP.title("escape the character")) - .element( - Snippet::source(source) - .path("$DIR/bad-char-literals.rs") - .line_start(1) - .fold(true) - .patch(Patch::new(204..205, r#"\n"#)), - ), + Group::with_title(Level::ERROR.title("character constant must be escaped: `\\n`")).element( + Snippet::source(source) + .path("$DIR/bad-char-literals.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(204..205)), + ), + Group::with_title(Level::HELP.title("escape the character")).element( + Snippet::source(source) + .path("$DIR/bad-char-literals.rs") + .line_start(1) + .fold(true) + .patch(Patch::new(204..205, r#"\n"#)), + ), ]; let expected = str![[r#" error: character constant must be escaped: `/n` @@ -2129,22 +2117,18 @@ fn main() {} "#; let input = &[ - Group::new() - .element(Level::ERROR.title("unclosed frontmatter")) - .element( - Snippet::source(source) - .path("$DIR/unclosed-1.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(0..221)), - ), - Group::new() - .element(Level::NOTE.title("frontmatter opening here was not closed")) - .element( - Snippet::source(source) - .path("$DIR/unclosed-1.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(0..4)), - ), + Group::with_title(Level::ERROR.title("unclosed frontmatter")).element( + Snippet::source(source) + .path("$DIR/unclosed-1.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(0..221)), + ), + Group::with_title(Level::NOTE.title("frontmatter opening here was not closed")).element( + Snippet::source(source) + .path("$DIR/unclosed-1.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(0..4)), + ), ]; let expected = str![[r#" error: unclosed frontmatter @@ -2187,22 +2171,18 @@ fn foo() -> &str { "#; let input = &[ - Group::new() - .element(Level::ERROR.title("unclosed frontmatter")) - .element( - Snippet::source(source) - .path("$DIR/unclosed-2.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(0..377)), - ), - Group::new() - .element(Level::NOTE.title("frontmatter opening here was not closed")) - .element( - Snippet::source(source) - .path("$DIR/unclosed-2.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(0..4)), - ), + Group::with_title(Level::ERROR.title("unclosed frontmatter")).element( + Snippet::source(source) + .path("$DIR/unclosed-2.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(0..377)), + ), + Group::with_title(Level::NOTE.title("frontmatter opening here was not closed")).element( + Snippet::source(source) + .path("$DIR/unclosed-2.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(0..4)), + ), ]; let expected = str![[r#" error: unclosed frontmatter @@ -2247,22 +2227,22 @@ fn foo(x: i32) -> i32 { "#; let input = &[ - Group::new() - .element(Level::ERROR.title("invalid preceding whitespace for frontmatter close")) + Group::with_title(Level::ERROR.title("invalid preceding whitespace for frontmatter close")) .element( Snippet::source(source) .path("$DIR/unclosed-3.rs") .fold(true) .annotation(AnnotationKind::Primary.span(302..310)), ), - Group::new() - .element(Level::NOTE.title("frontmatter close should not be preceded by whitespace")) - .element( - Snippet::source(source) - .path("$DIR/unclosed-3.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(302..306)), - ), + Group::with_title( + Level::NOTE.title("frontmatter close should not be preceded by whitespace"), + ) + .element( + Snippet::source(source) + .path("$DIR/unclosed-3.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(302..306)), + ), ]; let expected = str![[r#" error: invalid preceding whitespace for frontmatter close @@ -2297,22 +2277,18 @@ fn main() {} "#; let input = &[ - Group::new() - .element(Level::ERROR.title("unclosed frontmatter")) - .element( - Snippet::source(source) - .path("$DIR/unclosed-4.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(0..43)), - ), - Group::new() - .element(Level::NOTE.title("frontmatter opening here was not closed")) - .element( - Snippet::source(source) - .path("$DIR/unclosed-4.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(0..4)), - ), + Group::with_title(Level::ERROR.title("unclosed frontmatter")).element( + Snippet::source(source) + .path("$DIR/unclosed-4.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(0..43)), + ), + Group::with_title(Level::NOTE.title("frontmatter opening here was not closed")).element( + Snippet::source(source) + .path("$DIR/unclosed-4.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(0..4)), + ), ]; let expected = str![[r#" error: unclosed frontmatter @@ -2350,22 +2326,18 @@ fn main() {} "#; let input = &[ - Group::new() - .element(Level::ERROR.title("unclosed frontmatter")) - .element( - Snippet::source(source) - .path("$DIR/unclosed-5.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(0..176)), - ), - Group::new() - .element(Level::NOTE.title("frontmatter opening here was not closed")) - .element( - Snippet::source(source) - .path("$DIR/unclosed-5.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(0..4)), - ), + Group::with_title(Level::ERROR.title("unclosed frontmatter")).element( + Snippet::source(source) + .path("$DIR/unclosed-5.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(0..176)), + ), + Group::with_title(Level::NOTE.title("frontmatter opening here was not closed")).element( + Snippet::source(source) + .path("$DIR/unclosed-5.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(0..4)), + ), ]; let expected = str![[r#" @@ -2471,46 +2443,49 @@ pub enum E2 { } "#; - let input = &[Group::new().element(Level::ERROR - .title("expected unit struct, unit variant or constant, found tuple variant `E1::Z1`") - .id(r#"E0532"#)) - .element( - Snippet::source(source) - .path("$DIR/pat-tuple-field-count-cross.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(1760..1766)), + let input = &[ + Group::with_title( + Level::ERROR + .title( + "expected unit struct, unit variant or constant, found tuple variant `E1::Z1`", ) - .element( - Snippet::source(source1) - .path("$DIR/auxiliary/declarations-for-tuple-field-count-errors.rs") - .fold(true) - .annotation( - AnnotationKind::Context - .span(143..145) - .label("`E1::Z1` defined here"), - ) - .annotation( - AnnotationKind::Context - .span(139..141) - .label("similarly named unit variant `Z0` defined here"), - ), - ), - Group::new() - .element(Level::HELP.title("use the tuple variant pattern syntax instead")) - .element( - Snippet::source(source) - .path("$DIR/pat-tuple-field-count-cross.rs") - .fold(true) - .patch(Patch::new(1760..1766, r#"E1::Z1()"#)), + .id(r#"E0532"#), + ) + .element( + Snippet::source(source) + .path("$DIR/pat-tuple-field-count-cross.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(1760..1766)), + ) + .element( + Snippet::source(source1) + .path("$DIR/auxiliary/declarations-for-tuple-field-count-errors.rs") + .fold(true) + .annotation( + AnnotationKind::Context + .span(143..145) + .label("`E1::Z1` defined here"), + ) + .annotation( + AnnotationKind::Context + .span(139..141) + .label("similarly named unit variant `Z0` defined here"), ), - Group::new() - .element(Level::HELP.title("a unit variant with a similar name exists")) - .element( - Snippet::source(source) - .path("$DIR/pat-tuple-field-count-cross.rs") - .fold(true) - .patch(Patch::new(1764..1766, r#"Z0"#)), - )]; + ), + Group::with_title(Level::HELP.title("use the tuple variant pattern syntax instead")) + .element( + Snippet::source(source) + .path("$DIR/pat-tuple-field-count-cross.rs") + .fold(true) + .patch(Patch::new(1760..1766, r#"E1::Z1()"#)), + ), + Group::with_title(Level::HELP.title("a unit variant with a similar name exists")).element( + Snippet::source(source) + .path("$DIR/pat-tuple-field-count-cross.rs") + .fold(true) + .patch(Patch::new(1764..1766, r#"Z0"#)), + ), + ]; let expected = str![[r#" error[E0532]: expected unit struct, unit variant or constant, found tuple variant `E1::Z1` --> $DIR/pat-tuple-field-count-cross.rs:35:9 @@ -2549,9 +2524,8 @@ fn unterminated_nested_comment() { */ "#; - let input = &[Group::new() - .element(Level::ERROR.title("unterminated block comment").id("E0758")) - .element( + let input = &[ + Group::with_title(Level::ERROR.title("unterminated block comment").id("E0758")).element( Snippet::source(source) .path("$DIR/unterminated-nested-comment.rs") .fold(true) @@ -2569,7 +2543,8 @@ fn unterminated_nested_comment() { .label("...and last nested comment terminates here."), ) .annotation(AnnotationKind::Primary.span(0..31)), - )]; + ), + ]; let expected = str![[r#" error[E0758]: unterminated block comment @@ -2605,37 +2580,38 @@ fn mismatched_types1() { let s: &str = include_bytes!("file.txt"); //~ ERROR mismatched types }"#; - let input = &[Group::new() - .element(Level::ERROR.title("mismatched types").id("E0308")) - .element( - Snippet::source(file_txt_source) - .fold(true) - .line_start(3) - .path("$DIR/file.txt") - .annotation( - AnnotationKind::Primary - .span(0..0) - .label("expected `&[u8]`, found `&str`"), - ), - ) - .element( - Snippet::source(rust_source) - .path("$DIR/mismatched-types.rs") - .fold(true) - .annotation( - AnnotationKind::Context - .span(23..28) - .label("expected due to this"), - ) - .annotation( - AnnotationKind::Context - .span(31..55) - .label("in this macro invocation"), - ), - ) - .element( - Level::NOTE.title("expected reference `&[u8]`\n found reference `&'static str`"), - )]; + let input = &[ + Group::with_title(Level::ERROR.title("mismatched types").id("E0308")) + .element( + Snippet::source(file_txt_source) + .fold(true) + .line_start(3) + .path("$DIR/file.txt") + .annotation( + AnnotationKind::Primary + .span(0..0) + .label("expected `&[u8]`, found `&str`"), + ), + ) + .element( + Snippet::source(rust_source) + .path("$DIR/mismatched-types.rs") + .fold(true) + .annotation( + AnnotationKind::Context + .span(23..28) + .label("expected due to this"), + ) + .annotation( + AnnotationKind::Context + .span(31..55) + .label("in this macro invocation"), + ), + ) + .element( + Level::NOTE.title("expected reference `&[u8]`\n found reference `&'static str`"), + ), + ]; let expected = str![[r#" error[E0308]: mismatched types @@ -2667,26 +2643,28 @@ fn mismatched_types2() { let s: &str = include_bytes!("file.txt"); //~ ERROR mismatched types }"#; - let input = &[Group::new() - .element(Level::ERROR.title("mismatched types").id("E0308")) - .element( - Snippet::source(source) - .path("$DIR/mismatched-types.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(105..131) - .label("expected `&str`, found `&[u8; 0]`"), - ) - .annotation( - AnnotationKind::Context - .span(98..102) - .label("expected due to this"), - ), - ) - .element( - Level::NOTE.title("expected reference `&str`\n found reference `&'static [u8; 0]`"), - )]; + let input = &[ + Group::with_title(Level::ERROR.title("mismatched types").id("E0308")) + .element( + Snippet::source(source) + .path("$DIR/mismatched-types.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(105..131) + .label("expected `&str`, found `&[u8; 0]`"), + ) + .annotation( + AnnotationKind::Context + .span(98..102) + .label("expected due to this"), + ), + ) + .element( + Level::NOTE + .title("expected reference `&str`\n found reference `&'static [u8; 0]`"), + ), + ]; let expected = str![[r#" error[E0308]: mismatched types @@ -2720,32 +2698,28 @@ fn main() { "#; let input = &[ - Group::new() - .element(Level::ERROR.title("mismatched types").id("E0308")) - .element( - Snippet::source(source) - .path("$DIR/short-error-format.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(80..100) - .label("expected `u32`, found `String`"), - ) - .annotation( - AnnotationKind::Context - .span(76..79) - .label("arguments to this function are incorrect"), - ), - ), - Group::new() - .element(Level::NOTE.title("function defined here")) - .element( - Snippet::source(source) - .path("$DIR/short-error-format.rs") - .fold(true) - .annotation(AnnotationKind::Context.span(48..54).label("")) - .annotation(AnnotationKind::Primary.span(44..47)), - ), + Group::with_title(Level::ERROR.title("mismatched types").id("E0308")).element( + Snippet::source(source) + .path("$DIR/short-error-format.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(80..100) + .label("expected `u32`, found `String`"), + ) + .annotation( + AnnotationKind::Context + .span(76..79) + .label("arguments to this function are incorrect"), + ), + ), + Group::with_title(Level::NOTE.title("function defined here")).element( + Snippet::source(source) + .path("$DIR/short-error-format.rs") + .fold(true) + .annotation(AnnotationKind::Context.span(48..54).label("")) + .annotation(AnnotationKind::Primary.span(44..47)), + ), ]; let expected = str![[r#" @@ -2772,22 +2746,21 @@ fn main() { } "#; - let input = &[Group::new() - .element( - Level::ERROR - .title("no method named `salut` found for type `u32` in the current scope") - .id("E0599"), - ) - .element( - Snippet::source(source) - .path("$DIR/short-error-format.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(127..132) - .label("method not found in `u32`"), - ), - )]; + let input = &[Group::with_title( + Level::ERROR + .title("no method named `salut` found for type `u32` in the current scope") + .id("E0599"), + ) + .element( + Snippet::source(source) + .path("$DIR/short-error-format.rs") + .fold(true) + .annotation( + AnnotationKind::Primary + .span(127..132) + .label("method not found in `u32`"), + ), + )]; let expected = str![[r#" $DIR/short-error-format.rs:8:7: error[E0599]: no method named `salut` found for type `u32` in the current scope: method not found in `u32` @@ -2812,8 +2785,7 @@ pub struct Foo; //~^ ERROR "#; let input = &[ - Group::new() - .element(Level::ERROR.title("this URL is not a hyperlink")) + Group::with_title(Level::ERROR.title("this URL is not a hyperlink")) .element( Snippet::source(source_0) .path("$DIR/diagnostic-width.rs") @@ -2823,24 +2795,20 @@ pub struct Foo; //~^ ERROR .element( Level::NOTE.title("bare URLs are not automatically turned into clickable links"), ), - Group::new() - .element(Level::NOTE.title("the lint level is defined here")) - .element( - Snippet::source(source_0) - .path("$DIR/diagnostic-width.rs") - .fold(true) - .annotation(AnnotationKind::Primary.span(49..67)), - ), - Group::new() - .element(Level::HELP.title("use an automatic link instead")) - .element( - Snippet::source(source_1) - .path("$DIR/diagnostic-width.rs") - .line_start(4) - .fold(true) - .patch(Patch::new(40..40, "<")) - .patch(Patch::new(55..55, ">")), - ), + Group::with_title(Level::NOTE.title("the lint level is defined here")).element( + Snippet::source(source_0) + .path("$DIR/diagnostic-width.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(49..67)), + ), + Group::with_title(Level::HELP.title("use an automatic link instead")).element( + Snippet::source(source_1) + .path("$DIR/diagnostic-width.rs") + .line_start(4) + .fold(true) + .patch(Patch::new(40..40, "<")) + .patch(Patch::new(55..55, ">")), + ), ]; let expected = str![[r#" @@ -2882,8 +2850,7 @@ fn main() { let long_title3 = "or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value"; let input = &[ - Group::new() - .element(Level::WARNING.title(long_title1)) + Group::with_title(Level::WARNING.title(long_title1)) .element( Snippet::source(source1) .path("lint_example.rs") @@ -2893,27 +2860,24 @@ fn main() { .element(Level::WARNING.title("this changes meaning in Rust 2021")) .element(Level::NOTE.title(long_title2)) .element(Level::NOTE.title("`#[warn(array_into_iter)]` on by default")), - Group::new() - .element( - Level::HELP.title("use `.iter()` instead of `.into_iter()` to avoid ambiguity"), - ) - .element( - Snippet::source(source2) - .path("lint_example.rs") - .line_start(3) - .fold(true) - .patch(Patch::new(10..19, "iter")), - ), - Group::new() - .element(Level::HELP.title(long_title3)) - .element( - Snippet::source(source2) - .path("lint_example.rs") - .line_start(3) - .fold(true) - .patch(Patch::new(0..0, "IntoIterator::into_iter(")) - .patch(Patch::new(9..21, ")")), - ), + Group::with_title( + Level::HELP.title("use `.iter()` instead of `.into_iter()` to avoid ambiguity"), + ) + .element( + Snippet::source(source2) + .path("lint_example.rs") + .line_start(3) + .fold(true) + .patch(Patch::new(10..19, "iter")), + ), + Group::with_title(Level::HELP.title(long_title3)).element( + Snippet::source(source2) + .path("lint_example.rs") + .line_start(3) + .fold(true) + .patch(Patch::new(0..0, "IntoIterator::into_iter(")) + .patch(Patch::new(9..21, ")")), + ), ]; let expected = str![[r#" From 82773497ab0c6c27ec64edf60a1a7137028c8f21 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 1 Jul 2025 16:43:07 -0500 Subject: [PATCH 252/293] docs: Remove bad comments about Origin --- src/snippet.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/snippet.rs b/src/snippet.rs index 3045b2a7..a58c32ae 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -396,8 +396,6 @@ impl<'a> Origin<'a> { } /// Set the default line number to display - /// - /// Otherwise this will be inferred from the primary [`Annotation`] pub fn line(mut self, line: usize) -> Self { self.line = Some(line); self @@ -405,8 +403,6 @@ impl<'a> Origin<'a> { /// Set the default column to display /// - /// Otherwise this will be inferred from the primary [`Annotation`] - /// ///
/// /// `char_column` is only be respected if [`Origin::line`] is also set. From 838537fd5fdce918075865c168f683883f5f15c6 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 1 Jul 2025 16:45:36 -0500 Subject: [PATCH 253/293] docs: Describe Origin::primary --- src/snippet.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/snippet.rs b/src/snippet.rs index a58c32ae..851a55fe 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -267,9 +267,9 @@ impl<'a> Annotation<'a> { #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] #[non_exhaustive] pub enum AnnotationKind { - /// Match the primary [`Level`] of the group. + /// Shows the source that the [Group's Title][Group::with_title] references /// - /// See [`Group::with_level`] for details about how this is determined + /// For [`Title`]-less groups, see [`Group::with_level`] Primary, /// Additional context to explain the [`Primary`][Self::Primary] /// [`Annotation`] @@ -413,6 +413,7 @@ impl<'a> Origin<'a> { self } + /// Mark this as the source that the [Group's Title][Group::with_title] references pub fn primary(mut self, primary: bool) -> Self { self.primary = primary; self From 3e787fa6fe5cd1da58e2923952d9186382556685 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Tue, 1 Jul 2025 17:33:00 -0600 Subject: [PATCH 254/293] fix!: Make fold the default --- benches/bench.rs | 13 +- examples/custom_error.rs | 13 +- examples/custom_level.rs | 2 - examples/expected_type.rs | 1 - examples/format.rs | 1 + examples/highlight_source.rs | 1 - examples/highlight_title.rs | 2 - examples/id_hyperlink.rs | 1 - examples/multislice.rs | 2 + src/renderer/mod.rs | 1 - src/snippet.rs | 2 +- tests/color/fold_ann_multiline.rs | 1 - tests/color/fold_bad_origin_line.rs | 1 - tests/color/fold_leading.rs | 1 - tests/color/fold_trailing.rs | 1 - tests/color/multiline_removal_suggestion.rs | 3 +- tests/color/multiple_annotations.rs | 1 + tests/formatter.rs | 156 +++++++++----------- tests/rustc_tests.rs | 86 ++--------- 19 files changed, 93 insertions(+), 196 deletions(-) diff --git a/benches/bench.rs b/benches/bench.rs index 4e03ae8c..2adcc185 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -71,14 +71,11 @@ fn fold(bencher: divan::Bencher<'_, '_>, context: usize) { .bench_values(|(input, span)| { let message = &[ Group::with_title(Level::ERROR.title("mismatched types").id("E0308")).element( - Snippet::source(&input) - .fold(true) - .path("src/format.rs") - .annotation( - AnnotationKind::Context - .span(span) - .label("expected `Option` because of return type"), - ), + Snippet::source(&input).path("src/format.rs").annotation( + AnnotationKind::Context + .span(span) + .label("expected `Option` because of return type"), + ), ), ]; diff --git a/examples/custom_error.rs b/examples/custom_error.rs index a26dc4af..76ae0cce 100644 --- a/examples/custom_error.rs +++ b/examples/custom_error.rs @@ -22,14 +22,11 @@ pub static C: u32 = 0 - 1; .id("E0080"), ) .element( - Snippet::source(source) - .path("$DIR/err.rs") - .fold(true) - .annotation( - AnnotationKind::Primary - .span(386..391) - .label("attempt to compute `0_u32 - 1_u32`, which would overflow"), - ), + Snippet::source(source).path("$DIR/err.rs").annotation( + AnnotationKind::Primary + .span(386..391) + .label("attempt to compute `0_u32 - 1_u32`, which would overflow"), + ), )]; let renderer = Renderer::styled().theme(OutputTheme::Unicode); diff --git a/examples/custom_level.rs b/examples/custom_level.rs index 3cf475d0..41e8322f 100644 --- a/examples/custom_level.rs +++ b/examples/custom_level.rs @@ -39,7 +39,6 @@ fn main() { Snippet::source(source) .line_start(1) .path("$DIR/issue-114529-illegal-break-with-value.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(483..581) @@ -60,7 +59,6 @@ fn main() { Snippet::source(source) .line_start(1) .path("$DIR/issue-114529-illegal-break-with-value.rs") - .fold(true) .patch(Patch::new(483..581, "break")), ), ]; diff --git a/examples/expected_type.rs b/examples/expected_type.rs index 6bbf0812..37120b38 100644 --- a/examples/expected_type.rs +++ b/examples/expected_type.rs @@ -11,7 +11,6 @@ fn main() { Snippet::source(source) .line_start(26) .path("examples/footer.rs") - .fold(true) .annotation(AnnotationKind::Primary.span(193..195).label( "expected struct `annotate_snippets::snippet::Slice`, found reference", )) diff --git a/examples/format.rs b/examples/format.rs index 384453b2..5f9bad3f 100644 --- a/examples/format.rs +++ b/examples/format.rs @@ -28,6 +28,7 @@ fn main() { Snippet::source(source) .line_start(51) .path("src/format.rs") + .fold(false) .annotation( AnnotationKind::Context .span(5..19) diff --git a/examples/highlight_source.rs b/examples/highlight_source.rs index 297ad871..22ab0d68 100644 --- a/examples/highlight_source.rs +++ b/examples/highlight_source.rs @@ -13,7 +13,6 @@ fn main() {} .id("E0010")) .element( Snippet::source(source) - .fold(true) .path("$DIR/E0010-teach.rs") .annotation( AnnotationKind::Primary diff --git a/examples/highlight_title.rs b/examples/highlight_title.rs index 7f6ccb77..1de99cf1 100644 --- a/examples/highlight_title.rs +++ b/examples/highlight_title.rs @@ -45,7 +45,6 @@ fn main() { Group::with_title(Level::ERROR.title("mismatched types").id("E0308")) .element( Snippet::source(source) - .fold(true) .path("$DIR/highlighting.rs") .annotation( AnnotationKind::Primary @@ -61,7 +60,6 @@ fn main() { .element(Level::NOTE.pre_styled_title(&title)), Group::with_title(Level::NOTE.title("function defined here")).element( Snippet::source(source) - .fold(true) .path("$DIR/highlighting.rs") .annotation(AnnotationKind::Context.span(200..333).label("")) .annotation(AnnotationKind::Primary.span(194..199)), diff --git a/examples/id_hyperlink.rs b/examples/id_hyperlink.rs index 6259e4d1..9070b260 100644 --- a/examples/id_hyperlink.rs +++ b/examples/id_hyperlink.rs @@ -17,7 +17,6 @@ fn main() { Snippet::source(source) .line_start(1) .path("$DIR/terminal_urls.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(59..61) diff --git a/examples/multislice.rs b/examples/multislice.rs index 35b745c1..c494afa3 100644 --- a/examples/multislice.rs +++ b/examples/multislice.rs @@ -5,11 +5,13 @@ fn main() { .element( Snippet::>::source("Foo") .line_start(51) + .fold(false) .path("src/format.rs"), ) .element( Snippet::>::source("Faa") .line_start(129) + .fold(false) .path("src/display.rs"), )]; diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index fe29822f..65035c35 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -29,7 +29,6 @@ //! Snippet::source(source) //! .path("temp.rs") //! .line_start(1) -//! .fold(true) //! .annotation( //! AnnotationKind::Primary //! .span(10..13) diff --git a/src/snippet.rs b/src/snippet.rs index 851a55fe..1b317d72 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -168,7 +168,7 @@ impl<'a, T: Clone> Snippet<'a, T> { line_start: 1, source: source.into(), markers: vec![], - fold: false, + fold: true, } } diff --git a/tests/color/fold_ann_multiline.rs b/tests/color/fold_ann_multiline.rs index 68fd4f1b..5115b951 100644 --- a/tests/color/fold_ann_multiline.rs +++ b/tests/color/fold_ann_multiline.rs @@ -33,7 +33,6 @@ fn case() { Snippet::source(source) .path("src/format.rs") .line_start(51) - .fold(true) .annotation(AnnotationKind::Context.span(5..19).label( "expected `std::option::Option` because of return type", )) diff --git a/tests/color/fold_bad_origin_line.rs b/tests/color/fold_bad_origin_line.rs index 99da3c5d..1a04adbd 100644 --- a/tests/color/fold_bad_origin_line.rs +++ b/tests/color/fold_bad_origin_line.rs @@ -13,7 +13,6 @@ invalid syntax Snippet::source(source) .path("path/to/error.rs") .line_start(1) - .fold(true) .annotation(AnnotationKind::Context.span(2..16).label("error here")), )]; let expected = file!["fold_bad_origin_line.term.svg"]; diff --git a/tests/color/fold_leading.rs b/tests/color/fold_leading.rs index e941c805..f4d29e3a 100644 --- a/tests/color/fold_leading.rs +++ b/tests/color/fold_leading.rs @@ -26,7 +26,6 @@ workspace = 20 Snippet::source(source) .path("Cargo.toml") .line_start(1) - .fold(true) .annotation(AnnotationKind::Primary.span(132..134).label("")), )]; let expected = file!["fold_leading.term.svg"]; diff --git a/tests/color/fold_trailing.rs b/tests/color/fold_trailing.rs index 9c85d873..59455c02 100644 --- a/tests/color/fold_trailing.rs +++ b/tests/color/fold_trailing.rs @@ -25,7 +25,6 @@ edition = "2021" Snippet::source(source) .path("Cargo.toml") .line_start(1) - .fold(true) .annotation(AnnotationKind::Primary.span(8..10).label("")), )]; let expected = file!["fold_trailing.term.svg"]; diff --git a/tests/color/multiline_removal_suggestion.rs b/tests/color/multiline_removal_suggestion.rs index 6a98ec40..8559ee93 100644 --- a/tests/color/multiline_removal_suggestion.rs +++ b/tests/color/multiline_removal_suggestion.rs @@ -73,7 +73,6 @@ fn main() {} .element( Snippet::source(source) .path("$DIR/multiline-removal-suggestion.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(769..776) @@ -96,7 +95,7 @@ fn main() {} Group::with_title(Level::HELP.title("consider removing this method call, as the receiver has type `std::vec::IntoIter>` and `std::vec::IntoIter>: Iterator` trivially holds")).element( Snippet::source(source) .path("$DIR/multiline-removal-suggestion.rs") - .fold(true) + .patch(Patch::new(708..768, "")), ), ]; diff --git a/tests/color/multiple_annotations.rs b/tests/color/multiple_annotations.rs index 4533019a..a92c72f6 100644 --- a/tests/color/multiple_annotations.rs +++ b/tests/color/multiple_annotations.rs @@ -18,6 +18,7 @@ fn case() { let input = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source(source) .line_start(96) + .fold(false) .annotation( AnnotationKind::Primary .span(100..110) diff --git a/tests/formatter.rs b/tests/formatter.rs index a4c6f6ff..2c109577 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -8,8 +8,7 @@ fn test_i_29() { let snippets = &[Group::with_title(Level::ERROR.title("oops")).element( Snippet::source("First line\r\nSecond oops line") .path("") - .annotation(AnnotationKind::Primary.span(19..23).label("oops")) - .fold(true), + .annotation(AnnotationKind::Primary.span(19..23).label("oops")), )]; let expected = str![[r#" error: oops @@ -122,8 +121,11 @@ fn test_format_title() { #[test] fn test_format_snippet_only() { let source = "This is line 1\nThis is line 2"; - let input = &[Group::with_title(Level::ERROR.title("")) - .element(Snippet::>::source(source).line_start(5402))]; + let input = &[Group::with_title(Level::ERROR.title("")).element( + Snippet::>::source(source) + .line_start(5402) + .fold(false), + )]; let expected = str![[r#" error: @@ -143,12 +145,14 @@ fn test_format_snippets_continuation() { .element( Snippet::>::source(src_0) .line_start(5402) - .path("file1.rs"), + .path("file1.rs") + .fold(false), ) .element( Snippet::>::source(src_1) .line_start(2) - .path("file2.rs"), + .path("file2.rs") + .fold(false), )]; let expected = str![[r#" error: @@ -172,11 +176,14 @@ fn test_format_snippet_annotation_standalone() { // In line 2 let range = 22..24; let input = &[Group::with_title(Level::ERROR.title("")).element( - Snippet::source(&source).line_start(5402).annotation( - AnnotationKind::Context - .span(range.clone()) - .label("Test annotation"), - ), + Snippet::source(&source) + .line_start(5402) + .fold(false) + .annotation( + AnnotationKind::Context + .span(range.clone()) + .label("Test annotation"), + ), )]; let expected = str![[r#" error: @@ -221,8 +228,11 @@ fn test_i26() { #[test] fn test_source_content() { let source = "This is an example\nof content lines"; - let input = &[Group::with_title(Level::ERROR.title("")) - .element(Snippet::>::source(source).line_start(56))]; + let input = &[Group::with_title(Level::ERROR.title("")).element( + Snippet::>::source(source) + .line_start(56) + .fold(false), + )]; let expected = str![[r#" error: | @@ -275,8 +285,11 @@ error: #[test] fn test_only_source() { - let input = &[Group::with_title(Level::ERROR.title("")) - .element(Snippet::>::source("").path("file.rs"))]; + let input = &[Group::with_title(Level::ERROR.title("")).element( + Snippet::>::source("") + .path("file.rs") + .fold(false), + )]; let expected = str![[r#" error: --> file.rs @@ -290,8 +303,11 @@ error: #[test] fn test_anon_lines() { let source = "This is an example\nof content lines\n\nabc"; - let input = &[Group::with_title(Level::ERROR.title("")) - .element(Snippet::>::source(source).line_start(56))]; + let input = &[Group::with_title(Level::ERROR.title("")).element( + Snippet::>::source(source) + .line_start(56) + .fold(false), + )]; let expected = str![[r#" error: | @@ -310,7 +326,6 @@ fn issue_130() { Snippet::source("foo\nbar\nbaz") .path("file/path") .line_start(3) - .fold(true) .annotation(AnnotationKind::Primary.span(4..11)), // bar\nbaz )]; @@ -337,7 +352,6 @@ a\" Snippet::source(source) .path("file/path") .line_start(3) - .fold(true) .annotation(AnnotationKind::Primary.span(0..10)), // 1..10 works )]; @@ -360,6 +374,7 @@ fn char_and_nl_annotate_char() { Snippet::source(source) .path("file/path") .line_start(3) + .fold(false) .annotation(AnnotationKind::Primary.span(0..2)), // a\r )]; @@ -402,6 +417,7 @@ fn char_eol_annotate_char_double_width() { let snippets = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source("こん\r\nにちは\r\n世界") .path("") + .fold(false) .annotation(AnnotationKind::Primary.span(3..8)), // ん\r\n )]; @@ -428,6 +444,7 @@ fn annotate_eol() { Snippet::source(source) .path("file/path") .line_start(3) + .fold(false) .annotation(AnnotationKind::Primary.span(1..2)), // \r )]; @@ -496,6 +513,7 @@ fn annotate_eol4() { Snippet::source(source) .path("file/path") .line_start(3) + .fold(false) .annotation(AnnotationKind::Primary.span(2..2)), // \n )]; @@ -516,6 +534,7 @@ fn annotate_eol_double_width() { let snippets = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source("こん\r\nにちは\r\n世界") .path("") + .fold(false) .annotation(AnnotationKind::Primary.span(7..8)), // \n )]; @@ -609,6 +628,7 @@ fn multiline_eol_start_double_width() { let snippets = &[Group::with_title(Level::ERROR.title("")).element( Snippet::source("こん\r\nにちは\r\n世界") .path("") + .fold(false) .annotation(AnnotationKind::Primary.span(7..11)), // \r\nに )]; @@ -659,6 +679,7 @@ fn multiline_eol_start_eol_end2() { Snippet::source(source) .path("file/path") .line_start(3) + .fold(false) .annotation(AnnotationKind::Primary.span(2..5)), // \nb\r )]; @@ -982,24 +1003,12 @@ fn two_suggestions_same_span() { .title("expected value, found enum `A`") .id("E0423"), ) - .element( - Snippet::source(source) - .fold(true) - .annotation(AnnotationKind::Primary.span(4..5)), - ), + .element(Snippet::source(source).annotation(AnnotationKind::Primary.span(4..5))), Group::with_title( Level::HELP.title("you might have meant to use one of the following enum variants"), ) - .element( - Snippet::source(source) - .fold(true) - .patch(Patch::new(4..5, "(A::Tuple())")), - ) - .element( - Snippet::source(source) - .fold(true) - .patch(Patch::new(4..5, "A::Unit")), - ), + .element(Snippet::source(source).patch(Patch::new(4..5, "(A::Tuple())"))) + .element(Snippet::source(source).patch(Patch::new(4..5, "A::Unit"))), ]; let expected = str![[r#" @@ -1047,7 +1056,7 @@ fn main() { .id("E0599")).element( Snippet::source(source) .line_start(1) - .fold(true) + .annotation( AnnotationKind::Context .span(18..40) @@ -1064,12 +1073,12 @@ fn main() { )) .element( Snippet::source(source) - .fold(true) + .patch(Patch::new(1..1, "use banana::Apple;\n")), ) .element( Snippet::source(source) - .fold(true) + .patch(Patch::new(1..1, "use banana::Peach;\n")), )]; let expected = str![[r#" @@ -1104,14 +1113,11 @@ fn single_line_non_overlapping_suggestions() { ) .element( Snippet::source(source) - .fold(true) .line_start(1) .annotation(AnnotationKind::Primary.span(4..5)), ), Group::with_title(Level::HELP.title("make these changes and things will work")).element( Snippet::source(source) - .fold(true) - .fold(true) .patch(Patch::new(4..5, "(A::Tuple())")) .patch(Patch::new(6..9, "bar")), ), @@ -1139,14 +1145,11 @@ fn single_line_non_overlapping_suggestions2() { let input_new = &[ Group::with_title(Level::ERROR.title("Found `ThisIsVeryLong`").id("E0423")).element( Snippet::source(source) - .fold(true) .line_start(1) .annotation(AnnotationKind::Primary.span(4..18)), ), Group::with_title(Level::HELP.title("make these changes and things will work")).element( Snippet::source(source) - .fold(true) - .fold(true) .patch(Patch::new(4..18, "(A::Tuple())")) .patch(Patch::new(19..22, "bar")), ), @@ -1187,7 +1190,6 @@ fn multiple_replacements() { .element( Snippet::source(source) .line_start(1) - .fold(true) .annotation( AnnotationKind::Primary .span(49..59) @@ -1214,7 +1216,6 @@ fn multiple_replacements() { ) .element( Snippet::source(source) - .fold(true) .patch(Patch::new(14..14, "this: &Self")) .patch(Patch::new(26..30, "this")) .patch(Patch::new(66..68, "(self)")), @@ -1269,7 +1270,6 @@ fn main() { .element( Snippet::source(source) .line_start(1) - .fold(true) .annotation( AnnotationKind::Context .span(65..70) @@ -1291,7 +1291,6 @@ fn main() { )) .element( Snippet::source(source) - .fold(true) .patch(Patch::new( 55..59, "let iter = chars.by_ref();\n while let Some(", @@ -1349,28 +1348,18 @@ fn main() {}"#; .id("E0433"), ) .element( - Snippet::source(source).line_start(1).fold(true).annotation( + Snippet::source(source).line_start(1).annotation( AnnotationKind::Primary .span(122..124) .label("use of undeclared crate or module `st`"), ), ), Group::with_title(Level::HELP.title("there is a crate or module with a similar name")) - .element( - Snippet::source(source) - .fold(true) - .patch(Patch::new(122..124, "std")), - ), - Group::with_title(Level::HELP.title("consider importing this module")).element( - Snippet::source(source) - .fold(true) - .patch(Patch::new(1..1, "use std::cell;\n")), - ), - Group::with_title(Level::HELP.title("if you import `cell`, refer to it directly")).element( - Snippet::source(source) - .fold(true) - .patch(Patch::new(122..126, "")), - ), + .element(Snippet::source(source).patch(Patch::new(122..124, "std"))), + Group::with_title(Level::HELP.title("consider importing this module")) + .element(Snippet::source(source).patch(Patch::new(1..1, "use std::cell;\n"))), + Group::with_title(Level::HELP.title("if you import `cell`, refer to it directly")) + .element(Snippet::source(source).patch(Patch::new(122..126, ""))), ]; let expected = str![[r#" error[E0433]: failed to resolve: use of undeclared crate or module `st` @@ -1424,7 +1413,6 @@ fn main() {}"#; .element( Snippet::source(source) .line_start(1) - .fold(true) .annotation( AnnotationKind::Primary .span(39..49) @@ -1440,11 +1428,7 @@ fn main() {}"#; Level::HELP .title("consider removing the `?Sized` bound to make the type parameter `Sized`"), ) - .element( - Snippet::source(source) - .fold(true) - .patch(Patch::new(52..85, "")), - ), + .element(Snippet::source(source).patch(Patch::new(52..85, ""))), ]; let expected = str![[r#" error[E0277]: the size for values of type `T` cannot be known at compilation time @@ -1489,7 +1473,7 @@ fn main() {}"#; .id("E0277")).element(Snippet::source(source) .line_start(1) .path("$DIR/removal-of-multiline-trait-bound-in-where-clause.rs") - .fold(true) + .annotation( AnnotationKind::Primary .span(39..49) @@ -1507,7 +1491,7 @@ fn main() {}"#; Snippet::source(source) .line_start(1) .path("$DIR/removal-of-multiline-trait-bound-in-where-clause.rs") - .fold(true) + .annotation( AnnotationKind::Primary .span(16..17) @@ -1521,7 +1505,7 @@ fn main() {}"#; Snippet::source(source) .line_start(1) .path("$DIR/removal-of-multiline-trait-bound-in-where-clause.rs") - .fold(true) + .annotation( AnnotationKind::Primary .span(16..17) @@ -1538,7 +1522,7 @@ fn main() {}"#; .title("consider removing the `?Sized` bound to make the type parameter `Sized`") ).element( Snippet::source(source) - .fold(true) + .patch(Patch::new(56..89, "")) .patch(Patch::new(89..89, "+ Send")) , @@ -1604,7 +1588,6 @@ zappy .element( Snippet::source(source) .line_start(7) - .fold(true) .patch(Patch::new(3..21, "")) .patch(Patch::new(22..40, "")), ), @@ -1666,7 +1649,7 @@ fn main() { .id("E0271")).element(Snippet::source(source) .line_start(4) .path("$DIR/E0271.rs") - .fold(true) + .annotation( AnnotationKind::Primary .span(208..510) @@ -1677,7 +1660,7 @@ fn main() { Snippet::source(source) .line_start(4) .path("$DIR/E0271.rs") - .fold(true) + .annotation(AnnotationKind::Primary.span(89..90)) ).element( Level::NOTE @@ -1752,7 +1735,7 @@ fn main() { .id("E0271")).element(Snippet::source(source) .line_start(4) .path("$DIR/E0271.rs") - .fold(true) + .annotation( AnnotationKind::Primary .span(208..510) @@ -1763,7 +1746,7 @@ fn main() { Snippet::source(source) .line_start(4) .path("$DIR/E0271.rs") - .fold(true) + .annotation(AnnotationKind::Primary.span(89..90)) ).element( Level::NOTE @@ -1904,7 +1887,7 @@ fn main() { Snippet::source(source) .line_start(7) .path("$DIR/long-E0308.rs") - .fold(true) + .annotation( AnnotationKind::Primary .span(719..1001) @@ -1988,7 +1971,7 @@ fn main() { Snippet::source(source) .line_start(7) .path("$DIR/unicode-output.rs") - .fold(true) + .annotation( AnnotationKind::Primary .span(430..440) @@ -2009,7 +1992,7 @@ fn main() { Snippet::source(source) .line_start(7) .path("$DIR/unicode-output.rs") - .fold(true) + .annotation(AnnotationKind::Primary.span(77..210)) .annotation(AnnotationKind::Context.span(71..76)), )]; @@ -2207,7 +2190,6 @@ fn main() { Group::with_title(Level::ERROR.title("mismatched types").id("E0308")).element( Snippet::source(source) .path("$DIR/non-whitespace-trimming-unicode.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(1207..1209) @@ -2268,7 +2250,6 @@ fn main() { .element( Snippet::source(source) .path("$DIR/non-1-width-unicode-multiline-label.rs") - .fold(true) .annotation(AnnotationKind::Context.span(970..984).label("&str")) .annotation(AnnotationKind::Context.span(987..1001).label("&str")) .annotation( @@ -2282,7 +2263,6 @@ fn main() { .element( Snippet::source(source) .path("$DIR/non-1-width-unicode-multiline-label.rs") - .fold(true) .patch(Patch::new(984..984, ".to_owned()")), ), ]; @@ -2343,14 +2323,14 @@ fn foo() { .title("couldn't read `$DIR/not-utf8.bin`: stream did not contain valid UTF-8")).element( Snippet::source(source) .path("$DIR/not-utf8.rs") - .fold(true) + .annotation(AnnotationKind::Primary.span(136..160)), ), Group::with_title(Level::NOTE.title("byte `193` is not valid utf-8")) .element( Snippet::source(bin_source) .path("$DIR/not-utf8.bin") - .fold(true) + .annotation(AnnotationKind::Primary.span(0..0)), ) .element(Level::NOTE.title("this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)")), @@ -2404,7 +2384,6 @@ fn secondary_title_no_level_text() { .element( Snippet::source(source) .path("$DIR/mismatched-types.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(105..131) @@ -2450,7 +2429,6 @@ fn secondary_title_custom_level_text() { .element( Snippet::source(source) .path("$DIR/mismatched-types.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(105..131) @@ -2524,7 +2502,6 @@ fn main() { Snippet::source(source) .line_start(1) .path("$DIR/issue-114529-illegal-break-with-value.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(483..581) @@ -2546,7 +2523,6 @@ fn main() { Snippet::source(source) .line_start(1) .path("$DIR/issue-114529-illegal-break-with-value.rs") - .fold(true) .patch(Patch::new(483..581, "break")), ), ]; diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index 29b84006..4b1944a5 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -17,7 +17,6 @@ fn foo() { Snippet::source(source) .line_start(1) .path("test.rs") - .fold(true) .annotation(AnnotationKind::Primary.span(10..13).label("test")), )]; @@ -45,7 +44,6 @@ fn foo() { Snippet::source(source) .line_start(1) .path("test.rs") - .fold(true) .annotation(AnnotationKind::Primary.span(10..17).label("test")), )]; let expected = str![[r#" @@ -74,7 +72,6 @@ fn foo() { Snippet::source(source) .line_start(1) .path("test.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(14..32) @@ -115,7 +112,6 @@ fn foo() { Snippet::source(source) .line_start(1) .path("test.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(14..27) @@ -157,7 +153,6 @@ fn foo() { Snippet::source(source) .line_start(1) .path("test.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(17..38) @@ -199,7 +194,6 @@ fn foo() { Snippet::source(source) .line_start(1) .path("test.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(14..38) @@ -244,7 +238,6 @@ fn foo() { Snippet::source(source) .line_start(1) .path("test.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(14..38) @@ -290,7 +283,6 @@ fn foo() { Snippet::source(source) .line_start(1) .path("test.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(17..27) @@ -338,7 +330,6 @@ fn foo() { Snippet::source(source) .line_start(1) .path("test.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(14..27) @@ -380,7 +371,6 @@ fn foo() { Snippet::source(source) .line_start(1) .path("test.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(17..27) @@ -421,7 +411,6 @@ fn foo() { Snippet::source(source) .line_start(1) .path("test.rs") - .fold(true) .annotation(AnnotationKind::Primary.span(18..25).label("")) .annotation( AnnotationKind::Context @@ -452,7 +441,6 @@ fn foo() { Snippet::source(source) .line_start(1) .path("test.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(14..27) @@ -482,7 +470,6 @@ fn foo() { Snippet::source(source) .line_start(1) .path("test.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(18..25) @@ -515,7 +502,6 @@ fn foo() { Snippet::source(source) .line_start(1) .path("test.rs") - .fold(true) .annotation(AnnotationKind::Primary.span(14..27).label("")) .annotation( AnnotationKind::Context @@ -547,7 +533,6 @@ fn foo() { Snippet::source(source) .line_start(1) .path("test.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(14..18) @@ -579,7 +564,6 @@ fn foo() { Snippet::source(source) .line_start(1) .path("test.rs") - .fold(true) .annotation(AnnotationKind::Primary.span(14..27).label("")) .annotation(AnnotationKind::Context.span(18..25).label("")), )]; @@ -605,7 +589,6 @@ fn foo() { Snippet::source(source) .line_start(1) .path("test.rs") - .fold(true) .annotation(AnnotationKind::Primary.span(18..25).label("")) .annotation(AnnotationKind::Context.span(14..27).label("")) .annotation(AnnotationKind::Context.span(22..23).label("")), @@ -632,7 +615,6 @@ fn foo() { Snippet::source(source) .line_start(1) .path("test.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(14..27) @@ -669,7 +651,6 @@ fn foo() { Snippet::source(source) .line_start(1) .path("test.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(14..27) @@ -698,7 +679,6 @@ fn foo() { Snippet::source(source) .line_start(1) .path("test.rs") - .fold(true) .annotation(AnnotationKind::Primary.span(14..27).label("")), )]; @@ -736,7 +716,6 @@ fn foo() { Snippet::source(source) .line_start(1) .path("test.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(17..27) @@ -794,7 +773,6 @@ fn foo() { Snippet::source(source) .line_start(1) .path("test.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(17..73) @@ -849,7 +827,6 @@ fn f(){||yield(((){), Snippet::source(source) .line_start(1) .path("$DIR/issue-91334.rs") - .fold(true) .annotation( AnnotationKind::Context .span(151..152) @@ -923,7 +900,6 @@ fn main() { Snippet::source(source) .line_start(1) .path("$DIR/issue-114529-illegal-break-with-value.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(483..581) @@ -942,7 +918,6 @@ fn main() { Snippet::source(source) .line_start(1) .path("$DIR/issue-114529-illegal-break-with-value.rs") - .fold(true) .annotation(AnnotationKind::Context.span(483..581).label("break")), ), ]; @@ -1130,7 +1105,6 @@ fn nsize() { Snippet::source(source) .line_start(1) .path("$DIR/primitive_reprs_should_have_correct_length.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(4375..4381) @@ -1141,7 +1115,6 @@ fn nsize() { Snippet::source(source) .line_start(1) .path("$DIR/primitive_reprs_should_have_correct_length.rs") - .fold(true) .annotation( AnnotationKind::Context .span(225..240) @@ -1211,7 +1184,7 @@ fn main() { .id("E027s7")).element( Snippet::source(source) .line_start(1) - .fold(true) + .path("$DIR/align-fail.rs") .annotation( AnnotationKind::Primary @@ -1281,7 +1254,6 @@ fn main() {} Snippet::source(source) .line_start(1) .path("$DIR/missing-semicolon.rs") - .fold(true) .annotation( AnnotationKind::Context .span(108..144) @@ -1372,7 +1344,7 @@ outer_macro!(FirstStruct, FirstAttrStruct); Snippet::source(aux_source) .line_start(1) .path("$DIR/auxiliary/nested-macro-rules.rs") - .fold(true) + .annotation( AnnotationKind::Context .span(41..65) @@ -1384,7 +1356,7 @@ outer_macro!(FirstStruct, FirstAttrStruct); Snippet::source(source) .line_start(1) .path("$DIR/nested-macro-rules.rs") - .fold(true) + .annotation( AnnotationKind::Context .span(510..574) @@ -1404,7 +1376,7 @@ outer_macro!(FirstStruct, FirstAttrStruct); Snippet::source(source) .line_start(1) .path("$DIR/nested-macro-rules.rs") - .fold(true) + .annotation(AnnotationKind::Primary.span(224..245)), )]; let expected = str![[r#" @@ -1503,7 +1475,6 @@ macro_rules! inline { Snippet::source(source) .line_start(1) .path("$DIR/method-on-ambiguous-numeric-type.rs") - .fold(true) .annotation(AnnotationKind::Primary.span(916..919)), ), Group::with_title( @@ -1513,7 +1484,6 @@ macro_rules! inline { Snippet::source(aux_source) .line_start(1) .path("$DIR/auxiliary/macro-in-other-crate.rs") - .fold(true) .annotation(AnnotationKind::Context.span(69..69).label(": i32")), ), ]; @@ -1563,7 +1533,6 @@ fn main() {} Snippet::source(source) .line_start(1) .path("$DIR/issue-42234-unknown-receiver-type.rs") - .fold(true) .annotation(AnnotationKind::Primary.span(536..539).label( "cannot infer type of the type parameter `S` declared on the method `sum`", )), @@ -1670,7 +1639,7 @@ fn main() {} Snippet::source(source) .line_start(1) .path("$DIR/empty-match.rs") - .fold(true) + .annotation( AnnotationKind::Primary .span(2911..2928) @@ -1682,7 +1651,7 @@ fn main() {} Snippet::source(source) .line_start(1) .path("$DIR/empty-match.rs") - .fold(true) + .annotation(AnnotationKind::Primary.span(818..831)) .annotation(AnnotationKind::Context.span(842..844).label("not covered")) .annotation(AnnotationKind::Context.span(854..856).label("not covered")) @@ -1701,7 +1670,7 @@ fn main() {} Snippet::source(source) .line_start(1) .path("$DIR/empty-match.rs") - .fold(true) + .annotation(AnnotationKind::Context.span(485..485).label(",\n _ => todo!()")) )]; @@ -1763,7 +1732,7 @@ fn main() { Snippet::source(source) .line_start(1) .path("$DIR/object-fail.rs") - .fold(true) + .annotation( AnnotationKind::Primary .span(107..114) @@ -1785,7 +1754,7 @@ fn main() { Snippet::source(source) .line_start(1) .path("$DIR/object-fail.rs") - .fold(true) + .annotation( AnnotationKind::Context .span(32..39) @@ -1827,7 +1796,6 @@ fn main() {} Group::with_title(Level::ERROR.title("mismatched types").id("E0038")).element( Snippet::source(source) .path("$DIR/long-span.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(15..5055) @@ -1861,7 +1829,6 @@ fn main() {} Group::with_title(Level::ERROR.title("mismatched types").id("E0038")).element( Snippet::source(source) .path("$DIR/long-span.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(15..5055) @@ -1896,7 +1863,6 @@ fn main() {} Group::with_title(Level::ERROR.title("mismatched types").id("E0038")).element( Snippet::source(source) .path("$DIR/long-span.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(15..5055) @@ -1931,7 +1897,6 @@ fn main() {} Group::with_title(Level::ERROR.title("mismatched types").id("E0038")).element( Snippet::source(source) .path("$DIR/long-span.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(15..5055) @@ -1983,7 +1948,7 @@ fn main() { .element( Snippet::source(source) .path("$DIR/lint_map_unit_fn.rs") - .fold(true) + .annotation(AnnotationKind::Context.span(271..278).label( "this function returns `()`, which is likely not what you wanted", )) @@ -2005,7 +1970,7 @@ fn main() { .element( Snippet::source(source) .path("$DIR/lint_map_unit_fn.rs") - .fold(true) + .patch(Patch::new(267..270, r#"for_each"#)), )]; @@ -2071,14 +2036,12 @@ fn main() { Group::with_title(Level::ERROR.title("character constant must be escaped: `\\n`")).element( Snippet::source(source) .path("$DIR/bad-char-literals.rs") - .fold(true) .annotation(AnnotationKind::Primary.span(204..205)), ), Group::with_title(Level::HELP.title("escape the character")).element( Snippet::source(source) .path("$DIR/bad-char-literals.rs") .line_start(1) - .fold(true) .patch(Patch::new(204..205, r#"\n"#)), ), ]; @@ -2120,13 +2083,11 @@ fn main() {} Group::with_title(Level::ERROR.title("unclosed frontmatter")).element( Snippet::source(source) .path("$DIR/unclosed-1.rs") - .fold(true) .annotation(AnnotationKind::Primary.span(0..221)), ), Group::with_title(Level::NOTE.title("frontmatter opening here was not closed")).element( Snippet::source(source) .path("$DIR/unclosed-1.rs") - .fold(true) .annotation(AnnotationKind::Primary.span(0..4)), ), ]; @@ -2174,13 +2135,11 @@ fn foo() -> &str { Group::with_title(Level::ERROR.title("unclosed frontmatter")).element( Snippet::source(source) .path("$DIR/unclosed-2.rs") - .fold(true) .annotation(AnnotationKind::Primary.span(0..377)), ), Group::with_title(Level::NOTE.title("frontmatter opening here was not closed")).element( Snippet::source(source) .path("$DIR/unclosed-2.rs") - .fold(true) .annotation(AnnotationKind::Primary.span(0..4)), ), ]; @@ -2231,7 +2190,6 @@ fn foo(x: i32) -> i32 { .element( Snippet::source(source) .path("$DIR/unclosed-3.rs") - .fold(true) .annotation(AnnotationKind::Primary.span(302..310)), ), Group::with_title( @@ -2240,7 +2198,6 @@ fn foo(x: i32) -> i32 { .element( Snippet::source(source) .path("$DIR/unclosed-3.rs") - .fold(true) .annotation(AnnotationKind::Primary.span(302..306)), ), ]; @@ -2280,13 +2237,11 @@ fn main() {} Group::with_title(Level::ERROR.title("unclosed frontmatter")).element( Snippet::source(source) .path("$DIR/unclosed-4.rs") - .fold(true) .annotation(AnnotationKind::Primary.span(0..43)), ), Group::with_title(Level::NOTE.title("frontmatter opening here was not closed")).element( Snippet::source(source) .path("$DIR/unclosed-4.rs") - .fold(true) .annotation(AnnotationKind::Primary.span(0..4)), ), ]; @@ -2329,13 +2284,11 @@ fn main() {} Group::with_title(Level::ERROR.title("unclosed frontmatter")).element( Snippet::source(source) .path("$DIR/unclosed-5.rs") - .fold(true) .annotation(AnnotationKind::Primary.span(0..176)), ), Group::with_title(Level::NOTE.title("frontmatter opening here was not closed")).element( Snippet::source(source) .path("$DIR/unclosed-5.rs") - .fold(true) .annotation(AnnotationKind::Primary.span(0..4)), ), ]; @@ -2454,13 +2407,11 @@ pub enum E2 { .element( Snippet::source(source) .path("$DIR/pat-tuple-field-count-cross.rs") - .fold(true) .annotation(AnnotationKind::Primary.span(1760..1766)), ) .element( Snippet::source(source1) .path("$DIR/auxiliary/declarations-for-tuple-field-count-errors.rs") - .fold(true) .annotation( AnnotationKind::Context .span(143..145) @@ -2476,13 +2427,11 @@ pub enum E2 { .element( Snippet::source(source) .path("$DIR/pat-tuple-field-count-cross.rs") - .fold(true) .patch(Patch::new(1760..1766, r#"E1::Z1()"#)), ), Group::with_title(Level::HELP.title("a unit variant with a similar name exists")).element( Snippet::source(source) .path("$DIR/pat-tuple-field-count-cross.rs") - .fold(true) .patch(Patch::new(1764..1766, r#"Z0"#)), ), ]; @@ -2528,7 +2477,6 @@ fn unterminated_nested_comment() { Group::with_title(Level::ERROR.title("unterminated block comment").id("E0758")).element( Snippet::source(source) .path("$DIR/unterminated-nested-comment.rs") - .fold(true) .annotation( AnnotationKind::Context .span(0..2) @@ -2584,7 +2532,6 @@ fn mismatched_types1() { Group::with_title(Level::ERROR.title("mismatched types").id("E0308")) .element( Snippet::source(file_txt_source) - .fold(true) .line_start(3) .path("$DIR/file.txt") .annotation( @@ -2596,7 +2543,6 @@ fn mismatched_types1() { .element( Snippet::source(rust_source) .path("$DIR/mismatched-types.rs") - .fold(true) .annotation( AnnotationKind::Context .span(23..28) @@ -2648,7 +2594,6 @@ fn mismatched_types2() { .element( Snippet::source(source) .path("$DIR/mismatched-types.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(105..131) @@ -2701,7 +2646,6 @@ fn main() { Group::with_title(Level::ERROR.title("mismatched types").id("E0308")).element( Snippet::source(source) .path("$DIR/short-error-format.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(80..100) @@ -2716,7 +2660,6 @@ fn main() { Group::with_title(Level::NOTE.title("function defined here")).element( Snippet::source(source) .path("$DIR/short-error-format.rs") - .fold(true) .annotation(AnnotationKind::Context.span(48..54).label("")) .annotation(AnnotationKind::Primary.span(44..47)), ), @@ -2754,7 +2697,6 @@ fn main() { .element( Snippet::source(source) .path("$DIR/short-error-format.rs") - .fold(true) .annotation( AnnotationKind::Primary .span(127..132) @@ -2789,7 +2731,6 @@ pub struct Foo; //~^ ERROR .element( Snippet::source(source_0) .path("$DIR/diagnostic-width.rs") - .fold(true) .annotation(AnnotationKind::Primary.span(111..126)), ) .element( @@ -2798,14 +2739,12 @@ pub struct Foo; //~^ ERROR Group::with_title(Level::NOTE.title("the lint level is defined here")).element( Snippet::source(source_0) .path("$DIR/diagnostic-width.rs") - .fold(true) .annotation(AnnotationKind::Primary.span(49..67)), ), Group::with_title(Level::HELP.title("use an automatic link instead")).element( Snippet::source(source_1) .path("$DIR/diagnostic-width.rs") .line_start(4) - .fold(true) .patch(Patch::new(40..40, "<")) .patch(Patch::new(55..55, ">")), ), @@ -2854,7 +2793,6 @@ fn main() { .element( Snippet::source(source1) .path("lint_example.rs") - .fold(true) .annotation(AnnotationKind::Primary.span(40..49)), ) .element(Level::WARNING.title("this changes meaning in Rust 2021")) @@ -2867,14 +2805,12 @@ fn main() { Snippet::source(source2) .path("lint_example.rs") .line_start(3) - .fold(true) .patch(Patch::new(10..19, "iter")), ), Group::with_title(Level::HELP.title(long_title3)).element( Snippet::source(source2) .path("lint_example.rs") .line_start(3) - .fold(true) .patch(Patch::new(0..0, "IntoIterator::into_iter(")) .patch(Patch::new(9..21, ")")), ), From 5cf3738145e4a87c7da4a5d475546164e04ccae4 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 2 Jul 2025 09:10:15 -0500 Subject: [PATCH 255/293] docs: Cover Renderer::render --- src/renderer/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 65035c35..608613ba 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -225,6 +225,7 @@ impl Renderer { } impl Renderer { + /// Render a diagnostic, a series of [`Group`]s pub fn render(&self, groups: &[Group<'_>]) -> String { if self.short_message { self.render_short_message(groups).unwrap() From 981ef5b9f8031c15fb18b264090ec46d2a155f6e Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 2 Jul 2025 09:29:50 -0500 Subject: [PATCH 256/293] docs: Describe groups --- src/snippet.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/snippet.rs b/src/snippet.rs index 1b317d72..af06326b 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -18,6 +18,10 @@ pub(crate) struct Id<'a> { } /// An [`Element`] container +/// +/// A [diagnostic][crate::Renderer::render] is made of several `Group`s. +/// `Group`s are used to [annotate][AnnotationKind::Primary] [`Snippet`]s +/// with different [semantic reasons][Title]. #[derive(Clone, Debug)] pub struct Group<'a> { pub(crate) primary_level: Level<'a>, From 504b54a79a40f64c441b14f6230605d3102232fe Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 2 Jul 2025 09:57:45 -0500 Subject: [PATCH 257/293] docs: Describe Level::text --- src/level.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/level.rs b/src/level.rs index 5934a280..f608a8c9 100644 --- a/src/level.rs +++ b/src/level.rs @@ -50,6 +50,8 @@ impl<'a> Level<'a> { pub const NOTE: Level<'a> = NOTE; pub const HELP: Level<'a> = HELP; + /// Replace the text describing this [`Level`] + /// ///
/// /// Text passed to this function is considered "untrusted input", as such From ac6423c2b488cebf15286c9932d5f0cdb470adc2 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 2 Jul 2025 10:01:12 -0500 Subject: [PATCH 258/293] fix: Rename `Label::ERROR.text().title()` with `Label::ERROR.with_name().title()` --- examples/custom_error.rs | 2 +- examples/custom_level.rs | 2 +- src/level.rs | 6 +++--- tests/formatter.rs | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/custom_error.rs b/examples/custom_error.rs index 76ae0cce..dde6e3f3 100644 --- a/examples/custom_error.rs +++ b/examples/custom_error.rs @@ -17,7 +17,7 @@ pub static C: u32 = 0 - 1; "#; let message = &[Group::with_title( Level::ERROR - .text(Some("error: internal compiler error")) + .with_name(Some("error: internal compiler error")) .title("could not evaluate static initializer") .id("E0080"), ) diff --git a/examples/custom_level.rs b/examples/custom_level.rs index 41e8322f..97ec9ab3 100644 --- a/examples/custom_level.rs +++ b/examples/custom_level.rs @@ -52,7 +52,7 @@ fn main() { ), Group::with_title( Level::HELP - .text(Some("suggestion")) + .with_name(Some("suggestion")) .title("use `break` on its own without a value inside this `while` loop"), ) .element( diff --git a/src/level.rs b/src/level.rs index f608a8c9..a068e0f9 100644 --- a/src/level.rs +++ b/src/level.rs @@ -50,7 +50,7 @@ impl<'a> Level<'a> { pub const NOTE: Level<'a> = NOTE; pub const HELP: Level<'a> = HELP; - /// Replace the text describing this [`Level`] + /// Replace the name describing this [`Level`] /// ///
/// @@ -59,9 +59,9 @@ impl<'a> Level<'a> { /// not allowed to be passed to this function. /// ///
- pub fn text(self, text: impl Into>) -> Level<'a> { + pub fn with_name(self, name: impl Into>) -> Level<'a> { Level { - name: Some(text.into().0), + name: Some(name.into().0), level: self.level, } } diff --git a/tests/formatter.rs b/tests/formatter.rs index 2c109577..7968a9e8 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -2397,7 +2397,7 @@ fn secondary_title_no_level_text() { ) .element( Level::NOTE - .text(None::<&str>) + .with_name(None::<&str>) .title("expected reference `&str`\nfound reference `&'static [u8; 0]`"), ), ]; @@ -2442,7 +2442,7 @@ fn secondary_title_custom_level_text() { ) .element( Level::NOTE - .text(Some("custom")) + .with_name(Some("custom")) .title("expected reference `&str`\nfound reference `&'static [u8; 0]`"), ), ]; @@ -2515,7 +2515,7 @@ fn main() { ), Group::with_title( Level::HELP - .text(Some("suggestion")) + .with_name(Some("suggestion")) .title("use `break` on its own without a value inside this `while` loop") .id("S0123"), ) From 141206a6ea01c66b1c74f1a99db468c278e62e3f Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 2 Jul 2025 10:10:54 -0500 Subject: [PATCH 259/293] feat: Add Level::no_name --- src/level.rs | 5 +++++ tests/formatter.rs | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/level.rs b/src/level.rs index a068e0f9..036cf7db 100644 --- a/src/level.rs +++ b/src/level.rs @@ -65,6 +65,11 @@ impl<'a> Level<'a> { level: self.level, } } + + /// Do not show the [`Level`]s name + pub fn no_name(self) -> Level<'a> { + self.with_name(None::<&str>) + } } impl<'a> Level<'a> { diff --git a/tests/formatter.rs b/tests/formatter.rs index 7968a9e8..6ebfd948 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -2397,7 +2397,7 @@ fn secondary_title_no_level_text() { ) .element( Level::NOTE - .with_name(None::<&str>) + .no_name() .title("expected reference `&str`\nfound reference `&'static [u8; 0]`"), ), ]; From 8cd2f36c779657ba1ed4fdad5ae59d3a63a0ad7f Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 2 Jul 2025 10:31:24 -0500 Subject: [PATCH 260/293] refactor: Generalize Title::title to Title::text --- src/level.rs | 8 ++++---- src/renderer/mod.rs | 4 ++-- src/snippet.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/level.rs b/src/level.rs index 036cf7db..4fec9959 100644 --- a/src/level.rs +++ b/src/level.rs @@ -80,11 +80,11 @@ impl<'a> Level<'a> { /// not allowed to be passed to this function. /// ///
- pub fn title(self, title: impl Into>) -> Title<'a> { + pub fn title(self, text: impl Into>) -> Title<'a> { Title { level: self, id: None, - title: title.into(), + text: text.into(), is_pre_styled: false, } } @@ -97,11 +97,11 @@ impl<'a> Level<'a> { /// used to normalize untrusted text before it is passed to this function. /// ///
- pub fn pre_styled_title(self, title: impl Into>) -> Title<'a> { + pub fn pre_styled_title(self, text: impl Into>) -> Title<'a> { Title { level: self, id: None, - title: title.into(), + text: text.into(), is_pre_styled: true, } } diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 608613ba..0970c749 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -585,9 +585,9 @@ impl Renderer { }); let (title_str, style) = if title.is_pre_styled { - (title.title.to_string(), ElementStyle::NoStyle) + (title.text.to_string(), ElementStyle::NoStyle) } else { - (normalize_whitespace(&title.title), title_element_style) + (normalize_whitespace(&title.text), title_element_style) }; for (i, text) in title_str.lines().enumerate() { if i != 0 { diff --git a/src/snippet.rs b/src/snippet.rs index af06326b..4ea0ed79 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -110,7 +110,7 @@ pub struct Padding; pub struct Title<'a> { pub(crate) level: Level<'a>, pub(crate) id: Option>, - pub(crate) title: Cow<'a, str>, + pub(crate) text: Cow<'a, str>, pub(crate) is_pre_styled: bool, } From 6cefcbb243ff9d7e3e58f8a3faa77642cb38c54d Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 2 Jul 2025 10:36:20 -0500 Subject: [PATCH 261/293] docs(examples): Clarify we are highlighting a message, not a title --- examples/highlight_title.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/highlight_title.rs b/examples/highlight_title.rs index 1de99cf1..53575584 100644 --- a/examples/highlight_title.rs +++ b/examples/highlight_title.rs @@ -28,7 +28,7 @@ fn main() { let magenta = annotate_snippets::renderer::AnsiColor::Magenta .on_default() .effects(Effects::BOLD); - let title = format!( + let message = format!( "expected fn pointer `{}for<'a>{} fn(Box<{}(dyn Any + Send + 'a){}>) -> Pin<_>` found fn item `fn(Box<{}(dyn Any + Send + 'static){}>) -> Pin<_> {}{{wrapped_fn}}{}`", magenta.render(), @@ -57,7 +57,7 @@ fn main() { .label("arguments to this function are incorrect"), ), ) - .element(Level::NOTE.pre_styled_title(&title)), + .element(Level::NOTE.pre_styled_title(&message)), Group::with_title(Level::NOTE.title("function defined here")).element( Snippet::source(source) .path("$DIR/highlighting.rs") From 3a598feee1376ccacc1d76d7388c0426249f2f9e Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 2 Jul 2025 10:37:01 -0500 Subject: [PATCH 262/293] docs(examples): Clarify we are highlighting a message, not a title --- examples/{highlight_title.rs => highlight_message.rs} | 0 examples/{highlight_title.svg => highlight_message.svg} | 0 tests/examples.rs | 6 +++--- 3 files changed, 3 insertions(+), 3 deletions(-) rename examples/{highlight_title.rs => highlight_message.rs} (100%) rename examples/{highlight_title.svg => highlight_message.svg} (100%) diff --git a/examples/highlight_title.rs b/examples/highlight_message.rs similarity index 100% rename from examples/highlight_title.rs rename to examples/highlight_message.rs diff --git a/examples/highlight_title.svg b/examples/highlight_message.svg similarity index 100% rename from examples/highlight_title.svg rename to examples/highlight_message.svg diff --git a/tests/examples.rs b/tests/examples.rs index db00bc1f..226c31fd 100644 --- a/tests/examples.rs +++ b/tests/examples.rs @@ -50,9 +50,9 @@ fn highlight_source() { } #[test] -fn highlight_title() { - let target = "highlight_title"; - let expected = snapbox::file!["../examples/highlight_title.svg": TermSvg]; +fn highlight_message() { + let target = "highlight_message"; + let expected = snapbox::file!["../examples/highlight_message.svg": TermSvg]; assert_example(target, expected); } From ea73333d9d33b5f1218e1a0cded09d9e0cde9965 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 2 Jul 2025 10:38:16 -0500 Subject: [PATCH 263/293] fix: Rename Level::pre_styled_title to Level::message --- examples/highlight_message.rs | 2 +- src/level.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/highlight_message.rs b/examples/highlight_message.rs index 53575584..aaf49105 100644 --- a/examples/highlight_message.rs +++ b/examples/highlight_message.rs @@ -57,7 +57,7 @@ fn main() { .label("arguments to this function are incorrect"), ), ) - .element(Level::NOTE.pre_styled_title(&message)), + .element(Level::NOTE.message(&message)), Group::with_title(Level::NOTE.title("function defined here")).element( Snippet::source(source) .path("$DIR/highlighting.rs") diff --git a/src/level.rs b/src/level.rs index 4fec9959..972a2dd8 100644 --- a/src/level.rs +++ b/src/level.rs @@ -97,7 +97,7 @@ impl<'a> Level<'a> { /// used to normalize untrusted text before it is passed to this function. /// /// - pub fn pre_styled_title(self, text: impl Into>) -> Title<'a> { + pub fn message(self, text: impl Into>) -> Title<'a> { Title { level: self, id: None, From 7ec47b1e2c0a7c0e06b7bc39c1a19cc2d706e976 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 2 Jul 2025 10:40:13 -0500 Subject: [PATCH 264/293] docs: Switch all messages to Level::message --- examples/elide_header.rs | 2 +- tests/formatter.rs | 8 +++++--- tests/rustc_tests.rs | 12 ++++++------ 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/examples/elide_header.rs b/examples/elide_header.rs index 436bb25e..c7deda16 100644 --- a/examples/elide_header.rs +++ b/examples/elide_header.rs @@ -14,7 +14,7 @@ def foobar(door, bar={}): .fold(false) .annotation(AnnotationKind::Primary.span(56..58).label("B006")), ) - .element(Level::HELP.title("Replace with `None`; initialize within function"))]; + .element(Level::HELP.message("Replace with `None`; initialize within function"))]; let renderer = Renderer::styled(); anstream::println!("{}", renderer.render(message)); diff --git a/tests/formatter.rs b/tests/formatter.rs index 6ebfd948..fe16ca9c 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -199,7 +199,7 @@ error: #[test] fn test_format_footer_title() { let input = &[Group::with_title(Level::ERROR.title("")) - .element(Level::ERROR.title("This __is__ a title"))]; + .element(Level::ERROR.message("This __is__ a title"))]; let expected = str![[r#" error: | @@ -2258,7 +2258,9 @@ fn main() { .label("`+` cannot be used to concatenate two `&str` strings"), ), ) - .element(Level::NOTE.title("string concatenation requires an owned `String` on the left")), + .element( + Level::NOTE.message("string concatenation requires an owned `String` on the left"), + ), Group::with_title(Level::HELP.title("create an owned `String` from a string reference")) .element( Snippet::source(source) @@ -2333,7 +2335,7 @@ fn foo() { .annotation(AnnotationKind::Primary.span(0..0)), ) - .element(Level::NOTE.title("this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)")), + .element(Level::NOTE.message("this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)")), ]; let expected_ascii = str![[r#" diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index 4b1944a5..c9bba626 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -1659,8 +1659,8 @@ fn main() {} .annotation(AnnotationKind::Context.span(878..880).label("not covered")) .annotation(AnnotationKind::Context.span(890..892).label("not covered")) ) - .element(Level::NOTE.title("the matched value is of type `NonEmptyEnum5`")) - .element(Level::NOTE.title("match arms with guards don't count towards exhaustivity") + .element(Level::NOTE.message("the matched value is of type `NonEmptyEnum5`")) + .element(Level::NOTE.message("match arms with guards don't count towards exhaustivity") ), Group::with_title( Level::HELP @@ -1749,7 +1749,7 @@ fn main() { .primary(true) ) .element(Padding) - .element(Level::NOTE.title("...because it uses `Self` as a type parameter")) + .element(Level::NOTE.message("...because it uses `Self` as a type parameter")) .element( Snippet::source(source) .line_start(1) @@ -2795,9 +2795,9 @@ fn main() { .path("lint_example.rs") .annotation(AnnotationKind::Primary.span(40..49)), ) - .element(Level::WARNING.title("this changes meaning in Rust 2021")) - .element(Level::NOTE.title(long_title2)) - .element(Level::NOTE.title("`#[warn(array_into_iter)]` on by default")), + .element(Level::WARNING.message("this changes meaning in Rust 2021")) + .element(Level::NOTE.message(long_title2)) + .element(Level::NOTE.message("`#[warn(array_into_iter)]` on by default")), Group::with_title( Level::HELP.title("use `.iter()` instead of `.into_iter()` to avoid ambiguity"), ) From 169d8e231926dd7cc5d30ffc5f040d4e73fd840f Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 2 Jul 2025 10:51:28 -0500 Subject: [PATCH 265/293] docs: Clarify Level::title vs Level::message --- src/level.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/level.rs b/src/level.rs index 972a2dd8..74395237 100644 --- a/src/level.rs +++ b/src/level.rs @@ -73,6 +73,10 @@ impl<'a> Level<'a> { } impl<'a> Level<'a> { + /// A text [`Element`][crate::Element] to start a [`Group`][crate::Group] + /// + /// See [`Group::with_title`][crate::Group::with_title] + /// ///
/// /// Text passed to this function is considered "untrusted input", as such @@ -89,6 +93,8 @@ impl<'a> Level<'a> { } } + /// A text [`Element`][crate::Element] in a [`Group`][crate::Group] + /// ///
/// /// Text passed to this function is allowed to be pre-styled, as such all From 4373542d19cc4363f14ba40f32084c46a6961c07 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 2 Jul 2025 10:47:43 -0500 Subject: [PATCH 266/293] fix: Make Message a distinct type This makes it clearer that we shouldn't set `id` on this. If someone wants to set an `id`, they should create a new `Group` which will have a `Title`. --- src/level.rs | 9 ++--- src/renderer/mod.rs | 99 ++++++++++++++++++++++++++++++++++++++------- src/snippet.rs | 19 ++++++++- 3 files changed, 105 insertions(+), 22 deletions(-) diff --git a/src/level.rs b/src/level.rs index 74395237..8eaaa87d 100644 --- a/src/level.rs +++ b/src/level.rs @@ -2,7 +2,7 @@ use crate::renderer::stylesheet::Stylesheet; use crate::snippet::{ERROR_TXT, HELP_TXT, INFO_TXT, NOTE_TXT, WARNING_TXT}; -use crate::{OptionCow, Title}; +use crate::{Message, OptionCow, Title}; use anstyle::Style; use std::borrow::Cow; @@ -89,7 +89,6 @@ impl<'a> Level<'a> { level: self, id: None, text: text.into(), - is_pre_styled: false, } } @@ -103,12 +102,10 @@ impl<'a> Level<'a> { /// used to normalize untrusted text before it is passed to this function. /// ///
- pub fn message(self, text: impl Into>) -> Title<'a> { - Title { + pub fn message(self, text: impl Into>) -> Message<'a> { + Message { level: self, - id: None, text: text.into(), - is_pre_styled: true, } } diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 0970c749..b5eff063 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -48,7 +48,7 @@ use crate::renderer::source_map::{ }; use crate::renderer::styled_buffer::StyledBuffer; use crate::snippet::Id; -use crate::{Annotation, AnnotationKind, Element, Group, Origin, Patch, Snippet, Title}; +use crate::{Annotation, AnnotationKind, Element, Group, Message, Origin, Patch, Snippet, Title}; pub use anstyle::*; use margin::Margin; use std::borrow::Cow; @@ -303,7 +303,20 @@ impl Renderer { title, max_line_num_len, title_style, - matches!(peek, Some(Element::Title(_))), + matches!(peek, Some(Element::Title(_) | Element::Message(_))), + buffer_msg_line_offset, + ); + last_was_suggestion = false; + } + Element::Message(title) => { + let title_style = TitleStyle::Secondary; + let buffer_msg_line_offset = buffer.num_lines(); + self.render_title( + &mut buffer, + title, + max_line_num_len, + title_style, + matches!(peek, Some(Element::Title(_) | Element::Message(_))), buffer_msg_line_offset, ); last_was_suggestion = false; @@ -336,6 +349,16 @@ impl Renderer { ); } + Some(Element::Message(level)) + if level.level.name != Some(None) => + { + self.draw_col_separator_no_space( + &mut buffer, + current_line, + max_line_num_len + 1, + ); + } + None if group_len > 1 => self.draw_col_separator_end( &mut buffer, current_line, @@ -384,7 +407,8 @@ impl Renderer { if g == 0 && (matches!(section, Element::Origin(_)) || (matches!(section, Element::Title(_)) && i == 0) - || matches!(section, Element::Title(level) if level.level.name == Some(None))) + || matches!(section, Element::Title(level) if level.level.name == Some(None)) + || matches!(section, Element::Message(level) if level.level.name == Some(None))) { let current_line = buffer.num_lines(); if peek.is_none() && group_len > 1 { @@ -394,6 +418,13 @@ impl Renderer { max_line_num_len + 1, ); } else if matches!(peek, Some(Element::Title(level)) if level.level.name != Some(None)) + { + self.draw_col_separator_no_space( + &mut buffer, + current_line, + max_line_num_len + 1, + ); + } else if matches!(peek, Some(Element::Message(level)) if level.level.name != Some(None)) { self.draw_col_separator_no_space( &mut buffer, @@ -503,7 +534,7 @@ impl Renderer { fn render_title( &self, buffer: &mut StyledBuffer, - title: &Title<'_>, + title: &dyn MessageOrTitle, max_line_num_len: usize, title_style: TitleStyle, is_cont: bool, @@ -511,7 +542,7 @@ impl Renderer { ) { let (label_style, title_element_style) = match title_style { TitleStyle::MainHeader => ( - ElementStyle::Level(title.level.level), + ElementStyle::Level(title.level().level), if self.short_message { ElementStyle::NoStyle } else { @@ -519,7 +550,7 @@ impl Renderer { }, ), TitleStyle::Header => ( - ElementStyle::Level(title.level.level), + ElementStyle::Level(title.level().level), ElementStyle::HeaderMsg, ), TitleStyle::Secondary => { @@ -538,10 +569,10 @@ impl Renderer { }; let mut label_width = 0; - if title.level.name != Some(None) { - buffer.append(buffer_msg_line_offset, title.level.as_str(), label_style); - label_width += title.level.as_str().len(); - if let Some(Id { id: Some(id), url }) = &title.id { + if title.level().name != Some(None) { + buffer.append(buffer_msg_line_offset, title.level().as_str(), label_style); + label_width += title.level().as_str().len(); + if let Some(Id { id: Some(id), url }) = &title.id() { buffer.append(buffer_msg_line_offset, "[", label_style); if let Some(url) = url.as_ref() { buffer.append( @@ -584,10 +615,10 @@ impl Renderer { label_width }); - let (title_str, style) = if title.is_pre_styled { - (title.text.to_string(), ElementStyle::NoStyle) + let (title_str, style) = if title.is_pre_styled() { + (title.text().to_owned(), ElementStyle::NoStyle) } else { - (normalize_whitespace(&title.text), title_element_style) + (normalize_whitespace(title.text()), title_element_style) }; for (i, text) in title_str.lines().enumerate() { if i != 0 { @@ -2532,6 +2563,43 @@ impl Renderer { } } +trait MessageOrTitle { + fn level(&self) -> &Level<'_>; + fn id(&self) -> Option<&Id<'_>>; + fn text(&self) -> &str; + fn is_pre_styled(&self) -> bool; +} + +impl MessageOrTitle for Title<'_> { + fn level(&self) -> &Level<'_> { + &self.level + } + fn id(&self) -> Option<&Id<'_>> { + self.id.as_ref() + } + fn text(&self) -> &str { + self.text.as_ref() + } + fn is_pre_styled(&self) -> bool { + false + } +} + +impl MessageOrTitle for Message<'_> { + fn level(&self) -> &Level<'_> { + &self.level + } + fn id(&self) -> Option<&Id<'_>> { + None + } + fn text(&self) -> &str { + self.text.as_ref() + } + fn is_pre_styled(&self) -> bool { + true + } +} + // instead of taking the String length or dividing by 10 while > 0, we multiply a limit by 10 until // we're higher. If the loop isn't exited by the `return`, the last multiplication will wrap, which // is OK, because while we cannot fit a higher power of 10 in a usize, the loop will end anyway. @@ -2846,7 +2914,10 @@ fn max_line_number(groups: &[Group<'_>]) -> usize { v.elements .iter() .map(|s| match s { - Element::Title(_) | Element::Origin(_) | Element::Padding(_) => 0, + Element::Title(_) + | Element::Message(_) + | Element::Origin(_) + | Element::Padding(_) => 0, Element::Cause(cause) => { let end = cause .markers diff --git a/src/snippet.rs b/src/snippet.rs index 4ea0ed79..ef92ff4f 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -63,6 +63,7 @@ impl<'a> Group<'a> { #[non_exhaustive] pub enum Element<'a> { Title(Title<'a>), + Message(Message<'a>), Cause(Snippet<'a, Annotation<'a>>), Suggestion(Snippet<'a, Patch<'a>>), Origin(Origin<'a>), @@ -75,6 +76,12 @@ impl<'a> From> for Element<'a> { } } +impl<'a> From> for Element<'a> { + fn from(value: Message<'a>) -> Self { + Element::Message(value) + } +} + impl<'a> From>> for Element<'a> { fn from(value: Snippet<'a, Annotation<'a>>) -> Self { Element::Cause(value) @@ -103,7 +110,7 @@ impl From for Element<'_> { #[derive(Clone, Debug)] pub struct Padding; -/// A text [`Element`] in a [`Group`] +/// A text [`Element`] to start a [`Group`] /// /// See [`Level::title`] to create this. #[derive(Clone, Debug)] @@ -111,7 +118,6 @@ pub struct Title<'a> { pub(crate) level: Level<'a>, pub(crate) id: Option>, pub(crate) text: Cow<'a, str>, - pub(crate) is_pre_styled: bool, } impl<'a> Title<'a> { @@ -144,6 +150,15 @@ impl<'a> Title<'a> { } } +/// A text [`Element`] in a [`Group`] +/// +/// See [`Level::message`] to create this. +#[derive(Clone, Debug)] +pub struct Message<'a> { + pub(crate) level: Level<'a>, + pub(crate) text: Cow<'a, str>, +} + /// A source view [`Element`] in a [`Group`] /// /// If you do not have [source][Snippet::source] available, see instead [`Origin`] From ee4ba27532d70643d9ef597fc695443a4ffbd323 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 3 Jul 2025 09:48:03 -0500 Subject: [PATCH 267/293] docs: Add message to Level's docs --- src/level.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/level.rs b/src/level.rs index 8eaaa87d..b718d72b 100644 --- a/src/level.rs +++ b/src/level.rs @@ -36,7 +36,7 @@ pub const HELP: Level<'_> = Level { level: LevelInner::Help, }; -/// [`Title`] severity level +/// Severity level for [`Title`]s and [`Message`]s #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct Level<'a> { pub(crate) name: Option>>, From e4efef941776256682a1b75c7896362d1295a56b Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 3 Jul 2025 09:48:11 -0500 Subject: [PATCH 268/293] docs: Make Origin's summary consistent with the rest --- src/snippet.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/snippet.rs b/src/snippet.rs index ef92ff4f..df0cceec 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -386,7 +386,7 @@ impl<'a> Patch<'a> { } } -/// The referenced location (e.g. a path) +/// A source location [`Element`] in a [`Group`] /// /// If you have source available, see instead [`Snippet`] #[derive(Clone, Debug)] From 8375e0c310ef8d14178f2a994cbaa2f26544186e Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 3 Jul 2025 09:53:26 -0500 Subject: [PATCH 269/293] docs: Use inline format args --- examples/highlight_message.rs | 12 ++---------- src/renderer/styled_buffer.rs | 6 +++--- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/examples/highlight_message.rs b/examples/highlight_message.rs index aaf49105..ddcfb018 100644 --- a/examples/highlight_message.rs +++ b/examples/highlight_message.rs @@ -29,16 +29,8 @@ fn main() { .on_default() .effects(Effects::BOLD); let message = format!( - "expected fn pointer `{}for<'a>{} fn(Box<{}(dyn Any + Send + 'a){}>) -> Pin<_>` - found fn item `fn(Box<{}(dyn Any + Send + 'static){}>) -> Pin<_> {}{{wrapped_fn}}{}`", - magenta.render(), - magenta.render_reset(), - magenta.render(), - magenta.render_reset(), - magenta.render(), - magenta.render_reset(), - magenta.render(), - magenta.render_reset() + "expected fn pointer `{magenta}for<'a>{magenta:#} fn(Box<{magenta}(dyn Any + Send + 'a){magenta:#}>) -> Pin<_>` + found fn item `fn(Box<{magenta}(dyn Any + Send + 'static){magenta:#}>) -> Pin<_> {magenta}{{wrapped_fn}}{magenta:#}`", ); let message = &[ diff --git a/src/renderer/styled_buffer.rs b/src/renderer/styled_buffer.rs index de3d0815..b64aef9c 100644 --- a/src/renderer/styled_buffer.rs +++ b/src/renderer/styled_buffer.rs @@ -51,14 +51,14 @@ impl StyledBuffer { let ch_style = style.color_spec(level, stylesheet); if ch_style != current_style { if !line.is_empty() { - write!(str, "{}", current_style.render_reset())?; + write!(str, "{current_style:#}")?; } current_style = ch_style; - write!(str, "{}", current_style.render())?; + write!(str, "{current_style}")?; } write!(str, "{ch}")?; } - write!(str, "{}", current_style.render_reset())?; + write!(str, "{current_style:#}")?; if i != self.lines.len() - 1 { writeln!(str)?; } From da5100c70ea385c1341c04608a09915f5509bcb2 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 3 Jul 2025 09:55:33 -0500 Subject: [PATCH 270/293] docs: Make styling standout more --- examples/highlight_message.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/highlight_message.rs b/examples/highlight_message.rs index ddcfb018..4ebe5f50 100644 --- a/examples/highlight_message.rs +++ b/examples/highlight_message.rs @@ -1,5 +1,7 @@ use annotate_snippets::{AnnotationKind, Group, Level, Renderer, Snippet}; +use anstyle::AnsiColor; use anstyle::Effects; +use anstyle::Style; fn main() { let source = r#"// Make sure "highlighted" code is colored purple @@ -25,12 +27,10 @@ fn main() { query(wrapped_fn); }"#; - let magenta = annotate_snippets::renderer::AnsiColor::Magenta - .on_default() - .effects(Effects::BOLD); + const MAGENTA: Style = AnsiColor::Magenta.on_default().effects(Effects::BOLD); let message = format!( - "expected fn pointer `{magenta}for<'a>{magenta:#} fn(Box<{magenta}(dyn Any + Send + 'a){magenta:#}>) -> Pin<_>` - found fn item `fn(Box<{magenta}(dyn Any + Send + 'static){magenta:#}>) -> Pin<_> {magenta}{{wrapped_fn}}{magenta:#}`", + "expected fn pointer `{MAGENTA}for<'a>{MAGENTA:#} fn(Box<{MAGENTA}(dyn Any + Send + 'a){MAGENTA:#}>) -> Pin<_>` + found fn item `fn(Box<{MAGENTA}(dyn Any + Send + 'static){MAGENTA:#}>) -> Pin<_> {MAGENTA}{{wrapped_fn}}{MAGENTA:#}`", ); let message = &[ From 88072d6b081bd01596084bed04f9bf0de17861c0 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 3 Jul 2025 09:51:31 -0500 Subject: [PATCH 271/293] docs: Provide an example of multiple groups --- src/snippet.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/snippet.rs b/src/snippet.rs index df0cceec..984d9c98 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -22,6 +22,13 @@ pub(crate) struct Id<'a> { /// A [diagnostic][crate::Renderer::render] is made of several `Group`s. /// `Group`s are used to [annotate][AnnotationKind::Primary] [`Snippet`]s /// with different [semantic reasons][Title]. +/// +/// # Example +/// +/// ```rust +#[doc = include_str!("../examples/highlight_message.rs")] +/// ``` +#[doc = include_str!("../examples/highlight_message.svg")] #[derive(Clone, Debug)] pub struct Group<'a> { pub(crate) primary_level: Level<'a>, From 453a88f3b176997f86689def1acd844fd60895f9 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 3 Jul 2025 09:58:13 -0500 Subject: [PATCH 272/293] docs: Provide example for Group::with_level --- src/snippet.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/snippet.rs b/src/snippet.rs index 984d9c98..8fa76566 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -43,6 +43,13 @@ impl<'a> Group<'a> { } /// Create a title-less group with a primary [`Level`] for [`Annotation`]s + /// + /// # Example + /// + /// ```rust + #[doc = include_str!("../examples/elide_header.rs")] + /// ``` + #[doc = include_str!("../examples/elide_header.svg")] pub fn with_level(level: Level<'a>) -> Self { Self { primary_level: level, From 37c641c7507a32bcc731e55ab23d54d6cd985601 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 3 Jul 2025 10:10:55 -0500 Subject: [PATCH 273/293] test: Switch child elements from Title to Message These were missed --- tests/formatter.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/formatter.rs b/tests/formatter.rs index fe16ca9c..b8405b8d 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -2400,7 +2400,7 @@ fn secondary_title_no_level_text() { .element( Level::NOTE .no_name() - .title("expected reference `&str`\nfound reference `&'static [u8; 0]`"), + .message("expected reference `&str`\nfound reference `&'static [u8; 0]`"), ), ]; @@ -2445,7 +2445,7 @@ fn secondary_title_custom_level_text() { .element( Level::NOTE .with_name(Some("custom")) - .title("expected reference `&str`\nfound reference `&'static [u8; 0]`"), + .message("expected reference `&str`\nfound reference `&'static [u8; 0]`"), ), ]; From 7059fd6aed2a86b0b5277cd26dfe2b8c2e34e517 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 3 Jul 2025 10:03:35 -0500 Subject: [PATCH 274/293] docs: Provide example for Level::with_name --- src/level.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/level.rs b/src/level.rs index b718d72b..a0c21b04 100644 --- a/src/level.rs +++ b/src/level.rs @@ -59,6 +59,13 @@ impl<'a> Level<'a> { /// not allowed to be passed to this function. /// ///
+ /// + /// # Example + /// + /// ```rust + #[doc = include_str!("../examples/custom_level.rs")] + /// ``` + #[doc = include_str!("../examples/custom_level.svg")] pub fn with_name(self, name: impl Into>) -> Level<'a> { Level { name: Some(name.into().0), From c8ac04b1549db352a2857860085c1f4aec1530f8 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 3 Jul 2025 10:03:42 -0500 Subject: [PATCH 275/293] docs: Provide example for Level::no_name --- src/level.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/level.rs b/src/level.rs index a0c21b04..150c6a88 100644 --- a/src/level.rs +++ b/src/level.rs @@ -74,6 +74,38 @@ impl<'a> Level<'a> { } /// Do not show the [`Level`]s name + /// + /// # Example + /// + /// ```rust + /// # use annotate_snippets::{Group, Snippet, AnnotationKind, Level}; + ///let source = r#"fn main() { + /// let b: &[u8] = include_str!("file.txt"); //~ ERROR mismatched types + /// let s: &str = include_bytes!("file.txt"); //~ ERROR mismatched types + /// }"#; + /// let input = &[ + /// Group::with_title(Level::ERROR.title("mismatched types").id("E0308")) + /// .element( + /// Snippet::source(source) + /// .path("$DIR/mismatched-types.rs") + /// .annotation( + /// AnnotationKind::Primary + /// .span(105..131) + /// .label("expected `&str`, found `&[u8; 0]`"), + /// ) + /// .annotation( + /// AnnotationKind::Context + /// .span(98..102) + /// .label("expected due to this"), + /// ), + /// ) + /// .element( + /// Level::NOTE + /// .no_name() + /// .message("expected reference `&str`\nfound reference `&'static [u8; 0]`"), + /// ), + /// ]; + /// ``` pub fn no_name(self) -> Level<'a> { self.with_name(None::<&str>) } From 683bea74cbcddb70a1e0b681a111b1029a137d51 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 3 Jul 2025 10:08:32 -0500 Subject: [PATCH 276/293] docs: Order Level by likelihood of use --- src/level.rs | 112 ++++++++++++++++++++++++++------------------------- 1 file changed, 58 insertions(+), 54 deletions(-) diff --git a/src/level.rs b/src/level.rs index 150c6a88..b1b7e4ea 100644 --- a/src/level.rs +++ b/src/level.rs @@ -43,13 +43,71 @@ pub struct Level<'a> { pub(crate) level: LevelInner, } +/// # Constructors impl<'a> Level<'a> { pub const ERROR: Level<'a> = ERROR; pub const WARNING: Level<'a> = WARNING; pub const INFO: Level<'a> = INFO; pub const NOTE: Level<'a> = NOTE; pub const HELP: Level<'a> = HELP; +} + +impl<'a> Level<'a> { + /// A text [`Element`][crate::Element] to start a [`Group`][crate::Group] + /// + /// See [`Group::with_title`][crate::Group::with_title] + /// + ///
+ /// + /// Text passed to this function is considered "untrusted input", as such + /// all text is passed through a normalization function. Pre-styled text is + /// not allowed to be passed to this function. + /// + ///
+ pub fn title(self, text: impl Into>) -> Title<'a> { + Title { + level: self, + id: None, + text: text.into(), + } + } + + /// A text [`Element`][crate::Element] in a [`Group`][crate::Group] + /// + ///
+ /// + /// Text passed to this function is allowed to be pre-styled, as such all + /// text is considered "trusted input" and has no normalizations applied to + /// it. [`normalize_untrusted_str`](crate::normalize_untrusted_str) can be + /// used to normalize untrusted text before it is passed to this function. + /// + ///
+ pub fn message(self, text: impl Into>) -> Message<'a> { + Message { + level: self, + text: text.into(), + } + } + + pub(crate) fn as_str(&'a self) -> &'a str { + match (&self.name, self.level) { + (Some(Some(name)), _) => name.as_ref(), + (Some(None), _) => "", + (None, LevelInner::Error) => ERROR_TXT, + (None, LevelInner::Warning) => WARNING_TXT, + (None, LevelInner::Info) => INFO_TXT, + (None, LevelInner::Note) => NOTE_TXT, + (None, LevelInner::Help) => HELP_TXT, + } + } + + pub(crate) fn style(&self, stylesheet: &Stylesheet) -> Style { + self.level.style(stylesheet) + } +} +/// # Customize the `Level` +impl<'a> Level<'a> { /// Replace the name describing this [`Level`] /// ///
@@ -111,60 +169,6 @@ impl<'a> Level<'a> { } } -impl<'a> Level<'a> { - /// A text [`Element`][crate::Element] to start a [`Group`][crate::Group] - /// - /// See [`Group::with_title`][crate::Group::with_title] - /// - ///
- /// - /// Text passed to this function is considered "untrusted input", as such - /// all text is passed through a normalization function. Pre-styled text is - /// not allowed to be passed to this function. - /// - ///
- pub fn title(self, text: impl Into>) -> Title<'a> { - Title { - level: self, - id: None, - text: text.into(), - } - } - - /// A text [`Element`][crate::Element] in a [`Group`][crate::Group] - /// - ///
- /// - /// Text passed to this function is allowed to be pre-styled, as such all - /// text is considered "trusted input" and has no normalizations applied to - /// it. [`normalize_untrusted_str`](crate::normalize_untrusted_str) can be - /// used to normalize untrusted text before it is passed to this function. - /// - ///
- pub fn message(self, text: impl Into>) -> Message<'a> { - Message { - level: self, - text: text.into(), - } - } - - pub(crate) fn as_str(&'a self) -> &'a str { - match (&self.name, self.level) { - (Some(Some(name)), _) => name.as_ref(), - (Some(None), _) => "", - (None, LevelInner::Error) => ERROR_TXT, - (None, LevelInner::Warning) => WARNING_TXT, - (None, LevelInner::Info) => INFO_TXT, - (None, LevelInner::Note) => NOTE_TXT, - (None, LevelInner::Help) => HELP_TXT, - } - } - - pub(crate) fn style(&self, stylesheet: &Stylesheet) -> Style { - self.level.style(stylesheet) - } -} - #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub(crate) enum LevelInner { Error, From eb0d16da8bf43d21d28dc45953b17360a6806672 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 3 Jul 2025 10:08:57 -0500 Subject: [PATCH 277/293] docs: Provide an example for Level::title --- src/level.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/level.rs b/src/level.rs index b1b7e4ea..4685fb01 100644 --- a/src/level.rs +++ b/src/level.rs @@ -64,6 +64,15 @@ impl<'a> Level<'a> { /// not allowed to be passed to this function. /// ///
+ /// + /// # Example + /// + /// ```rust + /// # use annotate_snippets::{Group, Snippet, AnnotationKind, Level}; + /// let input = &[ + /// Group::with_title(Level::ERROR.title("mismatched types").id("E0308")) + /// ]; + /// ``` pub fn title(self, text: impl Into>) -> Title<'a> { Title { level: self, From c74a346907d659121a2c59055b19c8674ddd7cab Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 3 Jul 2025 10:08:51 -0500 Subject: [PATCH 278/293] docs: Provide an example for Level::message --- src/level.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/level.rs b/src/level.rs index 4685fb01..6596bf8e 100644 --- a/src/level.rs +++ b/src/level.rs @@ -91,6 +91,20 @@ impl<'a> Level<'a> { /// used to normalize untrusted text before it is passed to this function. /// /// + /// + /// # Example + /// + /// ```rust + /// # use annotate_snippets::{Group, Snippet, AnnotationKind, Level}; + /// let input = &[ + /// Group::with_title(Level::ERROR.title("mismatched types").id("E0308")) + /// .element( + /// Level::NOTE + /// .no_name() + /// .message("expected reference `&str`\nfound reference `&'static [u8; 0]`"), + /// ), + /// ]; + /// ``` pub fn message(self, text: impl Into>) -> Message<'a> { Message { level: self, From 6129319507d78e1118894e90ce6c6fbe3935999d Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 3 Jul 2025 10:14:25 -0500 Subject: [PATCH 279/293] docs: Provide an example for Origin --- src/snippet.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/snippet.rs b/src/snippet.rs index 8fa76566..390f3385 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -403,6 +403,18 @@ impl<'a> Patch<'a> { /// A source location [`Element`] in a [`Group`] /// /// If you have source available, see instead [`Snippet`] +/// +/// # Example +/// +/// ```rust +/// # use annotate_snippets::{Group, Snippet, AnnotationKind, Level, Origin}; +/// let input = &[ +/// Group::with_title(Level::ERROR.title("mismatched types").id("E0308")) +/// .element( +/// Origin::new("$DIR/mismatched-types.rs") +/// ) +/// ]; +/// ``` #[derive(Clone, Debug)] pub struct Origin<'a> { pub(crate) path: Cow<'a, str>, From e2b0339fdb978b469a18cbce4939c7c8e03275ad Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 3 Jul 2025 10:16:20 -0500 Subject: [PATCH 280/293] fix: Rename Origin::new to Origin::path This is to align with `Snippet::source` --- src/renderer/mod.rs | 4 ++-- src/snippet.rs | 6 +++--- tests/color/multiline_removal_suggestion.rs | 2 +- tests/rustc_tests.rs | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index b5eff063..759fbfb5 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -484,7 +484,7 @@ impl Renderer { } if let Some(path) = &cause.path { - let mut origin = Origin::new(path.as_ref()); + let mut origin = Origin::path(path.as_ref()); origin.primary = true; let source_map = SourceMap::new(&cause.source, cause.line_start); @@ -719,7 +719,7 @@ impl Renderer { is_cont: bool, ) { if let Some(path) = &snippet.path { - let mut origin = Origin::new(path.as_ref()); + let mut origin = Origin::path(path.as_ref()); // print out the span location and spacer before we print the annotated source // to do this, we need to know if this span will be primary let is_primary = primary_path == Some(&origin.path); diff --git a/src/snippet.rs b/src/snippet.rs index 390f3385..1d0d0e87 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -411,7 +411,7 @@ impl<'a> Patch<'a> { /// let input = &[ /// Group::with_title(Level::ERROR.title("mismatched types").id("E0308")) /// .element( -/// Origin::new("$DIR/mismatched-types.rs") +/// Origin::path("$DIR/mismatched-types.rs") /// ) /// ]; /// ``` @@ -431,7 +431,7 @@ impl<'a> Origin<'a> { /// not allowed to be passed to this function. /// /// - pub fn new(path: impl Into>) -> Self { + pub fn path(path: impl Into>) -> Self { Self { path: path.into(), line: None, @@ -467,7 +467,7 @@ impl<'a> Origin<'a> { impl<'a> From> for Origin<'a> { fn from(origin: Cow<'a, str>) -> Self { - Self::new(origin) + Self::path(origin) } } diff --git a/tests/color/multiline_removal_suggestion.rs b/tests/color/multiline_removal_suggestion.rs index 8559ee93..2442947b 100644 --- a/tests/color/multiline_removal_suggestion.rs +++ b/tests/color/multiline_removal_suggestion.rs @@ -88,7 +88,7 @@ fn main() {} ), Group::with_title(Level::NOTE.title("required by a bound in `flatten`")) .element( - Origin::new("/rustc/FAKE_PREFIX/library/core/src/iter/traits/iterator.rs") + Origin::path("/rustc/FAKE_PREFIX/library/core/src/iter/traits/iterator.rs") .line(1556) .char_column(4), ), diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index c9bba626..112a5c79 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -1743,7 +1743,7 @@ fn main() { Level::NOTE .title("for a trait to be dyn compatible it needs to allow building a vtable\nfor more information, visit ")) .element( - Origin::new("$SRC_DIR/core/src/cmp.rs") + Origin::path("$SRC_DIR/core/src/cmp.rs") .line(334) .char_column(14) .primary(true) From cf84eb67990cf2f01cdf3160a0094ca2f4f856a6 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Thu, 3 Jul 2025 10:00:21 -0600 Subject: [PATCH 281/293] fix: Address clippy::needless_doctest_main --- src/level.rs | 1 + src/snippet.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/level.rs b/src/level.rs index 6596bf8e..7aafe838 100644 --- a/src/level.rs +++ b/src/level.rs @@ -144,6 +144,7 @@ impl<'a> Level<'a> { /// # Example /// /// ```rust + /// # #[allow(clippy::needless_doctest_main)] #[doc = include_str!("../examples/custom_level.rs")] /// ``` #[doc = include_str!("../examples/custom_level.svg")] diff --git a/src/snippet.rs b/src/snippet.rs index 1d0d0e87..b140a14b 100644 --- a/src/snippet.rs +++ b/src/snippet.rs @@ -26,6 +26,7 @@ pub(crate) struct Id<'a> { /// # Example /// /// ```rust +/// # #[allow(clippy::needless_doctest_main)] #[doc = include_str!("../examples/highlight_message.rs")] /// ``` #[doc = include_str!("../examples/highlight_message.svg")] @@ -47,6 +48,7 @@ impl<'a> Group<'a> { /// # Example /// /// ```rust + /// # #[allow(clippy::needless_doctest_main)] #[doc = include_str!("../examples/elide_header.rs")] /// ``` #[doc = include_str!("../examples/elide_header.svg")] From 3a46662e04e2efb1f2f9428c0ec9b559a177a048 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Wed, 2 Jul 2025 22:37:08 -0600 Subject: [PATCH 282/293] test: Add a test for max_line_num with no fold --- tests/formatter.rs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/formatter.rs b/tests/formatter.rs index b8405b8d..dc661e7d 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -2574,3 +2574,41 @@ LL + break; let renderer_unicode = renderer_ascii.theme(OutputTheme::Unicode); assert_data_eq!(renderer_unicode.render(input), expected_unicode); } + +#[test] +fn max_line_num_no_fold() { + let source = r#"cargo +fuzzy +pizza +jumps +crazy +quack +zappy +"#; + + let input_new = &[Group::with_title( + Level::ERROR + .title("the size for values of type `T` cannot be known at compilation time") + .id("E0277"), + ) + .element( + Snippet::source(source) + .line_start(8) + .fold(false) + .annotation(AnnotationKind::Primary.span(6..11)), + )]; + let expected = str![[r#" +error[E0277]: the size for values of type `T` cannot be known at compilation time + | +8 | cargo +9 | fuzzy + | ^^^^^ +10| pizza +11| jumps +12| crazy +13| quack +14| zappy +"#]]; + let renderer = Renderer::plain(); + assert_data_eq!(renderer.render(input_new), expected); +} From 9a2155aad4e28a6f7e86a4aaa1f911d3c64d0629 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Wed, 2 Jul 2025 22:38:15 -0600 Subject: [PATCH 283/293] fix: If fold is false max_line_num is last source line --- src/renderer/mod.rs | 44 ++++++++++++++++++++++++++------------------ tests/formatter.rs | 18 +++++++++--------- 2 files changed, 35 insertions(+), 27 deletions(-) diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 759fbfb5..83e1a7da 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -2919,26 +2919,34 @@ fn max_line_number(groups: &[Group<'_>]) -> usize { | Element::Origin(_) | Element::Padding(_) => 0, Element::Cause(cause) => { - let end = cause - .markers - .iter() - .map(|a| a.span.end) - .max() - .unwrap_or(cause.source.len()) - .min(cause.source.len()); - - cause.line_start + newline_count(&cause.source[..end]) + if cause.fold { + let end = cause + .markers + .iter() + .map(|a| a.span.end) + .max() + .unwrap_or(cause.source.len()) + .min(cause.source.len()); + + cause.line_start + newline_count(&cause.source[..end]) + } else { + cause.line_start + newline_count(&cause.source) + } } Element::Suggestion(suggestion) => { - let end = suggestion - .markers - .iter() - .map(|a| a.span.end) - .max() - .unwrap_or(suggestion.source.len()) - .min(suggestion.source.len()); - - suggestion.line_start + newline_count(&suggestion.source[..end]) + if suggestion.fold { + let end = suggestion + .markers + .iter() + .map(|a| a.span.end) + .max() + .unwrap_or(suggestion.source.len()) + .min(suggestion.source.len()); + + suggestion.line_start + newline_count(&suggestion.source[..end]) + } else { + suggestion.line_start + newline_count(&suggestion.source) + } } }) .max() diff --git a/tests/formatter.rs b/tests/formatter.rs index dc661e7d..8745e566 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -2599,15 +2599,15 @@ zappy )]; let expected = str![[r#" error[E0277]: the size for values of type `T` cannot be known at compilation time - | -8 | cargo -9 | fuzzy - | ^^^^^ -10| pizza -11| jumps -12| crazy -13| quack -14| zappy + | + 8 | cargo + 9 | fuzzy + | ^^^^^ +10 | pizza +11 | jumps +12 | crazy +13 | quack +14 | zappy "#]]; let renderer = Renderer::plain(); assert_data_eq!(renderer.render(input_new), expected); From 510a9e69d4f9a105f17b349eb3801c6c9c2a56b3 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Tue, 1 Jul 2025 18:17:23 -0600 Subject: [PATCH 284/293] test: Add Annotating an empty span at start of line --- tests/formatter.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/formatter.rs b/tests/formatter.rs index 8745e566..eca0b826 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -2612,3 +2612,26 @@ error[E0277]: the size for values of type `T` cannot be known at compilation tim let renderer = Renderer::plain(); assert_data_eq!(renderer.render(input_new), expected); } + +#[test] +fn empty_span_start_line() { + let source = "#: E112\nif False:\nprint()\n#: E113\nprint()\n"; + let input = &[Group::with_level(Level::ERROR).element( + Snippet::source(source) + .line_start(7) + .fold(false) + .annotation(AnnotationKind::Primary.span(18..18).label("E112")), + )]; + + let expected = str![[r#" + | + 7 | #: E112 + 8 | if False: + 9 | print() + | ^ E112 +10 | #: E113 +11 | print() +"#]]; + let renderer = Renderer::plain(); + assert_data_eq!(renderer.render(input), expected); +} From 81012284c2732799e004dd03645c7cb94de53592 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Wed, 2 Jul 2025 23:27:24 -0600 Subject: [PATCH 285/293] test: Origin tests --- tests/rustc_tests.rs | 526 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 526 insertions(+) diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index 112a5c79..afec2712 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -2840,3 +2840,529 @@ help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicit let renderer = Renderer::plain(); assert_data_eq!(renderer.render(input), expected); } + +#[test] +fn autoderef_box_no_add() { + // tests/ui/autoref-autoderef/autoderef-box-no-add.rs + + let source = r#"//! Tests that auto-dereferencing does not allow addition of `Box` values. +//! +//! This test ensures that `Box` fields in structs (`Clam` and `Fish`) are not +//! automatically dereferenced to `isize` during addition operations, as `Box` +//! does not implement the `Add` trait. + +struct Clam { + x: Box, + y: Box, +} + +struct Fish { + a: Box, +} + +fn main() { + let a: Clam = Clam { + x: Box::new(1), + y: Box::new(2), + }; + let b: Clam = Clam { + x: Box::new(10), + y: Box::new(20), + }; + let z: isize = a.x + b.y; + //~^ ERROR cannot add `Box` to `Box` + println!("{}", z); + assert_eq!(z, 21); + let forty: Fish = Fish { a: Box::new(40) }; + let two: Fish = Fish { a: Box::new(2) }; + let answer: isize = forty.a + two.a; + //~^ ERROR cannot add `Box` to `Box` + println!("{}", answer); + assert_eq!(answer, 42); +} +"#; + let input = &[ + Group::with_title( + Level::ERROR + .title("cannot add `Box` to `Box`") + .id("E0369"), + ) + .element( + Snippet::source(source) + .path("$DIR/autoderef-box-no-add.rs") + .annotation(AnnotationKind::Context.span(583..586).label("Box")) + .annotation(AnnotationKind::Context.span(589..592).label("Box")) + .annotation(AnnotationKind::Primary.span(587..588)), + ), + Group::with_title( + Level::NOTE.title("the foreign item type `Box` doesn't implement `Add`"), + ) + .element( + Origin::path("$SRC_DIR/alloc/src/boxed.rs") + .line(231) + .char_column(0) + .primary(true), + ) + .element( + Origin::path("$SRC_DIR/alloc/src/boxed.rs") + .line(234) + .char_column(1), + ) + .element(Padding) + .element(Level::NOTE.message("not implement `Add`")), + ]; + + let expected_ascii = str![[r#" +error[E0369]: cannot add `Box` to `Box` + --> $DIR/autoderef-box-no-add.rs:25:24 + | +LL | let z: isize = a.x + b.y; + | --- ^ --- Box + | | + | Box + | +note: the foreign item type `Box` doesn't implement `Add` + --> $SRC_DIR/alloc/src/boxed.rs:231:0 + ::: $SRC_DIR/alloc/src/boxed.rs:234:1 + | + = note: not implement `Add` +"#]]; + let renderer = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer.render(input), expected_ascii); + + let expected_unicode = str![[r#" +error[E0369]: cannot add `Box` to `Box` + ╭▸ $DIR/autoderef-box-no-add.rs:25:24 + │ +LL │ let z: isize = a.x + b.y; + │ ┬── ━ ─── Box + │ │ + │ Box + ╰╴ +note: the foreign item type `Box` doesn't implement `Add` + ╭▸ $SRC_DIR/alloc/src/boxed.rs:231:0 + ⸬ $SRC_DIR/alloc/src/boxed.rs:234:1 + │ + ╰ note: not implement `Add` +"#]]; + let renderer = renderer.theme(OutputTheme::Unicode); + assert_data_eq!(renderer.render(input), expected_unicode); +} + +#[test] +fn dont_project_to_specializable_projection() { + // tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs + + let source = r#"//@ edition: 2021 +//@ known-bug: #108309 + +#![feature(min_specialization)] + +struct MyStruct; + +trait MyTrait { + async fn foo(_: T) -> &'static str; +} + +impl MyTrait for MyStruct { + default async fn foo(_: T) -> &'static str { + "default" + } +} + +impl MyTrait for MyStruct { + async fn foo(_: i32) -> &'static str { + "specialized" + } +} + +async fn async_main() { + assert_eq!(MyStruct::foo(42).await, "specialized"); + assert_eq!(indirection(42).await, "specialized"); +} + +async fn indirection(x: T) -> &'static str { + //explicit type coercion is currently necessary + // because of https://github.com/rust-lang/rust/issues/67918 + >::foo(x).await +} + +// ------------------------------------------------------------------------- // +// Implementation Details Below... + +use std::pin::{pin, Pin}; +use std::task::*; + +fn main() { + let mut fut = pin!(async_main()); + + // Poll loop, just to test the future... + let ctx = &mut Context::from_waker(Waker::noop()); + + loop { + match fut.as_mut().poll(ctx) { + Poll::Pending => {} + Poll::Ready(()) => break, + } + } +} +"#; + + let title_0 = "no method named `poll` found for struct `Pin<&mut impl Future>` in the current scope"; + let title_1 = "trait `Future` which provides `poll` is implemented but not in scope; perhaps you want to import it"; + + let input = &[ + Group::with_title(Level::ERROR.title(title_0).id("E0599")) + .element( + Snippet::source(source) + .path("$DIR/dont-project-to-specializable-projection.rs") + .annotation( + AnnotationKind::Primary + .span(1071..1075) + .label("method not found in `Pin<&mut impl Future>`"), + ), + ) + .element( + Origin::path("$SRC_DIR/core/src/future/future.rs") + .line(104) + .char_column(7) + .primary(true), + ) + .element(Padding) + .element( + Level::NOTE.message( + "the method is available for `Pin<&mut impl Future>` here", + ), + ) + .element(Padding) + .element( + Level::HELP.message("items from traits can only be used if the trait is in scope"), + ), + Group::with_title(Level::HELP.title(title_1)).element( + Snippet::source("struct MyStruct;\n") + .path("$DIR/dont-project-to-specializable-projection.rs") + .line_start(6) + .patch(Patch::new( + 0..0, + r#"use std::future::Future; +"#, + )), + ), + ]; + let expected_ascii = str![[r#" +error[E0599]: no method named `poll` found for struct `Pin<&mut impl Future>` in the current scope + --> $DIR/dont-project-to-specializable-projection.rs:48:28 + | +LL | match fut.as_mut().poll(ctx) { + | ^^^^ method not found in `Pin<&mut impl Future>` + --> $SRC_DIR/core/src/future/future.rs:104:7 + | + = note: the method is available for `Pin<&mut impl Future>` here + | + = help: items from traits can only be used if the trait is in scope +help: trait `Future` which provides `poll` is implemented but not in scope; perhaps you want to import it + | +LL + use std::future::Future; + | +"#]]; + let renderer = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer.render(input), expected_ascii); + + let expected_unicode = str![[r#" +error[E0599]: no method named `poll` found for struct `Pin<&mut impl Future>` in the current scope + ╭▸ $DIR/dont-project-to-specializable-projection.rs:48:28 + │ +LL │ match fut.as_mut().poll(ctx) { + │ ━━━━ method not found in `Pin<&mut impl Future>` + ╭▸ $SRC_DIR/core/src/future/future.rs:104:7 + │ + ╰ note: the method is available for `Pin<&mut impl Future>` here + │ + ╰ help: items from traits can only be used if the trait is in scope +help: trait `Future` which provides `poll` is implemented but not in scope; perhaps you want to import it + ╭╴ +LL + use std::future::Future; + ╰╴ +"#]]; + let renderer = renderer.theme(OutputTheme::Unicode); + assert_data_eq!(renderer.render(input), expected_unicode); +} + +#[test] +fn binary_op_not_allowed_issue_125631() { + // tests/ui/binop/binary-op-not-allowed-issue-125631.rs + + let source = r#"use std::io::{Error, ErrorKind}; +use std::thread; + +struct T1; +struct T2; + +fn main() { + (Error::new(ErrorKind::Other, "1"), T1, 1) == (Error::new(ErrorKind::Other, "1"), T1, 2); + //~^ERROR binary operation `==` cannot be applied to type + (Error::new(ErrorKind::Other, "2"), thread::current()) + == (Error::new(ErrorKind::Other, "2"), thread::current()); + //~^ERROR binary operation `==` cannot be applied to type + (Error::new(ErrorKind::Other, "4"), thread::current(), T1, T2) + == (Error::new(ErrorKind::Other, "4"), thread::current(), T1, T2); + //~^ERROR binary operation `==` cannot be applied to type +} +"#; + let title_0 = "binary operation `==` cannot be applied to type `(std::io::Error, Thread)`"; + let title_1 = + "the foreign item types don't implement required traits for this operation to be valid"; + + let input = &[ + Group::with_title(Level::ERROR.title(title_0).id("E0369")).element( + Snippet::source(source) + .path("$DIR/binary-op-not-allowed-issue-125631.rs") + .annotation( + AnnotationKind::Context + .span(246..300) + .label("(std::io::Error, Thread)"), + ) + .annotation( + AnnotationKind::Context + .span(312..366) + .label("(std::io::Error, Thread)"), + ) + .annotation(AnnotationKind::Primary.span(309..311)), + ), + Group::with_title(Level::NOTE.title(title_1)) + .element( + Origin::path("$SRC_DIR/std/src/io/error.rs") + .line(65) + .char_column(0) + .primary(true), + ) + .element(Padding) + .element(Level::NOTE.message("not implement `PartialEq`")) + .element( + Origin::path("$SRC_DIR/std/src/thread/mod.rs") + .line(1415) + .char_column(0) + .primary(true), + ) + .element(Padding) + .element(Level::NOTE.message("not implement `PartialEq`")), + ]; + + let expected_ascii = str![[r#" +error[E0369]: binary operation `==` cannot be applied to type `(std::io::Error, Thread)` + --> $DIR/binary-op-not-allowed-issue-125631.rs:11:9 + | +LL | (Error::new(ErrorKind::Other, "2"), thread::current()) + | ------------------------------------------------------ (std::io::Error, Thread) +LL | == (Error::new(ErrorKind::Other, "2"), thread::current()); + | ^^ ------------------------------------------------------ (std::io::Error, Thread) + | +note: the foreign item types don't implement required traits for this operation to be valid + --> $SRC_DIR/std/src/io/error.rs:65:0 + | + = note: not implement `PartialEq` + --> $SRC_DIR/std/src/thread/mod.rs:1415:0 + | + = note: not implement `PartialEq` +"#]]; + let renderer = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer.render(input), expected_ascii); + + let expected_unicode = str![[r#" +error[E0369]: binary operation `==` cannot be applied to type `(std::io::Error, Thread)` + ╭▸ $DIR/binary-op-not-allowed-issue-125631.rs:11:9 + │ +LL │ (Error::new(ErrorKind::Other, "2"), thread::current()) + │ ────────────────────────────────────────────────────── (std::io::Error, Thread) +LL │ == (Error::new(ErrorKind::Other, "2"), thread::current()); + │ ━━ ────────────────────────────────────────────────────── (std::io::Error, Thread) + ╰╴ +note: the foreign item types don't implement required traits for this operation to be valid + ╭▸ $SRC_DIR/std/src/io/error.rs:65:0 + │ + ╰ note: not implement `PartialEq` + ╭▸ $SRC_DIR/std/src/thread/mod.rs:1415:0 + │ + ╰ note: not implement `PartialEq` +"#]]; + let renderer = renderer.theme(OutputTheme::Unicode); + assert_data_eq!(renderer.render(input), expected_unicode); +} + +#[test] +fn deriving_meta_unknown_trait() { + // tests/ui/derives/deriving-meta-unknown-trait.rs + + let source = r#"#[derive(Eqr)] +//~^ ERROR cannot find derive macro `Eqr` in this scope +//~| ERROR cannot find derive macro `Eqr` in this scope +struct Foo; + +pub fn main() {} +"#; + + let input = + &[ + Group::with_title(Level::ERROR.title("cannot find derive macro `Eqr` in this scope")) + .element( + Snippet::source(source) + .path("$DIR/deriving-meta-unknown-trait.rs") + .annotation( + AnnotationKind::Primary + .span(9..12) + .label("help: a derive macro with a similar name exists: `Eq`"), + ), + ) + .element( + Origin::path("$SRC_DIR/core/src/cmp.rs") + .line(356) + .char_column(0) + .primary(true), + ) + .element(Padding) + .element(Level::NOTE.message("similarly named derive macro `Eq` defined here")) + .element(Padding) + .element(Level::NOTE.message( + "duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`", + )), + ]; + + let expected_ascii = str![[r#" +error: cannot find derive macro `Eqr` in this scope + --> $DIR/deriving-meta-unknown-trait.rs:1:10 + | +LL | #[derive(Eqr)] + | ^^^ help: a derive macro with a similar name exists: `Eq` + --> $SRC_DIR/core/src/cmp.rs:356:0 + | + = note: similarly named derive macro `Eq` defined here + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +"#]]; + let renderer = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer.render(input), expected_ascii); + + let expected_unicode = str![[r#" +error: cannot find derive macro `Eqr` in this scope + ╭▸ $DIR/deriving-meta-unknown-trait.rs:1:10 + │ +LL │ #[derive(Eqr)] + │ ━━━ help: a derive macro with a similar name exists: `Eq` + ╭▸ $SRC_DIR/core/src/cmp.rs:356:0 + │ + ╰ note: similarly named derive macro `Eq` defined here + │ + ╰ note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +"#]]; + let renderer = renderer.theme(OutputTheme::Unicode); + assert_data_eq!(renderer.render(input), expected_unicode); +} + +#[test] +fn not_repeatable() { + // tests/ui/proc-macro/quote/not-repeatable.rs + + let source = r#"#![feature(proc_macro_quote)] + +extern crate proc_macro; + +use proc_macro::quote; + +struct Ipv4Addr; + +fn main() { + let ip = Ipv4Addr; + let _ = quote! { $($ip)* }; //~ ERROR the method `quote_into_iter` exists for struct `Ipv4Addr`, but its trait bounds were not satisfied +} +"#; + let label_0 = "method `quote_into_iter` not found for this struct because it doesn't satisfy `Ipv4Addr: Iterator`, `Ipv4Addr: ToTokens`, `Ipv4Addr: proc_macro::ext::RepIteratorExt` or `Ipv4Addr: proc_macro::ext::RepToTokensExt`"; + let title_0 = "the method `quote_into_iter` exists for struct `Ipv4Addr`, but its trait bounds were not satisfied"; + let title_1 = r#"the following trait bounds were not satisfied: +`Ipv4Addr: Iterator` +which is required by `Ipv4Addr: proc_macro::ext::RepIteratorExt` +`&Ipv4Addr: Iterator` +which is required by `&Ipv4Addr: proc_macro::ext::RepIteratorExt` +`Ipv4Addr: ToTokens` +which is required by `Ipv4Addr: proc_macro::ext::RepToTokensExt` +`&mut Ipv4Addr: Iterator` +which is required by `&mut Ipv4Addr: proc_macro::ext::RepIteratorExt`"#; + + let input = &[ + Group::with_title(Level::ERROR.title(title_0).id("E0599")) + .element( + Snippet::source(source) + .path("$DIR/not-repeatable.rs") + .annotation(AnnotationKind::Primary.span(146..164).label( + "method cannot be called on `Ipv4Addr` due to unsatisfied trait bounds", + )) + .annotation(AnnotationKind::Context.span(81..96).label(label_0)), + ) + .element(Level::NOTE.message(title_1)), + Group::with_title( + Level::NOTE.title("the traits `Iterator` and `ToTokens` must be implemented"), + ) + .element( + Origin::path("$SRC_DIR/proc_macro/src/to_tokens.rs") + .line(11) + .char_column(0) + .primary(true), + ) + .element( + Origin::path("$SRC_DIR/core/src/iter/traits/iterator.rs") + .line(39) + .char_column(0) + .primary(true), + ), + ]; + let expected_ascii = str![[r##" +error[E0599]: the method `quote_into_iter` exists for struct `Ipv4Addr`, but its trait bounds were not satisfied + --> $DIR/not-repeatable.rs:11:13 + | +LL | struct Ipv4Addr; + | --------------- method `quote_into_iter` not found for this struct because it doesn't satisfy `Ipv4Addr: Iterator`, `Ipv4Addr: ToTokens`, `Ipv4Addr: proc_macro::ext::RepIteratorExt` or `Ipv4Addr: proc_macro::ext::RepToTokensExt` +... +LL | let _ = quote! { $($ip)* }; //~ ERROR the method `quote_into_iter` exists for struct `Ipv4Addr`, but its trait bounds were not s... + | ^^^^^^^^^^^^^^^^^^ method cannot be called on `Ipv4Addr` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `Ipv4Addr: Iterator` + which is required by `Ipv4Addr: proc_macro::ext::RepIteratorExt` + `&Ipv4Addr: Iterator` + which is required by `&Ipv4Addr: proc_macro::ext::RepIteratorExt` + `Ipv4Addr: ToTokens` + which is required by `Ipv4Addr: proc_macro::ext::RepToTokensExt` + `&mut Ipv4Addr: Iterator` + which is required by `&mut Ipv4Addr: proc_macro::ext::RepIteratorExt` +note: the traits `Iterator` and `ToTokens` must be implemented + --> $SRC_DIR/proc_macro/src/to_tokens.rs:11:0 + --> $SRC_DIR/core/src/iter/traits/iterator.rs:39:0 +"##]]; + let renderer = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer.render(input), expected_ascii); + + let expected_unicode = str![[r#" +error[E0599]: the method `quote_into_iter` exists for struct `Ipv4Addr`, but its trait bounds were not satisfied + ╭▸ $DIR/not-repeatable.rs:11:13 + │ +LL │ struct Ipv4Addr; + │ ─────────────── method `quote_into_iter` not found for this struct because it doesn't satisfy `Ipv4Addr: Iterator`, `Ipv4Addr: ToTokens`, `Ipv4Addr: proc_macro::ext::RepIteratorExt` or `Ipv4Addr: proc_macro::ext::RepToTokensExt` + ‡ +LL │ let _ = quote! { $($ip)* }; //~ ERROR the method `quote_into_iter` exists for struct `Ipv4Addr`, but its trait bounds were not sat… + │ ━━━━━━━━━━━━━━━━━━ method cannot be called on `Ipv4Addr` due to unsatisfied trait bounds + │ + ╰ note: the following trait bounds were not satisfied: + `Ipv4Addr: Iterator` + which is required by `Ipv4Addr: proc_macro::ext::RepIteratorExt` + `&Ipv4Addr: Iterator` + which is required by `&Ipv4Addr: proc_macro::ext::RepIteratorExt` + `Ipv4Addr: ToTokens` + which is required by `Ipv4Addr: proc_macro::ext::RepToTokensExt` + `&mut Ipv4Addr: Iterator` + which is required by `&mut Ipv4Addr: proc_macro::ext::RepIteratorExt` +note: the traits `Iterator` and `ToTokens` must be implemented + ╭▸ $SRC_DIR/proc_macro/src/to_tokens.rs:11:0 + ╭▸ $SRC_DIR/core/src/iter/traits/iterator.rs:39:0 +"#]]; + let renderer = renderer.theme(OutputTheme::Unicode); + assert_data_eq!(renderer.render(input), expected_unicode); +} From d1c2b85f4636ecbc36728b6fa274a5340b41758e Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Wed, 2 Jul 2025 23:44:23 -0600 Subject: [PATCH 286/293] fix: Make Title followed by Padding a continuation --- src/renderer/mod.rs | 6 +++++- tests/rustc_tests.rs | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 83e1a7da..53597ef5 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -316,7 +316,11 @@ impl Renderer { title, max_line_num_len, title_style, - matches!(peek, Some(Element::Title(_) | Element::Message(_))), + matches!( + peek, + Some(Element::Title(_) | Element::Message(_)) + | Some(Element::Padding(_)) + ), buffer_msg_line_offset, ); last_was_suggestion = false; diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index afec2712..2750da11 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -3076,7 +3076,7 @@ LL │ match fut.as_mut().poll(ctx) { │ ━━━━ method not found in `Pin<&mut impl Future>` ╭▸ $SRC_DIR/core/src/future/future.rs:104:7 │ - ╰ note: the method is available for `Pin<&mut impl Future>` here + ├ note: the method is available for `Pin<&mut impl Future>` here │ ╰ help: items from traits can only be used if the trait is in scope help: trait `Future` which provides `poll` is implemented but not in scope; perhaps you want to import it @@ -3250,7 +3250,7 @@ LL │ #[derive(Eqr)] │ ━━━ help: a derive macro with a similar name exists: `Eq` ╭▸ $SRC_DIR/core/src/cmp.rs:356:0 │ - ╰ note: similarly named derive macro `Eq` defined here + ├ note: similarly named derive macro `Eq` defined here │ ╰ note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` "#]]; From 8c46015024a1b33c763c840bba4d3e8a8bde62b5 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Wed, 2 Jul 2025 23:44:23 -0600 Subject: [PATCH 287/293] fix: Add end col seperator if Snippet is followed by a primary Origin --- src/renderer/mod.rs | 6 ++++++ tests/rustc_tests.rs | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 53597ef5..31712339 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -352,6 +352,12 @@ impl Renderer { max_line_num_len + 1, ); } + Some(Element::Origin(origin)) if origin.primary => self + .draw_col_separator_end( + &mut buffer, + current_line, + max_line_num_len + 1, + ), Some(Element::Message(level)) if level.level.name != Some(None) => diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index 2750da11..b32dd8fc 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -3055,6 +3055,7 @@ error[E0599]: no method named `poll` found for struct `Pin<&mut impl Future>` + | --> $SRC_DIR/core/src/future/future.rs:104:7 | = note: the method is available for `Pin<&mut impl Future>` here @@ -3074,6 +3075,7 @@ error[E0599]: no method named `poll` found for struct `Pin<&mut impl Future>` + ╰╴ ╭▸ $SRC_DIR/core/src/future/future.rs:104:7 │ ├ note: the method is available for `Pin<&mut impl Future>` here @@ -3233,6 +3235,7 @@ error: cannot find derive macro `Eqr` in this scope | LL | #[derive(Eqr)] | ^^^ help: a derive macro with a similar name exists: `Eq` + | --> $SRC_DIR/core/src/cmp.rs:356:0 | = note: similarly named derive macro `Eq` defined here @@ -3248,6 +3251,7 @@ error: cannot find derive macro `Eqr` in this scope │ LL │ #[derive(Eqr)] │ ━━━ help: a derive macro with a similar name exists: `Eq` + ╰╴ ╭▸ $SRC_DIR/core/src/cmp.rs:356:0 │ ├ note: similarly named derive macro `Eq` defined here From b461247cc6c3ad6d3492e4d0ef42d246011a79df Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Wed, 25 Jun 2025 10:11:39 -0600 Subject: [PATCH 288/293] test: Suggestion span beyond source --- tests/formatter.rs | 137 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/tests/formatter.rs b/tests/formatter.rs index eca0b826..84ab4a52 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -2635,3 +2635,140 @@ fn empty_span_start_line() { let renderer = Renderer::plain(); assert_data_eq!(renderer.render(input), expected); } + +#[test] +fn suggestion_span_one_bigger_than_source() { + let snippet_source = r#"#![allow(unused)] +fn main() { +[1, 2, 3].into_iter().for_each(|n| { *n; }); +} +"#; + + let suggestion_source = r#"[1, 2, 3].into_iter().for_each(|n| { *n; }); +"#; + + let long_title1 ="this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021"; + let long_title2 = "for more information, see "; + let long_title3 = "or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value"; + + let input = &[ + Group::with_title(Level::WARNING.title(long_title1)) + .element( + Snippet::source(snippet_source) + .path("lint_example.rs") + .annotation(AnnotationKind::Primary.span(40..49)), + ) + .element(Level::WARNING.message("this changes meaning in Rust 2021")) + .element(Level::NOTE.message(long_title2)) + .element(Level::NOTE.message("`#[warn(array_into_iter)]` on by default")), + Group::with_title( + Level::HELP.title("use `.iter()` instead of `.into_iter()` to avoid ambiguity"), + ) + .element( + Snippet::source(suggestion_source) + .path("lint_example.rs") + .line_start(3) + .patch(Patch::new(10..19, "iter")), + ), + Group::with_title(Level::HELP.title(long_title3)).element( + Snippet::source(suggestion_source) + .path("lint_example.rs") + .line_start(3) + .patch(Patch::new( + suggestion_source.len() + 1..suggestion_source.len() + 1, + "IntoIterator::into_iter(", + )), + ), + ]; + + let expected = str![[r#" +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 + --> lint_example.rs:3:11 + | +3 | [1, 2, 3].into_iter().for_each(|n| { *n; }); + | ^^^^^^^^^ + | + = warning: this changes meaning in Rust 2021 + = note: for more information, see + = note: `#[warn(array_into_iter)]` on by default +help: use `.iter()` instead of `.into_iter()` to avoid ambiguity + | +3 - [1, 2, 3].into_iter().for_each(|n| { *n; }); +3 + [1, 2, 3].iter().for_each(|n| { *n; }); + | +help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value + | +3 | IntoIterator::into_iter( + | +"#]]; + let renderer = Renderer::plain(); + assert_data_eq!(renderer.render(input), expected); +} + +#[test] +fn suggestion_span_bigger_than_source() { + let snippet_source = r#"#![allow(unused)] +fn main() { +[1, 2, 3].into_iter().for_each(|n| { *n; }); +} +"#; + let suggestion_source = r#"[1, 2, 3].into_iter().for_each(|n| { *n; }); +"#; + + let long_title1 ="this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021"; + let long_title2 = "for more information, see "; + let long_title3 = "or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value"; + + let input = &[ + Group::with_title(Level::WARNING.title(long_title1)) + .element( + Snippet::source(snippet_source) + .path("lint_example.rs") + .annotation(AnnotationKind::Primary.span(40..49)), + ) + .element(Level::WARNING.message("this changes meaning in Rust 2021")) + .element(Level::NOTE.message(long_title2)) + .element(Level::NOTE.message("`#[warn(array_into_iter)]` on by default")), + Group::with_title( + Level::HELP.title("use `.iter()` instead of `.into_iter()` to avoid ambiguity"), + ) + .element( + Snippet::source(suggestion_source) + .path("lint_example.rs") + .line_start(3) + .patch(Patch::new(10..19, "iter")), + ), + Group::with_title(Level::HELP.title(long_title3)).element( + Snippet::source(suggestion_source) + .path("lint_example.rs") + .line_start(3) + .patch(Patch::new( + suggestion_source.len() + 2..suggestion_source.len() + 2, + "IntoIterator::into_iter(", + )), + ), + ]; + + let expected = str![[r#" +warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 + --> lint_example.rs:3:11 + | +3 | [1, 2, 3].into_iter().for_each(|n| { *n; }); + | ^^^^^^^^^ + | + = warning: this changes meaning in Rust 2021 + = note: for more information, see + = note: `#[warn(array_into_iter)]` on by default +help: use `.iter()` instead of `.into_iter()` to avoid ambiguity + | +3 - [1, 2, 3].into_iter().for_each(|n| { *n; }); +3 + [1, 2, 3].iter().for_each(|n| { *n; }); + | +help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value + | +3 | IntoIterator::into_iter( + | +"#]]; + let renderer = Renderer::plain(); + assert_data_eq!(renderer.render(input), expected); +} From 83d2cbbf6ecf14926f563d39e84166809cc16b90 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Wed, 25 Jun 2025 10:14:49 -0600 Subject: [PATCH 289/293] fix!: Panic if Patch span is beyond the end of buffer --- src/renderer/source_map.rs | 13 +++++++++++++ tests/formatter.rs | 23 ++--------------------- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/src/renderer/source_map.rs b/src/renderer/source_map.rs index e2e4b61c..44b773b9 100644 --- a/src/renderer/source_map.rs +++ b/src/renderer/source_map.rs @@ -379,6 +379,19 @@ impl<'a> SourceMap<'a> { } line_count } + + let source_len = self.source.len(); + if let Some(bigger) = patches.iter().find_map(|x| { + // Allow patching one past the last character in the source. + if source_len + 1 < x.span.end { + Some(&x.span) + } else { + None + } + }) { + panic!("Patch span `{bigger:?}` is beyond the end of buffer `{source_len}`") + } + // Assumption: all spans are in the same file, and all spans // are disjoint. Sort in ascending order. patches.sort_by_key(|p| p.span.start); diff --git a/tests/formatter.rs b/tests/formatter.rs index 84ab4a52..1d21d13d 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -2706,6 +2706,7 @@ help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicit } #[test] +#[should_panic = "Patch span `47..47` is beyond the end of buffer `45`"] fn suggestion_span_bigger_than_source() { let snippet_source = r#"#![allow(unused)] fn main() { @@ -2749,26 +2750,6 @@ fn main() { ), ]; - let expected = str![[r#" -warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021 - --> lint_example.rs:3:11 - | -3 | [1, 2, 3].into_iter().for_each(|n| { *n; }); - | ^^^^^^^^^ - | - = warning: this changes meaning in Rust 2021 - = note: for more information, see - = note: `#[warn(array_into_iter)]` on by default -help: use `.iter()` instead of `.into_iter()` to avoid ambiguity - | -3 - [1, 2, 3].into_iter().for_each(|n| { *n; }); -3 + [1, 2, 3].iter().for_each(|n| { *n; }); - | -help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value - | -3 | IntoIterator::into_iter( - | -"#]]; let renderer = Renderer::plain(); - assert_data_eq!(renderer.render(input), expected); + renderer.render(input); } From 35d2ef68f2ad66f6bb54a38d8d5c32227e3e53c2 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Thu, 3 Jul 2025 04:16:23 -0600 Subject: [PATCH 290/293] test: Snippet with no path --- tests/formatter.rs | 68 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/tests/formatter.rs b/tests/formatter.rs index 1d21d13d..bd64dd7b 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -2753,3 +2753,71 @@ fn main() { let renderer = Renderer::plain(); renderer.render(input); } + +#[test] +fn snippet_no_path() { + // Taken from: https://docs.python.org/3/library/typing.html#annotating-callable-objects + + let source = "def __call__(self, *vals: bytes, maxlen: int | None = None) -> list[bytes]: ..."; + let input = &[Group::with_title(Level::ERROR.title("")).element( + Snippet::source(source).annotation(AnnotationKind::Primary.span(4..12).label("annotation")), + )]; + + let expected_ascii = str![[r#" +error: + | +1 | def __call__(self, *vals: bytes, maxlen: int | None = None) -> list[bytes]: ... + | ^^^^^^^^ annotation +"#]]; + let renderer = Renderer::plain(); + assert_data_eq!(renderer.render(input), expected_ascii); + + let expected_unicode = str![[r#" +error: + │ +1 │ def __call__(self, *vals: bytes, maxlen: int | None = None) -> list[bytes]: ... + ╰╴ ━━━━━━━━ annotation +"#]]; + let renderer = Renderer::plain().theme(OutputTheme::Unicode); + assert_data_eq!(renderer.render(input), expected_unicode); +} + +#[test] +fn multiple_snippet_no_path() { + // Taken from: https://docs.python.org/3/library/typing.html#annotating-callable-objects + + let source = "def __call__(self, *vals: bytes, maxlen: int | None = None) -> list[bytes]: ..."; + let input = &[Group::with_title(Level::ERROR.title("")) + .element( + Snippet::source(source) + .annotation(AnnotationKind::Primary.span(4..12).label("annotation")), + ) + .element( + Snippet::source(source) + .annotation(AnnotationKind::Primary.span(4..12).label("annotation")), + )]; + + let expected_ascii = str![[r#" +error: + | +1 | def __call__(self, *vals: bytes, maxlen: int | None = None) -> list[bytes]: ... + | ^^^^^^^^ annotation + | +1 | def __call__(self, *vals: bytes, maxlen: int | None = None) -> list[bytes]: ... + | ^^^^^^^^ annotation +"#]]; + let renderer = Renderer::plain(); + assert_data_eq!(renderer.render(input), expected_ascii); + + let expected_unicode = str![[r#" +error: + │ +1 │ def __call__(self, *vals: bytes, maxlen: int | None = None) -> list[bytes]: ... + │ ━━━━━━━━ annotation + │ +1 │ def __call__(self, *vals: bytes, maxlen: int | None = None) -> list[bytes]: ... + ╰╴ ━━━━━━━━ annotation +"#]]; + let renderer = Renderer::plain().theme(OutputTheme::Unicode); + assert_data_eq!(renderer.render(input), expected_unicode); +} From f1fcddaf6e3736718cbf6d729d64080f2deab3ef Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Thu, 3 Jul 2025 04:36:09 -0600 Subject: [PATCH 291/293] fix: Show Group/File start for Snippets without a path --- src/renderer/mod.rs | 63 ++++++++++++++++++++++++++++++++---- tests/color/issue_9.term.svg | 16 +++++---- tests/formatter.rs | 14 ++++---- 3 files changed, 74 insertions(+), 19 deletions(-) diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 31712339..80a88110 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -288,10 +288,14 @@ impl Renderer { } let mut message_iter = group.elements.iter().enumerate().peekable(); let mut last_was_suggestion = false; + let mut first_was_title = false; while let Some((i, section)) = message_iter.next() { let peek = message_iter.peek().map(|(_, s)| s).copied(); match §ion { Element::Title(title) => { + if i == 0 { + first_was_title = true; + } let title_style = match (i == 0, g == 0) { (true, true) => TitleStyle::MainHeader, (true, false) => TitleStyle::Header, @@ -329,11 +333,13 @@ impl Renderer { if let Some((source_map, annotated_lines)) = source_map_annotated_lines.pop_front() { + let is_primary = primary_path == cause.path.as_ref() + && i == first_was_title as usize; self.render_snippet_annotations( &mut buffer, max_line_num_len, cause, - primary_path, + is_primary, &source_map, &annotated_lines, max_depth, @@ -722,7 +728,7 @@ impl Renderer { buffer: &mut StyledBuffer, max_line_num_len: usize, snippet: &Snippet<'_, Annotation<'_>>, - primary_path: Option<&Cow<'_, str>>, + is_primary: bool, sm: &SourceMap<'_>, annotated_lines: &[AnnotatedLineInfo<'_>], multiline_depth: usize, @@ -732,7 +738,7 @@ impl Renderer { let mut origin = Origin::path(path.as_ref()); // print out the span location and spacer before we print the annotated source // to do this, we need to know if this span will be primary - let is_primary = primary_path == Some(&origin.path); + //let is_primary = primary_path == Some(&origin.path); if is_primary { origin.primary = true; @@ -776,11 +782,54 @@ impl Renderer { } let buffer_msg_line_offset = buffer.num_lines(); self.render_origin(buffer, max_line_num_len, &origin, buffer_msg_line_offset); - } + // Put in the spacer between the location and annotated source + self.draw_col_separator_no_space( + buffer, + buffer_msg_line_offset + 1, + max_line_num_len + 1, + ); + } else { + let buffer_msg_line_offset = buffer.num_lines(); + if is_primary { + if self.theme == OutputTheme::Unicode { + buffer.puts( + buffer_msg_line_offset, + max_line_num_len, + self.file_start(), + ElementStyle::LineNumber, + ); + } else { + self.draw_col_separator_no_space( + buffer, + buffer_msg_line_offset, + max_line_num_len + 1, + ); + } + } else { + // Add spacing line, as shown: + // --> $DIR/file:54:15 + // | + // LL | code + // | ^^^^ + // | (<- It prints *this* line) + // ::: $DIR/other_file.rs:15:5 + // | + // LL | code + // | ---- + self.draw_col_separator_no_space( + buffer, + buffer_msg_line_offset, + max_line_num_len + 1, + ); - // Put in the spacer between the location and annotated source - let buffer_msg_line_offset = buffer.num_lines(); - self.draw_col_separator_no_space(buffer, buffer_msg_line_offset, max_line_num_len + 1); + buffer.puts( + buffer_msg_line_offset + 1, + max_line_num_len, + self.secondary_file_start(), + ElementStyle::LineNumber, + ); + } + } // Contains the vertical lines' positions for active multiline annotations let mut multilines = Vec::new(); diff --git a/tests/color/issue_9.term.svg b/tests/color/issue_9.term.svg index 5ae5da77..da58ee8b 100644 --- a/tests/color/issue_9.term.svg +++ b/tests/color/issue_9.term.svg @@ -1,4 +1,4 @@ - +
| - 7 | let y = x; + ::: - | - value moved here + 7 | let y = x; - | + | - value moved here - 9 | x; + | - | ^ value used here after move + ::: + + 9 | x; + + | ^ value used here after move
diff --git a/tests/formatter.rs b/tests/formatter.rs index bd64dd7b..e7c08d47 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -2053,7 +2053,7 @@ error: title let expected_unicode = str![[r#" error: title - │ + ╭▸ 1 │ version = "0.1.0" 2 │ # Ensure that the spans from toml handle utf-8 correctly 3 │ authors = [ @@ -2093,7 +2093,7 @@ error: expected item, found `?` let expected_unicode = str![[r#" error: expected item, found `?` - │ + ╭▸ 1 │ … 宽的。这是宽的。这是宽的。这是宽的。这是宽的。这是宽的。*/? │ ━ expected item │ @@ -2130,7 +2130,7 @@ error: expected item, found `?` let expected_unicode = str![[r#" error: expected item, found `?` - │ + ╭▸ 1 │ … 的。这是宽的。这是宽的。这是宽的。… │ ━━ expected item │ @@ -2167,7 +2167,7 @@ error: expected item, found `?` let expected_unicode = str![[r#" error: expected item, found `?` - │ + ╭▸ 1 │ …aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa*/? │ ━ expected item │ @@ -2774,7 +2774,7 @@ error: let expected_unicode = str![[r#" error: - │ + ╭▸ 1 │ def __call__(self, *vals: bytes, maxlen: int | None = None) -> list[bytes]: ... ╰╴ ━━━━━━━━ annotation "#]]; @@ -2803,6 +2803,7 @@ error: 1 | def __call__(self, *vals: bytes, maxlen: int | None = None) -> list[bytes]: ... | ^^^^^^^^ annotation | + ::: 1 | def __call__(self, *vals: bytes, maxlen: int | None = None) -> list[bytes]: ... | ^^^^^^^^ annotation "#]]; @@ -2811,10 +2812,11 @@ error: let expected_unicode = str![[r#" error: - │ + ╭▸ 1 │ def __call__(self, *vals: bytes, maxlen: int | None = None) -> list[bytes]: ... │ ━━━━━━━━ annotation │ + ⸬ 1 │ def __call__(self, *vals: bytes, maxlen: int | None = None) -> list[bytes]: ... ╰╴ ━━━━━━━━ annotation "#]]; From 7a4fd3e1e9ecfa5c6b5c00f14b0c192a2785152a Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Thu, 3 Jul 2025 14:48:28 -0600 Subject: [PATCH 292/293] test: Add test for Message text ending with \n --- tests/rustc_tests.rs | 74 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index b32dd8fc..52e8bbe7 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -3370,3 +3370,77 @@ note: the traits `Iterator` and `ToTokens` must be implemented let renderer = renderer.theme(OutputTheme::Unicode); assert_data_eq!(renderer.render(input), expected_unicode); } + +#[test] +fn not_found_self_type_differs_shadowing_trait_item() { + // tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.rs + + let source = r#"#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + +// Check that it's okay to report “[inherent] associated type […] not found” for inherent associated +// type candidates that are not applicable (due to unsuitable Self type) even if there exists a +// “shadowed” associated type from a trait with the same name since its use would be ambiguous +// anyway if the IAT didn't exist. +// FIXME(inherent_associated_types): Figure out which error would be more helpful here. + +//@ revisions: shadowed uncovered + +struct S(T); + +trait Tr { + type Pr; +} + +impl Tr for S { + type Pr = (); +} + +#[cfg(shadowed)] +impl S<()> { + type Pr = i32; +} + +fn main() { + let _: S::::Pr = (); + //[shadowed]~^ ERROR associated type `Pr` not found + //[uncovered]~^^ ERROR associated type `Pr` not found +} +"#; + + let input = &[Group::with_title( + Level::ERROR + .title("associated type `Pr` not found for `S` in the current scope") + .id("E0220"), + ) + .element( + Snippet::source(source) + .path("$DIR/not-found-self-type-differs-shadowing-trait-item.rs") + .annotation( + AnnotationKind::Primary + .span(705..707) + .label("associated item not found in `S`"), + ) + .annotation( + AnnotationKind::Context + .span(532..543) + .label("associated type `Pr` not found for this struct"), + ), + ) + .element(Level::NOTE.title("the associated type was found for\n"))]; + + let expected = str![[r#" +error[E0220]: associated type `Pr` not found for `S` in the current scope + --> $DIR/not-found-self-type-differs-shadowing-trait-item.rs:28:23 + | +LL | struct S(T); + | ----------- associated type `Pr` not found for this struct +... +LL | let _: S::::Pr = (); + | ^^ associated item not found in `S` + | + = note: the associated type was found for +"#]]; + let renderer = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer.render(input), expected); +} From 82abe2699d655cb946bbf7684b67a5e7291051f2 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Thu, 3 Jul 2025 14:56:12 -0600 Subject: [PATCH 293/293] fix: Render newline if a Message ends with one --- src/renderer/mod.rs | 2 +- tests/rustc_tests.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 80a88110..8d3c6a2a 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -636,7 +636,7 @@ impl Renderer { } else { (normalize_whitespace(title.text()), title_element_style) }; - for (i, text) in title_str.lines().enumerate() { + for (i, text) in title_str.split('\n').enumerate() { if i != 0 { buffer.append(buffer_msg_line_offset + i, &padding, ElementStyle::NoStyle); if title_style == TitleStyle::Secondary diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index 52e8bbe7..dd5dbe82 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -3440,6 +3440,7 @@ LL | let _: S::::Pr = (); | ^^ associated item not found in `S` | = note: the associated type was found for + "#]]; let renderer = Renderer::plain().anonymized_line_numbers(true); assert_data_eq!(renderer.render(input), expected);