summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaibo Huang <hhb@google.com>2020-12-01 22:38:01 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2020-12-01 22:38:01 +0000
commit9b40cf03b6ac8815fc659b424691af5202957db1 (patch)
tree291f85450ee9cb3667a166c313c51e87bf5647eb
parent78c5058bfed09cfade339194ea618d95c4b7885b (diff)
parent7c93dcc3f45be4fcd9b59969804c9d073fbdd900 (diff)
downloadcodespan-reporting-9b40cf03b6ac8815fc659b424691af5202957db1.tar.gz
Upgrade rust/crates/codespan-reporting to 0.11.0 am: f8e9299b32 am: 7c93dcc3f4
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/codespan-reporting/+/1515035 Change-Id: Ie76be7373cb00955e55c501bf538ce0016f9d8d1
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--Android.bp4
-rw-r--r--CHANGELOG.md80
-rw-r--r--Cargo.lock264
-rw-r--r--Cargo.toml4
-rw-r--r--Cargo.toml.orig4
-rw-r--r--METADATA8
-rw-r--r--examples/custom_files.rs49
-rw-r--r--examples/readme_preview.rs5
-rw-r--r--src/diagnostic.rs12
-rw-r--r--src/files.rs138
-rw-r--r--src/term.rs19
-rw-r--r--src/term/config.rs20
-rw-r--r--src/term/renderer.rs149
-rw-r--r--src/term/views.rs219
-rw-r--r--tests/snapshots/term__empty__medium_color.snap11
-rw-r--r--tests/snapshots/term__empty__medium_no_color.snap11
-rw-r--r--tests/snapshots/term__empty_ranges__medium_color.snap9
-rw-r--r--tests/snapshots/term__empty_ranges__medium_no_color.snap9
-rw-r--r--tests/snapshots/term__fizz_buzz__medium_color.snap11
-rw-r--r--tests/snapshots/term__fizz_buzz__medium_no_color.snap11
-rw-r--r--tests/snapshots/term__fizz_buzz__rich_color.snap4
-rw-r--r--tests/snapshots/term__fizz_buzz__rich_no_color.snap4
-rw-r--r--tests/snapshots/term__message__medium_color.snap9
-rw-r--r--tests/snapshots/term__message__medium_no_color.snap9
-rw-r--r--tests/snapshots/term__message_and_notes__medium_color.snap13
-rw-r--r--tests/snapshots/term__message_and_notes__medium_no_color.snap13
-rw-r--r--tests/snapshots/term__message_errorcode__rich_no_color.snap21
-rw-r--r--tests/snapshots/term__message_errorcode__short_no_color.snap13
-rw-r--r--tests/snapshots/term__multifile__medium_color.snap12
-rw-r--r--tests/snapshots/term__multifile__medium_no_color.snap12
-rw-r--r--tests/snapshots/term__multiline_omit__rich_no_color.snap38
-rw-r--r--tests/snapshots/term__multiline_overlapping__medium_color.snap9
-rw-r--r--tests/snapshots/term__multiline_overlapping__medium_no_color.snap9
-rw-r--r--tests/snapshots/term__multiline_overlapping__rich_color.snap2
-rw-r--r--tests/snapshots/term__multiline_overlapping__rich_no_color.snap2
-rw-r--r--tests/snapshots/term__overlapping__medium_color.snap17
-rw-r--r--tests/snapshots/term__overlapping__medium_no_color.snap17
-rw-r--r--tests/snapshots/term__overlapping__rich_color.snap4
-rw-r--r--tests/snapshots/term__overlapping__rich_no_color.snap4
-rw-r--r--tests/snapshots/term__position_indicator__medium_no_color.snap7
-rw-r--r--tests/snapshots/term__position_indicator__rich_no_color.snap14
-rw-r--r--tests/snapshots/term__position_indicator__short_no_color.snap6
-rw-r--r--tests/snapshots/term__same_line__medium_color.snap8
-rw-r--r--tests/snapshots/term__same_line__medium_no_color.snap8
-rw-r--r--tests/snapshots/term__same_line__rich_color.snap2
-rw-r--r--tests/snapshots/term__same_line__rich_no_color.snap2
-rw-r--r--tests/snapshots/term__same_ranges__medium_color.snap7
-rw-r--r--tests/snapshots/term__same_ranges__medium_no_color.snap7
-rw-r--r--tests/snapshots/term__unicode__medium_no_color.snap29
-rw-r--r--tests/snapshots/term__unicode_spans__medium_no_color.snap9
-rw-r--r--tests/term.rs185
52 files changed, 1112 insertions, 423 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 4139f46..edbabaa 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
{
"git": {
- "sha1": "50bceff36e169673b49bfffa1809bba6be9bd07f"
+ "sha1": "2f26ac696b796968db370bea505095abc17ecfa4"
}
}
diff --git a/Android.bp b/Android.bp
index 10cfe99..8e17a51 100644
--- a/Android.bp
+++ b/Android.bp
@@ -13,5 +13,5 @@ rust_library {
}
// dependent_library ["feature_list"]
-// termcolor-1.1.0
-// unicode-width-0.1.7 "default"
+// termcolor-1.1.2
+// unicode-width-0.1.8 "default"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index abd9bb5..da91f22 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,12 +7,87 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
+## [0.11.0] - 2020-11-30
+
+There is now a [code of conduct](https://github.com/brendanzab/codespan/blob/master/CODE_OF_CONDUCT.md)
+and a [contributing guide](https://github.com/brendanzab/codespan/blob/master/CONTRIBUTING.md).
+
+Some versions were skipped to sync up with the `codespan-lsp` crate. The release
+process has been changed so this should not happen again.
+
+### Added
+
+- If a label spans over multiple lines, not all lines are rendered.
+ The number of lines rendered at beginning and end is configurable separately.
+- There is now a custom error type.
+- There now is a medium rendering mode that is like the short rendering mode
+ but also shows notes from the diagnostic.
+- `PartialEq` and `Eq` implementations for the `diagnostic::{Diagnostic, Label, Severity}` types.
+
+### Changed
+
+- All errors now use the error type `codespan_reporting::file::Error`.
+ This type also replaces the custom error type for `codespan-lsp`.
+
+### Fixed
+
+- Empty error codes are not rendered.
+- The locus ("location of the diagnostic") is now computed so it is always at the first
+ primary label, or at the first secondary label if no primary labels are available.
+- All `unwrap`s outside of tests and examples have been removed.
+- Some internal improvements, including various code style improvements by using Clippy.
+- Improved documentation, also mentioning how the ordering of labels is handled.
+
## [0.9.5] - 2020-06-24
### Changed
- Sections of source code that are marked with primary labels are now rendered
using the primary highlight color.
+- Tab stops are now rendered properly.
+
+ We used to just render `\t` characters in source snippets with the same
+ number of spaces. For example, when rendering with a tab width of `3` we
+ would print:
+ ```
+ warning: tab test
+ ┌─ tab_columns:1:2
+ │
+ 1 │ hello
+ │ ^^^^^
+ 2 │ ∙ hello
+ │ ^^^^^
+ 3 │ ∙∙ hello
+ │ ^^^^^
+ 4 │ ∙∙∙ hello
+ │ ^^^^^
+ 5 │ ∙∙∙∙ hello
+ │ ^^^^^
+ 6 │ ∙∙∙∙∙ hello
+ │ ^^^^^
+ 7 │ ∙∙∙∙∙∙ hello
+ │ ^^^^^
+ ```
+ Now we properly take into account the column of the tab character:
+ ```
+ warning: tab test
+ ┌─ tab_columns:1:2
+ │
+ 1 │ hello
+ │ ^^^^^
+ 2 │ ∙ hello
+ │ ^^^^^
+ 3 │ ∙∙ hello
+ │ ^^^^^
+ 4 │ ∙∙∙ hello
+ │ ^^^^^
+ 5 │ ∙∙∙∙ hello
+ │ ^^^^^
+ 6 │ ∙∙∙∙∙ hello
+ │ ^^^^^
+ 7 │ ∙∙∙∙∙∙ hello
+ │ ^^^^^
+ ```
## [0.9.4] - 2020-05-18
@@ -245,8 +320,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [0.2.1] - 2019-02-26
## [0.2.0] - 2018-10-11
-[Unreleased]: https://github.com/brendanzab/codespan/compare/v0.9.5...HEAD
-[0.9.4]: https://github.com/brendanzab/codespan/compare/v0.9.4...v0.9.5
+[Unreleased]: https://github.com/brendanzab/codespan/compare/v0.11.0...HEAD
+[0.11.0]: https://github.com/brendanzab/codespan/compare/v0.9.5...v0.11.0
+[0.9.5]: https://github.com/brendanzab/codespan/compare/v0.9.4...v0.9.5
[0.9.4]: https://github.com/brendanzab/codespan/compare/v0.9.3...v0.9.4
[0.9.3]: https://github.com/brendanzab/codespan/compare/v0.9.2...v0.9.3
[0.9.2]: https://github.com/brendanzab/codespan/compare/v0.9.1...v0.9.2
diff --git a/Cargo.lock b/Cargo.lock
index e41e6d0..c43523a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -11,21 +11,9 @@ dependencies = [
[[package]]
name = "anyhow"
-version = "1.0.31"
+version = "1.0.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85bb70cc08ec97ca5450e6eba421deeea5f172c0fc61f78b5357b2a8e8be195f"
-
-[[package]]
-name = "arrayref"
-version = "0.3.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
-
-[[package]]
-name = "arrayvec"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
+checksum = "bf8dcb5b4bbaa28653b647d8c77bd4ed40183b48882e130c1f1ffb73de069fd7"
[[package]]
name = "atty"
@@ -39,39 +27,16 @@ dependencies = [
]
[[package]]
-name = "autocfg"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
-
-[[package]]
-name = "base64"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
-
-[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
-name = "blake2b_simd"
-version = "0.5.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a"
-dependencies = [
- "arrayref",
- "arrayvec",
- "constant_time_eq",
-]
-
-[[package]]
name = "cc"
-version = "1.0.54"
+version = "1.0.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311"
+checksum = "95752358c8f7552394baf48cd82695b345628ad3f170d607de3ca03b8dacca15"
[[package]]
name = "cfg-if"
@@ -80,10 +45,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
name = "clap"
-version = "2.33.1"
+version = "2.33.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129"
+checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
dependencies = [
"ansi_term",
"atty",
@@ -95,20 +66,8 @@ dependencies = [
]
[[package]]
-name = "clicolors-control"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e"
-dependencies = [
- "atty",
- "lazy_static",
- "libc",
- "winapi",
-]
-
-[[package]]
name = "codespan-reporting"
-version = "0.9.5"
+version = "0.11.0"
dependencies = [
"anyhow",
"insta",
@@ -124,11 +83,10 @@ dependencies = [
[[package]]
name = "console"
-version = "0.10.3"
+version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2586208b33573b7f76ccfbe5adb076394c88deaf81b84d7213969805b0a952a7"
+checksum = "c0b1aacfaffdbff75be81c15a399b4bedf78aaefe840e8af1d299ac2ade885d2"
dependencies = [
- "clicolors-control",
"encode_unicode",
"lazy_static",
"libc",
@@ -138,23 +96,6 @@ dependencies = [
]
[[package]]
-name = "constant_time_eq"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
-
-[[package]]
-name = "crossbeam-utils"
-version = "0.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
-dependencies = [
- "autocfg",
- "cfg-if",
- "lazy_static",
-]
-
-[[package]]
name = "difference"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -162,19 +103,19 @@ checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
[[package]]
name = "dirs-next"
-version = "1.0.1"
+version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1cbcf9241d9e8d106295bd496bbe2e9cffd5fa098f2a8c9e2bbcbf09773c11a8"
+checksum = "cf36e65a80337bea855cd4ef9b8401ffce06a7baedf2e85ec467b1ac3f6e82b6"
dependencies = [
- "cfg-if",
+ "cfg-if 1.0.0",
"dirs-sys-next",
]
[[package]]
name = "dirs-sys-next"
-version = "0.1.0"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c60f7b8a8953926148223260454befb50c751d3c50e1c178c4fd1ace4083c9a"
+checksum = "99de365f605554ae33f115102a02057d4fc18b01f3284d6870be0938743cfe7d"
dependencies = [
"libc",
"redox_users",
@@ -195,11 +136,11 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
[[package]]
name = "getrandom"
-version = "0.1.14"
+version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
+checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
"libc",
"wasi",
]
@@ -215,18 +156,18 @@ dependencies = [
[[package]]
name = "hermit-abi"
-version = "0.1.14"
+version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909"
+checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8"
dependencies = [
"libc",
]
[[package]]
name = "insta"
-version = "0.16.0"
+version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8386e795fb3927131ea4cede203c529a333652eb6dc4ff29616b832b27e9b096"
+checksum = "863bf97e7130bf788f29a99bc4073735af6b8ecc3da6a39c23b3a688d2d3109a"
dependencies = [
"console",
"difference",
@@ -250,9 +191,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
-version = "0.2.71"
+version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
+checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
[[package]]
name = "linked-hash-map"
@@ -262,37 +203,36 @@ checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a"
[[package]]
name = "log"
-version = "0.4.8"
+version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
+checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
]
[[package]]
name = "memchr"
-version = "2.3.3"
+version = "2.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
+checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
[[package]]
name = "nix"
-version = "0.17.0"
+version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363"
+checksum = "83450fe6a6142ddd95fb064b746083fc4ef1705fe81f64a64e1d4b39f54a1055"
dependencies = [
"bitflags",
"cc",
- "cfg-if",
+ "cfg-if 0.1.10",
"libc",
- "void",
]
[[package]]
name = "peg"
-version = "0.6.2"
+version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9075875c14bb21f25f11cad4b6ad2e4dd443b8fb83900b2fbdd6ebd744b82e97"
+checksum = "9f76678828272f177ac33b7e2ac2e3e73cc6c1cd1e3e387928aa69562fa51367"
dependencies = [
"peg-macros",
"peg-runtime",
@@ -300,9 +240,9 @@ dependencies = [
[[package]]
name = "peg-macros"
-version = "0.6.2"
+version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c24c165fd39e995246140cc78df55c56c6733ba87e6658cb3e197b8856c62852"
+checksum = "636d60acf97633e48d266d7415a9355d4389cea327a193f87df395d88cd2b14d"
dependencies = [
"peg-runtime",
"proc-macro2",
@@ -311,15 +251,15 @@ dependencies = [
[[package]]
name = "peg-runtime"
-version = "0.6.2"
+version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c1a2897e69d986c7986747ebad425cf03746ec5e3e09bb3b2600f91301ba864"
+checksum = "9555b1514d2d99d78150d3c799d4c357a3e2c2a8062cd108e93a06d9057629c5"
[[package]]
name = "proc-macro-error"
-version = "1.0.2"
+version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "98e9e4b82e0ef281812565ea4751049f1bdcdfccda7d3f459f2e138a40c08678"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
@@ -330,22 +270,20 @@ dependencies = [
[[package]]
name = "proc-macro-error-attr"
-version = "1.0.2"
+version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f5444ead4e9935abd7f27dc51f7e852a0569ac888096d5ec2499470794e2e53"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
- "syn",
- "syn-mid",
"version_check",
]
[[package]]
name = "proc-macro2"
-version = "1.0.18"
+version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa"
+checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
dependencies = [
"unicode-xid",
]
@@ -361,40 +299,27 @@ dependencies = [
[[package]]
name = "redox_syscall"
-version = "0.1.56"
+version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
+checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
[[package]]
name = "redox_users"
-version = "0.3.4"
+version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431"
+checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d"
dependencies = [
"getrandom",
"redox_syscall",
- "rust-argon2",
-]
-
-[[package]]
-name = "rust-argon2"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017"
-dependencies = [
- "base64",
- "blake2b_simd",
- "constant_time_eq",
- "crossbeam-utils",
]
[[package]]
name = "rustyline"
-version = "6.2.0"
+version = "6.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3358c21cbbc1a751892528db4e1de4b7a2b6a73f001e215aaba97d712cfa9777"
+checksum = "6f0d5e7b0219a3eadd5439498525d4765c59b7c993ef0c12244865cd2d988413"
dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
"dirs-next",
"libc",
"log",
@@ -421,18 +346,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serde"
-version = "1.0.114"
+version = "1.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3"
+checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.114"
+version = "1.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e"
+checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e"
dependencies = [
"proc-macro2",
"quote",
@@ -441,9 +366,9 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.55"
+version = "1.0.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec2c5d7e739bc07a3e73381a39d61fdb5f671c60c1df26a130690665803d8226"
+checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95"
dependencies = [
"itoa",
"ryu",
@@ -452,9 +377,9 @@ dependencies = [
[[package]]
name = "serde_yaml"
-version = "0.8.13"
+version = "0.8.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae3e2dd40a7cdc18ca80db804b7f461a39bb721160a85c9a1fa30134bf3c02a5"
+checksum = "f7baae0a99f1a324984bcdc5f0718384c1f69775f1c7eec8b859b71b443e3fd7"
dependencies = [
"dtoa",
"linked-hash-map",
@@ -470,9 +395,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "structopt"
-version = "0.3.15"
+version = "0.3.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de2f5e239ee807089b62adce73e48c625e0ed80df02c7ab3f068f5db5281065c"
+checksum = "126d630294ec449fae0b16f964e35bf3c74f940da9dca17ee9b905f7b3112eb8"
dependencies = [
"clap",
"lazy_static",
@@ -481,9 +406,9 @@ dependencies = [
[[package]]
name = "structopt-derive"
-version = "0.4.8"
+version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "510413f9de616762a4fbeab62509bf15c729603b72d7cd71280fbca431b1c118"
+checksum = "65e51c492f9e23a220534971ff5afc14037289de430e3c83f9daf6a1b6ae91e8"
dependencies = [
"heck",
"proc-macro-error",
@@ -494,9 +419,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "1.0.33"
+version = "1.0.52"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8d5d96e8cbb005d6959f119f773bfaebb5684296108fb32600c00cde305b2cd"
+checksum = "6c1e438504729046a5cfae47f97c30d6d083c7d91d94603efdae3477fc070d4c"
dependencies = [
"proc-macro2",
"quote",
@@ -504,30 +429,19 @@ dependencies = [
]
[[package]]
-name = "syn-mid"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
name = "termcolor"
-version = "1.1.0"
+version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
+checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
dependencies = [
"winapi-util",
]
[[package]]
name = "terminal_size"
-version = "0.1.12"
+version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8038f95fc7a6f351163f4b964af631bd26c9e828f7db085f2a84aca56f70d13b"
+checksum = "4bd2d183bd3fac5f5fe38ddbeb4dc9aec4a39a9d7d59e7491d900302da01cbe1"
dependencies = [
"libc",
"winapi",
@@ -535,9 +449,9 @@ dependencies = [
[[package]]
name = "termios"
-version = "0.3.2"
+version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f0fcee7b24a25675de40d5bb4de6e41b0df07bc9856295e7e2b3a3600c400c2"
+checksum = "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b"
dependencies = [
"libc",
]
@@ -553,27 +467,27 @@ dependencies = [
[[package]]
name = "unicode-segmentation"
-version = "1.6.0"
+version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
+checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796"
[[package]]
name = "unicode-width"
-version = "0.1.7"
+version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
+checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
[[package]]
name = "unicode-xid"
-version = "0.2.0"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
+checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "unindent"
-version = "0.1.6"
+version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af41d708427f8fd0e915dcebb2cae0f0e6acb2a939b2d399c265c39a38a18942"
+checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7"
[[package]]
name = "utf8parse"
@@ -594,12 +508,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
[[package]]
-name = "void"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
-
-[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -607,9 +515,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "winapi"
-version = "0.3.8"
+version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
diff --git a/Cargo.toml b/Cargo.toml
index 294d127..9a7fcd1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@
[package]
edition = "2018"
name = "codespan-reporting"
-version = "0.9.5"
+version = "0.11.0"
authors = ["Brendan Zabarauskas <bjzaba@yahoo.com.au>"]
exclude = ["assets/**"]
description = "Beautiful diagnostic reporting for text-based programming languages"
@@ -36,7 +36,7 @@ version = "0.1"
version = "1"
[dev-dependencies.insta]
-version = "0.16"
+version = "1.0"
[dev-dependencies.lazy_static]
version = "1.4"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 427e854..0a6f79e 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,6 +1,6 @@
[package]
name = "codespan-reporting"
-version = "0.9.5"
+version = "0.11.0"
readme = "../README.md"
license = "Apache-2.0"
authors = ["Brendan Zabarauskas <bjzaba@yahoo.com.au>"]
@@ -18,7 +18,7 @@ unicode-width = "0.1"
[dev-dependencies]
anyhow = "1"
-insta = "0.16"
+insta = "1.0"
lazy_static = "1.4"
peg = "0.6"
rustyline = "6"
diff --git a/METADATA b/METADATA
index b8b9d82..612e190 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/codespan-reporting/codespan-reporting-0.9.5.crate"
+ value: "https://static.crates.io/crates/codespan-reporting/codespan-reporting-0.11.0.crate"
}
- version: "0.9.5"
+ version: "0.11.0"
license_type: NOTICE
last_upgrade_date {
year: 2020
- month: 7
- day: 10
+ month: 11
+ day: 30
}
}
diff --git a/examples/custom_files.rs b/examples/custom_files.rs
index 2edfaa9..dbbacda 100644
--- a/examples/custom_files.rs
+++ b/examples/custom_files.rs
@@ -30,7 +30,7 @@ fn main() -> anyhow::Result<()> {
];
let writer = StandardStream::stderr(ColorChoice::Always);
- let config = codespan_reporting::term::Config::default();
+ let config = term::Config::default();
for message in &messages {
let writer = &mut writer.lock();
term::emit(writer, &config, &files, &message.to_diagnostic())?;
@@ -56,13 +56,20 @@ mod files {
}
impl File {
- fn line_start(&self, line_index: usize) -> Option<usize> {
+ fn line_start(&self, line_index: usize) -> Result<usize, files::Error> {
use std::cmp::Ordering;
match line_index.cmp(&self.line_starts.len()) {
- Ordering::Less => self.line_starts.get(line_index).cloned(),
- Ordering::Equal => Some(self.source.len()),
- Ordering::Greater => None,
+ Ordering::Less => Ok(self
+ .line_starts
+ .get(line_index)
+ .expect("failed despite previous check")
+ .clone()),
+ Ordering::Equal => Ok(self.source.len()),
+ Ordering::Greater => Err(files::Error::LineTooLarge {
+ given: line_index,
+ max: self.line_starts.len() - 1,
+ }),
}
}
}
@@ -106,8 +113,10 @@ mod files {
}
/// Get the file corresponding to the given id.
- fn get(&self, file_id: FileId) -> Option<&File> {
- self.files.get(file_id.0 as usize)
+ fn get(&self, file_id: FileId) -> Result<&File, files::Error> {
+ self.files
+ .get(file_id.0 as usize)
+ .ok_or(files::Error::FileMissing)
}
}
@@ -116,27 +125,31 @@ mod files {
type Name = &'files str;
type Source = &'files str;
- fn name(&self, file_id: FileId) -> Option<&str> {
- Some(self.get(file_id)?.name.as_ref())
+ fn name(&self, file_id: FileId) -> Result<&str, files::Error> {
+ Ok(self.get(file_id)?.name.as_ref())
}
- fn source(&self, file_id: FileId) -> Option<&str> {
- Some(&self.get(file_id)?.source)
+ fn source(&self, file_id: FileId) -> Result<&str, files::Error> {
+ Ok(&self.get(file_id)?.source)
}
- fn line_index(&self, file_id: FileId, byte_index: usize) -> Option<usize> {
- match self.get(file_id)?.line_starts.binary_search(&byte_index) {
- Ok(line) => Some(line),
- Err(next_line) => Some(next_line - 1),
- }
+ fn line_index(&self, file_id: FileId, byte_index: usize) -> Result<usize, files::Error> {
+ self.get(file_id)?
+ .line_starts
+ .binary_search(&byte_index)
+ .or_else(|next_line| Ok(next_line - 1))
}
- fn line_range(&self, file_id: FileId, line_index: usize) -> Option<Range<usize>> {
+ fn line_range(
+ &self,
+ file_id: FileId,
+ line_index: usize,
+ ) -> Result<Range<usize>, files::Error> {
let file = self.get(file_id)?;
let line_start = file.line_start(line_index)?;
let next_line_start = file.line_start(line_index + 1)?;
- Some(line_start..next_line_start)
+ Ok(line_start..next_line_start)
}
}
}
diff --git a/examples/readme_preview.rs b/examples/readme_preview.rs
index aa3d8cf..2cf96f6 100644
--- a/examples/readme_preview.rs
+++ b/examples/readme_preview.rs
@@ -81,7 +81,10 @@ fn main() -> anyhow::Result<()> {
Opts::Svg => {
let mut buffer = Vec::new();
let mut writer = HtmlEscapeWriter::new(SvgWriter::new(&mut buffer));
- let config = codespan_reporting::term::Config::default();
+ let config = codespan_reporting::term::Config {
+ styles: codespan_reporting::term::Styles::with_blue(Color::Blue),
+ ..codespan_reporting::term::Config::default()
+ };
for diagnostic in &diagnostics {
term::emit(&mut writer, &config, &file, &diagnostic)?;
diff --git a/src/diagnostic.rs b/src/diagnostic.rs
index 559c899..7dddcec 100644
--- a/src/diagnostic.rs
+++ b/src/diagnostic.rs
@@ -16,7 +16,7 @@ use std::ops::Range;
/// assert!(Severity::Warning > Severity::Note);
/// assert!(Severity::Note > Severity::Help);
/// ```
-#[derive(Copy, Clone, PartialEq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub enum Severity {
/// An unexpected bug.
@@ -50,7 +50,7 @@ impl PartialOrd for Severity {
}
}
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub enum LabelStyle {
/// Labels that describe the primary cause of a diagnostic.
@@ -60,7 +60,7 @@ pub enum LabelStyle {
}
/// A label describing an underlined region of code associated with a diagnostic.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct Label<FileId> {
/// The style of the label.
@@ -112,7 +112,9 @@ impl<FileId> Label<FileId> {
/// Represents a diagnostic message that can provide information like errors and
/// warnings to the user.
-#[derive(Clone, Debug)]
+///
+/// The position of a Diagnostic is considered to be the position of the [`Label`] that has the earliest starting position and has the highest style which appears in all the labels of the diagnostic.
+#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct Diagnostic<FileId> {
/// The overall severity of the diagnostic
@@ -126,6 +128,8 @@ pub struct Diagnostic<FileId> {
/// sense on its own, without additional context provided by labels and notes.
pub message: String,
/// Source labels that describe the cause of the diagnostic.
+ /// The order of the labels inside the vector does not have any meaning.
+ /// The labels are always arranged in the order they appear in the source code.
pub labels: Vec<Label<FileId>>,
/// Notes that are associated with the primary cause of the diagnostic.
/// These can include line breaks for improved formatting.
diff --git a/src/files.rs b/src/files.rs
index 41691b9..b25cd79 100644
--- a/src/files.rs
+++ b/src/files.rs
@@ -7,7 +7,7 @@
//! Simple implementations of this trait are implemented:
//!
//! - [`SimpleFile`]: For single-file use-cases
-//! - [`SimpleFiles`]: For single-file use-cases
+//! - [`SimpleFiles`]: For multi-file use-cases
//!
//! These data structures provide a pretty minimal API, however,
//! so end-users are encouraged to create their own implementations for their
@@ -25,6 +25,58 @@
use std::ops::Range;
+/// An enum representing an error that happened while looking up a file or a piece of content in that file.
+#[derive(Debug)]
+#[non_exhaustive]
+pub enum Error {
+ /// A required file is not in the file database.
+ FileMissing,
+ /// The file is present, but does not contain the specified byte index.
+ IndexTooLarge { given: usize, max: usize },
+ /// The file is present, but does not contain the specified line index.
+ LineTooLarge { given: usize, max: usize },
+ /// The file is present and contains the specified line index, but the line does not contain the specified column index.
+ ColumnTooLarge { given: usize, max: usize },
+ /// The given index is contained in the file, but is not a boundary of a UTF-8 code point.
+ InvalidCharBoundary { given: usize },
+ /// There was a error while doing IO.
+ Io(std::io::Error),
+}
+
+impl From<std::io::Error> for Error {
+ fn from(err: std::io::Error) -> Error {
+ Error::Io(err)
+ }
+}
+
+impl std::fmt::Display for Error {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ Error::FileMissing => write!(f, "file missing"),
+ Error::IndexTooLarge { given, max } => {
+ write!(f, "invalid index {}, maximum index is {}", given, max)
+ }
+ Error::LineTooLarge { given, max } => {
+ write!(f, "invalid line {}, maximum line is {}", given, max)
+ }
+ Error::ColumnTooLarge { given, max } => {
+ write!(f, "invalid column {}, maximum column {}", given, max)
+ }
+ Error::InvalidCharBoundary { .. } => write!(f, "index is not a code point boundary"),
+ Error::Io(err) => write!(f, "{}", err),
+ }
+ }
+}
+
+impl std::error::Error for Error {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ match &self {
+ Error::Io(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
/// A minimal interface for accessing source files when rendering diagnostics.
///
/// A lifetime parameter `'a` is provided to allow any of the returned values to returned by reference.
@@ -40,12 +92,14 @@ pub trait Files<'a> {
type Source: 'a + AsRef<str>;
/// The user-facing name of a file.
- fn name(&'a self, id: Self::FileId) -> Option<Self::Name>;
+ fn name(&'a self, id: Self::FileId) -> Result<Self::Name, Error>;
/// The source code of a file.
- fn source(&'a self, id: Self::FileId) -> Option<Self::Source>;
+ fn source(&'a self, id: Self::FileId) -> Result<Self::Source, Error>;
/// The index of the line at the given byte index.
+ /// If the byte index is past the end of the file, returns the maximum line index in the file.
+ /// This means that this function only fails if the file is not present.
///
/// # Note for trait implementors
///
@@ -56,9 +110,11 @@ pub trait Files<'a> {
///
/// [`line_starts`]: crate::files::line_starts
/// [`files`]: crate::files
- fn line_index(&'a self, id: Self::FileId, byte_index: usize) -> Option<usize>;
+ fn line_index(&'a self, id: Self::FileId, byte_index: usize) -> Result<usize, Error>;
/// The user-facing line number at the given line index.
+ /// It is not necessarily checked that the specified line index
+ /// is actually in the file.
///
/// # Note for trait implementors
///
@@ -68,8 +124,8 @@ pub trait Files<'a> {
///
/// [line-macro]: https://en.cppreference.com/w/c/preprocessor/line
#[allow(unused_variables)]
- fn line_number(&'a self, id: Self::FileId, line_index: usize) -> Option<usize> {
- Some(line_index + 1)
+ fn line_number(&'a self, id: Self::FileId, line_index: usize) -> Result<usize, Error> {
+ Ok(line_index + 1)
}
/// The user-facing column number at the given line index and byte index.
@@ -87,27 +143,27 @@ pub trait Files<'a> {
id: Self::FileId,
line_index: usize,
byte_index: usize,
- ) -> Option<usize> {
+ ) -> Result<usize, Error> {
let source = self.source(id)?;
let line_range = self.line_range(id, line_index)?;
let column_index = column_index(source.as_ref(), line_range, byte_index);
- Some(column_index + 1)
+ Ok(column_index + 1)
}
- /// Convenience method for returning line and column number at the given a
+ /// Convenience method for returning line and column number at the given
/// byte index in the file.
- fn location(&'a self, id: Self::FileId, byte_index: usize) -> Option<Location> {
+ fn location(&'a self, id: Self::FileId, byte_index: usize) -> Result<Location, Error> {
let line_index = self.line_index(id, byte_index)?;
- Some(Location {
+ Ok(Location {
line_number: self.line_number(id, line_index)?,
column_number: self.column_number(id, line_index, byte_index)?,
})
}
/// The byte range of line in the source of the file.
- fn line_range(&'a self, id: Self::FileId, line_index: usize) -> Option<Range<usize>>;
+ fn line_range(&'a self, id: Self::FileId, line_index: usize) -> Result<Range<usize>, Error>;
}
/// A user-facing location in a source file.
@@ -115,7 +171,7 @@ pub trait Files<'a> {
/// Returned by [`Files::location`].
///
/// [`Files::location`]: Files::location
-#[derive(Debug, Copy, Clone)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Location {
/// The user-facing line number.
pub line_number: usize,
@@ -238,13 +294,22 @@ where
&self.source
}
- fn line_start(&self, line_index: usize) -> Option<usize> {
+ /// Return the starting byte index of the line with the specified line index.
+ /// Convenience method that already generates errors if necessary.
+ fn line_start(&self, line_index: usize) -> Result<usize, Error> {
use std::cmp::Ordering;
match line_index.cmp(&self.line_starts.len()) {
- Ordering::Less => self.line_starts.get(line_index).cloned(),
- Ordering::Equal => Some(self.source.as_ref().len()),
- Ordering::Greater => None,
+ Ordering::Less => Ok(self
+ .line_starts
+ .get(line_index)
+ .cloned()
+ .expect("failed despite previous check")),
+ Ordering::Equal => Ok(self.source.as_ref().len()),
+ Ordering::Greater => Err(Error::LineTooLarge {
+ given: line_index,
+ max: self.line_starts.len() - 1,
+ }),
}
}
}
@@ -258,26 +323,26 @@ where
type Name = Name;
type Source = &'a str;
- fn name(&self, (): ()) -> Option<Name> {
- Some(self.name.clone())
+ fn name(&self, (): ()) -> Result<Name, Error> {
+ Ok(self.name.clone())
}
- fn source(&self, (): ()) -> Option<&str> {
- Some(self.source.as_ref())
+ fn source(&self, (): ()) -> Result<&str, Error> {
+ Ok(self.source.as_ref())
}
- fn line_index(&self, (): (), byte_index: usize) -> Option<usize> {
- match self.line_starts.binary_search(&byte_index) {
- Ok(line) => Some(line),
- Err(next_line) => Some(next_line - 1),
- }
+ fn line_index(&self, (): (), byte_index: usize) -> Result<usize, Error> {
+ Ok(self
+ .line_starts
+ .binary_search(&byte_index)
+ .unwrap_or_else(|next_line| next_line - 1))
}
- fn line_range(&self, (): (), line_index: usize) -> Option<Range<usize>> {
+ fn line_range(&self, (): (), line_index: usize) -> Result<Range<usize>, Error> {
let line_start = self.line_start(line_index)?;
let next_line_start = self.line_start(line_index + 1)?;
- Some(line_start..next_line_start)
+ Ok(line_start..next_line_start)
}
}
@@ -285,6 +350,7 @@ where
///
/// This is useful for simple language tests, but it might be worth creating a
/// custom implementation when a language scales beyond a certain size.
+/// It is a glorified `Vec<SimpleFile>` that implements the `Files` trait.
#[derive(Debug, Clone)]
pub struct SimpleFiles<Name, Source> {
files: Vec<SimpleFile<Name, Source>>,
@@ -309,8 +375,8 @@ where
}
/// Get the file corresponding to the given id.
- pub fn get(&self, file_id: usize) -> Option<&SimpleFile<Name, Source>> {
- self.files.get(file_id)
+ pub fn get(&self, file_id: usize) -> Result<&SimpleFile<Name, Source>, Error> {
+ self.files.get(file_id).ok_or(Error::FileMissing)
}
}
@@ -323,19 +389,19 @@ where
type Name = Name;
type Source = &'a str;
- fn name(&self, file_id: usize) -> Option<Name> {
- Some(self.get(file_id)?.name().clone())
+ fn name(&self, file_id: usize) -> Result<Name, Error> {
+ Ok(self.get(file_id)?.name().clone())
}
- fn source(&self, file_id: usize) -> Option<&str> {
- Some(self.get(file_id)?.source().as_ref())
+ fn source(&self, file_id: usize) -> Result<&str, Error> {
+ Ok(self.get(file_id)?.source().as_ref())
}
- fn line_index(&self, file_id: usize, byte_index: usize) -> Option<usize> {
+ fn line_index(&self, file_id: usize, byte_index: usize) -> Result<usize, Error> {
self.get(file_id)?.line_index((), byte_index)
}
- fn line_range(&self, file_id: usize, line_index: usize) -> Option<Range<usize>> {
+ fn line_range(&self, file_id: usize, line_index: usize) -> Result<Range<usize>, Error> {
self.get(file_id)?.line_range((), line_index)
}
}
diff --git a/src/term.rs b/src/term.rs
index c852e70..59baeb0 100644
--- a/src/term.rs
+++ b/src/term.rs
@@ -1,6 +1,5 @@
//! Terminal back-end for emitting diagnostics.
-use std::io;
use std::str::FromStr;
use termcolor::{ColorChoice, WriteColor};
@@ -42,10 +41,8 @@ pub use self::config::{Chars, Config, DisplayStyle, Styles};
/// pub color: ColorArg,
/// }
///
-/// fn main() {
-/// let opts = Opts::from_args();
-/// let writer = StandardStream::stderr(opts.color.into());
-/// }
+/// let opts = Opts::from_args();
+/// let writer = StandardStream::stderr(opts.color.into());
/// ```
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct ColorArg(pub ColorChoice);
@@ -82,19 +79,25 @@ impl Into<ColorChoice> for ColorArg {
}
/// Emit a diagnostic using the given writer, context, config, and files.
+///
+/// The return value covers all error cases. These error case can arise if:
+/// * a file was removed from the file database.
+/// * a file was changed so that it is too small to have an index
+/// * IO fails
pub fn emit<'files, F: Files<'files>>(
writer: &mut dyn WriteColor,
config: &Config,
files: &'files F,
diagnostic: &Diagnostic<F::FileId>,
-) -> io::Result<()> {
+) -> Result<(), super::files::Error> {
use self::renderer::Renderer;
use self::views::{RichDiagnostic, ShortDiagnostic};
let mut renderer = Renderer::new(writer, config);
match config.display_style {
- DisplayStyle::Rich => RichDiagnostic::new(diagnostic).render(files, &mut renderer),
- DisplayStyle::Short => ShortDiagnostic::new(diagnostic).render(files, &mut renderer),
+ DisplayStyle::Rich => RichDiagnostic::new(diagnostic, config).render(files, &mut renderer),
+ DisplayStyle::Medium => ShortDiagnostic::new(diagnostic, true).render(files, &mut renderer),
+ DisplayStyle::Short => ShortDiagnostic::new(diagnostic, false).render(files, &mut renderer),
}
}
diff --git a/src/term/config.rs b/src/term/config.rs
index 7b834d7..18cbd44 100644
--- a/src/term/config.rs
+++ b/src/term/config.rs
@@ -17,6 +17,14 @@ pub struct Config {
pub styles: Styles,
/// Characters to use when rendering the diagnostic.
pub chars: Chars,
+ /// The minimum number of lines to be shown after the line on which a multiline [`Label`] begins.
+ ///
+ /// Defaults to: `3`.
+ pub start_context_lines: usize,
+ /// The minimum number of lines to be shown before the line on which a multiline [`Label`] ends.
+ ///
+ /// Defaults to: `1`.
+ pub end_context_lines: usize,
}
impl Default for Config {
@@ -26,6 +34,8 @@ impl Default for Config {
tab_width: 4,
styles: Styles::default(),
chars: Chars::default(),
+ start_context_lines: 3,
+ end_context_lines: 1,
}
}
}
@@ -49,6 +59,16 @@ pub enum DisplayStyle {
///
/// ```
Rich,
+ /// Output a condensed diagnostic, with a line number, severity, message and notes (if any).
+ ///
+ /// ```text
+ /// test:2:9: error[E0001]: unexpected type in `+` application
+ /// = expected type `Int`
+ /// found type `String`
+ ///
+ /// error[E0002]: Bad config found
+ /// ```
+ Medium,
/// Output a short diagnostic, with a line number, severity, and message.
///
/// ```text
diff --git a/src/term/renderer.rs b/src/term/renderer.rs
index ab5656e..cd82e88 100644
--- a/src/term/renderer.rs
+++ b/src/term/renderer.rs
@@ -1,9 +1,9 @@
use std::io::{self, Write};
-use std::ops::{Range, RangeTo};
+use std::ops::Range;
use termcolor::{ColorSpec, WriteColor};
use crate::diagnostic::{LabelStyle, Severity};
-use crate::files::Location;
+use crate::files::{Error, Location};
use crate::term::{Chars, Config, Styles};
/// The 'location focus' of a source code snippet.
@@ -23,20 +23,22 @@ pub type SingleLabel<'diagnostic> = (LabelStyle, Range<usize>, &'diagnostic str)
/// A multi-line label to render.
///
-/// Locations are relative to the start of where the source cord is rendered.
+/// Locations are relative to the start of where the source code is rendered.
pub enum MultiLabel<'diagnostic> {
- /// Left top corner for multi-line labels.
- ///
- /// ```text
- /// ╭
- /// ```
- TopLeft,
/// Multi-line label top.
+ /// The contained value indicates where the label starts.
///
/// ```text
/// ╭────────────^
/// ```
- Top(RangeTo<usize>),
+ ///
+ /// Can also be rendered at the beginning of the line
+ /// if there is only whitespace before the label starts.
+ ///
+ /// /// ```text
+ /// ╭
+ /// ```
+ Top(usize),
/// Left vertical labels for multi-line labels.
///
/// ```text
@@ -44,11 +46,12 @@ pub enum MultiLabel<'diagnostic> {
/// ```
Left,
/// Multi-line label bottom, with an optional message.
+ /// The first value indicates where the label ends.
///
/// ```text
/// ╰────────────^ blah blah
/// ```
- Bottom(RangeTo<usize>, &'diagnostic str),
+ Bottom(usize, &'diagnostic str),
}
#[derive(Copy, Clone)]
@@ -138,7 +141,7 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
severity: Severity,
code: Option<&str>,
message: &str,
- ) -> io::Result<()> {
+ ) -> Result<(), Error> {
// Write locus
//
// ```text
@@ -168,7 +171,7 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
// ```text
// [E0001]
// ```
- if let Some(code) = &code {
+ if let Some(code) = &code.filter(|code| !code.is_empty()) {
write!(self, "[{}]", code)?;
}
@@ -181,15 +184,14 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
write!(self, ": {}", message)?;
self.reset()?;
- write!(self, "\n")?;
+ writeln!(self)?;
Ok(())
}
/// Empty line.
- pub fn render_empty(&mut self) -> io::Result<()> {
- write!(self, "\n")?;
-
+ pub fn render_empty(&mut self) -> Result<(), Error> {
+ writeln!(self)?;
Ok(())
}
@@ -198,7 +200,11 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
/// ```text
/// ┌─ test:2:9
/// ```
- pub fn render_snippet_start(&mut self, outer_padding: usize, locus: &Locus) -> io::Result<()> {
+ pub fn render_snippet_start(
+ &mut self,
+ outer_padding: usize,
+ locus: &Locus,
+ ) -> Result<(), Error> {
self.outer_gutter(outer_padding)?;
self.set_color(&self.styles().source_border)?;
@@ -209,7 +215,7 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
write!(self, " ")?;
self.snippet_locus(&locus)?;
- write!(self, "\n")?;
+ writeln!(self)?;
Ok(())
}
@@ -229,7 +235,7 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
single_labels: &[SingleLabel<'_>],
num_multi_labels: usize,
multi_labels: &[(usize, LabelStyle, MultiLabel<'_>)],
- ) -> io::Result<()> {
+ ) -> Result<(), Error> {
// Trim trailing newlines, linefeeds, and null chars from source, if they exist.
// FIXME: Use the number of trimmed placeholders when rendering single line carets
let source = source.trim_end_matches(['\n', '\r', '\0'].as_ref());
@@ -250,7 +256,9 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
match multi_labels_iter.peek() {
Some((label_index, label_style, label)) if *label_index == label_column => {
match label {
- MultiLabel::TopLeft => {
+ MultiLabel::Top(start)
+ if *start <= source.len() - source.trim_start().len() =>
+ {
self.label_multi_top_left(severity, *label_style)?;
}
MultiLabel::Top(..) => self.inner_gutter_space()?,
@@ -276,9 +284,9 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
}) || multi_labels.iter().any(|(_, ls, label)| {
*ls == LabelStyle::Primary
&& match label {
- MultiLabel::Top(range) => column_range.start >= range.end,
- MultiLabel::TopLeft | MultiLabel::Left => true,
- MultiLabel::Bottom(range, _) => column_range.end <= range.end,
+ MultiLabel::Top(start) => column_range.start >= *start,
+ MultiLabel::Left => true,
+ MultiLabel::Bottom(start, _) => column_range.end <= *start,
}
});
@@ -299,7 +307,7 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
if in_primary {
self.reset()?;
}
- write!(self, "\n")?;
+ writeln!(self)?;
}
// Write single labels underneath source
@@ -456,7 +464,7 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
write!(self, "{}", message)?;
self.reset()?;
}
- write!(self, "\n")?;
+ writeln!(self)?;
// Write hanging labels pointing to carets
//
@@ -483,7 +491,7 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
trailing_label,
source.char_indices(),
)?;
- write!(self, "\n")?;
+ writeln!(self)?;
// Write hanging labels pointing to carets
//
@@ -511,7 +519,7 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
self.set_color(self.styles().label(severity, *label_style))?;
write!(self, "{}", message)?;
self.reset()?;
- write!(self, "\n")?;
+ writeln!(self)?;
}
}
}
@@ -524,7 +532,11 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
// ```
for (multi_label_index, (_, label_style, label)) in multi_labels.iter().enumerate() {
let (label_style, range, bottom_message) = match label {
- MultiLabel::TopLeft | MultiLabel::Left => continue, // no label caret needed
+ MultiLabel::Left => continue, // no label caret needed
+ // no label caret needed if this can be started in front of the line
+ MultiLabel::Top(start) if *start <= source.len() - source.trim_start().len() => {
+ continue
+ }
MultiLabel::Top(range) => (*label_style, range, None),
MultiLabel::Bottom(range, message) => (*label_style, range, Some(message)),
};
@@ -543,7 +555,7 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
match multi_labels_iter.peek() {
Some((i, (label_index, ls, label))) if *label_index == label_column => {
match label {
- MultiLabel::TopLeft | MultiLabel::Left => {
+ MultiLabel::Left => {
self.label_multi_left(severity, *ls, underline.map(|(s, _)| s))?;
}
MultiLabel::Top(..) if multi_label_index > *i => {
@@ -571,11 +583,10 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
}
// Finish the top or bottom caret
- let range = range.clone();
match bottom_message {
- None => self.label_multi_top_caret(severity, label_style, source, range)?,
+ None => self.label_multi_top_caret(severity, label_style, source, *range)?,
Some(message) => {
- self.label_multi_bottom_caret(severity, label_style, source, range, message)?
+ self.label_multi_bottom_caret(severity, label_style, source, *range, message)?
}
}
}
@@ -594,11 +605,11 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
severity: Severity,
num_multi_labels: usize,
multi_labels: &[(usize, LabelStyle, MultiLabel<'_>)],
- ) -> io::Result<()> {
+ ) -> Result<(), Error> {
self.outer_gutter(outer_padding)?;
self.border_left()?;
self.inner_gutter(severity, num_multi_labels, multi_labels)?;
- write!(self, "\n")?;
+ writeln!(self)?;
Ok(())
}
@@ -613,11 +624,11 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
severity: Severity,
num_multi_labels: usize,
multi_labels: &[(usize, LabelStyle, MultiLabel<'_>)],
- ) -> io::Result<()> {
+ ) -> Result<(), Error> {
self.outer_gutter(outer_padding)?;
self.border_left_break()?;
self.inner_gutter(severity, num_multi_labels, multi_labels)?;
- write!(self, "\n")?;
+ writeln!(self)?;
Ok(())
}
@@ -627,7 +638,11 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
/// = expected type `Int`
/// found type `String`
/// ```
- pub fn render_snippet_note(&mut self, outer_padding: usize, message: &str) -> io::Result<()> {
+ pub fn render_snippet_note(
+ &mut self,
+ outer_padding: usize,
+ message: &str,
+ ) -> Result<(), Error> {
for (note_line_index, line) in message.lines().enumerate() {
self.outer_gutter(outer_padding)?;
match note_line_index {
@@ -639,8 +654,7 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
_ => write!(self, " ")?,
}
// Write line of message
- write!(self, " {}", line)?;
- write!(self, "\n")?;
+ writeln!(self, " {}", line)?;
}
Ok(())
@@ -674,25 +688,29 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
}
/// Location focus.
- fn snippet_locus(&mut self, locus: &Locus) -> io::Result<()> {
+ fn snippet_locus(&mut self, locus: &Locus) -> Result<(), Error> {
write!(
self,
"{name}:{line_number}:{column_number}",
name = locus.name,
line_number = locus.location.line_number,
column_number = locus.location.column_number,
- )
+ )?;
+ Ok(())
}
/// The outer gutter of a source line.
- fn outer_gutter(&mut self, outer_padding: usize) -> io::Result<()> {
- write!(self, "{space: >width$}", space = "", width = outer_padding)?;
- write!(self, " ")?;
+ fn outer_gutter(&mut self, outer_padding: usize) -> Result<(), Error> {
+ write!(self, "{space: >width$} ", space = "", width = outer_padding)?;
Ok(())
}
/// The outer gutter of a source line, with line number.
- fn outer_gutter_number(&mut self, line_number: usize, outer_padding: usize) -> io::Result<()> {
+ fn outer_gutter_number(
+ &mut self,
+ line_number: usize,
+ outer_padding: usize,
+ ) -> Result<(), Error> {
self.set_color(&self.styles().line_number)?;
write!(
self,
@@ -706,7 +724,7 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
}
/// The left-hand border of a source line.
- fn border_left(&mut self) -> io::Result<()> {
+ fn border_left(&mut self) -> Result<(), Error> {
self.set_color(&self.styles().source_border)?;
write!(self, "{}", self.chars().source_border_left)?;
self.reset()?;
@@ -714,7 +732,7 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
}
/// The broken left-hand border of a source line.
- fn border_left_break(&mut self) -> io::Result<()> {
+ fn border_left_break(&mut self) -> Result<(), Error> {
self.set_color(&self.styles().source_border)?;
write!(self, "{}", self.chars().source_border_left_break)?;
self.reset()?;
@@ -729,7 +747,7 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
single_labels: &[SingleLabel<'_>],
trailing_label: Option<(usize, &SingleLabel<'_>)>,
char_indices: impl Iterator<Item = (usize, char)>,
- ) -> io::Result<()> {
+ ) -> Result<(), Error> {
for (metrics, ch) in self.char_metrics(char_indices) {
let column_range = metrics.byte_index..(metrics.byte_index + ch.len_utf8());
let label_style = hanging_labels(single_labels, trailing_label)
@@ -765,7 +783,7 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
severity: Severity,
label_style: LabelStyle,
underline: Option<LabelStyle>,
- ) -> io::Result<()> {
+ ) -> Result<(), Error> {
match underline {
None => write!(self, " ")?,
// Continue an underline horizontally
@@ -790,7 +808,7 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
&mut self,
severity: Severity,
label_style: LabelStyle,
- ) -> io::Result<()> {
+ ) -> Result<(), Error> {
write!(self, " ")?;
self.set_color(self.styles().label(severity, label_style))?;
write!(self, "{}", self.chars().multi_top_left)?;
@@ -807,7 +825,7 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
&mut self,
severity: Severity,
label_style: LabelStyle,
- ) -> io::Result<()> {
+ ) -> Result<(), Error> {
write!(self, " ")?;
self.set_color(self.styles().label(severity, label_style))?;
write!(self, "{}", self.chars().multi_bottom_left)?;
@@ -825,13 +843,13 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
severity: Severity,
label_style: LabelStyle,
source: &str,
- range: RangeTo<usize>,
- ) -> io::Result<()> {
+ start: usize,
+ ) -> Result<(), Error> {
self.set_color(self.styles().label(severity, label_style))?;
for (metrics, _) in self
.char_metrics(source.char_indices())
- .take_while(|(metrics, _)| metrics.byte_index < range.end + 1)
+ .take_while(|(metrics, _)| metrics.byte_index < start + 1)
{
// FIXME: improve rendering of carets between character boundaries
(0..metrics.unicode_width)
@@ -844,7 +862,7 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
};
write!(self, "{}", caret_start)?;
self.reset()?;
- write!(self, "\n")?;
+ writeln!(self)?;
Ok(())
}
@@ -858,14 +876,14 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
severity: Severity,
label_style: LabelStyle,
source: &str,
- range: RangeTo<usize>,
+ start: usize,
message: &str,
- ) -> io::Result<()> {
+ ) -> Result<(), Error> {
self.set_color(self.styles().label(severity, label_style))?;
for (metrics, _) in self
.char_metrics(source.char_indices())
- .take_while(|(metrics, _)| metrics.byte_index < range.end)
+ .take_while(|(metrics, _)| metrics.byte_index < start)
{
// FIXME: improve rendering of carets between character boundaries
(0..metrics.unicode_width)
@@ -881,7 +899,7 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
write!(self, " {}", message)?;
}
self.reset()?;
- write!(self, "\n")?;
+ writeln!(self)?;
Ok(())
}
@@ -890,7 +908,7 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
&mut self,
severity: Severity,
underline: Option<Underline>,
- ) -> io::Result<()> {
+ ) -> Result<(), Error> {
match underline {
None => self.inner_gutter_space(),
Some((label_style, vertical_bound)) => {
@@ -907,8 +925,9 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
}
/// Writes an empty gutter space.
- fn inner_gutter_space(&mut self) -> io::Result<()> {
- write!(self, " ")
+ fn inner_gutter_space(&mut self) -> Result<(), Error> {
+ write!(self, " ")?;
+ Ok(())
}
/// Writes an inner gutter, with the left lines if necessary.
@@ -917,12 +936,12 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
severity: Severity,
num_multi_labels: usize,
multi_labels: &[(usize, LabelStyle, MultiLabel<'_>)],
- ) -> io::Result<()> {
+ ) -> Result<(), Error> {
let mut multi_labels_iter = multi_labels.iter().peekable();
for label_column in 0..num_multi_labels {
match multi_labels_iter.peek() {
Some((label_index, ls, label)) if *label_index == label_column => match label {
- MultiLabel::TopLeft | MultiLabel::Left | MultiLabel::Bottom(..) => {
+ MultiLabel::Left | MultiLabel::Bottom(..) => {
self.label_multi_left(severity, *ls, None)?;
multi_labels_iter.next();
}
diff --git a/src/term/views.rs b/src/term/views.rs
index aa79914..f09d958 100644
--- a/src/term/views.rs
+++ b/src/term/views.rs
@@ -1,9 +1,9 @@
-use std::io;
use std::ops::Range;
use crate::diagnostic::{Diagnostic, LabelStyle};
-use crate::files::{Files, Location};
+use crate::files::{Error, Files, Location};
use crate::term::renderer::{Locus, MultiLabel, Renderer, SingleLabel};
+use crate::term::Config;
/// Count the number of decimal digits in `n`.
fn count_digits(mut n: usize) -> usize {
@@ -16,23 +16,27 @@ fn count_digits(mut n: usize) -> usize {
}
/// Output a richly formatted diagnostic, with source code previews.
-pub struct RichDiagnostic<'diagnostic, FileId> {
+pub struct RichDiagnostic<'diagnostic, 'config, FileId> {
diagnostic: &'diagnostic Diagnostic<FileId>,
+ config: &'config Config,
}
-impl<'diagnostic, FileId> RichDiagnostic<'diagnostic, FileId>
+impl<'diagnostic, 'config, FileId> RichDiagnostic<'diagnostic, 'config, FileId>
where
FileId: Copy + PartialEq,
{
- pub fn new(diagnostic: &'diagnostic Diagnostic<FileId>) -> RichDiagnostic<'diagnostic, FileId> {
- RichDiagnostic { diagnostic }
+ pub fn new(
+ diagnostic: &'diagnostic Diagnostic<FileId>,
+ config: &'config Config,
+ ) -> RichDiagnostic<'diagnostic, 'config, FileId> {
+ RichDiagnostic { diagnostic, config }
}
pub fn render<'files>(
&self,
files: &'files impl Files<'files, FileId = FileId>,
renderer: &mut Renderer<'_, '_>,
- ) -> io::Result<()>
+ ) -> Result<(), Error>
where
FileId: 'files,
{
@@ -45,6 +49,7 @@ where
location: Location,
num_multi_labels: usize,
lines: BTreeMap<usize, Line<'diagnostic>>,
+ max_label_style: LabelStyle,
}
impl<'diagnostic, FileId> LabeledFile<'diagnostic, FileId> {
@@ -59,6 +64,8 @@ where
number: line_number,
single_labels: vec![],
multi_labels: vec![],
+ // This has to be false by default so we know if it must be rendered by another condition already.
+ must_render: false,
})
}
}
@@ -69,6 +76,7 @@ where
// TODO: How do we reuse these allocations?
single_labels: Vec<SingleLabel<'diagnostic>>,
multi_labels: Vec<(usize, LabelStyle, MultiLabel<'diagnostic>)>,
+ must_render: bool,
}
// TODO: Make this data structure external, to allow for allocation reuse
@@ -79,15 +87,12 @@ where
// Group labels by file
for label in &self.diagnostic.labels {
- let source = files.source(label.file_id).unwrap();
- let source = source.as_ref();
-
- let start_line_index = files.line_index(label.file_id, label.range.start).unwrap();
- let start_line_number = files.line_number(label.file_id, start_line_index).unwrap();
- let start_line_range = files.line_range(label.file_id, start_line_index).unwrap();
- let end_line_index = files.line_index(label.file_id, label.range.end).unwrap();
- let end_line_number = files.line_number(label.file_id, end_line_index).unwrap();
- let end_line_range = files.line_range(label.file_id, end_line_index).unwrap();
+ let start_line_index = files.line_index(label.file_id, label.range.start)?;
+ let start_line_number = files.line_number(label.file_id, start_line_index)?;
+ let start_line_range = files.line_range(label.file_id, start_line_index)?;
+ let end_line_index = files.line_index(label.file_id, label.range.end)?;
+ let end_line_number = files.line_number(label.file_id, end_line_index)?;
+ let end_line_range = files.line_range(label.file_id, end_line_index)?;
outer_padding = std::cmp::max(outer_padding, count_digits(start_line_number));
outer_padding = std::cmp::max(outer_padding, count_digits(end_line_number));
@@ -100,23 +105,33 @@ where
.find(|labeled_file| label.file_id == labeled_file.file_id)
{
Some(labeled_file) => {
- if labeled_file.start > label.range.start {
+ // another diagnostic also referenced this file
+ if labeled_file.max_label_style > label.style
+ || (labeled_file.max_label_style == label.style
+ && labeled_file.start > label.range.start)
+ {
+ // this label has a higher style or has the same style but starts earlier
labeled_file.start = label.range.start;
- labeled_file.location =
- files.location(label.file_id, label.range.start).unwrap();
+ labeled_file.location = files.location(label.file_id, label.range.start)?;
+ labeled_file.max_label_style = label.style;
}
labeled_file
}
None => {
+ // no other diagnostic referenced this file yet
labeled_files.push(LabeledFile {
file_id: label.file_id,
start: label.range.start,
- name: files.name(label.file_id).unwrap().to_string(),
- location: files.location(label.file_id, label.range.start).unwrap(),
+ name: files.name(label.file_id)?.to_string(),
+ location: files.location(label.file_id, label.range.start)?,
num_multi_labels: 0,
lines: BTreeMap::new(),
+ max_label_style: label.style,
});
- labeled_files.last_mut().unwrap()
+ // this unwrap should never fail because we just pushed an element
+ labeled_files
+ .last_mut()
+ .expect("just pushed an element that disappeared")
}
};
@@ -128,7 +143,10 @@ where
// │ ^^ expected `Int` but found `String`
// ```
let label_start = label.range.start - start_line_range.start;
- let label_end = label.range.end - start_line_range.start;
+ // Ensure that we print at least one caret, even when we
+ // have a zero-length source range.
+ let label_end =
+ usize::max(label.range.end - start_line_range.start, label_start + 1);
let line = labeled_file.get_or_insert_line(
start_line_index,
@@ -149,15 +167,11 @@ where
Ok(index) | Err(index) => index,
};
- // Ensure that we print at least one caret, even when we
- // have a zero-length source range.
- let mut label_range = label_start..label_end;
- if label_range.len() == 0 {
- label_range.end = label_range.start + 1;
- }
-
line.single_labels
- .insert(index, (label.style, label_range, &label.message));
+ .insert(index, (label.style, label_start..label_end, &label.message));
+
+ // If this line is not rendered, the SingleLabel is not visible.
+ line.must_render = true;
} else {
// Multiple lines
//
@@ -176,29 +190,21 @@ where
// First labeled line
let label_start = label.range.start - start_line_range.start;
- let prefix_source = &source[start_line_range.start..label.range.start];
-
- labeled_file
- .get_or_insert_line(start_line_index, start_line_range, start_line_number)
- .multi_labels
- // TODO: Do this in the `Renderer`?
- .push(match prefix_source.trim() {
- // Section is prefixed by empty space, so we don't need to take
- // up a new line.
- //
- // ```text
- // 4 │ ╭ case (mod num 5) (mod num 3) of
- // ```
- "" => (label_index, label.style, MultiLabel::TopLeft),
- // There's source code in the prefix, so run a label
- // underneath it to get to the start of the range.
- //
- // ```text
- // 4 │ fizz₁ num = case (mod num 5) (mod num 3) of
- // │ ╭─────────────^
- // ```
- _ => (label_index, label.style, MultiLabel::Top(..label_start)),
- });
+
+ let start_line = labeled_file.get_or_insert_line(
+ start_line_index,
+ start_line_range.clone(),
+ start_line_number,
+ );
+
+ start_line.multi_labels.push((
+ label_index,
+ label.style,
+ MultiLabel::Top(label_start),
+ ));
+
+ // The first line has to be rendered so the start of the label is visible.
+ start_line.must_render = true;
// Marked lines
//
@@ -207,17 +213,24 @@ where
// 6 │ │ 0 _ => "Fizz"
// 7 │ │ _ 0 => "Buzz"
// ```
- // TODO(#125): If start line and end line are too far apart, add a source break.
for line_index in (start_line_index + 1)..end_line_index {
- let line_range = files.line_range(label.file_id, line_index).unwrap();
- let line_number = files.line_number(label.file_id, line_index).unwrap();
+ let line_range = files.line_range(label.file_id, line_index)?;
+ let line_number = files.line_number(label.file_id, line_index)?;
outer_padding = std::cmp::max(outer_padding, count_digits(line_number));
- labeled_file
- .get_or_insert_line(line_index, line_range, line_number)
- .multi_labels
+ let line = labeled_file.get_or_insert_line(line_index, line_range, line_number);
+
+ line.multi_labels
.push((label_index, label.style, MultiLabel::Left));
+
+ // The line should be rendered to match the configuration of how much context to show.
+ line.must_render |=
+ // Is this line part of the context after the start of the label?
+ line_index - start_line_index <= self.config.start_context_lines
+ ||
+ // Is this line part of the context before the end of the label?
+ end_line_index - line_index <= self.config.end_context_lines;
}
// Last labeled line
@@ -228,14 +241,20 @@ where
// ```
let label_end = label.range.end - end_line_range.start;
- labeled_file
- .get_or_insert_line(end_line_index, end_line_range, end_line_number)
- .multi_labels
- .push((
- label_index,
- label.style,
- MultiLabel::Bottom(..label_end, &label.message),
- ));
+ let end_line = labeled_file.get_or_insert_line(
+ end_line_index,
+ end_line_range,
+ end_line_number,
+ );
+
+ end_line.multi_labels.push((
+ label_index,
+ label.style,
+ MultiLabel::Bottom(label_end, &label.message),
+ ));
+
+ // The last line has to be rendered so the end of the label is visible.
+ end_line.must_render = true;
}
}
@@ -247,7 +266,7 @@ where
renderer.render_header(
None,
self.diagnostic.severity,
- self.diagnostic.code.as_ref().map(String::as_str),
+ self.diagnostic.code.as_deref(),
self.diagnostic.message.as_str(),
)?;
@@ -262,7 +281,7 @@ where
// ```
let mut labeled_files = labeled_files.into_iter().peekable();
while let Some(labeled_file) = labeled_files.next() {
- let source = files.source(labeled_file.file_id).unwrap();
+ let source = files.source(labeled_file.file_id)?;
let source = source.as_ref();
// Top left border and locus.
@@ -286,8 +305,11 @@ where
)?;
}
- let mut lines = labeled_file.lines.into_iter().peekable();
- let current_labels = Vec::new();
+ let mut lines = labeled_file
+ .lines
+ .iter()
+ .filter(|(_, line)| line.must_render)
+ .peekable();
while let Some((line_index, line)) = lines.next() {
renderer.render_snippet_source(
@@ -303,21 +325,29 @@ where
// Check to see if we need to render any intermediate stuff
// before rendering the next line.
if let Some((next_line_index, _)) = lines.peek() {
- match next_line_index.checked_sub(line_index) {
+ match next_line_index.checked_sub(*line_index) {
// Consecutive lines
Some(1) => {}
// One line between the current line and the next line
Some(2) => {
// Write a source line
let file_id = labeled_file.file_id;
+
+ // This line was not intended to be rendered initially.
+ // To render the line right, we have to get back the original labels.
+ let labels = labeled_file
+ .lines
+ .get(&(line_index + 1))
+ .map_or(&[][..], |line| &line.multi_labels[..]);
+
renderer.render_snippet_source(
outer_padding,
- files.line_number(file_id, line_index + 1).unwrap(),
- &source[files.line_range(file_id, line_index + 1).unwrap()],
+ files.line_number(file_id, line_index + 1)?,
+ &source[files.line_range(file_id, line_index + 1)?],
self.diagnostic.severity,
&[],
labeled_file.num_multi_labels,
- &current_labels,
+ labels,
)?;
}
// More than one line between the current line and the next line.
@@ -331,7 +361,7 @@ where
outer_padding,
self.diagnostic.severity,
labeled_file.num_multi_labels,
- &current_labels,
+ &line.multi_labels,
)?;
}
}
@@ -350,7 +380,7 @@ where
outer_padding,
self.diagnostic.severity,
labeled_file.num_multi_labels,
- &current_labels,
+ &[],
)?;
}
}
@@ -364,15 +394,14 @@ where
for note in &self.diagnostic.notes {
renderer.render_snippet_note(outer_padding, note)?;
}
- renderer.render_empty()?;
-
- Ok(())
+ renderer.render_empty()
}
}
/// Output a short diagnostic, with a line number, severity, and message.
pub struct ShortDiagnostic<'diagnostic, FileId> {
diagnostic: &'diagnostic Diagnostic<FileId>,
+ show_notes: bool,
}
impl<'diagnostic, FileId> ShortDiagnostic<'diagnostic, FileId>
@@ -381,15 +410,19 @@ where
{
pub fn new(
diagnostic: &'diagnostic Diagnostic<FileId>,
+ show_notes: bool,
) -> ShortDiagnostic<'diagnostic, FileId> {
- ShortDiagnostic { diagnostic }
+ ShortDiagnostic {
+ diagnostic,
+ show_notes,
+ }
}
pub fn render<'files>(
&self,
files: &'files impl Files<'files, FileId = FileId>,
renderer: &mut Renderer<'_, '_>,
- ) -> io::Result<()>
+ ) -> Result<(), Error>
where
FileId: 'files,
{
@@ -405,11 +438,11 @@ where
renderer.render_header(
Some(&Locus {
- name: files.name(label.file_id).unwrap().to_string(),
- location: files.location(label.file_id, label.range.start).unwrap(),
+ name: files.name(label.file_id)?.to_string(),
+ location: files.location(label.file_id, label.range.start)?,
}),
self.diagnostic.severity,
- self.diagnostic.code.as_ref().map(String::as_str),
+ self.diagnostic.code.as_deref(),
self.diagnostic.message.as_str(),
)?;
}
@@ -423,11 +456,23 @@ where
renderer.render_header(
None,
self.diagnostic.severity,
- self.diagnostic.code.as_ref().map(String::as_str),
+ self.diagnostic.code.as_deref(),
self.diagnostic.message.as_str(),
)?;
}
+ if self.show_notes {
+ // Additional notes
+ //
+ // ```text
+ // = expected type `Int`
+ // found type `String`
+ // ```
+ for note in &self.diagnostic.notes {
+ renderer.render_snippet_note(0, note)?;
+ }
+ }
+
Ok(())
}
}
diff --git a/tests/snapshots/term__empty__medium_color.snap b/tests/snapshots/term__empty__medium_color.snap
new file mode 100644
index 0000000..e4a14fb
--- /dev/null
+++ b/tests/snapshots/term__empty__medium_color.snap
@@ -0,0 +1,11 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_color(&config)
+---
+{fg:Red bold bright}bug{bold bright}: {/}
+{fg:Red bold bright}error{bold bright}: {/}
+{fg:Yellow bold bright}warning{bold bright}: {/}
+{fg:Green bold bright}note{bold bright}: {/}
+{fg:Cyan bold bright}help{bold bright}: {/}
+{fg:Red bold bright}bug{bold bright}: {/}
+
diff --git a/tests/snapshots/term__empty__medium_no_color.snap b/tests/snapshots/term__empty__medium_no_color.snap
new file mode 100644
index 0000000..6a8bf45
--- /dev/null
+++ b/tests/snapshots/term__empty__medium_no_color.snap
@@ -0,0 +1,11 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_no_color(&config)
+---
+bug:
+error:
+warning:
+note:
+help:
+bug:
+
diff --git a/tests/snapshots/term__empty_ranges__medium_color.snap b/tests/snapshots/term__empty_ranges__medium_color.snap
new file mode 100644
index 0000000..3713ee4
--- /dev/null
+++ b/tests/snapshots/term__empty_ranges__medium_color.snap
@@ -0,0 +1,9 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_color(&config)
+---
+hello:1:7: {fg:Green bold bright}note{bold bright}: middle{/}
+hello:1:13: {fg:Green bold bright}note{bold bright}: end of line{/}
+hello:2:11: {fg:Green bold bright}note{bold bright}: end of line{/}
+hello:3:4: {fg:Green bold bright}note{bold bright}: end of file{/}
+
diff --git a/tests/snapshots/term__empty_ranges__medium_no_color.snap b/tests/snapshots/term__empty_ranges__medium_no_color.snap
new file mode 100644
index 0000000..635a830
--- /dev/null
+++ b/tests/snapshots/term__empty_ranges__medium_no_color.snap
@@ -0,0 +1,9 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_no_color(&config)
+---
+hello:1:7: note: middle
+hello:1:13: note: end of line
+hello:2:11: note: end of line
+hello:3:4: note: end of file
+
diff --git a/tests/snapshots/term__fizz_buzz__medium_color.snap b/tests/snapshots/term__fizz_buzz__medium_color.snap
new file mode 100644
index 0000000..ef97c2c
--- /dev/null
+++ b/tests/snapshots/term__fizz_buzz__medium_color.snap
@@ -0,0 +1,11 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_color(&config)
+---
+FizzBuzz.fun:8:12: {fg:Red bold bright}error[E0308]{bold bright}: `case` clauses have incompatible types{/}
+ {fg:Blue}={/} expected type `String`
+ found type `Nat`
+FizzBuzz.fun:16:16: {fg:Red bold bright}error[E0308]{bold bright}: `case` clauses have incompatible types{/}
+ {fg:Blue}={/} expected type `String`
+ found type `Nat`
+
diff --git a/tests/snapshots/term__fizz_buzz__medium_no_color.snap b/tests/snapshots/term__fizz_buzz__medium_no_color.snap
new file mode 100644
index 0000000..1120064
--- /dev/null
+++ b/tests/snapshots/term__fizz_buzz__medium_no_color.snap
@@ -0,0 +1,11 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_no_color(&config)
+---
+FizzBuzz.fun:8:12: error[E0308]: `case` clauses have incompatible types
+ = expected type `String`
+ found type `Nat`
+FizzBuzz.fun:16:16: error[E0308]: `case` clauses have incompatible types
+ = expected type `String`
+ found type `Nat`
+
diff --git a/tests/snapshots/term__fizz_buzz__rich_color.snap b/tests/snapshots/term__fizz_buzz__rich_color.snap
index a051eef..79dded2 100644
--- a/tests/snapshots/term__fizz_buzz__rich_color.snap
+++ b/tests/snapshots/term__fizz_buzz__rich_color.snap
@@ -3,7 +3,7 @@ source: codespan-reporting/tests/term.rs
expression: TEST_DATA.emit_color(&config)
---
{fg:Red bold bright}error[E0308]{bold bright}: `case` clauses have incompatible types{/}
- {fg:Blue}┌─{/} FizzBuzz.fun:3:15
+ {fg:Blue}┌─{/} FizzBuzz.fun:8:12
{fg:Blue}│{/}
{fg:Blue}3{/} {fg:Blue}│{/} fizz₁ : Nat → String
{fg:Blue}│{/} {fg:Blue}------{/} {fg:Blue}expected type `String` found here{/}
@@ -20,7 +20,7 @@ expression: TEST_DATA.emit_color(&config)
found type `Nat`
{fg:Red bold bright}error[E0308]{bold bright}: `case` clauses have incompatible types{/}
- {fg:Blue}┌─{/} FizzBuzz.fun:10:15
+ {fg:Blue}┌─{/} FizzBuzz.fun:16:16
{fg:Blue}│{/}
{fg:Blue}10{/} {fg:Blue}│{/} fizz₂ : Nat → String
{fg:Blue}│{/} {fg:Blue}------{/} {fg:Blue}expected type `String` found here{/}
diff --git a/tests/snapshots/term__fizz_buzz__rich_no_color.snap b/tests/snapshots/term__fizz_buzz__rich_no_color.snap
index dac0107..a0b7260 100644
--- a/tests/snapshots/term__fizz_buzz__rich_no_color.snap
+++ b/tests/snapshots/term__fizz_buzz__rich_no_color.snap
@@ -3,7 +3,7 @@ source: codespan-reporting/tests/term.rs
expression: TEST_DATA.emit_no_color(&config)
---
error[E0308]: `case` clauses have incompatible types
- ┌─ FizzBuzz.fun:3:15
+ ┌─ FizzBuzz.fun:8:12
3 │ fizz₁ : Nat → String
│ ------ expected type `String` found here
@@ -20,7 +20,7 @@ error[E0308]: `case` clauses have incompatible types
found type `Nat`
error[E0308]: `case` clauses have incompatible types
- ┌─ FizzBuzz.fun:10:15
+ ┌─ FizzBuzz.fun:16:16
10 │ fizz₂ : Nat → String
│ ------ expected type `String` found here
diff --git a/tests/snapshots/term__message__medium_color.snap b/tests/snapshots/term__message__medium_color.snap
new file mode 100644
index 0000000..f0b16d8
--- /dev/null
+++ b/tests/snapshots/term__message__medium_color.snap
@@ -0,0 +1,9 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_color(&config)
+---
+{fg:Red bold bright}error{bold bright}: a message{/}
+{fg:Yellow bold bright}warning{bold bright}: a message{/}
+{fg:Green bold bright}note{bold bright}: a message{/}
+{fg:Cyan bold bright}help{bold bright}: a message{/}
+
diff --git a/tests/snapshots/term__message__medium_no_color.snap b/tests/snapshots/term__message__medium_no_color.snap
new file mode 100644
index 0000000..43565ac
--- /dev/null
+++ b/tests/snapshots/term__message__medium_no_color.snap
@@ -0,0 +1,9 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_no_color(&config)
+---
+error: a message
+warning: a message
+note: a message
+help: a message
+
diff --git a/tests/snapshots/term__message_and_notes__medium_color.snap b/tests/snapshots/term__message_and_notes__medium_color.snap
new file mode 100644
index 0000000..f44b2a4
--- /dev/null
+++ b/tests/snapshots/term__message_and_notes__medium_color.snap
@@ -0,0 +1,13 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_color(&config)
+---
+{fg:Red bold bright}error{bold bright}: a message{/}
+ {fg:Blue}={/} a note
+{fg:Yellow bold bright}warning{bold bright}: a message{/}
+ {fg:Blue}={/} a note
+{fg:Green bold bright}note{bold bright}: a message{/}
+ {fg:Blue}={/} a note
+{fg:Cyan bold bright}help{bold bright}: a message{/}
+ {fg:Blue}={/} a note
+
diff --git a/tests/snapshots/term__message_and_notes__medium_no_color.snap b/tests/snapshots/term__message_and_notes__medium_no_color.snap
new file mode 100644
index 0000000..bab7a65
--- /dev/null
+++ b/tests/snapshots/term__message_and_notes__medium_no_color.snap
@@ -0,0 +1,13 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_no_color(&config)
+---
+error: a message
+ = a note
+warning: a message
+ = a note
+note: a message
+ = a note
+help: a message
+ = a note
+
diff --git a/tests/snapshots/term__message_errorcode__rich_no_color.snap b/tests/snapshots/term__message_errorcode__rich_no_color.snap
new file mode 100644
index 0000000..e82fb7c
--- /dev/null
+++ b/tests/snapshots/term__message_errorcode__rich_no_color.snap
@@ -0,0 +1,21 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_no_color(&config)
+---
+error[E0001]: a message
+
+warning[W001]: a message
+
+note[N0815]: a message
+
+help[H4711]: a message
+
+error: where did my errorcode go?
+
+warning: where did my errorcode go?
+
+note: where did my errorcode go?
+
+help: where did my errorcode go?
+
+
diff --git a/tests/snapshots/term__message_errorcode__short_no_color.snap b/tests/snapshots/term__message_errorcode__short_no_color.snap
new file mode 100644
index 0000000..ccddd8d
--- /dev/null
+++ b/tests/snapshots/term__message_errorcode__short_no_color.snap
@@ -0,0 +1,13 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_no_color(&config)
+---
+error[E0001]: a message
+warning[W001]: a message
+note[N0815]: a message
+help[H4711]: a message
+error: where did my errorcode go?
+warning: where did my errorcode go?
+note: where did my errorcode go?
+help: where did my errorcode go?
+
diff --git a/tests/snapshots/term__multifile__medium_color.snap b/tests/snapshots/term__multifile__medium_color.snap
new file mode 100644
index 0000000..6c03d83
--- /dev/null
+++ b/tests/snapshots/term__multifile__medium_color.snap
@@ -0,0 +1,12 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_color(&config)
+---
+Data/Nat.fun:7:13: {fg:Red bold bright}error{bold bright}: unknown builtin: `NATRAL`{/}
+ {fg:Blue}={/} there is a builtin with a similar name: `NATURAL`
+Data/Nat.fun:17:16: {fg:Yellow bold bright}warning{bold bright}: unused parameter pattern: `n₂`{/}
+ {fg:Blue}={/} consider using a wildcard pattern: `_`
+Test.fun:4:11: {fg:Red bold bright}error[E0001]{bold bright}: unexpected type in application of `_+_`{/}
+ {fg:Blue}={/} expected type `Nat`
+ found type `String`
+
diff --git a/tests/snapshots/term__multifile__medium_no_color.snap b/tests/snapshots/term__multifile__medium_no_color.snap
new file mode 100644
index 0000000..db33fc0
--- /dev/null
+++ b/tests/snapshots/term__multifile__medium_no_color.snap
@@ -0,0 +1,12 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_no_color(&config)
+---
+Data/Nat.fun:7:13: error: unknown builtin: `NATRAL`
+ = there is a builtin with a similar name: `NATURAL`
+Data/Nat.fun:17:16: warning: unused parameter pattern: `n₂`
+ = consider using a wildcard pattern: `_`
+Test.fun:4:11: error[E0001]: unexpected type in application of `_+_`
+ = expected type `Nat`
+ found type `String`
+
diff --git a/tests/snapshots/term__multiline_omit__rich_no_color.snap b/tests/snapshots/term__multiline_omit__rich_no_color.snap
new file mode 100644
index 0000000..bb9363d
--- /dev/null
+++ b/tests/snapshots/term__multiline_omit__rich_no_color.snap
@@ -0,0 +1,38 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_no_color(&config)
+---
+error[empty_if]: empty elseif block
+ ┌─ empty_if_comments.lua:1:1
+ │
+ 1 │ ╭ elseif 3 then
+ 2 │ │
+ 3 │ │ ╭
+ 4 │ │ │
+ 5 │ │ │
+ · │ │
+ 8 │ │ │
+ 9 │ │ │
+ │ │ ╰' content should be in here
+10 │ │ else
+ │ ╰───^
+
+error[E0308]: mismatched types
+ ┌─ src/lib.rs:2:6
+ │
+ 2 │ 1
+ │ ╭─────^
+ 3 │ │ + 1
+ 4 │ │ + 1
+ · │
+ 7 │ │ +1
+ │ │ - missing whitespace
+ 8 │ │ + 1
+ 9 │ │ + 1
+10 │ │ + 1
+ │ ╰───────^ expected (), found integer
+ │
+ = note: expected type `()`
+ found type `{integer}`
+
+
diff --git a/tests/snapshots/term__multiline_overlapping__medium_color.snap b/tests/snapshots/term__multiline_overlapping__medium_color.snap
new file mode 100644
index 0000000..afddf24
--- /dev/null
+++ b/tests/snapshots/term__multiline_overlapping__medium_color.snap
@@ -0,0 +1,9 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_color(&config)
+---
+codespan/src/file.rs:4:34: {fg:Red bold bright}error[E0308]{bold bright}: match arms have incompatible types{/}
+ {fg:Blue}={/} expected type `Result<ByteIndex, LineIndexOutOfBoundsError>`
+ found type `LineIndexOutOfBoundsError`
+
+
diff --git a/tests/snapshots/term__multiline_overlapping__medium_no_color.snap b/tests/snapshots/term__multiline_overlapping__medium_no_color.snap
new file mode 100644
index 0000000..0e50bd8
--- /dev/null
+++ b/tests/snapshots/term__multiline_overlapping__medium_no_color.snap
@@ -0,0 +1,9 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_no_color(&config)
+---
+codespan/src/file.rs:4:34: error[E0308]: match arms have incompatible types
+ = expected type `Result<ByteIndex, LineIndexOutOfBoundsError>`
+ found type `LineIndexOutOfBoundsError`
+
+
diff --git a/tests/snapshots/term__multiline_overlapping__rich_color.snap b/tests/snapshots/term__multiline_overlapping__rich_color.snap
index fee20e1..10701fb 100644
--- a/tests/snapshots/term__multiline_overlapping__rich_color.snap
+++ b/tests/snapshots/term__multiline_overlapping__rich_color.snap
@@ -3,7 +3,7 @@ source: codespan-reporting/tests/term.rs
expression: TEST_DATA.emit_color(&config)
---
{fg:Red bold bright}error[E0308]{bold bright}: match arms have incompatible types{/}
- {fg:Blue}┌─{/} codespan/src/file.rs:1:9
+ {fg:Blue}┌─{/} codespan/src/file.rs:4:34
{fg:Blue}│{/}
{fg:Blue}1{/} {fg:Blue}│{/} {fg:Blue}╭{/} match line_index.compare(self.last_line_index()) {
{fg:Blue}2{/} {fg:Blue}│{/} {fg:Blue}│{/} Ordering::Less => Ok(self.line_starts()[line_index.to_usize()]),
diff --git a/tests/snapshots/term__multiline_overlapping__rich_no_color.snap b/tests/snapshots/term__multiline_overlapping__rich_no_color.snap
index 8f82c15..f6802c8 100644
--- a/tests/snapshots/term__multiline_overlapping__rich_no_color.snap
+++ b/tests/snapshots/term__multiline_overlapping__rich_no_color.snap
@@ -3,7 +3,7 @@ source: codespan-reporting/tests/term.rs
expression: TEST_DATA.emit_no_color(&config)
---
error[E0308]: match arms have incompatible types
- ┌─ codespan/src/file.rs:1:9
+ ┌─ codespan/src/file.rs:4:34
1 │ ╭ match line_index.compare(self.last_line_index()) {
2 │ │ Ordering::Less => Ok(self.line_starts()[line_index.to_usize()]),
diff --git a/tests/snapshots/term__overlapping__medium_color.snap b/tests/snapshots/term__overlapping__medium_color.snap
new file mode 100644
index 0000000..9ccf3e5
--- /dev/null
+++ b/tests/snapshots/term__overlapping__medium_color.snap
@@ -0,0 +1,17 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_color(&config)
+---
+nested_impl_trait.rs:5:56: {fg:Red bold bright}error[E0666]{bold bright}: nested `impl Trait` is not allowed{/}
+typeck_type_placeholder_item.rs:1:18: {fg:Red bold bright}error[E0121]{bold bright}: the type placeholder `_` is not allowed within types on item signatures{/}
+typeck_type_placeholder_item.rs:2:25: {fg:Red bold bright}error[E0121]{bold bright}: the type placeholder `_` is not allowed within types on item signatures{/}
+typeck_type_placeholder_item.rs:2:28: {fg:Red bold bright}error[E0121]{bold bright}: the type placeholder `_` is not allowed within types on item signatures{/}
+no_send_res_ports.rs:25:5: {fg:Red bold bright}error[E0277]{bold bright}: `std::rc::Rc<()>` cannot be sent between threads safely{/}
+ {fg:Blue}={/} help: within `[closure@no_send_res_ports.rs:29:19: 33:6 x:main::Foo]`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>`
+ {fg:Blue}={/} note: required because it appears within the type `Port<()>`
+ {fg:Blue}={/} note: required because it appears within the type `main::Foo`
+ {fg:Blue}={/} note: required because it appears within the type `[closure@no_send_res_ports.rs:29:19: 33:6 x:main::Foo]`
+{fg:Red bold bright}error{bold bright}: aborting due 5 previous errors{/}
+ {fg:Blue}={/} Some errors have detailed explanations: E0121, E0277, E0666.
+ {fg:Blue}={/} For more information about an error, try `rustc --explain E0121`.
+
diff --git a/tests/snapshots/term__overlapping__medium_no_color.snap b/tests/snapshots/term__overlapping__medium_no_color.snap
new file mode 100644
index 0000000..3b9eac9
--- /dev/null
+++ b/tests/snapshots/term__overlapping__medium_no_color.snap
@@ -0,0 +1,17 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_no_color(&config)
+---
+nested_impl_trait.rs:5:56: error[E0666]: nested `impl Trait` is not allowed
+typeck_type_placeholder_item.rs:1:18: error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+typeck_type_placeholder_item.rs:2:25: error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+typeck_type_placeholder_item.rs:2:28: error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+no_send_res_ports.rs:25:5: error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely
+ = help: within `[closure@no_send_res_ports.rs:29:19: 33:6 x:main::Foo]`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>`
+ = note: required because it appears within the type `Port<()>`
+ = note: required because it appears within the type `main::Foo`
+ = note: required because it appears within the type `[closure@no_send_res_ports.rs:29:19: 33:6 x:main::Foo]`
+error: aborting due 5 previous errors
+ = Some errors have detailed explanations: E0121, E0277, E0666.
+ = For more information about an error, try `rustc --explain E0121`.
+
diff --git a/tests/snapshots/term__overlapping__rich_color.snap b/tests/snapshots/term__overlapping__rich_color.snap
index 92f061f..d29a429 100644
--- a/tests/snapshots/term__overlapping__rich_color.snap
+++ b/tests/snapshots/term__overlapping__rich_color.snap
@@ -3,7 +3,7 @@ source: codespan-reporting/tests/term.rs
expression: TEST_DATA.emit_color(&config)
---
{fg:Red bold bright}error[E0666]{bold bright}: nested `impl Trait` is not allowed{/}
- {fg:Blue}┌─{/} nested_impl_trait.rs:5:46
+ {fg:Blue}┌─{/} nested_impl_trait.rs:5:56
{fg:Blue}│{/}
{fg:Blue}5{/} {fg:Blue}│{/} fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<{fg:Red}impl Debug{/}> { x }
{fg:Blue}│{/} {fg:Blue}----------{fg:Red}^^^^^^^^^^{fg:Blue}-{/}
@@ -21,7 +21,7 @@ expression: TEST_DATA.emit_color(&config)
{fg:Blue}│{/} {fg:Blue}help: replace with the correct return type: `i32`{/}
{fg:Red bold bright}error[E0121]{bold bright}: the type placeholder `_` is not allowed within types on item signatures{/}
- {fg:Blue}┌─{/} typeck_type_placeholder_item.rs:2:24
+ {fg:Blue}┌─{/} typeck_type_placeholder_item.rs:2:25
{fg:Blue}│{/}
{fg:Blue}2{/} {fg:Blue}│{/} fn fn_test2(x: i32) -> ({fg:Red}_{/}, {fg:Red}_{/}) { (x, x) }
{fg:Blue}│{/} {fg:Blue}-{fg:Red}^{fg:Blue}--{fg:Red}^{fg:Blue}-{/}
diff --git a/tests/snapshots/term__overlapping__rich_no_color.snap b/tests/snapshots/term__overlapping__rich_no_color.snap
index e4a944d..32f8eec 100644
--- a/tests/snapshots/term__overlapping__rich_no_color.snap
+++ b/tests/snapshots/term__overlapping__rich_no_color.snap
@@ -3,7 +3,7 @@ source: codespan-reporting/tests/term.rs
expression: TEST_DATA.emit_no_color(&config)
---
error[E0666]: nested `impl Trait` is not allowed
- ┌─ nested_impl_trait.rs:5:46
+ ┌─ nested_impl_trait.rs:5:56
5 │ fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
│ ----------^^^^^^^^^^-
@@ -21,7 +21,7 @@ error[E0121]: the type placeholder `_` is not allowed within types on item signa
│ help: replace with the correct return type: `i32`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
- ┌─ typeck_type_placeholder_item.rs:2:24
+ ┌─ typeck_type_placeholder_item.rs:2:25
2 │ fn fn_test2(x: i32) -> (_, _) { (x, x) }
│ -^--^-
diff --git a/tests/snapshots/term__position_indicator__medium_no_color.snap b/tests/snapshots/term__position_indicator__medium_no_color.snap
new file mode 100644
index 0000000..0e40c83
--- /dev/null
+++ b/tests/snapshots/term__position_indicator__medium_no_color.snap
@@ -0,0 +1,7 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_no_color(&config)
+---
+tests/main.js:4:3: warning[ParserWarning]: The strict mode declaration in the body of function `foo` is redundant, as the outer scope is already in strict mode
+
+
diff --git a/tests/snapshots/term__position_indicator__rich_no_color.snap b/tests/snapshots/term__position_indicator__rich_no_color.snap
new file mode 100644
index 0000000..35217e4
--- /dev/null
+++ b/tests/snapshots/term__position_indicator__rich_no_color.snap
@@ -0,0 +1,14 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_no_color(&config)
+---
+warning[ParserWarning]: The strict mode declaration in the body of function `foo` is redundant, as the outer scope is already in strict mode
+ ┌─ tests/main.js:4:3
+ │
+1 │ "use strict";
+ │ ------------ Strict mode is first declared here
+ ·
+4 │ "use strict";
+ │ ^^^^^^^^^^^^ This strict mode declaration is redundant
+
+
diff --git a/tests/snapshots/term__position_indicator__short_no_color.snap b/tests/snapshots/term__position_indicator__short_no_color.snap
new file mode 100644
index 0000000..3ec348d
--- /dev/null
+++ b/tests/snapshots/term__position_indicator__short_no_color.snap
@@ -0,0 +1,6 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_no_color(&config)
+---
+tests/main.js:4:3: warning[ParserWarning]: The strict mode declaration in the body of function `foo` is redundant, as the outer scope is already in strict mode
+
diff --git a/tests/snapshots/term__same_line__medium_color.snap b/tests/snapshots/term__same_line__medium_color.snap
new file mode 100644
index 0000000..43e1eb0
--- /dev/null
+++ b/tests/snapshots/term__same_line__medium_color.snap
@@ -0,0 +1,8 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_color(&config)
+---
+one_line.rs:3:12: {fg:Red bold bright}error[E0499]{bold bright}: cannot borrow `v` as mutable more than once at a time{/}
+{fg:Red bold bright}error{bold bright}: aborting due to previous error{/}
+ {fg:Blue}={/} For more information about this error, try `rustc --explain E0499`.
+
diff --git a/tests/snapshots/term__same_line__medium_no_color.snap b/tests/snapshots/term__same_line__medium_no_color.snap
new file mode 100644
index 0000000..6bb55ed
--- /dev/null
+++ b/tests/snapshots/term__same_line__medium_no_color.snap
@@ -0,0 +1,8 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_no_color(&config)
+---
+one_line.rs:3:12: error[E0499]: cannot borrow `v` as mutable more than once at a time
+error: aborting due to previous error
+ = For more information about this error, try `rustc --explain E0499`.
+
diff --git a/tests/snapshots/term__same_line__rich_color.snap b/tests/snapshots/term__same_line__rich_color.snap
index 59bd616..38addbb 100644
--- a/tests/snapshots/term__same_line__rich_color.snap
+++ b/tests/snapshots/term__same_line__rich_color.snap
@@ -3,7 +3,7 @@ source: codespan-reporting/tests/term.rs
expression: TEST_DATA.emit_color(&config)
---
{fg:Red bold bright}error[E0499]{bold bright}: cannot borrow `v` as mutable more than once at a time{/}
- {fg:Blue}┌─{/} one_line.rs:3:5
+ {fg:Blue}┌─{/} one_line.rs:3:12
{fg:Blue}│{/}
{fg:Blue}3{/} {fg:Blue}│{/} v.push({fg:Red}v{/}.pop().unwrap());
{fg:Blue}│{/} {fg:Blue}-{/} {fg:Blue}----{/} {fg:Red}^{/} {fg:Red}second mutable borrow occurs here{/}
diff --git a/tests/snapshots/term__same_line__rich_no_color.snap b/tests/snapshots/term__same_line__rich_no_color.snap
index 7342f3f..75511a4 100644
--- a/tests/snapshots/term__same_line__rich_no_color.snap
+++ b/tests/snapshots/term__same_line__rich_no_color.snap
@@ -3,7 +3,7 @@ source: codespan-reporting/tests/term.rs
expression: TEST_DATA.emit_no_color(&config)
---
error[E0499]: cannot borrow `v` as mutable more than once at a time
- ┌─ one_line.rs:3:5
+ ┌─ one_line.rs:3:12
3 │ v.push(v.pop().unwrap());
│ - ---- ^ second mutable borrow occurs here
diff --git a/tests/snapshots/term__same_ranges__medium_color.snap b/tests/snapshots/term__same_ranges__medium_color.snap
new file mode 100644
index 0000000..095b975
--- /dev/null
+++ b/tests/snapshots/term__same_ranges__medium_color.snap
@@ -0,0 +1,7 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_color(&config)
+---
+same_range:1:5: {fg:Red bold bright}error{bold bright}: Unexpected token{/}
+
+
diff --git a/tests/snapshots/term__same_ranges__medium_no_color.snap b/tests/snapshots/term__same_ranges__medium_no_color.snap
new file mode 100644
index 0000000..a452022
--- /dev/null
+++ b/tests/snapshots/term__same_ranges__medium_no_color.snap
@@ -0,0 +1,7 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_no_color(&config)
+---
+same_range:1:5: error: Unexpected token
+
+
diff --git a/tests/snapshots/term__unicode__medium_no_color.snap b/tests/snapshots/term__unicode__medium_no_color.snap
new file mode 100644
index 0000000..b5f8780
--- /dev/null
+++ b/tests/snapshots/term__unicode__medium_no_color.snap
@@ -0,0 +1,29 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_no_color(&config)
+---
+unicode.rs:1:8: error[E0703]: invalid ABI: found `路濫狼á́́`
+ = valid ABIs:
+ - aapcs
+ - amdgpu-kernel
+ - C
+ - cdecl
+ - efiapi
+ - fastcall
+ - msp430-interrupt
+ - platform-intrinsic
+ - ptx-kernel
+ - Rust
+ - rust-call
+ - rust-intrinsic
+ - stdcall
+ - system
+ - sysv64
+ - thiscall
+ - unadjusted
+ - vectorcall
+ - win64
+ - x86-interrupt
+error: aborting due to previous error
+ = For more information about this error, try `rustc --explain E0703`.
+
diff --git a/tests/snapshots/term__unicode_spans__medium_no_color.snap b/tests/snapshots/term__unicode_spans__medium_no_color.snap
new file mode 100644
index 0000000..1b19451
--- /dev/null
+++ b/tests/snapshots/term__unicode_spans__medium_no_color.snap
@@ -0,0 +1,9 @@
+---
+source: codespan-reporting/tests/term.rs
+expression: TEST_DATA.emit_no_color(&config)
+---
+moon_jump.rs:1:1: error[E01]: cow may not jump during new moon.
+note: invalid unicode range
+note: invalid unicode range
+note: invalid unicode range
+
diff --git a/tests/term.rs b/tests/term.rs
index ee02372..15c9566 100644
--- a/tests/term.rs
+++ b/tests/term.rs
@@ -26,6 +26,17 @@ macro_rules! test_emit {
insta::assert_snapshot!(TEST_DATA.emit_color(&config));
}
};
+ (medium_color) => {
+ #[test]
+ fn medium_color() {
+ let config = Config {
+ display_style: DisplayStyle::Medium,
+ ..TEST_CONFIG.clone()
+ };
+
+ insta::assert_snapshot!(TEST_DATA.emit_color(&config));
+ }
+ };
(short_color) => {
#[test]
fn short_color() {
@@ -48,6 +59,17 @@ macro_rules! test_emit {
insta::assert_snapshot!(TEST_DATA.emit_no_color(&config));
}
};
+ (medium_no_color) => {
+ #[test]
+ fn medium_no_color() {
+ let config = Config {
+ display_style: DisplayStyle::Medium,
+ ..TEST_CONFIG.clone()
+ };
+
+ insta::assert_snapshot!(TEST_DATA.emit_no_color(&config));
+ }
+ };
(short_no_color) => {
#[test]
fn short_no_color() {
@@ -82,8 +104,10 @@ mod empty {
}
test_emit!(rich_color);
+ test_emit!(medium_color);
test_emit!(short_color);
test_emit!(rich_no_color);
+ test_emit!(medium_no_color);
test_emit!(short_no_color);
}
@@ -130,8 +154,10 @@ mod same_line {
}
test_emit!(rich_color);
+ test_emit!(medium_color);
test_emit!(short_color);
test_emit!(rich_no_color);
+ test_emit!(medium_no_color);
test_emit!(short_no_color);
}
@@ -272,8 +298,10 @@ mod overlapping {
}
test_emit!(rich_color);
+ test_emit!(medium_color);
test_emit!(short_color);
test_emit!(rich_no_color);
+ test_emit!(medium_no_color);
test_emit!(short_no_color);
}
@@ -296,8 +324,10 @@ mod message {
}
test_emit!(rich_color);
+ test_emit!(medium_color);
test_emit!(short_color);
test_emit!(rich_no_color);
+ test_emit!(medium_no_color);
test_emit!(short_no_color);
}
@@ -320,8 +350,36 @@ mod message_and_notes {
}
test_emit!(rich_color);
+ test_emit!(medium_color);
test_emit!(short_color);
test_emit!(rich_no_color);
+ test_emit!(medium_no_color);
+ test_emit!(short_no_color);
+}
+
+mod message_errorcode {
+ use super::*;
+
+ lazy_static::lazy_static! {
+ static ref TEST_DATA: TestData<'static, SimpleFiles<&'static str, &'static str>> = {
+ let files = SimpleFiles::new();
+
+ let diagnostics = vec![
+ Diagnostic::error().with_message("a message").with_code("E0001"),
+ Diagnostic::warning().with_message("a message").with_code("W001"),
+ Diagnostic::note().with_message("a message").with_code("N0815"),
+ Diagnostic::help().with_message("a message").with_code("H4711"),
+ Diagnostic::error().with_message("where did my errorcode go?").with_code(""),
+ Diagnostic::warning().with_message("where did my errorcode go?").with_code(""),
+ Diagnostic::note().with_message("where did my errorcode go?").with_code(""),
+ Diagnostic::help().with_message("where did my errorcode go?").with_code(""),
+ ];
+
+ TestData { files, diagnostics }
+ };
+ }
+
+ test_emit!(rich_no_color);
test_emit!(short_no_color);
}
@@ -353,8 +411,10 @@ mod empty_ranges {
}
test_emit!(rich_color);
+ test_emit!(medium_color);
test_emit!(short_color);
test_emit!(rich_no_color);
+ test_emit!(medium_no_color);
test_emit!(short_no_color);
}
@@ -379,8 +439,10 @@ mod same_ranges {
}
test_emit!(rich_color);
+ test_emit!(medium_color);
test_emit!(short_color);
test_emit!(rich_no_color);
+ test_emit!(medium_no_color);
test_emit!(short_no_color);
}
@@ -463,8 +525,10 @@ mod multifile {
}
test_emit!(rich_color);
+ test_emit!(medium_color);
test_emit!(short_color);
test_emit!(rich_no_color);
+ test_emit!(medium_no_color);
test_emit!(short_no_color);
}
@@ -540,8 +604,10 @@ mod fizz_buzz {
}
test_emit!(rich_color);
+ test_emit!(medium_color);
test_emit!(short_color);
test_emit!(rich_no_color);
+ test_emit!(medium_no_color);
test_emit!(short_no_color);
}
@@ -569,9 +635,10 @@ mod multiline_overlapping {
.with_message("match arms have incompatible types")
.with_code("E0308")
.with_labels(vec![
+ // this secondary label is before the primary label to test the locus calculation (see issue #259)
+ Label::secondary((), 89..134).with_message("this is found to be of type `Result<ByteIndex, LineIndexOutOfBoundsError>`"),
Label::primary((), 230..351).with_message("expected enum `Result`, found struct `LineIndexOutOfBoundsError`"),
Label::secondary((), 8..362).with_message("`match` arms have incompatible types"),
- Label::secondary((), 89..134).with_message("this is found to be of type `Result<ByteIndex, LineIndexOutOfBoundsError>`"),
Label::secondary((), 167..195).with_message("this is found to be of type `Result<ByteIndex, LineIndexOutOfBoundsError>`"),
])
.with_notes(vec![unindent::unindent(
@@ -587,8 +654,10 @@ mod multiline_overlapping {
}
test_emit!(rich_color);
+ test_emit!(medium_color);
test_emit!(short_color);
test_emit!(rich_no_color);
+ test_emit!(medium_no_color);
test_emit!(short_no_color);
}
@@ -792,6 +861,7 @@ mod unicode {
}
test_emit!(rich_no_color);
+ test_emit!(medium_no_color);
test_emit!(short_no_color);
}
@@ -842,5 +912,118 @@ mod unicode_spans {
}
test_emit!(rich_no_color);
+ test_emit!(medium_no_color);
test_emit!(short_no_color);
}
+
+mod position_indicator {
+ use super::*;
+
+ lazy_static::lazy_static! {
+ static ref TEST_DATA: TestData<'static, SimpleFile<&'static str, String>> = {
+ let file = SimpleFile::new(
+ "tests/main.js",
+ [
+ "\"use strict\";",
+ "let zero=0;",
+ "function foo() {",
+ " \"use strict\";",
+ " one=1;",
+ "}",
+ ].join("\n"),
+ );
+ let diagnostics = vec![
+ Diagnostic::warning()
+ .with_code("ParserWarning")
+ .with_message("The strict mode declaration in the body of function `foo` is redundant, as the outer scope is already in strict mode")
+ .with_labels(vec![
+ Label::primary((), 45..57)
+ .with_message("This strict mode declaration is redundant"),
+ Label::secondary((), 0..12)
+ .with_message("Strict mode is first declared here"),
+ ]),
+ ];
+ TestData{files: file, diagnostics }
+ };
+ }
+
+ test_emit!(rich_no_color);
+ test_emit!(medium_no_color);
+ test_emit!(short_no_color);
+}
+
+mod multiline_omit {
+ use super::*;
+
+ lazy_static::lazy_static! {
+ static ref TEST_CONFIG: Config = Config {
+ styles: Styles::with_blue(Color::Blue),
+ start_context_lines: 2,
+ end_context_lines: 1,
+ ..Config::default()
+ };
+
+ static ref TEST_DATA: TestData<'static, SimpleFiles<&'static str, String>> = {
+ let mut files = SimpleFiles::new();
+
+ let file_id1 = files.add(
+ "empty_if_comments.lua",
+ [
+ "elseif 3 then", // primary label starts here
+ "", // context line
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "", // context line
+ "else", // primary label ends here
+ ]
+ .join("\n"),
+ );
+
+ let file_id2 = files.add(
+ "src/lib.rs",
+ [
+ "fn main() {",
+ " 1", // primary label starts here
+ " + 1", // context line
+ " + 1", // skip
+ " + 1", // skip
+ " + 1", // skip
+ " +1", // secondary label here
+ " + 1", // this single line will not be skipped; the previously filtered out label must be retrieved
+ " + 1", // context line
+ " + 1", // primary label ends here
+ "}",
+ ]
+ .join("\n"),
+ );
+
+ let diagnostics = vec![
+ Diagnostic::error()
+ .with_message("empty elseif block")
+ .with_code("empty_if")
+ .with_labels(vec![
+ Label::primary(file_id1, 0..23),
+ Label::secondary(file_id1, 15..21).with_message("content should be in here"),
+ ]),
+ Diagnostic::error()
+ .with_message("mismatched types")
+ .with_code("E0308")
+ .with_labels(vec![
+ Label::primary(file_id2, 17..80).with_message("expected (), found integer"),
+ Label::secondary(file_id2, 55..55).with_message("missing whitespace"),
+ ])
+ .with_notes(vec![
+ "note:\texpected type `()`\n\tfound type `{integer}`".to_owned()
+ ]),
+ ];
+
+ TestData { files, diagnostics }
+ };
+ }
+
+ test_emit!(rich_no_color);
+}