diff options
author | Haibo Huang <hhb@google.com> | 2020-12-01 22:38:01 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2020-12-01 22:38:01 +0000 |
commit | 9b40cf03b6ac8815fc659b424691af5202957db1 (patch) | |
tree | 291f85450ee9cb3667a166c313c51e87bf5647eb | |
parent | 78c5058bfed09cfade339194ea618d95c4b7885b (diff) | |
parent | 7c93dcc3f45be4fcd9b59969804c9d073fbdd900 (diff) | |
download | codespan-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
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" } } @@ -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 @@ -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", @@ -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" @@ -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, - ¤t_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, - ¤t_labels, + &line.multi_labels, )?; } } @@ -350,7 +380,7 @@ where outer_padding, self.diagnostic.severity, labeled_file.num_multi_labels, - ¤t_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); +} |