codespan-reporting-0.11.1/.cargo_vcs_info.json0000644000000001120000000000000147100ustar { "git": { "sha1": "fd389a13f5bb6d625b71e2e4694b26e127f393f9" } } codespan-reporting-0.11.1/CHANGELOG.md000064400000000000000000000336130000000000000153030ustar 00000000000000# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ## [0.11.1] - 2021-01-18 ### Added - Add `Chars::{box_drawing, ascii}` functions, the latter supporting a rustc-style of output that only uses ASCII characters (not above U+007F) for use cases that do not allow for box drawing characters, e.g. terminals that do not support them. ### Changed - `Diagnostic::with_labels` and `Diagnostic::with_notes` now append additional labels rather tan overwriting them, meaning that the documentation and behaviour match more closely. The behaviour will only differ if you call the same builder methods multiple times. If you call every builder method once only, nothing should change. - `config::Chars::snippet_start` is now a String instead of a single `char`. ## [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.
Example For example, when rendering with a tab width of `3` we would print: ```text 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: ```text 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 ### Changed - We have made the caret rendering easier to read when there are multiple labels on the same line. We also avoid printing trailing borders on the final source source snippet if no notes are present.
Example Instead of this: ```text ┌─ one_line.rs:3:5 │ 3 │ v.push(v.pop().unwrap()); │ - first borrow later used by call │ ---- first mutable borrow occurs here │ ^ second mutable borrow occurs here │ ``` …we now render the following: ```text ┌─ one_line.rs:3:5 │ 3 │ v.push(v.pop().unwrap()); │ - ---- ^ second mutable borrow occurs here │ │ │ │ │ first mutable borrow occurs here │ first borrow later used by call ```
### Fixed - Diagnostic rendering no longer panics if label ranges are between UTF-8 character boundaries. ## [0.9.3] - 2020-04-29 ### Changed - Some panics were fixed when invalid unicode boundaries are supplied. - Labels that marked the same span were originally rendered in reverse order. This was a mistake! We've now fixed this.
Example For example, this diagnostic: ```text ┌─ same_range:1:7 │ 1 │ ::S { } │ - Expected '(' │ ^ Unexpected '{' │ ``` …will now be rendered as: ```text ┌─ same_range:1:7 │ 1 │ ::S { } │ ^ Unexpected '{' │ - Expected '(' │ ```
- We've reduced the prominence of the 'locus' on source snippets by simplifying the border and reducing the spacing around it. This is to help focus attention on the underlined source snippet and error messages, rather than the location, which should be a secondary focus.
Example For example we originally rendered this: ```text error: unknown builtin: `NATRAL` ┌── Data/Nat.fun:7:13 ─── │ 7 │ {-# BUILTIN NATRAL Nat #-} │ ^^^^^^ unknown builtin │ = there is a builtin with a similar name: `NATURAL` ``` …and now we render this: ```text error: unknown builtin: `NATRAL` ┌─ Data/Nat.fun:7:13 │ 7 │ {-# BUILTIN NATRAL Nat #-} │ ^^^^^^ unknown builtin │ = there is a builtin with a similar name: `NATURAL` ```
## [0.9.2] - 2020-03-29 ### Changed - Render overlapping multiline marks on the same lines of source code.
Example For example: ```text error[E0308]: match arms have incompatible types ┌── codespan/src/file.rs:1:9 ─── │ 1 │ ╭ match line_index.compare(self.last_line_index()) { 2 │ │ Ordering::Less => Ok(self.line_starts()[line_index.to_usize()]), 3 │ │ Ordering::Equal => Ok(self.source_span().end()), 4 │ │ Ordering::Greater => LineIndexOutOfBoundsError { 5 │ │ given: line_index, 6 │ │ max: self.last_line_index(), 7 │ │ }, 8 │ │ } │ ╰─────────' `match` arms have incompatible types · 2 │ Ordering::Less => Ok(self.line_starts()[line_index.to_usize()]), │ --------------------------------------------- this is found to be of type `Result` 3 │ Ordering::Equal => Ok(self.source_span().end()), │ ---------------------------- this is found to be of type `Result` 4 │ Ordering::Greater => LineIndexOutOfBoundsError { │ ╭──────────────────────────────────^ 5 │ │ given: line_index, 6 │ │ max: self.last_line_index(), 7 │ │ }, │ ╰─────────────^ expected enum `Result`, found struct `LineIndexOutOfBoundsError` │ = expected type `Result` found type `LineIndexOutOfBoundsError` ``` …is now rendered as: ```text error[E0308]: match arms have incompatible types ┌── codespan/src/file.rs:1:9 ─── │ 1 │ ╭ match line_index.compare(self.last_line_index()) { 2 │ │ Ordering::Less => Ok(self.line_starts()[line_index.to_usize()]), │ │ --------------------------------------------- this is found to be of type `Result` 3 │ │ Ordering::Equal => Ok(self.source_span().end()), │ │ ---------------------------- this is found to be of type `Result` 4 │ │ Ordering::Greater => LineIndexOutOfBoundsError { │ ╭─│──────────────────────────────────^ 5 │ │ │ given: line_index, 6 │ │ │ max: self.last_line_index(), 7 │ │ │ }, │ ╰─│─────────────^ expected enum `Result`, found struct `LineIndexOutOfBoundsError` 8 │ │ } │ ╰─────────' `match` arms have incompatible types │ = expected type `Result` found type `LineIndexOutOfBoundsError` ```
## [0.9.1] - 2020-03-23 ### Added - `codespan_reporting::diagnostic::Diagnostic` now implements `Debug`. ### Changed - Single-line labels are now rendered together, under the same source line.
Example For example: ```text ┌── one_line.rs:3:5 ─── │ 3 │ v.push(v.pop().unwrap()); │ - first borrow later used by call · 3 │ v.push(v.pop().unwrap()); │ ---- first mutable borrow occurs here · 3 │ v.push(v.pop().unwrap()); │ ^ second mutable borrow occurs here │ ``` …is now rendered as: ```text ┌── one_line.rs:3:5 ─── │ 3 │ v.push(v.pop().unwrap()); │ - first borrow later used by call │ ---- first mutable borrow occurs here │ ^ second mutable borrow occurs here │ ```
## [0.9.0] - 2020-03-11 ### Added - The `codespan_reporting::files` module was added as a way to decouple `codespan_reporting` from `codespan`. - `codespan_reporting::files::Files` allows users to implement custom file databases that work with `codespan_reporting`. This should make it easier to integrate with libraries like Salsa, and also makes it less invasive to use `codespan_reporting` on existing projects. - `codespan_reporting::files::SimpleFile` is a simple implementation of `codespan_reporting::files::Files` where only a single file is needed. - `codespan_reporting::files::SimpleFiles` is a simple implementation of `codespan_reporting::files::Files` where multiple files are needed. ### Changed - The `codespan_reporting::diagnostic` module has been greatly revamped, making the builder API format more nicely with rustfmt, and allowing for multiple primary labels. - The output of `codespan_reporting::term::emit` was improved, with the following changes: - labels on consecutive lines no longer render breaks between them - source lines are rendered when there is only one line between labels - the inner gutter of code snippets is now aligned consistently - the outer gutter of consecutive code snippets are now aligned consistently - `codespan_reporting::term::emit` now takes writers as a trait object (rather than using static dispatch) in order to reduce coda bloat and improve compile times. - The field names in `codespan_reporting::term::Chars` were tweaked for consistency. ### Removed - `codespan_reporting` no longer depends on `codespan`. Note that `codespan` can _still_ be used with `codespan_reporting`, as `codespan::Files` now implements `codespan_reporting::files::Files`. ## [0.8.0] - 2020-02-24 ## [0.7.0] - 2020-01-06 ## [0.6.0] - 2019-12-18 ## [0.5.0] - 2019-10-02 ## [0.4.1] - 2019-08-25 ## [0.4.0] - 2019-08-22 ## [0.3.0] - 2019-05-01 ## [0.2.1] - 2019-02-26 ## [0.2.0] - 2018-10-11 [Unreleased]: https://github.com/brendanzab/codespan/compare/v0.11.1...HEAD [0.11.1]: https://github.com/brendanzab/codespan/compare/v0.11.0..v0.11.1 [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 [0.9.1]: https://github.com/brendanzab/codespan/compare/v0.9.0...v0.9.1 [0.9.0]: https://github.com/brendanzab/codespan/compare/v0.8.0...v0.9.0 [0.8.0]: https://github.com/brendanzab/codespan/compare/v0.7.0...v0.8.0 [0.7.0]: https://github.com/brendanzab/codespan/compare/v0.6.0...v0.7.0 [0.6.0]: https://github.com/brendanzab/codespan/compare/v0.5.0...v0.6.0 [0.5.0]: https://github.com/brendanzab/codespan/compare/v0.4.1...v0.5.0 [0.4.1]: https://github.com/brendanzab/codespan/compare/v0.4.0...v0.4.1 [0.4.0]: https://github.com/brendanzab/codespan/compare/v0.3.0...v0.4.0 [0.3.0]: https://github.com/brendanzab/codespan/compare/v0.2.1...v0.3.0 [0.2.1]: https://github.com/brendanzab/codespan/compare/v0.2.0...v0.2.1 [0.2.0]: https://github.com/brendanzab/codespan/releases/tag/v0.2.0 codespan-reporting-0.11.1/Cargo.lock0000644000000337610000000000000127030ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] name = "ansi_term" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" dependencies = [ "winapi", ] [[package]] name = "anyhow" version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi", "libc", "winapi", ] [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "cc" version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" [[package]] name = "cfg-if" version = "0.1.10" 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.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" dependencies = [ "ansi_term", "atty", "bitflags", "strsim", "textwrap", "unicode-width", "vec_map", ] [[package]] name = "codespan-reporting" version = "0.11.1" dependencies = [ "anyhow", "insta", "lazy_static", "peg", "rustyline", "serde", "structopt", "termcolor", "unicode-width", "unindent", ] [[package]] name = "console" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cc80946b3480f421c2f17ed1cb841753a371c7c5104f51d507e13f532c856aa" dependencies = [ "encode_unicode", "lazy_static", "libc", "terminal_size", "winapi", ] [[package]] name = "dirs-next" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf36e65a80337bea855cd4ef9b8401ffce06a7baedf2e85ec467b1ac3f6e82b6" dependencies = [ "cfg-if 1.0.0", "dirs-sys-next", ] [[package]] name = "dirs-sys-next" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", "redox_users", "winapi", ] [[package]] name = "dtoa" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88d7ed2934d741c6b37e33e3832298e8850b53fd2d2bea03873375596c7cea4e" [[package]] name = "encode_unicode" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "getrandom" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ "cfg-if 1.0.0", "libc", "wasi", ] [[package]] name = "heck" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" dependencies = [ "unicode-segmentation", ] [[package]] name = "hermit-abi" version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" dependencies = [ "libc", ] [[package]] name = "insta" version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd354a2c8c8083d58414597a4ecada1984f9b82ea7e87eeabddc869eaf120992" dependencies = [ "console", "lazy_static", "serde", "serde_json", "serde_yaml", "similar", "uuid", ] [[package]] name = "itoa" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" [[package]] name = "linked-hash-map" version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" [[package]] name = "log" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ "cfg-if 1.0.0", ] [[package]] name = "memchr" version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" [[package]] name = "nix" version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83450fe6a6142ddd95fb064b746083fc4ef1705fe81f64a64e1d4b39f54a1055" dependencies = [ "bitflags", "cc", "cfg-if 0.1.10", "libc", ] [[package]] name = "peg" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f76678828272f177ac33b7e2ac2e3e73cc6c1cd1e3e387928aa69562fa51367" dependencies = [ "peg-macros", "peg-runtime", ] [[package]] name = "peg-macros" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "636d60acf97633e48d266d7415a9355d4389cea327a193f87df395d88cd2b14d" dependencies = [ "peg-runtime", "proc-macro2", "quote", ] [[package]] name = "peg-runtime" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9555b1514d2d99d78150d3c799d4c357a3e2c2a8062cd108e93a06d9057629c5" [[package]] name = "proc-macro-error" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", "syn", "version_check", ] [[package]] name = "proc-macro-error-attr" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ "proc-macro2", "quote", "version_check", ] [[package]] name = "proc-macro2" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" dependencies = [ "unicode-xid", ] [[package]] name = "quote" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" dependencies = [ "bitflags", ] [[package]] name = "redox_users" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ "getrandom", "redox_syscall", ] [[package]] name = "rustyline" version = "6.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f0d5e7b0219a3eadd5439498525d4765c59b7c993ef0c12244865cd2d988413" dependencies = [ "cfg-if 0.1.10", "dirs-next", "libc", "log", "memchr", "nix", "scopeguard", "unicode-segmentation", "unicode-width", "utf8parse", "winapi", ] [[package]] name = "ryu" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" version = "1.0.123" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.123" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.62" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea1c6153794552ea7cf7cf63b1231a25de00ec90db326ba6264440fa08e31486" dependencies = [ "itoa", "ryu", "serde", ] [[package]] name = "serde_yaml" version = "0.8.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15654ed4ab61726bf918a39cb8d98a2e2995b002387807fa6ba58fdf7f59bb23" dependencies = [ "dtoa", "linked-hash-map", "serde", "yaml-rust", ] [[package]] name = "similar" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a04629d2e8ecdcf30e0188e3699ed6d50d5750d0219db146a790065fe92a897" [[package]] name = "strsim" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "structopt" version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5277acd7ee46e63e5168a80734c9f6ee81b1367a7d8772a2d765df2a3705d28c" dependencies = [ "clap", "lazy_static", "structopt-derive", ] [[package]] name = "structopt-derive" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ba9cdfda491b814720b6b06e0cac513d922fc407582032e8706e9f137976f90" dependencies = [ "heck", "proc-macro-error", "proc-macro2", "quote", "syn", ] [[package]] name = "syn" version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" dependencies = [ "proc-macro2", "quote", "unicode-xid", ] [[package]] name = "termcolor" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" dependencies = [ "winapi-util", ] [[package]] name = "terminal_size" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86ca8ced750734db02076f44132d802af0b33b09942331f4459dde8636fd2406" dependencies = [ "libc", "winapi", ] [[package]] name = "textwrap" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" dependencies = [ "unicode-width", ] [[package]] name = "unicode-segmentation" version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" [[package]] name = "unicode-width" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" [[package]] name = "unicode-xid" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" [[package]] name = "unindent" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7" [[package]] name = "utf8parse" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" [[package]] name = "uuid" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" [[package]] name = "vec_map" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version_check" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ "winapi", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "yaml-rust" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" dependencies = [ "linked-hash-map", ] codespan-reporting-0.11.1/Cargo.toml0000644000000027350000000000000127230ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2018" name = "codespan-reporting" version = "0.11.1" authors = ["Brendan Zabarauskas "] exclude = ["assets/**"] description = "Beautiful diagnostic reporting for text-based programming languages" homepage = "https://github.com/brendanzab/codespan" documentation = "https://docs.rs/codespan-reporting" readme = "../README.md" license = "Apache-2.0" repository = "https://github.com/brendanzab/codespan" [dependencies.serde] version = "1" features = ["derive"] optional = true [dependencies.termcolor] version = "1" [dependencies.unicode-width] version = "0.1" [dev-dependencies.anyhow] version = "1" [dev-dependencies.insta] version = "1.6.3" [dev-dependencies.lazy_static] version = "1.4" [dev-dependencies.peg] version = "0.6" [dev-dependencies.rustyline] version = "6" [dev-dependencies.structopt] version = "0.3" [dev-dependencies.unindent] version = "0.1" [features] ascii-only = [] serialization = ["serde", "serde/rc"] codespan-reporting-0.11.1/Cargo.toml.orig000064400000000000000000000013720000000000000163560ustar 00000000000000[package] name = "codespan-reporting" version = "0.11.1" readme = "../README.md" license = "Apache-2.0" authors = ["Brendan Zabarauskas "] description = "Beautiful diagnostic reporting for text-based programming languages" homepage = "https://github.com/brendanzab/codespan" repository = "https://github.com/brendanzab/codespan" documentation = "https://docs.rs/codespan-reporting" exclude = ["assets/**"] edition = "2018" [dependencies] serde = { version = "1", optional = true, features = ["derive"] } termcolor = "1" unicode-width = "0.1" [dev-dependencies] anyhow = "1" insta = "1.6.3" lazy_static = "1.4" peg = "0.6" rustyline = "6" structopt = "0.3" unindent = "0.1" [features] serialization = ["serde", "serde/rc"] ascii-only = [] codespan-reporting-0.11.1/examples/custom_files.rs000064400000000000000000000140270000000000000203500ustar 00000000000000//! An example that shows how to implement a simple custom file database. //! The database uses 32-bit file-ids, which could be useful for optimizing //! memory usage. //! //! To run this example, execute the following command from the top level of //! this repository: //! //! ```sh //! cargo run --example custom_files //! ``` use codespan_reporting::diagnostic::{Diagnostic, Label}; use codespan_reporting::term; use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; use std::ops::Range; fn main() -> anyhow::Result<()> { let mut files = files::Files::new(); let file_id0 = files.add("0.greeting", "hello world!").unwrap(); let file_id1 = files.add("1.greeting", "bye world").unwrap(); let messages = vec![ Message::UnwantedGreetings { greetings: vec![(file_id0, 0..5), (file_id1, 0..3)], }, Message::OverTheTopExclamations { exclamations: vec![(file_id0, 11..12)], }, ]; let writer = StandardStream::stderr(ColorChoice::Always); let config = term::Config::default(); for message in &messages { let writer = &mut writer.lock(); term::emit(writer, &config, &files, &message.to_diagnostic())?; } Ok(()) } /// A module containing the file implementation mod files { use codespan_reporting::files; use std::ops::Range; /// A file that is backed by an `Arc`. #[derive(Debug, Clone)] struct File { /// The name of the file. name: String, /// The source code of the file. source: String, /// The starting byte indices in the source code. line_starts: Vec, } impl File { fn line_start(&self, line_index: usize) -> Result { use std::cmp::Ordering; match line_index.cmp(&self.line_starts.len()) { 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, }), } } } /// An opaque file identifier. #[derive(Copy, Clone, PartialEq, Eq)] pub struct FileId(u32); #[derive(Debug, Clone)] pub struct Files { files: Vec, } impl Files { /// Create a new files database. pub fn new() -> Files { Files { files: Vec::new() } } /// Add a file to the database, returning the handle that can be used to /// refer to it again. pub fn add( &mut self, name: impl Into, source: impl Into, ) -> Option { use std::convert::TryFrom; let file_id = FileId(u32::try_from(self.files.len()).ok()?); let name = name.into(); let source = source.into(); let line_starts = files::line_starts(&source).collect(); self.files.push(File { name, line_starts, source, }); Some(file_id) } /// Get the file corresponding to the given id. fn get(&self, file_id: FileId) -> Result<&File, files::Error> { self.files .get(file_id.0 as usize) .ok_or(files::Error::FileMissing) } } impl<'files> files::Files<'files> for Files { type FileId = FileId; type Name = &'files str; type Source = &'files str; fn name(&self, file_id: FileId) -> Result<&str, files::Error> { Ok(self.get(file_id)?.name.as_ref()) } 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) -> Result { 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, ) -> Result, 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)?; Ok(line_start..next_line_start) } } } /// A Diagnostic message. enum Message { UnwantedGreetings { greetings: Vec<(files::FileId, Range)>, }, OverTheTopExclamations { exclamations: Vec<(files::FileId, Range)>, }, } impl Message { fn to_diagnostic(&self) -> Diagnostic { match self { Message::UnwantedGreetings { greetings } => Diagnostic::error() .with_message("greetings are not allowed") .with_labels( greetings .iter() .map(|(file_id, range)| { Label::primary(*file_id, range.clone()).with_message("a greeting") }) .collect(), ) .with_notes(vec![ "found greetings!".to_owned(), "pleas no greetings :(".to_owned(), ]), Message::OverTheTopExclamations { exclamations } => Diagnostic::error() .with_message("over-the-top exclamations") .with_labels( exclamations .iter() .map(|(file_id, range)| { Label::primary(*file_id, range.clone()).with_message("an exclamation") }) .collect(), ) .with_notes(vec!["ridiculous!".to_owned()]), } } } codespan-reporting-0.11.1/examples/peg_calculator.rs000064400000000000000000000042340000000000000206370ustar 00000000000000//! An example of using `peg` with `codespan_reporting`. //! //! To run this example, execute the following command from the top level of //! this repository: //! //! ```sh //! cargo run --example peg_calculator //! ``` use codespan_reporting::diagnostic::{Diagnostic, Label}; use codespan_reporting::files::SimpleFile; use codespan_reporting::term; use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; use rustyline::error::ReadlineError; use rustyline::Editor; peg::parser! { grammar arithmetic() for str { rule number() -> i64 = n:$(['0'..='9']+) { n.parse().unwrap() } pub rule calculate() -> i64 = precedence!{ x:(@) "+" y:@ { x + y } x:(@) "-" y:@ { x - y } "-" v:@ { - v } -- x:(@) "*" y:@ { x * y } x:(@) "/" y:@ { x / y } -- x:@ "^" y:(@) { i64::pow(x, y as u32) } v:@ "!" { (1..v+1).product() } -- "(" v:calculate() ")" { v } n:number() { n } } } } fn main() -> anyhow::Result<()> { let writer = StandardStream::stderr(ColorChoice::Always); let config = codespan_reporting::term::Config::default(); let mut editor = Editor::<()>::new(); loop { let line = match editor.readline("> ") { Ok(line) => line, Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => return Ok(()), Err(error) => return Err(error.into()), }; match arithmetic::calculate(&line) { Ok(number) => println!("{}", number), Err(error) => { let file = SimpleFile::new("", line); let start = error.location.offset; let diagnostic = Diagnostic::error() .with_message("parse error") .with_labels(vec![ Label::primary((), start..start).with_message("parse error") ]) .with_notes(vec![format!("expected: {}", error.expected)]); term::emit(&mut writer.lock(), &config, &file, &diagnostic)?; } } } } codespan-reporting-0.11.1/examples/readme_preview.rs000064400000000000000000000251710000000000000206540ustar 00000000000000//! Renders the preview SVG for the README. //! //! To update the preview, execute the following command from the top level of //! the repository: //! //! ```sh //! cargo run --example readme_preview svg > codespan-reporting/assets/readme_preview.svg //! ``` use codespan_reporting::diagnostic::{Diagnostic, Label}; use codespan_reporting::files::SimpleFile; use codespan_reporting::term::termcolor::{Color, ColorSpec, StandardStream, WriteColor}; use codespan_reporting::term::{self, ColorArg}; use std::io::{self, Write}; use structopt::StructOpt; #[derive(Debug, StructOpt)] #[structopt(name = "emit")] pub enum Opts { /// Render SVG output Svg, /// Render Stderr output Stderr { /// Configure coloring of output #[structopt( long = "color", parse(try_from_str), default_value = "auto", possible_values = ColorArg::VARIANTS, case_insensitive = true )] color: ColorArg, }, } fn main() -> anyhow::Result<()> { let file = SimpleFile::new( "FizzBuzz.fun", unindent::unindent( r#" module FizzBuzz where fizz₁ : Nat → String fizz₁ num = case (mod num 5) (mod num 3) of 0 0 => "FizzBuzz" 0 _ => "Fizz" _ 0 => "Buzz" _ _ => num fizz₂ : Nat → String fizz₂ num = case (mod num 5) (mod num 3) of 0 0 => "FizzBuzz" 0 _ => "Fizz" _ 0 => "Buzz" _ _ => num "#, ), ); let diagnostics = [Diagnostic::error() .with_message("`case` clauses have incompatible types") .with_code("E0308") .with_labels(vec![ Label::primary((), 328..331).with_message("expected `String`, found `Nat`"), Label::secondary((), 211..331).with_message("`case` clauses have incompatible types"), Label::secondary((), 258..268).with_message("this is found to be of type `String`"), Label::secondary((), 284..290).with_message("this is found to be of type `String`"), Label::secondary((), 306..312).with_message("this is found to be of type `String`"), Label::secondary((), 186..192).with_message("expected type `String` found here"), ]) .with_notes(vec![unindent::unindent( " expected type `String` found type `Nat` ", )])]; // let mut files = SimpleFiles::new(); match Opts::from_args() { Opts::Svg => { let mut buffer = Vec::new(); let mut writer = HtmlEscapeWriter::new(SvgWriter::new(&mut buffer)); 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)?; } let num_lines = buffer.iter().filter(|byte| **byte == b'\n').count() + 1; let padding = 10; let font_size = 12; let line_spacing = 3; let width = 882; let height = padding + num_lines * (font_size + line_spacing) + padding; let stdout = std::io::stdout(); let writer = &mut stdout.lock(); write!( writer, r#"
"#,
                padding = padding,
                font_size = font_size,
                width = width,
                height = height,
            )?;

            writer.write_all(&buffer)?;

            write!(
                writer,
                "
" )?; } Opts::Stderr { color } => { let writer = StandardStream::stderr(color.into()); let config = codespan_reporting::term::Config::default(); for diagnostic in &diagnostics { term::emit(&mut writer.lock(), &config, &file, &diagnostic)?; } } } Ok(()) } /// Rudimentary HTML escaper which performs the following conversions: /// /// - `<` ⇒ `<` /// - `>` ⇒ `>` /// - `&` ⇒ `&` pub struct HtmlEscapeWriter { upstream: W, } impl HtmlEscapeWriter { pub fn new(upstream: W) -> HtmlEscapeWriter { HtmlEscapeWriter { upstream } } } impl Write for HtmlEscapeWriter { fn write(&mut self, buf: &[u8]) -> io::Result { let mut last_term = 0usize; for (i, byte) in buf.iter().enumerate() { let escape = match byte { b'<' => &b"<"[..], b'>' => &b">"[..], b'&' => &b"&"[..], _ => continue, }; self.upstream.write_all(&buf[last_term..i])?; last_term = i + 1; self.upstream.write_all(escape)?; } self.upstream.write_all(&buf[last_term..])?; Ok(buf.len()) } fn flush(&mut self) -> io::Result<()> { self.upstream.flush() } } impl WriteColor for HtmlEscapeWriter { fn supports_color(&self) -> bool { self.upstream.supports_color() } fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { self.upstream.set_color(spec) } fn reset(&mut self) -> io::Result<()> { self.upstream.reset() } } pub struct SvgWriter { upstream: W, color: ColorSpec, } impl SvgWriter { pub fn new(upstream: W) -> SvgWriter { SvgWriter { upstream, color: ColorSpec::new(), } } } impl Write for SvgWriter { fn write(&mut self, buf: &[u8]) -> io::Result { self.upstream.write(buf) } fn flush(&mut self) -> io::Result<()> { self.upstream.flush() } } impl WriteColor for SvgWriter { fn supports_color(&self) -> bool { true } fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { #![allow(unused_assignments)] if self.color == *spec { return Ok(()); } else { if !self.color.is_none() { write!(self, "")?; } self.color = spec.clone(); } if spec.is_none() { write!(self, "")?; return Ok(()); } else { write!(self, "(first: bool, writer: &mut SvgWriter) -> io::Result { if !first { write!(writer, " ")?; } Ok(false) }; fn write_color(color: &Color, writer: &mut SvgWriter) -> io::Result<()> { match color { Color::Black => write!(writer, "black"), Color::Blue => write!(writer, "blue"), Color::Green => write!(writer, "green"), Color::Red => write!(writer, "red"), Color::Cyan => write!(writer, "cyan"), Color::Magenta => write!(writer, "magenta"), Color::Yellow => write!(writer, "yellow"), Color::White => write!(writer, "white"), // TODO: other colors _ => Ok(()), } }; if let Some(fg) = spec.fg() { first = write_first(first, self)?; write!(self, "fg ")?; write_color(fg, self)?; } if let Some(bg) = spec.bg() { first = write_first(first, self)?; write!(self, "bg ")?; write_color(bg, self)?; } if spec.bold() { first = write_first(first, self)?; write!(self, "bold")?; } if spec.underline() { first = write_first(first, self)?; write!(self, "underline")?; } if spec.intense() { first = write_first(first, self)?; write!(self, "bright")?; } write!(self, "\">")?; Ok(()) } fn reset(&mut self) -> io::Result<()> { let color = self.color.clone(); if color != ColorSpec::new() { write!(self, "")?; self.color = ColorSpec::new(); } Ok(()) } } codespan-reporting-0.11.1/examples/reusable_diagnostic.rs000064400000000000000000000065660000000000000216730ustar 00000000000000use codespan_reporting::diagnostic::{Diagnostic, Label}; use codespan_reporting::files::SimpleFile; use codespan_reporting::term::termcolor::StandardStream; use codespan_reporting::term::{self, ColorArg}; use std::ops::Range; use structopt::StructOpt; #[derive(Debug, StructOpt)] #[structopt(name = "emit")] pub struct Opts { #[structopt(long = "color", parse(try_from_str), default_value = "auto", possible_values = ColorArg::VARIANTS, case_insensitive = true )] color: ColorArg, } fn main() -> anyhow::Result<()> { let file = SimpleFile::new( "main.rs", unindent::unindent( r#" fn main() { let foo: i32 = "hello, world"; foo += 1; } "#, ), ); let errors = [ Error::MismatchType( Item::new(20..23, "i32"), Item::new(31..45, "\"hello, world\""), ), Error::MutatingImmutable(Item::new(20..23, "foo"), Item::new(51..59, "foo += 1")), ]; let opts = Opts::from_args(); let writer = StandardStream::stderr(opts.color.into()); let config = codespan_reporting::term::Config::default(); for diagnostic in errors.iter().map(Error::report) { term::emit(&mut writer.lock(), &config, &file, &diagnostic)?; } Ok(()) } /// An error enum that represent all possible errors within your program enum Error { MismatchType(Item, Item), MutatingImmutable(Item, Item), } impl Error { fn report(&self) -> Diagnostic<()> { match self { Error::MismatchType(left, right) => Diagnostic::error() .with_code("E0308") .with_message("mismatch types") .with_labels(vec![ Label::primary((), right.range.clone()).with_message(format!( "Expected `{}`, found: `{}`", left.content, right.content, )), Label::secondary((), left.range.clone()).with_message("expected due to this"), ]), Error::MutatingImmutable(original, mutating) => Diagnostic::error() .with_code("E0384") .with_message(format!( "cannot mutate immutable variable `{}`", original.content, )) .with_labels(vec![ Label::secondary((), original.range.clone()).with_message(unindent::unindent( &format!( r#" first assignment to `{0}` help: make this binding mutable: `mut {0}` "#, original.content, ), )), Label::primary((), mutating.range.clone()) .with_message("cannot assign twice to immutable variable"), ]), } } } /// An item in the source code to be used in the `Error` enum. /// In a more complex program it could also contain a `files::FileId` to handle errors that occur inside multiple files. struct Item { range: Range, content: String, } impl Item { fn new(range: Range, content: impl Into) -> Item { let content = content.into(); Item { range, content } } } codespan-reporting-0.11.1/examples/term.rs000064400000000000000000000134170000000000000166250ustar 00000000000000//! To run this example, execute the following command from the top level of //! this repository: //! //! ```sh //! cargo run --example term //! ``` use codespan_reporting::diagnostic::{Diagnostic, Label}; use codespan_reporting::files::SimpleFiles; use codespan_reporting::term::termcolor::StandardStream; use codespan_reporting::term::{self, ColorArg}; use structopt::StructOpt; #[derive(Debug, StructOpt)] #[structopt(name = "emit")] pub struct Opts { /// Configure coloring of output #[structopt( long = "color", parse(try_from_str), default_value = "auto", possible_values = ColorArg::VARIANTS, case_insensitive = true )] pub color: ColorArg, } fn main() -> anyhow::Result<()> { let opts = Opts::from_args(); let mut files = SimpleFiles::new(); let file_id1 = files.add( "Data/Nat.fun", unindent::unindent( " module Data.Nat where data Nat : Type where zero : Nat succ : Nat → Nat {-# BUILTIN NATRAL Nat #-} infixl 6 _+_ _-_ _+_ : Nat → Nat → Nat zero + n₂ = n₂ succ n₁ + n₂ = succ (n₁ + n₂) _-_ : Nat → Nat → Nat n₁ - zero = n₁ zero - succ n₂ = zero succ n₁ - succ n₂ = n₁ - n₂ ", ), ); let file_id2 = files.add( "Test.fun", unindent::unindent( r#" module Test where _ : Nat _ = 123 + "hello" "#, ), ); let file_id3 = files.add( "FizzBuzz.fun", unindent::unindent( r#" module FizzBuzz where fizz₁ : Nat → String fizz₁ num = case (mod num 5) (mod num 3) of 0 0 => "FizzBuzz" 0 _ => "Fizz" _ 0 => "Buzz" _ _ => num fizz₂ : Nat → String fizz₂ num = case (mod num 5) (mod num 3) of 0 0 => "FizzBuzz" 0 _ => "Fizz" _ 0 => "Buzz" _ _ => num "#, ), ); let diagnostics = [ // Unknown builtin error Diagnostic::error() .with_message("unknown builtin: `NATRAL`") .with_labels(vec![ Label::primary(file_id1, 96..102).with_message("unknown builtin") ]) .with_notes(vec![ "there is a builtin with a similar name: `NATURAL`".to_owned() ]), // Unused parameter warning Diagnostic::warning() .with_message("unused parameter pattern: `n₂`") .with_labels(vec![ Label::primary(file_id1, 285..289).with_message("unused parameter") ]) .with_notes(vec!["consider using a wildcard pattern: `_`".to_owned()]), // Unexpected type error Diagnostic::error() .with_message("unexpected type in application of `_+_`") .with_code("E0001") .with_labels(vec![ Label::primary(file_id2, 37..44).with_message("expected `Nat`, found `String`"), Label::secondary(file_id1, 130..155) .with_message("based on the definition of `_+_`"), ]) .with_notes(vec![unindent::unindent( " expected type `Nat` found type `String` ", )]), // Incompatible match clause error Diagnostic::error() .with_message("`case` clauses have incompatible types") .with_code("E0308") .with_labels(vec![ Label::primary(file_id3, 163..166).with_message("expected `String`, found `Nat`"), Label::secondary(file_id3, 62..166) .with_message("`case` clauses have incompatible types"), Label::secondary(file_id3, 41..47) .with_message("expected type `String` found here"), ]) .with_notes(vec![unindent::unindent( " expected type `String` found type `Nat` ", )]), // Incompatible match clause error Diagnostic::error() .with_message("`case` clauses have incompatible types") .with_code("E0308") .with_labels(vec![ Label::primary(file_id3, 328..331).with_message("expected `String`, found `Nat`"), Label::secondary(file_id3, 211..331) .with_message("`case` clauses have incompatible types"), Label::secondary(file_id3, 258..268) .with_message("this is found to be of type `String`"), Label::secondary(file_id3, 284..290) .with_message("this is found to be of type `String`"), Label::secondary(file_id3, 306..312) .with_message("this is found to be of type `String`"), Label::secondary(file_id3, 186..192) .with_message("expected type `String` found here"), ]) .with_notes(vec![unindent::unindent( " expected type `String` found type `Nat` ", )]), ]; let writer = StandardStream::stderr(opts.color.into()); let config = codespan_reporting::term::Config::default(); for diagnostic in &diagnostics { term::emit(&mut writer.lock(), &config, &files, &diagnostic)?; } Ok(()) } codespan-reporting-0.11.1/src/diagnostic.rs000064400000000000000000000152270000000000000167540ustar 00000000000000//! Diagnostic data structures. #[cfg(feature = "serialization")] use serde::{Deserialize, Serialize}; use std::ops::Range; /// A severity level for diagnostic messages. /// /// These are ordered in the following way: /// /// ```rust /// use codespan_reporting::diagnostic::Severity; /// /// assert!(Severity::Bug > Severity::Error); /// assert!(Severity::Error > Severity::Warning); /// assert!(Severity::Warning > Severity::Note); /// assert!(Severity::Note > Severity::Help); /// ``` #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))] pub enum Severity { /// An unexpected bug. Bug, /// An error. Error, /// A warning. Warning, /// A note. Note, /// A help message. Help, } impl Severity { /// We want bugs to be the maximum severity, errors next, etc... fn to_cmp_int(self) -> u8 { match self { Severity::Bug => 5, Severity::Error => 4, Severity::Warning => 3, Severity::Note => 2, Severity::Help => 1, } } } impl PartialOrd for Severity { fn partial_cmp(&self, other: &Severity) -> Option { u8::partial_cmp(&self.to_cmp_int(), &other.to_cmp_int()) } } #[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. Primary, /// Labels that provide additional context for a diagnostic. Secondary, } /// A label describing an underlined region of code associated with a diagnostic. #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))] pub struct Label { /// The style of the label. pub style: LabelStyle, /// The file that we are labelling. pub file_id: FileId, /// The range in bytes we are going to include in the final snippet. pub range: Range, /// An optional message to provide some additional information for the /// underlined code. These should not include line breaks. pub message: String, } impl Label { /// Create a new label. pub fn new( style: LabelStyle, file_id: FileId, range: impl Into>, ) -> Label { Label { style, file_id, range: range.into(), message: String::new(), } } /// Create a new label with a style of [`LabelStyle::Primary`]. /// /// [`LabelStyle::Primary`]: LabelStyle::Primary pub fn primary(file_id: FileId, range: impl Into>) -> Label { Label::new(LabelStyle::Primary, file_id, range) } /// Create a new label with a style of [`LabelStyle::Secondary`]. /// /// [`LabelStyle::Secondary`]: LabelStyle::Secondary pub fn secondary(file_id: FileId, range: impl Into>) -> Label { Label::new(LabelStyle::Secondary, file_id, range) } /// Add a message to the diagnostic. pub fn with_message(mut self, message: impl Into) -> Label { self.message = message.into(); self } } /// Represents a diagnostic message that can provide information like errors and /// warnings to the user. /// /// 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 { /// The overall severity of the diagnostic pub severity: Severity, /// An optional code that identifies this diagnostic. pub code: Option, /// The main message associated with this diagnostic. /// /// These should not include line breaks, and in order support the 'short' /// diagnostic display mod, the message should be specific enough to make /// 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>, /// Notes that are associated with the primary cause of the diagnostic. /// These can include line breaks for improved formatting. pub notes: Vec, } impl Diagnostic { /// Create a new diagnostic. pub fn new(severity: Severity) -> Diagnostic { Diagnostic { severity, code: None, message: String::new(), labels: Vec::new(), notes: Vec::new(), } } /// Create a new diagnostic with a severity of [`Severity::Bug`]. /// /// [`Severity::Bug`]: Severity::Bug pub fn bug() -> Diagnostic { Diagnostic::new(Severity::Bug) } /// Create a new diagnostic with a severity of [`Severity::Error`]. /// /// [`Severity::Error`]: Severity::Error pub fn error() -> Diagnostic { Diagnostic::new(Severity::Error) } /// Create a new diagnostic with a severity of [`Severity::Warning`]. /// /// [`Severity::Warning`]: Severity::Warning pub fn warning() -> Diagnostic { Diagnostic::new(Severity::Warning) } /// Create a new diagnostic with a severity of [`Severity::Note`]. /// /// [`Severity::Note`]: Severity::Note pub fn note() -> Diagnostic { Diagnostic::new(Severity::Note) } /// Create a new diagnostic with a severity of [`Severity::Help`]. /// /// [`Severity::Help`]: Severity::Help pub fn help() -> Diagnostic { Diagnostic::new(Severity::Help) } /// Set the error code of the diagnostic. pub fn with_code(mut self, code: impl Into) -> Diagnostic { self.code = Some(code.into()); self } /// Set the message of the diagnostic. pub fn with_message(mut self, message: impl Into) -> Diagnostic { self.message = message.into(); self } /// Add some labels to the diagnostic. pub fn with_labels(mut self, mut labels: Vec>) -> Diagnostic { self.labels.append(&mut labels); self } /// Add some notes to the diagnostic. pub fn with_notes(mut self, mut notes: Vec) -> Diagnostic { self.notes.append(&mut notes); self } } codespan-reporting-0.11.1/src/files.rs000064400000000000000000000353530000000000000157340ustar 00000000000000//! Source file support for diagnostic reporting. //! //! The main trait defined in this module is the [`Files`] trait, which provides //! provides the minimum amount of functionality required for printing [`Diagnostics`] //! with the [`term::emit`] function. //! //! Simple implementations of this trait are implemented: //! //! - [`SimpleFile`]: 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 //! own specific use-cases, such as an implementation that accesses the file //! system directly (and caches the line start locations), or an implementation //! using an incremental compilation library like [`salsa`]. //! //! [`term::emit`]: crate::term::emit //! [`Diagnostics`]: crate::diagnostic::Diagnostic //! [`Files`]: Files //! [`SimpleFile`]: SimpleFile //! [`SimpleFiles`]: SimpleFiles //! //! [`salsa`]: https://crates.io/crates/salsa 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 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. /// This is to workaround the lack of higher kinded lifetime parameters. /// This can be ignored if this is not needed, however. pub trait Files<'a> { /// A unique identifier for files in the file provider. This will be used /// for rendering `diagnostic::Label`s in the corresponding source files. type FileId: 'a + Copy + PartialEq; /// The user-facing name of a file, to be displayed in diagnostics. type Name: 'a + std::fmt::Display; /// The source code of a file. type Source: 'a + AsRef; /// The user-facing name of a file. fn name(&'a self, id: Self::FileId) -> Result; /// The source code of a file. fn source(&'a self, id: Self::FileId) -> Result; /// 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 /// /// This can be implemented efficiently by performing a binary search over /// a list of line starts that was computed by calling the [`line_starts`] /// function that is exported from the [`files`] module. It might be useful /// to pre-compute and cache these line starts. /// /// [`line_starts`]: crate::files::line_starts /// [`files`]: crate::files fn line_index(&'a self, id: Self::FileId, byte_index: usize) -> Result; /// 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 /// /// This is usually 1-indexed from the beginning of the file, but /// can be useful for implementing something like the /// [C preprocessor's `#line` macro][line-macro]. /// /// [line-macro]: https://en.cppreference.com/w/c/preprocessor/line #[allow(unused_variables)] fn line_number(&'a self, id: Self::FileId, line_index: usize) -> Result { Ok(line_index + 1) } /// The user-facing column number at the given line index and byte index. /// /// # Note for trait implementors /// /// This is usually 1-indexed from the the start of the line. /// A default implementation is provided, based on the [`column_index`] /// function that is exported from the [`files`] module. /// /// [`files`]: crate::files /// [`column_index`]: crate::files::column_index fn column_number( &'a self, id: Self::FileId, line_index: usize, byte_index: usize, ) -> Result { 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); Ok(column_index + 1) } /// 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) -> Result { let line_index = self.line_index(id, byte_index)?; 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) -> Result, Error>; } /// A user-facing location in a source file. /// /// Returned by [`Files::location`]. /// /// [`Files::location`]: Files::location #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct Location { /// The user-facing line number. pub line_number: usize, /// The user-facing column number. pub column_number: usize, } /// The column index at the given byte index in the source file. /// This is the number of characters to the given byte index. /// /// If the byte index is smaller than the start of the line, then `0` is returned. /// If the byte index is past the end of the line, the column index of the last /// character `+ 1` is returned. /// /// # Example /// /// ```rust /// use codespan_reporting::files; /// /// let source = "\n\n🗻∈🌏\n\n"; /// /// assert_eq!(files::column_index(source, 0..1, 0), 0); /// assert_eq!(files::column_index(source, 2..13, 0), 0); /// assert_eq!(files::column_index(source, 2..13, 2 + 0), 0); /// assert_eq!(files::column_index(source, 2..13, 2 + 1), 0); /// assert_eq!(files::column_index(source, 2..13, 2 + 4), 1); /// assert_eq!(files::column_index(source, 2..13, 2 + 8), 2); /// assert_eq!(files::column_index(source, 2..13, 2 + 10), 2); /// assert_eq!(files::column_index(source, 2..13, 2 + 11), 3); /// assert_eq!(files::column_index(source, 2..13, 2 + 12), 3); /// ``` pub fn column_index(source: &str, line_range: Range, byte_index: usize) -> usize { let end_index = std::cmp::min(byte_index, std::cmp::min(line_range.end, source.len())); (line_range.start..end_index) .filter(|byte_index| source.is_char_boundary(byte_index + 1)) .count() } /// Return the starting byte index of each line in the source string. /// /// This can make it easier to implement [`Files::line_index`] by allowing /// implementors of [`Files`] to pre-compute the line starts, then search for /// the corresponding line range, as shown in the example below. /// /// [`Files`]: Files /// [`Files::line_index`]: Files::line_index /// /// # Example /// /// ```rust /// use codespan_reporting::files; /// /// let source = "foo\nbar\r\n\nbaz"; /// let line_starts: Vec<_> = files::line_starts(source).collect(); /// /// assert_eq!( /// line_starts, /// [ /// 0, // "foo\n" /// 4, // "bar\r\n" /// 9, // "" /// 10, // "baz" /// ], /// ); /// /// fn line_index(line_starts: &[usize], byte_index: usize) -> Option { /// match line_starts.binary_search(&byte_index) { /// Ok(line) => Some(line), /// Err(next_line) => Some(next_line - 1), /// } /// } /// /// assert_eq!(line_index(&line_starts, 5), Some(1)); /// ``` // NOTE: this is copied in `codespan::file::line_starts` and should be kept in sync. pub fn line_starts<'source>(source: &'source str) -> impl 'source + Iterator { std::iter::once(0).chain(source.match_indices('\n').map(|(i, _)| i + 1)) } /// A file database that contains a single source file. /// /// Because there is only single file in this database we use `()` as a [`FileId`]. /// /// This is useful for simple language tests, but it might be worth creating a /// custom implementation when a language scales beyond a certain size. /// /// [`FileId`]: Files::FileId #[derive(Debug, Clone)] pub struct SimpleFile { /// The name of the file. name: Name, /// The source code of the file. source: Source, /// The starting byte indices in the source code. line_starts: Vec, } impl SimpleFile where Name: std::fmt::Display, Source: AsRef, { /// Create a new source file. pub fn new(name: Name, source: Source) -> SimpleFile { SimpleFile { name, line_starts: line_starts(source.as_ref()).collect(), source, } } /// Return the name of the file. pub fn name(&self) -> &Name { &self.name } /// Return the source of the file. pub fn source(&self) -> &Source { &self.source } /// 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 { use std::cmp::Ordering; match line_index.cmp(&self.line_starts.len()) { 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, }), } } } impl<'a, Name, Source> Files<'a> for SimpleFile where Name: 'a + std::fmt::Display + Clone, Source: 'a + AsRef, { type FileId = (); type Name = Name; type Source = &'a str; fn name(&self, (): ()) -> Result { Ok(self.name.clone()) } fn source(&self, (): ()) -> Result<&str, Error> { Ok(self.source.as_ref()) } fn line_index(&self, (): (), byte_index: usize) -> Result { Ok(self .line_starts .binary_search(&byte_index) .unwrap_or_else(|next_line| next_line - 1)) } fn line_range(&self, (): (), line_index: usize) -> Result, Error> { let line_start = self.line_start(line_index)?; let next_line_start = self.line_start(line_index + 1)?; Ok(line_start..next_line_start) } } /// A file database that can store multiple source files. /// /// 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` that implements the `Files` trait. #[derive(Debug, Clone)] pub struct SimpleFiles { files: Vec>, } impl SimpleFiles where Name: std::fmt::Display, Source: AsRef, { /// Create a new files database. pub fn new() -> SimpleFiles { SimpleFiles { files: Vec::new() } } /// Add a file to the database, returning the handle that can be used to /// refer to it again. pub fn add(&mut self, name: Name, source: Source) -> usize { let file_id = self.files.len(); self.files.push(SimpleFile::new(name, source)); file_id } /// Get the file corresponding to the given id. pub fn get(&self, file_id: usize) -> Result<&SimpleFile, Error> { self.files.get(file_id).ok_or(Error::FileMissing) } } impl<'a, Name, Source> Files<'a> for SimpleFiles where Name: 'a + std::fmt::Display + Clone, Source: 'a + AsRef, { type FileId = usize; type Name = Name; type Source = &'a str; fn name(&self, file_id: usize) -> Result { Ok(self.get(file_id)?.name().clone()) } 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) -> Result { self.get(file_id)?.line_index((), byte_index) } fn line_range(&self, file_id: usize, line_index: usize) -> Result, Error> { self.get(file_id)?.line_range((), line_index) } } #[cfg(test)] mod test { use super::*; const TEST_SOURCE: &str = "foo\nbar\r\n\nbaz"; #[test] fn line_starts() { let file = SimpleFile::new("test", TEST_SOURCE); assert_eq!( file.line_starts, [ 0, // "foo\n" 4, // "bar\r\n" 9, // "" 10, // "baz" ], ); } #[test] fn line_span_sources() { let file = SimpleFile::new("test", TEST_SOURCE); let line_sources = (0..4) .map(|line| { let line_range = file.line_range((), line).unwrap(); &file.source[line_range] }) .collect::>(); assert_eq!(line_sources, ["foo\n", "bar\r\n", "\n", "baz"]); } } codespan-reporting-0.11.1/src/lib.rs000064400000000000000000000002040000000000000153630ustar 00000000000000//! Diagnostic reporting support for the codespan crate. #![forbid(unsafe_code)] pub mod diagnostic; pub mod files; pub mod term; codespan-reporting-0.11.1/src/term/config.rs000064400000000000000000000270300000000000000170370ustar 00000000000000use termcolor::{Color, ColorSpec}; use crate::diagnostic::{LabelStyle, Severity}; /// Configures how a diagnostic is rendered. #[derive(Clone, Debug)] pub struct Config { /// The display style to use when rendering diagnostics. /// Defaults to: [`DisplayStyle::Rich`]. /// /// [`DisplayStyle::Rich`]: DisplayStyle::Rich pub display_style: DisplayStyle, /// Column width of tabs. /// Defaults to: `4`. pub tab_width: usize, /// Styles to use when rendering the diagnostic. 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`. /// /// [`Label`]: crate::diagnostic::Label 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`. /// /// [`Label`]: crate::diagnostic::Label pub end_context_lines: usize, } impl Default for Config { fn default() -> Config { Config { display_style: DisplayStyle::Rich, tab_width: 4, styles: Styles::default(), chars: Chars::default(), start_context_lines: 3, end_context_lines: 1, } } } /// The display style to use when rendering diagnostics. #[derive(Clone, Debug)] pub enum DisplayStyle { /// Output a richly formatted diagnostic, with source code previews. /// /// ```text /// error[E0001]: unexpected type in `+` application /// ┌─ test:2:9 /// │ /// 2 │ (+ test "") /// │ ^^ expected `Int` but found `String` /// │ /// = expected type `Int` /// found type `String` /// /// error[E0002]: Bad config found /// /// ``` 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 /// test:2:9: error[E0001]: unexpected type in `+` application /// error[E0002]: Bad config found /// ``` Short, } /// Styles to use when rendering the diagnostic. #[derive(Clone, Debug)] pub struct Styles { /// The style to use when rendering bug headers. /// Defaults to `fg:red bold intense`. pub header_bug: ColorSpec, /// The style to use when rendering error headers. /// Defaults to `fg:red bold intense`. pub header_error: ColorSpec, /// The style to use when rendering warning headers. /// Defaults to `fg:yellow bold intense`. pub header_warning: ColorSpec, /// The style to use when rendering note headers. /// Defaults to `fg:green bold intense`. pub header_note: ColorSpec, /// The style to use when rendering help headers. /// Defaults to `fg:cyan bold intense`. pub header_help: ColorSpec, /// The style to use when the main diagnostic message. /// Defaults to `bold intense`. pub header_message: ColorSpec, /// The style to use when rendering bug labels. /// Defaults to `fg:red`. pub primary_label_bug: ColorSpec, /// The style to use when rendering error labels. /// Defaults to `fg:red`. pub primary_label_error: ColorSpec, /// The style to use when rendering warning labels. /// Defaults to `fg:yellow`. pub primary_label_warning: ColorSpec, /// The style to use when rendering note labels. /// Defaults to `fg:green`. pub primary_label_note: ColorSpec, /// The style to use when rendering help labels. /// Defaults to `fg:cyan`. pub primary_label_help: ColorSpec, /// The style to use when rendering secondary labels. /// Defaults `fg:blue` (or `fg:cyan` on windows). pub secondary_label: ColorSpec, /// The style to use when rendering the line numbers. /// Defaults `fg:blue` (or `fg:cyan` on windows). pub line_number: ColorSpec, /// The style to use when rendering the source code borders. /// Defaults `fg:blue` (or `fg:cyan` on windows). pub source_border: ColorSpec, /// The style to use when rendering the note bullets. /// Defaults `fg:blue` (or `fg:cyan` on windows). pub note_bullet: ColorSpec, } impl Styles { /// The style used to mark a header at a given severity. pub fn header(&self, severity: Severity) -> &ColorSpec { match severity { Severity::Bug => &self.header_bug, Severity::Error => &self.header_error, Severity::Warning => &self.header_warning, Severity::Note => &self.header_note, Severity::Help => &self.header_help, } } /// The style used to mark a primary or secondary label at a given severity. pub fn label(&self, severity: Severity, label_style: LabelStyle) -> &ColorSpec { match (label_style, severity) { (LabelStyle::Primary, Severity::Bug) => &self.primary_label_bug, (LabelStyle::Primary, Severity::Error) => &self.primary_label_error, (LabelStyle::Primary, Severity::Warning) => &self.primary_label_warning, (LabelStyle::Primary, Severity::Note) => &self.primary_label_note, (LabelStyle::Primary, Severity::Help) => &self.primary_label_help, (LabelStyle::Secondary, _) => &self.secondary_label, } } #[doc(hidden)] pub fn with_blue(blue: Color) -> Styles { let header = ColorSpec::new().set_bold(true).set_intense(true).clone(); Styles { header_bug: header.clone().set_fg(Some(Color::Red)).clone(), header_error: header.clone().set_fg(Some(Color::Red)).clone(), header_warning: header.clone().set_fg(Some(Color::Yellow)).clone(), header_note: header.clone().set_fg(Some(Color::Green)).clone(), header_help: header.clone().set_fg(Some(Color::Cyan)).clone(), header_message: header, primary_label_bug: ColorSpec::new().set_fg(Some(Color::Red)).clone(), primary_label_error: ColorSpec::new().set_fg(Some(Color::Red)).clone(), primary_label_warning: ColorSpec::new().set_fg(Some(Color::Yellow)).clone(), primary_label_note: ColorSpec::new().set_fg(Some(Color::Green)).clone(), primary_label_help: ColorSpec::new().set_fg(Some(Color::Cyan)).clone(), secondary_label: ColorSpec::new().set_fg(Some(blue)).clone(), line_number: ColorSpec::new().set_fg(Some(blue)).clone(), source_border: ColorSpec::new().set_fg(Some(blue)).clone(), note_bullet: ColorSpec::new().set_fg(Some(blue)).clone(), } } } impl Default for Styles { fn default() -> Styles { // Blue is really difficult to see on the standard windows command line #[cfg(windows)] const BLUE: Color = Color::Cyan; #[cfg(not(windows))] const BLUE: Color = Color::Blue; Self::with_blue(BLUE) } } /// Characters to use when rendering the diagnostic. /// /// By using [`Chars::ascii()`] you can switch to an ASCII-only format suitable /// for rendering on terminals that do not support box drawing characters. #[derive(Clone, Debug)] pub struct Chars { /// The characters to use for the top-left border of the snippet. /// Defaults to: `"┌─"` or `"-->"` with [`Chars::ascii()`]. pub snippet_start: String, /// The character to use for the left border of the source. /// Defaults to: `'│'` or `'|'` with [`Chars::ascii()`]. pub source_border_left: char, /// The character to use for the left border break of the source. /// Defaults to: `'·'` or `'.'` with [`Chars::ascii()`]. pub source_border_left_break: char, /// The character to use for the note bullet. /// Defaults to: `'='`. pub note_bullet: char, /// The character to use for marking a single-line primary label. /// Defaults to: `'^'`. pub single_primary_caret: char, /// The character to use for marking a single-line secondary label. /// Defaults to: `'-'`. pub single_secondary_caret: char, /// The character to use for marking the start of a multi-line primary label. /// Defaults to: `'^'`. pub multi_primary_caret_start: char, /// The character to use for marking the end of a multi-line primary label. /// Defaults to: `'^'`. pub multi_primary_caret_end: char, /// The character to use for marking the start of a multi-line secondary label. /// Defaults to: `'\''`. pub multi_secondary_caret_start: char, /// The character to use for marking the end of a multi-line secondary label. /// Defaults to: `'\''`. pub multi_secondary_caret_end: char, /// The character to use for the top-left corner of a multi-line label. /// Defaults to: `'╭'` or `'/'` with [`Chars::ascii()`]. pub multi_top_left: char, /// The character to use for the top of a multi-line label. /// Defaults to: `'─'` or `'-'` with [`Chars::ascii()`]. pub multi_top: char, /// The character to use for the bottom-left corner of a multi-line label. /// Defaults to: `'╰'` or `'\'` with [`Chars::ascii()`]. pub multi_bottom_left: char, /// The character to use when marking the bottom of a multi-line label. /// Defaults to: `'─'` or `'-'` with [`Chars::ascii()`]. pub multi_bottom: char, /// The character to use for the left of a multi-line label. /// Defaults to: `'│'` or `'|'` with [`Chars::ascii()`]. pub multi_left: char, /// The character to use for the left of a pointer underneath a caret. /// Defaults to: `'│'` or `'|'` with [`Chars::ascii()`]. pub pointer_left: char, } impl Default for Chars { fn default() -> Chars { Chars::box_drawing() } } impl Chars { /// A character set that uses Unicode box drawing characters. pub fn box_drawing() -> Chars { Chars { snippet_start: "┌─".into(), source_border_left: '│', source_border_left_break: '·', note_bullet: '=', single_primary_caret: '^', single_secondary_caret: '-', multi_primary_caret_start: '^', multi_primary_caret_end: '^', multi_secondary_caret_start: '\'', multi_secondary_caret_end: '\'', multi_top_left: '╭', multi_top: '─', multi_bottom_left: '╰', multi_bottom: '─', multi_left: '│', pointer_left: '│', } } /// A character set that only uses ASCII characters. /// /// This is useful if your terminal's font does not support box drawing /// characters well and results in output that looks similar to rustc's /// diagnostic output. pub fn ascii() -> Chars { Chars { snippet_start: "-->".into(), source_border_left: '|', source_border_left_break: '.', note_bullet: '=', single_primary_caret: '^', single_secondary_caret: '-', multi_primary_caret_start: '^', multi_primary_caret_end: '^', multi_secondary_caret_start: '\'', multi_secondary_caret_end: '\'', multi_top_left: '/', multi_top: '-', multi_bottom_left: '\\', multi_bottom: '-', multi_left: '|', pointer_left: '|', } } } codespan-reporting-0.11.1/src/term/renderer.rs000064400000000000000000001115130000000000000174000ustar 00000000000000use std::io::{self, Write}; use std::ops::Range; use termcolor::{ColorSpec, WriteColor}; use crate::diagnostic::{LabelStyle, Severity}; use crate::files::{Error, Location}; use crate::term::{Chars, Config, Styles}; /// The 'location focus' of a source code snippet. pub struct Locus { /// The user-facing name of the file. pub name: String, /// The location. pub location: Location, } /// Single-line label, with an optional message. /// /// ```text /// ^^^^^^^^^ blah blah /// ``` pub type SingleLabel<'diagnostic> = (LabelStyle, Range, &'diagnostic str); /// A multi-line label to render. /// /// Locations are relative to the start of where the source code is rendered. pub enum MultiLabel<'diagnostic> { /// Multi-line label top. /// The contained value indicates where the label starts. /// /// ```text /// ╭────────────^ /// ``` /// /// 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 /// │ /// ``` Left, /// Multi-line label bottom, with an optional message. /// The first value indicates where the label ends. /// /// ```text /// ╰────────────^ blah blah /// ``` Bottom(usize, &'diagnostic str), } #[derive(Copy, Clone)] enum VerticalBound { Top, Bottom, } type Underline = (LabelStyle, VerticalBound); /// A renderer of display list entries. /// /// The following diagram gives an overview of each of the parts of the renderer's output: /// /// ```text /// ┌ outer gutter /// │ ┌ left border /// │ │ ┌ inner gutter /// │ │ │ ┌─────────────────────────── source ─────────────────────────────┐ /// │ │ │ │ │ /// ┌──────────────────────────────────────────────────────────────────────────── /// header ── │ error[0001]: oh noes, a cupcake has occurred! /// snippet start ── │ ┌─ test:9:0 /// snippet empty ── │ │ /// snippet line ── │ 9 │ ╭ Cupcake ipsum dolor. Sit amet marshmallow topping cheesecake /// snippet line ── │ 10 │ │ muffin. Halvah croissant candy canes bonbon candy. Apple pie jelly /// │ │ ╭─│─────────^ /// snippet break ── │ · │ │ /// snippet line ── │ 33 │ │ │ Muffin danish chocolate soufflé pastry icing bonbon oat cake. /// snippet line ── │ 34 │ │ │ Powder cake jujubes oat cake. Lemon drops tootsie roll marshmallow /// │ │ │ ╰─────────────────────────────^ blah blah /// snippet break ── │ · │ /// snippet line ── │ 38 │ │ Brownie lemon drops chocolate jelly-o candy canes. Danish marzipan /// snippet line ── │ 39 │ │ jujubes soufflé carrot cake marshmallow tiramisu caramels candy canes. /// │ │ │ ^^^^^^^^^^^^^^^^^^^ -------------------- blah blah /// │ │ │ │ /// │ │ │ blah blah /// │ │ │ note: this is a note /// snippet line ── │ 40 │ │ Fruitcake jelly-o danish toffee. Tootsie roll pastry cheesecake /// snippet line ── │ 41 │ │ soufflé marzipan. Chocolate bar oat cake jujubes lollipop pastry /// snippet line ── │ 42 │ │ cupcake. Candy canes cupcake toffee gingerbread candy canes muffin /// │ │ │ ^^^^^^^^^^^^^^^^^^ blah blah /// │ │ ╰──────────^ blah blah /// snippet break ── │ · /// snippet line ── │ 82 │ gingerbread toffee chupa chups chupa chups jelly-o cotton candy. /// │ │ ^^^^^^ ------- blah blah /// snippet empty ── │ │ /// snippet note ── │ = blah blah /// snippet note ── │ = blah blah blah /// │ blah blah /// snippet note ── │ = blah blah blah /// │ blah blah /// empty ── │ /// ``` /// /// Filler text from http://www.cupcakeipsum.com pub struct Renderer<'writer, 'config> { writer: &'writer mut dyn WriteColor, config: &'config Config, } impl<'writer, 'config> Renderer<'writer, 'config> { /// Construct a renderer from the given writer and config. pub fn new( writer: &'writer mut dyn WriteColor, config: &'config Config, ) -> Renderer<'writer, 'config> { Renderer { writer, config } } fn chars(&self) -> &'config Chars { &self.config.chars } fn styles(&self) -> &'config Styles { &self.config.styles } /// Diagnostic header, with severity, code, and message. /// /// ```text /// error[E0001]: unexpected type in `+` application /// ``` pub fn render_header( &mut self, locus: Option<&Locus>, severity: Severity, code: Option<&str>, message: &str, ) -> Result<(), Error> { // Write locus // // ```text // test:2:9: // ``` if let Some(locus) = locus { self.snippet_locus(locus)?; write!(self, ": ")?; } // Write severity name // // ```text // error // ``` self.set_color(self.styles().header(severity))?; match severity { Severity::Bug => write!(self, "bug")?, Severity::Error => write!(self, "error")?, Severity::Warning => write!(self, "warning")?, Severity::Help => write!(self, "help")?, Severity::Note => write!(self, "note")?, } // Write error code // // ```text // [E0001] // ``` if let Some(code) = &code.filter(|code| !code.is_empty()) { write!(self, "[{}]", code)?; } // Write diagnostic message // // ```text // : unexpected type in `+` application // ``` self.set_color(&self.styles().header_message)?; write!(self, ": {}", message)?; self.reset()?; writeln!(self)?; Ok(()) } /// Empty line. pub fn render_empty(&mut self) -> Result<(), Error> { writeln!(self)?; Ok(()) } /// Top left border and locus. /// /// ```text /// ┌─ test:2:9 /// ``` 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)?; write!(self, "{}", self.chars().snippet_start)?; self.reset()?; write!(self, " ")?; self.snippet_locus(&locus)?; writeln!(self)?; Ok(()) } /// A line of source code. /// /// ```text /// 10 │ │ muffin. Halvah croissant candy canes bonbon candy. Apple pie jelly /// │ ╭─│─────────^ /// ``` pub fn render_snippet_source( &mut self, outer_padding: usize, line_number: usize, source: &str, severity: Severity, single_labels: &[SingleLabel<'_>], num_multi_labels: usize, multi_labels: &[(usize, LabelStyle, MultiLabel<'_>)], ) -> 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()); // Write source line // // ```text // 10 │ │ muffin. Halvah croissant candy canes bonbon candy. Apple pie jelly // ``` { // Write outer gutter (with line number) and border self.outer_gutter_number(line_number, outer_padding)?; self.border_left()?; // Write inner gutter (with multi-line continuations on the left if necessary) 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, label_style, label)) if *label_index == label_column => { match label { 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()?, MultiLabel::Left | MultiLabel::Bottom(..) => { self.label_multi_left(severity, *label_style, None)?; } } multi_labels_iter.next(); } Some((_, _, _)) | None => self.inner_gutter_space()?, } } // Write source text write!(self, " ")?; let mut in_primary = false; for (metrics, ch) in self.char_metrics(source.char_indices()) { let column_range = metrics.byte_index..(metrics.byte_index + ch.len_utf8()); // Check if we are overlapping a primary label let is_primary = single_labels.iter().any(|(ls, range, _)| { *ls == LabelStyle::Primary && is_overlapping(range, &column_range) }) || multi_labels.iter().any(|(_, ls, label)| { *ls == LabelStyle::Primary && match label { MultiLabel::Top(start) => column_range.start >= *start, MultiLabel::Left => true, MultiLabel::Bottom(start, _) => column_range.end <= *start, } }); // Set the source color if we are in a primary label if is_primary && !in_primary { self.set_color(self.styles().label(severity, LabelStyle::Primary))?; in_primary = true; } else if !is_primary && in_primary { self.reset()?; in_primary = false; } match ch { '\t' => (0..metrics.unicode_width).try_for_each(|_| write!(self, " "))?, _ => write!(self, "{}", ch)?, } } if in_primary { self.reset()?; } writeln!(self)?; } // Write single labels underneath source // // ```text // │ - ---- ^^^ second mutable borrow occurs here // │ │ │ // │ │ first mutable borrow occurs here // │ first borrow later used by call // │ help: some help here // ``` if !single_labels.is_empty() { // Our plan is as follows: // // 1. Do an initial scan to find: // - The number of non-empty messages. // - The right-most start and end positions of labels. // - A candidate for a trailing label (where the label's message // is printed to the left of the caret). // 2. Check if the trailing label candidate overlaps another label - // if so we print it underneath the carets with the other labels. // 3. Print a line of carets, and (possibly) the trailing message // to the left. // 4. Print vertical lines pointing to the carets, and the messages // for those carets. // // We try our best avoid introducing new dynamic allocations, // instead preferring to iterate over the labels multiple times. It // is unclear what the performance tradeoffs are however, so further // investigation may be required. // The number of non-empty messages to print. let mut num_messages = 0; // The right-most start position, eg: // // ```text // -^^^^---- ^^^^^^^ // │ // right-most start position // ``` let mut max_label_start = 0; // The right-most end position, eg: // // ```text // -^^^^---- ^^^^^^^ // │ // right-most end position // ``` let mut max_label_end = 0; // A trailing message, eg: // // ```text // ^^^ second mutable borrow occurs here // ``` let mut trailing_label = None; for (label_index, label) in single_labels.iter().enumerate() { let (_, range, message) = label; if !message.is_empty() { num_messages += 1; } max_label_start = std::cmp::max(max_label_start, range.start); max_label_end = std::cmp::max(max_label_end, range.end); // This is a candidate for the trailing label, so let's record it. if range.end == max_label_end { if message.is_empty() { trailing_label = None; } else { trailing_label = Some((label_index, label)); } } } if let Some((trailing_label_index, (_, trailing_range, _))) = trailing_label { // Check to see if the trailing label candidate overlaps any of // the other labels on the current line. if single_labels .iter() .enumerate() .filter(|(label_index, _)| *label_index != trailing_label_index) .any(|(_, (_, range, _))| is_overlapping(trailing_range, range)) { // If it does, we'll instead want to render it below the // carets along with the other hanging labels. trailing_label = None; } } // Write a line of carets // // ```text // │ ^^^^^^ -------^^^^^^^^^-------^^^^^----- ^^^^ trailing label message // ``` self.outer_gutter(outer_padding)?; self.border_left()?; self.inner_gutter(severity, num_multi_labels, multi_labels)?; write!(self, " ")?; let mut previous_label_style = None; let placeholder_metrics = Metrics { byte_index: source.len(), unicode_width: 1, }; for (metrics, ch) in self .char_metrics(source.char_indices()) // Add a placeholder source column at the end to allow for // printing carets at the end of lines, eg: // // ```text // 1 │ Hello world! // │ ^ // ``` .chain(std::iter::once((placeholder_metrics, '\0'))) { // Find the current label style at this column let column_range = metrics.byte_index..(metrics.byte_index + ch.len_utf8()); let current_label_style = single_labels .iter() .filter(|(_, range, _)| is_overlapping(range, &column_range)) .map(|(label_style, _, _)| *label_style) .max_by_key(label_priority_key); // Update writer style if necessary if previous_label_style != current_label_style { match current_label_style { None => self.reset()?, Some(label_style) => { self.set_color(self.styles().label(severity, label_style))?; } } } let caret_ch = match current_label_style { Some(LabelStyle::Primary) => Some(self.chars().single_primary_caret), Some(LabelStyle::Secondary) => Some(self.chars().single_secondary_caret), // Only print padding if we are before the end of the last single line caret None if metrics.byte_index < max_label_end => Some(' '), None => None, }; if let Some(caret_ch) = caret_ch { // FIXME: improve rendering of carets between character boundaries (0..metrics.unicode_width).try_for_each(|_| write!(self, "{}", caret_ch))?; } previous_label_style = current_label_style; } // Reset style if it was previously set if previous_label_style.is_some() { self.reset()?; } // Write first trailing label message if let Some((_, (label_style, _, message))) = trailing_label { write!(self, " ")?; self.set_color(self.styles().label(severity, *label_style))?; write!(self, "{}", message)?; self.reset()?; } writeln!(self)?; // Write hanging labels pointing to carets // // ```text // │ │ │ // │ │ first mutable borrow occurs here // │ first borrow later used by call // │ help: some help here // ``` if num_messages > trailing_label.iter().count() { // Write first set of vertical lines before hanging labels // // ```text // │ │ │ // ``` self.outer_gutter(outer_padding)?; self.border_left()?; self.inner_gutter(severity, num_multi_labels, multi_labels)?; write!(self, " ")?; self.caret_pointers( severity, max_label_start, single_labels, trailing_label, source.char_indices(), )?; writeln!(self)?; // Write hanging labels pointing to carets // // ```text // │ │ first mutable borrow occurs here // │ first borrow later used by call // │ help: some help here // ``` for (label_style, range, message) in hanging_labels(single_labels, trailing_label).rev() { self.outer_gutter(outer_padding)?; self.border_left()?; self.inner_gutter(severity, num_multi_labels, multi_labels)?; write!(self, " ")?; self.caret_pointers( severity, max_label_start, single_labels, trailing_label, source .char_indices() .take_while(|(byte_index, _)| *byte_index < range.start), )?; self.set_color(self.styles().label(severity, *label_style))?; write!(self, "{}", message)?; self.reset()?; writeln!(self)?; } } } // Write top or bottom label carets underneath source // // ```text // │ ╰───│──────────────────^ woops // │ ╭─│─────────^ // ``` for (multi_label_index, (_, label_style, label)) in multi_labels.iter().enumerate() { let (label_style, range, bottom_message) = match label { 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)), }; self.outer_gutter(outer_padding)?; self.border_left()?; // Write inner gutter. // // ```text // │ ╭─│───│ // ``` let mut underline = None; let mut multi_labels_iter = multi_labels.iter().enumerate().peekable(); for label_column in 0..num_multi_labels { match multi_labels_iter.peek() { Some((i, (label_index, ls, label))) if *label_index == label_column => { match label { MultiLabel::Left => { self.label_multi_left(severity, *ls, underline.map(|(s, _)| s))?; } MultiLabel::Top(..) if multi_label_index > *i => { self.label_multi_left(severity, *ls, underline.map(|(s, _)| s))?; } MultiLabel::Bottom(..) if multi_label_index < *i => { self.label_multi_left(severity, *ls, underline.map(|(s, _)| s))?; } MultiLabel::Top(..) if multi_label_index == *i => { underline = Some((*ls, VerticalBound::Top)); self.label_multi_top_left(severity, label_style)? } MultiLabel::Bottom(..) if multi_label_index == *i => { underline = Some((*ls, VerticalBound::Bottom)); self.label_multi_bottom_left(severity, label_style)?; } MultiLabel::Top(..) | MultiLabel::Bottom(..) => { self.inner_gutter_column(severity, underline)?; } } multi_labels_iter.next(); } Some((_, _)) | None => self.inner_gutter_column(severity, underline)?, } } // Finish the top or bottom caret match bottom_message { None => self.label_multi_top_caret(severity, label_style, source, *range)?, Some(message) => { self.label_multi_bottom_caret(severity, label_style, source, *range, message)? } } } Ok(()) } /// An empty source line, for providing additional whitespace to source snippets. /// /// ```text /// │ │ │ /// ``` pub fn render_snippet_empty( &mut self, outer_padding: usize, severity: Severity, num_multi_labels: usize, multi_labels: &[(usize, LabelStyle, MultiLabel<'_>)], ) -> Result<(), Error> { self.outer_gutter(outer_padding)?; self.border_left()?; self.inner_gutter(severity, num_multi_labels, multi_labels)?; writeln!(self)?; Ok(()) } /// A broken source line, for labeling skipped sections of source. /// /// ```text /// · │ │ /// ``` pub fn render_snippet_break( &mut self, outer_padding: usize, severity: Severity, num_multi_labels: usize, multi_labels: &[(usize, LabelStyle, MultiLabel<'_>)], ) -> Result<(), Error> { self.outer_gutter(outer_padding)?; self.border_left_break()?; self.inner_gutter(severity, num_multi_labels, multi_labels)?; writeln!(self)?; Ok(()) } /// Additional notes. /// /// ```text /// = expected type `Int` /// found type `String` /// ``` 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 { 0 => { self.set_color(&self.styles().note_bullet)?; write!(self, "{}", self.chars().note_bullet)?; self.reset()?; } _ => write!(self, " ")?, } // Write line of message writeln!(self, " {}", line)?; } Ok(()) } /// Adds tab-stop aware unicode-width computations to an iterator over /// character indices. Assumes that the character indices begin at the start /// of the line. fn char_metrics( &self, char_indices: impl Iterator, ) -> impl Iterator { use unicode_width::UnicodeWidthChar; let tab_width = self.config.tab_width; let mut unicode_column = 0; char_indices.map(move |(byte_index, ch)| { let metrics = Metrics { byte_index, unicode_width: match (ch, tab_width) { ('\t', 0) => 0, // Guard divide-by-zero ('\t', _) => tab_width - (unicode_column % tab_width), (ch, _) => ch.width().unwrap_or(0), }, }; unicode_column += metrics.unicode_width; (metrics, ch) }) } /// Location focus. 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) -> 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, ) -> Result<(), Error> { self.set_color(&self.styles().line_number)?; write!( self, "{line_number: >width$}", line_number = line_number, width = outer_padding, )?; self.reset()?; write!(self, " ")?; Ok(()) } /// The left-hand border of a source line. fn border_left(&mut self) -> Result<(), Error> { self.set_color(&self.styles().source_border)?; write!(self, "{}", self.chars().source_border_left)?; self.reset()?; Ok(()) } /// The broken left-hand border of a source line. 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()?; Ok(()) } /// Write vertical lines pointing to carets. fn caret_pointers( &mut self, severity: Severity, max_label_start: usize, single_labels: &[SingleLabel<'_>], trailing_label: Option<(usize, &SingleLabel<'_>)>, char_indices: impl Iterator, ) -> 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) .filter(|(_, range, _)| column_range.contains(&range.start)) .map(|(label_style, _, _)| *label_style) .max_by_key(label_priority_key); let mut spaces = match label_style { None => 0..metrics.unicode_width, Some(label_style) => { self.set_color(self.styles().label(severity, label_style))?; write!(self, "{}", self.chars().pointer_left)?; self.reset()?; 1..metrics.unicode_width } }; // Only print padding if we are before the end of the last single line caret if metrics.byte_index <= max_label_start { spaces.try_for_each(|_| write!(self, " "))?; } } Ok(()) } /// The left of a multi-line label. /// /// ```text /// │ /// ``` fn label_multi_left( &mut self, severity: Severity, label_style: LabelStyle, underline: Option, ) -> Result<(), Error> { match underline { None => write!(self, " ")?, // Continue an underline horizontally Some(label_style) => { self.set_color(self.styles().label(severity, label_style))?; write!(self, "{}", self.chars().multi_top)?; self.reset()?; } } self.set_color(self.styles().label(severity, label_style))?; write!(self, "{}", self.chars().multi_left)?; self.reset()?; Ok(()) } /// The top-left of a multi-line label. /// /// ```text /// ╭ /// ``` fn label_multi_top_left( &mut self, severity: Severity, label_style: LabelStyle, ) -> Result<(), Error> { write!(self, " ")?; self.set_color(self.styles().label(severity, label_style))?; write!(self, "{}", self.chars().multi_top_left)?; self.reset()?; Ok(()) } /// The bottom left of a multi-line label. /// /// ```text /// ╰ /// ``` fn label_multi_bottom_left( &mut self, severity: Severity, label_style: LabelStyle, ) -> Result<(), Error> { write!(self, " ")?; self.set_color(self.styles().label(severity, label_style))?; write!(self, "{}", self.chars().multi_bottom_left)?; self.reset()?; Ok(()) } /// Multi-line label top. /// /// ```text /// ─────────────^ /// ``` fn label_multi_top_caret( &mut self, severity: Severity, label_style: LabelStyle, source: &str, 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 < start + 1) { // FIXME: improve rendering of carets between character boundaries (0..metrics.unicode_width) .try_for_each(|_| write!(self, "{}", self.chars().multi_top))?; } let caret_start = match label_style { LabelStyle::Primary => self.config.chars.multi_primary_caret_start, LabelStyle::Secondary => self.config.chars.multi_secondary_caret_start, }; write!(self, "{}", caret_start)?; self.reset()?; writeln!(self)?; Ok(()) } /// Multi-line label bottom, with a message. /// /// ```text /// ─────────────^ expected `Int` but found `String` /// ``` fn label_multi_bottom_caret( &mut self, severity: Severity, label_style: LabelStyle, source: &str, start: usize, message: &str, ) -> 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 < start) { // FIXME: improve rendering of carets between character boundaries (0..metrics.unicode_width) .try_for_each(|_| write!(self, "{}", self.chars().multi_bottom))?; } let caret_end = match label_style { LabelStyle::Primary => self.config.chars.multi_primary_caret_start, LabelStyle::Secondary => self.config.chars.multi_secondary_caret_start, }; write!(self, "{}", caret_end)?; if !message.is_empty() { write!(self, " {}", message)?; } self.reset()?; writeln!(self)?; Ok(()) } /// Writes an empty gutter space, or continues an underline horizontally. fn inner_gutter_column( &mut self, severity: Severity, underline: Option, ) -> Result<(), Error> { match underline { None => self.inner_gutter_space(), Some((label_style, vertical_bound)) => { self.set_color(self.styles().label(severity, label_style))?; let ch = match vertical_bound { VerticalBound::Top => self.config.chars.multi_top, VerticalBound::Bottom => self.config.chars.multi_bottom, }; write!(self, "{0}{0}", ch)?; self.reset()?; Ok(()) } } } /// Writes an empty gutter space. fn inner_gutter_space(&mut self) -> Result<(), Error> { write!(self, " ")?; Ok(()) } /// Writes an inner gutter, with the left lines if necessary. fn inner_gutter( &mut self, severity: Severity, num_multi_labels: usize, multi_labels: &[(usize, LabelStyle, MultiLabel<'_>)], ) -> 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::Left | MultiLabel::Bottom(..) => { self.label_multi_left(severity, *ls, None)?; multi_labels_iter.next(); } MultiLabel::Top(..) => { self.inner_gutter_space()?; multi_labels_iter.next(); } }, Some((_, _, _)) | None => self.inner_gutter_space()?, } } Ok(()) } } impl<'writer, 'config> Write for Renderer<'writer, 'config> { fn write(&mut self, buf: &[u8]) -> io::Result { self.writer.write(buf) } fn flush(&mut self) -> io::Result<()> { self.writer.flush() } } impl<'writer, 'config> WriteColor for Renderer<'writer, 'config> { fn supports_color(&self) -> bool { self.writer.supports_color() } fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { self.writer.set_color(spec) } fn reset(&mut self) -> io::Result<()> { self.writer.reset() } fn is_synchronous(&self) -> bool { self.writer.is_synchronous() } } struct Metrics { byte_index: usize, unicode_width: usize, } /// Check if two ranges overlap fn is_overlapping(range0: &Range, range1: &Range) -> bool { let start = std::cmp::max(range0.start, range1.start); let end = std::cmp::min(range0.end, range1.end); start < end } /// For prioritizing primary labels over secondary labels when rendering carets. fn label_priority_key(label_style: &LabelStyle) -> u8 { match label_style { LabelStyle::Secondary => 0, LabelStyle::Primary => 1, } } /// Return an iterator that yields the labels that require hanging messages /// rendered underneath them. fn hanging_labels<'labels, 'diagnostic>( single_labels: &'labels [SingleLabel<'diagnostic>], trailing_label: Option<(usize, &'labels SingleLabel<'diagnostic>)>, ) -> impl 'labels + DoubleEndedIterator> { single_labels .iter() .enumerate() .filter(|(_, (_, _, message))| !message.is_empty()) .filter(move |(i, _)| trailing_label.map_or(true, |(j, _)| *i != j)) .map(|(_, label)| label) } codespan-reporting-0.11.1/src/term/views.rs000064400000000000000000000444020000000000000167310ustar 00000000000000use std::ops::Range; use crate::diagnostic::{Diagnostic, LabelStyle}; 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 { let mut count = 0; while n != 0 { count += 1; n /= 10; // remove last digit } count } /// Output a richly formatted diagnostic, with source code previews. pub struct RichDiagnostic<'diagnostic, 'config, FileId> { diagnostic: &'diagnostic Diagnostic, config: &'config Config, } impl<'diagnostic, 'config, FileId> RichDiagnostic<'diagnostic, 'config, FileId> where FileId: Copy + PartialEq, { pub fn new( diagnostic: &'diagnostic Diagnostic, 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<'_, '_>, ) -> Result<(), Error> where FileId: 'files, { use std::collections::BTreeMap; struct LabeledFile<'diagnostic, FileId> { file_id: FileId, start: usize, name: String, location: Location, num_multi_labels: usize, lines: BTreeMap>, max_label_style: LabelStyle, } impl<'diagnostic, FileId> LabeledFile<'diagnostic, FileId> { fn get_or_insert_line( &mut self, line_index: usize, line_range: Range, line_number: usize, ) -> &mut Line<'diagnostic> { self.lines.entry(line_index).or_insert_with(|| Line { range: line_range, 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, }) } } struct Line<'diagnostic> { number: usize, range: std::ops::Range, // TODO: How do we reuse these allocations? single_labels: Vec>, multi_labels: Vec<(usize, LabelStyle, MultiLabel<'diagnostic>)>, must_render: bool, } // TODO: Make this data structure external, to allow for allocation reuse let mut labeled_files = Vec::>::new(); // Keep track of the outer padding to use when rendering the // snippets of source code. let mut outer_padding = 0; // Group labels by file for label in &self.diagnostic.labels { 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)); // NOTE: This could be made more efficient by using an associative // data structure like a hashmap or B-tree, but we use a vector to // preserve the order that unique files appear in the list of labels. let labeled_file = match labeled_files .iter_mut() .find(|labeled_file| label.file_id == labeled_file.file_id) { Some(labeled_file) => { // 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)?; 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)?.to_string(), location: files.location(label.file_id, label.range.start)?, num_multi_labels: 0, lines: BTreeMap::new(), max_label_style: label.style, }); // this unwrap should never fail because we just pushed an element labeled_files .last_mut() .expect("just pushed an element that disappeared") } }; if start_line_index == end_line_index { // Single line // // ```text // 2 │ (+ test "") // │ ^^ expected `Int` but found `String` // ``` let label_start = label.range.start - 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, start_line_range, start_line_number, ); // Ensure that the single line labels are lexicographically // sorted by the range of source code that they cover. let index = match line.single_labels.binary_search_by(|(_, range, _)| { // `Range` doesn't implement `Ord`, so convert to `(usize, usize)` // to piggyback off its lexicographic comparison implementation. (range.start, range.end).cmp(&(label_start, label_end)) }) { // If the ranges are the same, order the labels in reverse // to how they were originally specified in the diagnostic. // This helps with printing in the renderer. Ok(index) | Err(index) => index, }; line.single_labels .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 // // ```text // 4 │ fizz₁ num = case (mod num 5) (mod num 3) of // │ ╭─────────────^ // 5 │ │ 0 0 => "FizzBuzz" // 6 │ │ 0 _ => "Fizz" // 7 │ │ _ 0 => "Buzz" // 8 │ │ _ _ => num // │ ╰──────────────^ `case` clauses have incompatible types // ``` let label_index = labeled_file.num_multi_labels; labeled_file.num_multi_labels += 1; // First labeled line let label_start = label.range.start - start_line_range.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 // // ```text // 5 │ │ 0 0 => "FizzBuzz" // 6 │ │ 0 _ => "Fizz" // 7 │ │ _ 0 => "Buzz" // ``` for line_index in (start_line_index + 1)..end_line_index { 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)); 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 // // ```text // 8 │ │ _ _ => num // │ ╰──────────────^ `case` clauses have incompatible types // ``` let label_end = label.range.end - end_line_range.start; 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; } } // Header and message // // ```text // error[E0001]: unexpected type in `+` application // ``` renderer.render_header( None, self.diagnostic.severity, self.diagnostic.code.as_deref(), self.diagnostic.message.as_str(), )?; // Source snippets // // ```text // ┌─ test:2:9 // │ // 2 │ (+ test "") // │ ^^ expected `Int` but found `String` // │ // ``` 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)?; let source = source.as_ref(); // Top left border and locus. // // ```text // ┌─ test:2:9 // ``` if !labeled_file.lines.is_empty() { renderer.render_snippet_start( outer_padding, &Locus { name: labeled_file.name, location: labeled_file.location, }, )?; renderer.render_snippet_empty( outer_padding, self.diagnostic.severity, labeled_file.num_multi_labels, &[], )?; } 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( outer_padding, line.number, &source[line.range.clone()], self.diagnostic.severity, &line.single_labels, labeled_file.num_multi_labels, &line.multi_labels, )?; // 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) { // 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)?, &source[files.line_range(file_id, line_index + 1)?], self.diagnostic.severity, &[], labeled_file.num_multi_labels, labels, )?; } // More than one line between the current line and the next line. Some(_) | None => { // Source break // // ```text // · // ``` renderer.render_snippet_break( outer_padding, self.diagnostic.severity, labeled_file.num_multi_labels, &line.multi_labels, )?; } } } } // Check to see if we should render a trailing border after the // final line of the snippet. if labeled_files.peek().is_none() && self.diagnostic.notes.is_empty() { // We don't render a border if we are at the final newline // without trailing notes, because it would end up looking too // spaced-out in combination with the final new line. } else { // Render the trailing snippet border. renderer.render_snippet_empty( outer_padding, self.diagnostic.severity, labeled_file.num_multi_labels, &[], )?; } } // Additional notes // // ```text // = expected type `Int` // found type `String` // ``` for note in &self.diagnostic.notes { renderer.render_snippet_note(outer_padding, note)?; } renderer.render_empty() } } /// Output a short diagnostic, with a line number, severity, and message. pub struct ShortDiagnostic<'diagnostic, FileId> { diagnostic: &'diagnostic Diagnostic, show_notes: bool, } impl<'diagnostic, FileId> ShortDiagnostic<'diagnostic, FileId> where FileId: Copy + PartialEq, { pub fn new( diagnostic: &'diagnostic Diagnostic, show_notes: bool, ) -> ShortDiagnostic<'diagnostic, FileId> { ShortDiagnostic { diagnostic, show_notes, } } pub fn render<'files>( &self, files: &'files impl Files<'files, FileId = FileId>, renderer: &mut Renderer<'_, '_>, ) -> Result<(), Error> where FileId: 'files, { // Located headers // // ```text // test:2:9: error[E0001]: unexpected type in `+` application // ``` let mut primary_labels_encountered = 0; let labels = self.diagnostic.labels.iter(); for label in labels.filter(|label| label.style == LabelStyle::Primary) { primary_labels_encountered += 1; renderer.render_header( Some(&Locus { name: files.name(label.file_id)?.to_string(), location: files.location(label.file_id, label.range.start)?, }), self.diagnostic.severity, self.diagnostic.code.as_deref(), self.diagnostic.message.as_str(), )?; } // Fallback to printing a non-located header if no primary labels were encountered // // ```text // error[E0002]: Bad config found // ``` if primary_labels_encountered == 0 { renderer.render_header( None, self.diagnostic.severity, 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(()) } } codespan-reporting-0.11.1/src/term.rs000064400000000000000000000073140000000000000155750ustar 00000000000000//! Terminal back-end for emitting diagnostics. use std::str::FromStr; use termcolor::{ColorChoice, WriteColor}; use crate::diagnostic::Diagnostic; use crate::files::Files; mod config; mod renderer; mod views; pub use termcolor; pub use self::config::{Chars, Config, DisplayStyle, Styles}; /// A command line argument that configures the coloring of the output. /// /// This can be used with command line argument parsers like [`clap`] or [`structopt`]. /// /// [`clap`]: https://crates.io/crates/clap /// [`structopt`]: https://crates.io/crates/structopt /// /// # Example /// /// ```rust /// use codespan_reporting::term::termcolor::StandardStream; /// use codespan_reporting::term::ColorArg; /// use structopt::StructOpt; /// /// #[derive(Debug, StructOpt)] /// #[structopt(name = "groovey-app")] /// pub struct Opts { /// /// Configure coloring of output /// #[structopt( /// long = "color", /// default_value = "auto", /// possible_values = ColorArg::VARIANTS, /// case_insensitive = true, /// )] /// pub color: ColorArg, /// } /// /// let opts = Opts::from_args(); /// let writer = StandardStream::stderr(opts.color.into()); /// ``` #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct ColorArg(pub ColorChoice); impl ColorArg { /// Allowed values the argument. /// /// This is useful for generating documentation via [`clap`] or `structopt`'s /// `possible_values` configuration. /// /// [`clap`]: https://crates.io/crates/clap /// [`structopt`]: https://crates.io/crates/structopt pub const VARIANTS: &'static [&'static str] = &["auto", "always", "ansi", "never"]; } impl FromStr for ColorArg { type Err = &'static str; fn from_str(src: &str) -> Result { match src { _ if src.eq_ignore_ascii_case("auto") => Ok(ColorArg(ColorChoice::Auto)), _ if src.eq_ignore_ascii_case("always") => Ok(ColorArg(ColorChoice::Always)), _ if src.eq_ignore_ascii_case("ansi") => Ok(ColorArg(ColorChoice::AlwaysAnsi)), _ if src.eq_ignore_ascii_case("never") => Ok(ColorArg(ColorChoice::Never)), _ => Err("valid values: auto, always, ansi, never"), } } } impl Into for ColorArg { fn into(self) -> ColorChoice { self.0 } } /// 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, ) -> 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, 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), } } #[cfg(test)] mod tests { use super::*; use crate::diagnostic::Label; use crate::files::SimpleFiles; #[test] fn unsized_emit() { let mut files = SimpleFiles::new(); let id = files.add("test", ""); let mut writer = termcolor::NoColor::new(Vec::::new()); let diagnostic = Diagnostic::bug().with_labels(vec![Label::primary(id, 0..0)]); emit(&mut writer, &Config::default(), &files, &diagnostic).unwrap(); } } codespan-reporting-0.11.1/tests/snapshots/term__empty__medium_color.snap000064400000000000000000000005460000000000000247610ustar 00000000000000--- 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}: {/} codespan-reporting-0.11.1/tests/snapshots/term__empty__medium_no_color.snap000064400000000000000000000002130000000000000254440ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- bug: error: warning: note: help: bug: codespan-reporting-0.11.1/tests/snapshots/term__empty__rich_ascii_no_color.snap000064400000000000000000000002210000000000000262600ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- bug: error: warning: note: help: bug: codespan-reporting-0.11.1/tests/snapshots/term__empty__rich_color.snap000064400000000000000000000005540000000000000244250ustar 00000000000000--- 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}: {/} codespan-reporting-0.11.1/tests/snapshots/term__empty__rich_no_color.snap000064400000000000000000000002210000000000000251100ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- bug: error: warning: note: help: bug: codespan-reporting-0.11.1/tests/snapshots/term__empty__short_color.snap000064400000000000000000000005460000000000000246400ustar 00000000000000--- 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}: {/} codespan-reporting-0.11.1/tests/snapshots/term__empty__short_no_color.snap000064400000000000000000000002130000000000000253230ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- bug: error: warning: note: help: bug: codespan-reporting-0.11.1/tests/snapshots/term__empty_ranges__medium_color.snap000064400000000000000000000005450000000000000263170ustar 00000000000000--- 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{/} codespan-reporting-0.11.1/tests/snapshots/term__empty_ranges__medium_no_color.snap000064400000000000000000000003200000000000000270020ustar 00000000000000--- 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 codespan-reporting-0.11.1/tests/snapshots/term__empty_ranges__rich_ascii_no_color.snap000064400000000000000000000006230000000000000276250ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- note: middle --> hello:1:7 | 1 | Hello world! | ^ middle note: end of line --> hello:1:13 | 1 | Hello world! | ^ end of line note: end of line --> hello:2:11 | 2 | Bye world! | ^ end of line note: end of file --> hello:3:4 | 3 | | ^ end of file codespan-reporting-0.11.1/tests/snapshots/term__empty_ranges__rich_color.snap000064400000000000000000000016610000000000000257640ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_color(&config) --- {fg:Green bold bright}note{bold bright}: middle{/} {fg:Blue}┌─{/} hello:1:7 {fg:Blue}│{/} {fg:Blue}1{/} {fg:Blue}│{/} Hello {fg:Green}w{/}orld! {fg:Blue}│{/} {fg:Green}^{/} {fg:Green}middle{/} {fg:Green bold bright}note{bold bright}: end of line{/} {fg:Blue}┌─{/} hello:1:13 {fg:Blue}│{/} {fg:Blue}1{/} {fg:Blue}│{/} Hello world! {fg:Blue}│{/} {fg:Green}^{/} {fg:Green}end of line{/} {fg:Green bold bright}note{bold bright}: end of line{/} {fg:Blue}┌─{/} hello:2:11 {fg:Blue}│{/} {fg:Blue}2{/} {fg:Blue}│{/} Bye world! {fg:Blue}│{/} {fg:Green}^{/} {fg:Green}end of line{/} {fg:Green bold bright}note{bold bright}: end of file{/} {fg:Blue}┌─{/} hello:3:4 {fg:Blue}│{/} {fg:Blue}3{/} {fg:Blue}│{/} {fg:Blue}│{/} {fg:Green}^{/} {fg:Green}end of file{/} codespan-reporting-0.11.1/tests/snapshots/term__empty_ranges__rich_no_color.snap000064400000000000000000000006670000000000000264650ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- note: middle ┌─ hello:1:7 │ 1 │ Hello world! │ ^ middle note: end of line ┌─ hello:1:13 │ 1 │ Hello world! │ ^ end of line note: end of line ┌─ hello:2:11 │ 2 │ Bye world! │ ^ end of line note: end of file ┌─ hello:3:4 │ 3 │ │ ^ end of file codespan-reporting-0.11.1/tests/snapshots/term__empty_ranges__short_color.snap000064400000000000000000000005450000000000000261760ustar 00000000000000--- 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{/} codespan-reporting-0.11.1/tests/snapshots/term__empty_ranges__short_no_color.snap000064400000000000000000000003200000000000000266610ustar 00000000000000--- 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 codespan-reporting-0.11.1/tests/snapshots/term__fizz_buzz__medium_color.snap000064400000000000000000000006570000000000000256620ustar 00000000000000--- 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` codespan-reporting-0.11.1/tests/snapshots/term__fizz_buzz__medium_no_color.snap000064400000000000000000000005220000000000000263450ustar 00000000000000--- 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` codespan-reporting-0.11.1/tests/snapshots/term__fizz_buzz__rich_ascii_no_color.snap000064400000000000000000000025130000000000000271640ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- error[E0308]: `case` clauses have incompatible types --> FizzBuzz.fun:8:12 | 3 | fizz₁ : Nat → String | ------ expected type `String` found here 4 | fizz₁ num = case (mod num 5) (mod num 3) of | /-------------' 5 | | 0 0 => "FizzBuzz" 6 | | 0 _ => "Fizz" 7 | | _ 0 => "Buzz" 8 | | _ _ => num | | ^^^ expected `String`, found `Nat` | \--------------' `case` clauses have incompatible types | = expected type `String` found type `Nat` error[E0308]: `case` clauses have incompatible types --> FizzBuzz.fun:16:16 | 10 | fizz₂ : Nat → String | ------ expected type `String` found here 11 | fizz₂ num = 12 | / case (mod num 5) (mod num 3) of 13 | | 0 0 => "FizzBuzz" | | ---------- this is found to be of type `String` 14 | | 0 _ => "Fizz" | | ------ this is found to be of type `String` 15 | | _ 0 => "Buzz" | | ------ this is found to be of type `String` 16 | | _ _ => num | | ^^^ expected `String`, found `Nat` | \------------------' `case` clauses have incompatible types | = expected type `String` found type `Nat` codespan-reporting-0.11.1/tests/snapshots/term__fizz_buzz__rich_color.snap000064400000000000000000000050020000000000000253140ustar 00000000000000--- 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:8:12 {fg:Blue}│{/} {fg:Blue}3{/} {fg:Blue}│{/} fizz₁ : Nat → String {fg:Blue}│{/} {fg:Blue}------{/} {fg:Blue}expected type `String` found here{/} {fg:Blue}4{/} {fg:Blue}│{/} fizz₁ num = case (mod num 5) (mod num 3) of {fg:Blue}│{/} {fg:Blue}╭{/}{fg:Blue}─────────────'{/} {fg:Blue}5{/} {fg:Blue}│{/} {fg:Blue}│{/} 0 0 => "FizzBuzz" {fg:Blue}6{/} {fg:Blue}│{/} {fg:Blue}│{/} 0 _ => "Fizz" {fg:Blue}7{/} {fg:Blue}│{/} {fg:Blue}│{/} _ 0 => "Buzz" {fg:Blue}8{/} {fg:Blue}│{/} {fg:Blue}│{/} _ _ => {fg:Red}num{/} {fg:Blue}│{/} {fg:Blue}│{/} {fg:Red}^^^{/} {fg:Red}expected `String`, found `Nat`{/} {fg:Blue}│{/} {fg:Blue}╰{/}{fg:Blue}──────────────' `case` clauses have incompatible types{/} {fg:Blue}│{/} {fg:Blue}={/} expected type `String` found type `Nat` {fg:Red bold bright}error[E0308]{bold bright}: `case` clauses have incompatible types{/} {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{/} {fg:Blue}11{/} {fg:Blue}│{/} fizz₂ num = {fg:Blue}12{/} {fg:Blue}│{/} {fg:Blue}╭{/} case (mod num 5) (mod num 3) of {fg:Blue}13{/} {fg:Blue}│{/} {fg:Blue}│{/} 0 0 => "FizzBuzz" {fg:Blue}│{/} {fg:Blue}│{/} {fg:Blue}----------{/} {fg:Blue}this is found to be of type `String`{/} {fg:Blue}14{/} {fg:Blue}│{/} {fg:Blue}│{/} 0 _ => "Fizz" {fg:Blue}│{/} {fg:Blue}│{/} {fg:Blue}------{/} {fg:Blue}this is found to be of type `String`{/} {fg:Blue}15{/} {fg:Blue}│{/} {fg:Blue}│{/} _ 0 => "Buzz" {fg:Blue}│{/} {fg:Blue}│{/} {fg:Blue}------{/} {fg:Blue}this is found to be of type `String`{/} {fg:Blue}16{/} {fg:Blue}│{/} {fg:Blue}│{/} _ _ => {fg:Red}num{/} {fg:Blue}│{/} {fg:Blue}│{/} {fg:Red}^^^{/} {fg:Red}expected `String`, found `Nat`{/} {fg:Blue}│{/} {fg:Blue}╰{/}{fg:Blue}──────────────────' `case` clauses have incompatible types{/} {fg:Blue}│{/} {fg:Blue}={/} expected type `String` found type `Nat` codespan-reporting-0.11.1/tests/snapshots/term__fizz_buzz__rich_no_color.snap000064400000000000000000000030030000000000000260070ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- error[E0308]: `case` clauses have incompatible types ┌─ FizzBuzz.fun:8:12 │ 3 │ fizz₁ : Nat → String │ ------ expected type `String` found here 4 │ fizz₁ num = case (mod num 5) (mod num 3) of │ ╭─────────────' 5 │ │ 0 0 => "FizzBuzz" 6 │ │ 0 _ => "Fizz" 7 │ │ _ 0 => "Buzz" 8 │ │ _ _ => num │ │ ^^^ expected `String`, found `Nat` │ ╰──────────────' `case` clauses have incompatible types │ = expected type `String` found type `Nat` error[E0308]: `case` clauses have incompatible types ┌─ FizzBuzz.fun:16:16 │ 10 │ fizz₂ : Nat → String │ ------ expected type `String` found here 11 │ fizz₂ num = 12 │ ╭ case (mod num 5) (mod num 3) of 13 │ │ 0 0 => "FizzBuzz" │ │ ---------- this is found to be of type `String` 14 │ │ 0 _ => "Fizz" │ │ ------ this is found to be of type `String` 15 │ │ _ 0 => "Buzz" │ │ ------ this is found to be of type `String` 16 │ │ _ _ => num │ │ ^^^ expected `String`, found `Nat` │ ╰──────────────────' `case` clauses have incompatible types │ = expected type `String` found type `Nat` codespan-reporting-0.11.1/tests/snapshots/term__fizz_buzz__short_color.snap000064400000000000000000000004650000000000000255360ustar 00000000000000--- 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{/} FizzBuzz.fun:16:16: {fg:Red bold bright}error[E0308]{bold bright}: `case` clauses have incompatible types{/} codespan-reporting-0.11.1/tests/snapshots/term__fizz_buzz__short_no_color.snap000064400000000000000000000003600000000000000262240ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- FizzBuzz.fun:8:12: error[E0308]: `case` clauses have incompatible types FizzBuzz.fun:16:16: error[E0308]: `case` clauses have incompatible types codespan-reporting-0.11.1/tests/snapshots/term__message__medium_color.snap000064400000000000000000000004660000000000000252500ustar 00000000000000--- 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{/} codespan-reporting-0.11.1/tests/snapshots/term__message__medium_no_color.snap000064400000000000000000000002430000000000000257350ustar 00000000000000--- 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 codespan-reporting-0.11.1/tests/snapshots/term__message__rich_ascii_no_color.snap000064400000000000000000000002470000000000000265560ustar 00000000000000--- 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 codespan-reporting-0.11.1/tests/snapshots/term__message__rich_color.snap000064400000000000000000000004720000000000000247120ustar 00000000000000--- 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{/} codespan-reporting-0.11.1/tests/snapshots/term__message__rich_no_color.snap000064400000000000000000000002470000000000000254060ustar 00000000000000--- 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 codespan-reporting-0.11.1/tests/snapshots/term__message__short_color.snap000064400000000000000000000004660000000000000251270ustar 00000000000000--- 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{/} codespan-reporting-0.11.1/tests/snapshots/term__message__short_no_color.snap000064400000000000000000000002430000000000000256140ustar 00000000000000--- 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 codespan-reporting-0.11.1/tests/snapshots/term__message_and_notes__medium_color.snap000064400000000000000000000006160000000000000272770ustar 00000000000000--- 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 codespan-reporting-0.11.1/tests/snapshots/term__message_and_notes__medium_no_color.snap000064400000000000000000000003130000000000000277650ustar 00000000000000--- 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 codespan-reporting-0.11.1/tests/snapshots/term__message_and_notes__rich_ascii_no_color.snap000064400000000000000000000003170000000000000306060ustar 00000000000000--- 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 codespan-reporting-0.11.1/tests/snapshots/term__message_and_notes__rich_color.snap000064400000000000000000000006220000000000000267410ustar 00000000000000--- 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 codespan-reporting-0.11.1/tests/snapshots/term__message_and_notes__rich_no_color.snap000064400000000000000000000003170000000000000274360ustar 00000000000000--- 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 codespan-reporting-0.11.1/tests/snapshots/term__message_and_notes__short_color.snap000064400000000000000000000004660000000000000271610ustar 00000000000000--- 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{/} codespan-reporting-0.11.1/tests/snapshots/term__message_and_notes__short_no_color.snap000064400000000000000000000002430000000000000276460ustar 00000000000000--- 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 codespan-reporting-0.11.1/tests/snapshots/term__message_errorcode__rich_ascii_no_color.snap000064400000000000000000000005160000000000000306210ustar 00000000000000--- 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? codespan-reporting-0.11.1/tests/snapshots/term__message_errorcode__rich_no_color.snap000064400000000000000000000005160000000000000274510ustar 00000000000000--- 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? codespan-reporting-0.11.1/tests/snapshots/term__message_errorcode__short_no_color.snap000064400000000000000000000005060000000000000276620ustar 00000000000000--- 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? codespan-reporting-0.11.1/tests/snapshots/term__multifile__medium_color.snap000064400000000000000000000010660000000000000256130ustar 00000000000000--- 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` codespan-reporting-0.11.1/tests/snapshots/term__multifile__medium_no_color.snap000064400000000000000000000006460000000000000263120ustar 00000000000000--- 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` codespan-reporting-0.11.1/tests/snapshots/term__multifile__rich_ascii_no_color.snap000064400000000000000000000014660000000000000271300ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- error: unknown builtin: `NATRAL` --> Data/Nat.fun:7:13 | 7 | {-# BUILTIN NATRAL Nat #-} | ^^^^^^ unknown builtin | = there is a builtin with a similar name: `NATURAL` warning: unused parameter pattern: `n₂` --> Data/Nat.fun:17:16 | 17 | zero - succ n₂ = zero | ^^ unused parameter | = consider using a wildcard pattern: `_` error[E0001]: unexpected type in application of `_+_` --> Test.fun:4:11 | 4 | _ = 123 + "hello" | ^^^^^^^ expected `Nat`, found `String` | --> Data/Nat.fun:11:1 | 11 | _+_ : Nat → Nat → Nat | --------------------- based on the definition of `_+_` | = expected type `Nat` found type `String` codespan-reporting-0.11.1/tests/snapshots/term__multifile__rich_color.snap000064400000000000000000000026260000000000000252630ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_color(&config) --- {fg:Red bold bright}error{bold bright}: unknown builtin: `NATRAL`{/} {fg:Blue}┌─{/} Data/Nat.fun:7:13 {fg:Blue}│{/} {fg:Blue}7{/} {fg:Blue}│{/} {-# BUILTIN {fg:Red}NATRAL{/} Nat #-} {fg:Blue}│{/} {fg:Red}^^^^^^{/} {fg:Red}unknown builtin{/} {fg:Blue}│{/} {fg:Blue}={/} there is a builtin with a similar name: `NATURAL` {fg:Yellow bold bright}warning{bold bright}: unused parameter pattern: `n₂`{/} {fg:Blue}┌─{/} Data/Nat.fun:17:16 {fg:Blue}│{/} {fg:Blue}17{/} {fg:Blue}│{/} zero - succ {fg:Yellow}n₂{/} = zero {fg:Blue}│{/} {fg:Yellow}^^{/} {fg:Yellow}unused parameter{/} {fg:Blue}│{/} {fg:Blue}={/} consider using a wildcard pattern: `_` {fg:Red bold bright}error[E0001]{bold bright}: unexpected type in application of `_+_`{/} {fg:Blue}┌─{/} Test.fun:4:11 {fg:Blue}│{/} {fg:Blue} 4{/} {fg:Blue}│{/} _ = 123 + {fg:Red}"hello"{/} {fg:Blue}│{/} {fg:Red}^^^^^^^{/} {fg:Red}expected `Nat`, found `String`{/} {fg:Blue}│{/} {fg:Blue}┌─{/} Data/Nat.fun:11:1 {fg:Blue}│{/} {fg:Blue}11{/} {fg:Blue}│{/} _+_ : Nat → Nat → Nat {fg:Blue}│{/} {fg:Blue}---------------------{/} {fg:Blue}based on the definition of `_+_`{/} {fg:Blue}│{/} {fg:Blue}={/} expected type `Nat` found type `String` codespan-reporting-0.11.1/tests/snapshots/term__multifile__rich_no_color.snap000064400000000000000000000015420000000000000257530ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- error: unknown builtin: `NATRAL` ┌─ Data/Nat.fun:7:13 │ 7 │ {-# BUILTIN NATRAL Nat #-} │ ^^^^^^ unknown builtin │ = there is a builtin with a similar name: `NATURAL` warning: unused parameter pattern: `n₂` ┌─ Data/Nat.fun:17:16 │ 17 │ zero - succ n₂ = zero │ ^^ unused parameter │ = consider using a wildcard pattern: `_` error[E0001]: unexpected type in application of `_+_` ┌─ Test.fun:4:11 │ 4 │ _ = 123 + "hello" │ ^^^^^^^ expected `Nat`, found `String` │ ┌─ Data/Nat.fun:11:1 │ 11 │ _+_ : Nat → Nat → Nat │ --------------------- based on the definition of `_+_` │ = expected type `Nat` found type `String` codespan-reporting-0.11.1/tests/snapshots/term__multifile__short_color.snap000064400000000000000000000006020000000000000254650ustar 00000000000000--- 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`{/} Data/Nat.fun:17:16: {fg:Yellow bold bright}warning{bold bright}: unused parameter pattern: `n₂`{/} Test.fun:4:11: {fg:Red bold bright}error[E0001]{bold bright}: unexpected type in application of `_+_`{/} codespan-reporting-0.11.1/tests/snapshots/term__multifile__short_no_color.snap000064400000000000000000000004260000000000000261650ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- Data/Nat.fun:7:13: error: unknown builtin: `NATRAL` Data/Nat.fun:17:16: warning: unused parameter pattern: `n₂` Test.fun:4:11: error[E0001]: unexpected type in application of `_+_` codespan-reporting-0.11.1/tests/snapshots/term__multiline_omit__rich_no_color.snap000064400000000000000000000014270000000000000270150ustar 00000000000000--- 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}` codespan-reporting-0.11.1/tests/snapshots/term__multiline_overlapping__medium_color.snap000064400000000000000000000005060000000000000302270ustar 00000000000000--- 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` found type `LineIndexOutOfBoundsError` codespan-reporting-0.11.1/tests/snapshots/term__multiline_overlapping__medium_no_color.snap000064400000000000000000000004310000000000000307200ustar 00000000000000--- 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` found type `LineIndexOutOfBoundsError` codespan-reporting-0.11.1/tests/snapshots/term__multiline_overlapping__rich_ascii_no_color.snap000064400000000000000000000023020000000000000315340ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- error[E0308]: match arms have incompatible types --> 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()]), | | --------------------------------------------- this is found to be of type `Result` 3 | | Ordering::Equal => Ok(self.source_span().end()), | | ---------------------------- this is found to be of type `Result` 4 | | Ordering::Greater => LineIndexOutOfBoundsError { | /-|----------------------------------^ 5 | | | given: line_index, 6 | | | max: self.last_line_index(), 7 | | | }, | \-|-------------^ expected enum `Result`, found struct `LineIndexOutOfBoundsError` 8 | | } | \---------' `match` arms have incompatible types | = expected type `Result` found type `LineIndexOutOfBoundsError` codespan-reporting-0.11.1/tests/snapshots/term__multiline_overlapping__rich_color.snap000064400000000000000000000040570000000000000277010ustar 00000000000000--- 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: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()]), {fg:Blue}│{/} {fg:Blue}│{/} {fg:Blue}---------------------------------------------{/} {fg:Blue}this is found to be of type `Result`{/} {fg:Blue}3{/} {fg:Blue}│{/} {fg:Blue}│{/} Ordering::Equal => Ok(self.source_span().end()), {fg:Blue}│{/} {fg:Blue}│{/} {fg:Blue}----------------------------{/} {fg:Blue}this is found to be of type `Result`{/} {fg:Blue}4{/} {fg:Blue}│{/} {fg:Blue}│{/} Ordering::Greater => {fg:Red}LineIndexOutOfBoundsError {{/} {fg:Blue}│{/} {fg:Red}╭{/}{fg:Red}─{/}{fg:Blue}│{/}{fg:Red}──────────────────────────────────^{/} {fg:Blue}5{/} {fg:Blue}│{/} {fg:Red}│{/} {fg:Blue}│{/} {fg:Red} given: line_index,{/} {fg:Blue}6{/} {fg:Blue}│{/} {fg:Red}│{/} {fg:Blue}│{/} {fg:Red} max: self.last_line_index(),{/} {fg:Blue}7{/} {fg:Blue}│{/} {fg:Red}│{/} {fg:Blue}│{/} {fg:Red} }{/}, {fg:Blue}│{/} {fg:Red}╰{/}{fg:Red}─{/}{fg:Blue}│{/}{fg:Red}─────────────^ expected enum `Result`, found struct `LineIndexOutOfBoundsError`{/} {fg:Blue}8{/} {fg:Blue}│{/} {fg:Blue}│{/} } {fg:Blue}│{/} {fg:Blue}╰{/}{fg:Blue}─────────' `match` arms have incompatible types{/} {fg:Blue}│{/} {fg:Blue}={/} expected type `Result` found type `LineIndexOutOfBoundsError` codespan-reporting-0.11.1/tests/snapshots/term__multiline_overlapping__rich_no_color.snap000064400000000000000000000025730000000000000303760ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- error[E0308]: match arms have incompatible types ┌─ 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()]), │ │ --------------------------------------------- this is found to be of type `Result` 3 │ │ Ordering::Equal => Ok(self.source_span().end()), │ │ ---------------------------- this is found to be of type `Result` 4 │ │ Ordering::Greater => LineIndexOutOfBoundsError { │ ╭─│──────────────────────────────────^ 5 │ │ │ given: line_index, 6 │ │ │ max: self.last_line_index(), 7 │ │ │ }, │ ╰─│─────────────^ expected enum `Result`, found struct `LineIndexOutOfBoundsError` 8 │ │ } │ ╰─────────' `match` arms have incompatible types │ = expected type `Result` found type `LineIndexOutOfBoundsError` codespan-reporting-0.11.1/tests/snapshots/term__multiline_overlapping__short_color.snap000064400000000000000000000003140000000000000301030ustar 00000000000000--- 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{/} codespan-reporting-0.11.1/tests/snapshots/term__multiline_overlapping__short_no_color.snap000064400000000000000000000002530000000000000306010ustar 00000000000000--- 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 codespan-reporting-0.11.1/tests/snapshots/term__overlapping__medium_color.snap000064400000000000000000000027100000000000000261440ustar 00000000000000--- 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`. codespan-reporting-0.11.1/tests/snapshots/term__overlapping__medium_no_color.snap000064400000000000000000000022530000000000000266420ustar 00000000000000--- 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`. codespan-reporting-0.11.1/tests/snapshots/term__overlapping__rich_ascii_no_color.snap000064400000000000000000000046130000000000000274610ustar 00000000000000--- 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:56 | 5 | fn bad_in_ret_position(x: impl Into) -> impl Into { x } | ----------^^^^^^^^^^- | | | | | nested `impl Trait` here | outer `impl Trait` error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> typeck_type_placeholder_item.rs:1:18 | 1 | fn fn_test1() -> _ { 5 } | ^ | | | not allowed in type signatures | 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:25 | 2 | fn fn_test2(x: i32) -> (_, _) { (x, x) } | -^--^- | || | | || not allowed in type signatures | |not allowed in type signatures | help: replace with the correct return type: `(i32, i32)` error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely --> no_send_res_ports.rs:25:5 | 25 | thread::spawn(move|| { | ^^^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely | /-------------------' 26 | | let y = x; 27 | | println!("{:?}", y); 28 | | }); | \------' within this `[closure@no_send_res_ports.rs:29:19: 33:6 x:main::Foo]` | --> libstd/thread/mod.rs:5:8 | 5 | F: Send + 'static, | ---- required by this bound in `std::thread::spawn` | = 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`. codespan-reporting-0.11.1/tests/snapshots/term__overlapping__rich_color.snap000064400000000000000000000074210000000000000256150ustar 00000000000000--- 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:56 {fg:Blue}│{/} {fg:Blue}5{/} {fg:Blue}│{/} fn bad_in_ret_position(x: impl Into) -> impl Into<{fg:Red}impl Debug{/}> { x } {fg:Blue}│{/} {fg:Blue}----------{fg:Red}^^^^^^^^^^{fg:Blue}-{/} {fg:Blue}│{/} {fg:Blue}│{/} {fg:Red}│{/} {fg:Blue}│{/} {fg:Blue}│{/} {fg:Red}nested `impl Trait` here{/} {fg:Blue}│{/} {fg:Blue}outer `impl Trait`{/} {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:1:18 {fg:Blue}│{/} {fg:Blue}1{/} {fg:Blue}│{/} fn fn_test1() -> {fg:Red}_{/} { 5 } {fg:Blue}│{/} {fg:Red}^{/} {fg:Blue}│{/} {fg:Red}│{/} {fg:Blue}│{/} {fg:Red}not allowed in type signatures{/} {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: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}-{/} {fg:Blue}│{/} {fg:Blue}│{/}{fg:Red}│{/} {fg:Red}│{/} {fg:Blue}│{/} {fg:Blue}│{/}{fg:Red}│{/} {fg:Red}not allowed in type signatures{/} {fg:Blue}│{/} {fg:Blue}│{/}{fg:Red}not allowed in type signatures{/} {fg:Blue}│{/} {fg:Blue}help: replace with the correct return type: `(i32, i32)`{/} {fg:Red bold bright}error[E0277]{bold bright}: `std::rc::Rc<()>` cannot be sent between threads safely{/} {fg:Blue}┌─{/} no_send_res_ports.rs:25:5 {fg:Blue}│{/} {fg:Blue}25{/} {fg:Blue}│{/} {fg:Red}thread::spawn{/}(move|| { {fg:Blue}│{/} {fg:Red}^^^^^^^^^^^^^{/} {fg:Red}`std::rc::Rc<()>` cannot be sent between threads safely{/} {fg:Blue}│{/} {fg:Blue}╭{/}{fg:Blue}───────────────────'{/} {fg:Blue}26{/} {fg:Blue}│{/} {fg:Blue}│{/} let y = x; {fg:Blue}27{/} {fg:Blue}│{/} {fg:Blue}│{/} println!("{:?}", y); {fg:Blue}28{/} {fg:Blue}│{/} {fg:Blue}│{/} }); {fg:Blue}│{/} {fg:Blue}╰{/}{fg:Blue}──────' within this `[closure@no_send_res_ports.rs:29:19: 33:6 x:main::Foo]`{/} {fg:Blue}│{/} {fg:Blue}┌─{/} libstd/thread/mod.rs:5:8 {fg:Blue}│{/} {fg:Blue} 5{/} {fg:Blue}│{/} F: Send + 'static, {fg:Blue}│{/} {fg:Blue}----{/} {fg:Blue}required by this bound in `std::thread::spawn`{/} {fg:Blue}│{/} {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`. codespan-reporting-0.11.1/tests/snapshots/term__overlapping__rich_no_color.snap000064400000000000000000000050520000000000000263070ustar 00000000000000--- 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:56 │ 5 │ fn bad_in_ret_position(x: impl Into) -> impl Into { x } │ ----------^^^^^^^^^^- │ │ │ │ │ nested `impl Trait` here │ outer `impl Trait` error[E0121]: the type placeholder `_` is not allowed within types on item signatures ┌─ typeck_type_placeholder_item.rs:1:18 │ 1 │ fn fn_test1() -> _ { 5 } │ ^ │ │ │ not allowed in type signatures │ 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:25 │ 2 │ fn fn_test2(x: i32) -> (_, _) { (x, x) } │ -^--^- │ ││ │ │ ││ not allowed in type signatures │ │not allowed in type signatures │ help: replace with the correct return type: `(i32, i32)` error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely ┌─ no_send_res_ports.rs:25:5 │ 25 │ thread::spawn(move|| { │ ^^^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely │ ╭───────────────────' 26 │ │ let y = x; 27 │ │ println!("{:?}", y); 28 │ │ }); │ ╰──────' within this `[closure@no_send_res_ports.rs:29:19: 33:6 x:main::Foo]` │ ┌─ libstd/thread/mod.rs:5:8 │ 5 │ F: Send + 'static, │ ---- required by this bound in `std::thread::spawn` │ = 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`. codespan-reporting-0.11.1/tests/snapshots/term__overlapping__short_color.snap000064400000000000000000000015730000000000000260310ustar 00000000000000--- 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:Red bold bright}error{bold bright}: aborting due 5 previous errors{/} codespan-reporting-0.11.1/tests/snapshots/term__overlapping__short_no_color.snap000064400000000000000000000012460000000000000265220ustar 00000000000000--- 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 error: aborting due 5 previous errors codespan-reporting-0.11.1/tests/snapshots/term__position_indicator__medium_no_color.snap000064400000000000000000000004000000000000000302040ustar 00000000000000--- 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 codespan-reporting-0.11.1/tests/snapshots/term__position_indicator__rich_ascii_no_color.snap000064400000000000000000000006440000000000000310330ustar 00000000000000--- 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 codespan-reporting-0.11.1/tests/snapshots/term__position_indicator__rich_no_color.snap000064400000000000000000000006620000000000000276630ustar 00000000000000--- 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 codespan-reporting-0.11.1/tests/snapshots/term__position_indicator__short_no_color.snap000064400000000000000000000003770000000000000301000ustar 00000000000000--- 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 codespan-reporting-0.11.1/tests/snapshots/term__same_line__medium_color.snap000064400000000000000000000005630000000000000255560ustar 00000000000000--- 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`. codespan-reporting-0.11.1/tests/snapshots/term__same_line__medium_no_color.snap000064400000000000000000000004420000000000000262460ustar 00000000000000--- 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`. codespan-reporting-0.11.1/tests/snapshots/term__same_line__rich_ascii_no_color.snap000064400000000000000000000007460000000000000270720ustar 00000000000000--- 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:12 | 3 | v.push(v.pop().unwrap()); | - ---- ^ second mutable borrow occurs here | | | | | first mutable borrow occurs here | first borrow later used by call error: aborting due to previous error = For more information about this error, try `rustc --explain E0499`. codespan-reporting-0.11.1/tests/snapshots/term__same_line__rich_color.snap000064400000000000000000000014410000000000000252170ustar 00000000000000--- 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: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{/} {fg:Blue}│{/} {fg:Blue}│{/} {fg:Blue}│{/} {fg:Blue}│{/} {fg:Blue}│{/} {fg:Blue}first mutable borrow occurs here{/} {fg:Blue}│{/} {fg:Blue}first borrow later used by call{/} {fg:Red bold bright}error{bold bright}: aborting due to previous error{/} {fg:Blue}={/} For more information about this error, try `rustc --explain E0499`. codespan-reporting-0.11.1/tests/snapshots/term__same_line__rich_no_color.snap000064400000000000000000000007730000000000000257220ustar 00000000000000--- 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:12 │ 3 │ v.push(v.pop().unwrap()); │ - ---- ^ second mutable borrow occurs here │ │ │ │ │ first mutable borrow occurs here │ first borrow later used by call error: aborting due to previous error = For more information about this error, try `rustc --explain E0499`. codespan-reporting-0.11.1/tests/snapshots/term__same_line__short_color.snap000064400000000000000000000004400000000000000254270ustar 00000000000000--- 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{/} codespan-reporting-0.11.1/tests/snapshots/term__same_line__short_no_color.snap000064400000000000000000000003330000000000000261240ustar 00000000000000--- 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 codespan-reporting-0.11.1/tests/snapshots/term__same_ranges__medium_color.snap000064400000000000000000000002510000000000000261000ustar 00000000000000--- 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{/} codespan-reporting-0.11.1/tests/snapshots/term__same_ranges__medium_no_color.snap000064400000000000000000000002100000000000000265670ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- same_range:1:5: error: Unexpected token codespan-reporting-0.11.1/tests/snapshots/term__same_ranges__rich_ascii_no_color.snap000064400000000000000000000003350000000000000274140ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- error: Unexpected token --> same_range:1:5 | 1 | ::S { } | ^ | | | Unexpected '{' | Expected '(' codespan-reporting-0.11.1/tests/snapshots/term__same_ranges__rich_color.snap000064400000000000000000000006470000000000000255560ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_color(&config) --- {fg:Red bold bright}error{bold bright}: Unexpected token{/} {fg:Blue}┌─{/} same_range:1:5 {fg:Blue}│{/} {fg:Blue}1{/} {fg:Blue}│{/} ::S {fg:Red}{{/} } {fg:Blue}│{/} {fg:Red}^{/} {fg:Blue}│{/} {fg:Red}│{/} {fg:Blue}│{/} {fg:Red}Unexpected '{'{/} {fg:Blue}│{/} {fg:Blue}Expected '('{/} codespan-reporting-0.11.1/tests/snapshots/term__same_ranges__rich_no_color.snap000064400000000000000000000003560000000000000262470ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- error: Unexpected token ┌─ same_range:1:5 │ 1 │ ::S { } │ ^ │ │ │ Unexpected '{' │ Expected '(' codespan-reporting-0.11.1/tests/snapshots/term__same_ranges__short_color.snap000064400000000000000000000002500000000000000257560ustar 00000000000000--- 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{/} codespan-reporting-0.11.1/tests/snapshots/term__same_ranges__short_no_color.snap000064400000000000000000000002070000000000000264540ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- same_range:1:5: error: Unexpected token codespan-reporting-0.11.1/tests/snapshots/term__tab_columns__tab_width_2_no_color.snap000064400000000000000000000006430000000000000275310ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- warning: tab test ┌─ tab_columns:1:2 │ 1 │ hello │ ^^^^^ 2 │ ∙ hello │ ^^^^^ 3 │ ∙∙ hello │ ^^^^^ 4 │ ∙∙∙ hello │ ^^^^^ 5 │ ∙∙∙∙ hello │ ^^^^^ 6 │ ∙∙∙∙∙ hello │ ^^^^^ 7 │ ∙∙∙∙∙∙ hello │ ^^^^^ codespan-reporting-0.11.1/tests/snapshots/term__tab_columns__tab_width_3_no_color.snap000064400000000000000000000006530000000000000275330ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- warning: tab test ┌─ tab_columns:1:2 │ 1 │ hello │ ^^^^^ 2 │ ∙ hello │ ^^^^^ 3 │ ∙∙ hello │ ^^^^^ 4 │ ∙∙∙ hello │ ^^^^^ 5 │ ∙∙∙∙ hello │ ^^^^^ 6 │ ∙∙∙∙∙ hello │ ^^^^^ 7 │ ∙∙∙∙∙∙ hello │ ^^^^^ codespan-reporting-0.11.1/tests/snapshots/term__tab_columns__tab_width_6_no_color.snap000064400000000000000000000007030000000000000275320ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- warning: tab test ┌─ tab_columns:1:2 │ 1 │ hello │ ^^^^^ 2 │ ∙ hello │ ^^^^^ 3 │ ∙∙ hello │ ^^^^^ 4 │ ∙∙∙ hello │ ^^^^^ 5 │ ∙∙∙∙ hello │ ^^^^^ 6 │ ∙∙∙∙∙ hello │ ^^^^^ 7 │ ∙∙∙∙∙∙ hello │ ^^^^^ codespan-reporting-0.11.1/tests/snapshots/term__tab_columns__tab_width_default_no_color.snap000064400000000000000000000006630000000000000310160ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- warning: tab test ┌─ tab_columns:1:2 │ 1 │ hello │ ^^^^^ 2 │ ∙ hello │ ^^^^^ 3 │ ∙∙ hello │ ^^^^^ 4 │ ∙∙∙ hello │ ^^^^^ 5 │ ∙∙∙∙ hello │ ^^^^^ 6 │ ∙∙∙∙∙ hello │ ^^^^^ 7 │ ∙∙∙∙∙∙ hello │ ^^^^^ codespan-reporting-0.11.1/tests/snapshots/term__tabbed__tab_width_3_no_color.snap000064400000000000000000000007670000000000000264540ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- warning: unknown weapon `DogJaw` ┌─ tabbed:3:11 │ 3 │ Weapon: DogJaw │ ^^^^^^ the weapon warning: unknown condition `attack-cooldown` ┌─ tabbed:4:23 │ 4 │ ReloadingCondition: attack-cooldown │ ^^^^^^^^^^^^^^^ the condition warning: unknown field `Foo` ┌─ tabbed:5:2 │ 5 │ Foo: Bar │ ^^^ the field codespan-reporting-0.11.1/tests/snapshots/term__tabbed__tab_width_6_no_color.snap000064400000000000000000000010330000000000000264420ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- warning: unknown weapon `DogJaw` ┌─ tabbed:3:11 │ 3 │ Weapon: DogJaw │ ^^^^^^ the weapon warning: unknown condition `attack-cooldown` ┌─ tabbed:4:23 │ 4 │ ReloadingCondition: attack-cooldown │ ^^^^^^^^^^^^^^^ the condition warning: unknown field `Foo` ┌─ tabbed:5:2 │ 5 │ Foo: Bar │ ^^^ the field codespan-reporting-0.11.1/tests/snapshots/term__tabbed__tab_width_default_no_color.snap000064400000000000000000000007770000000000000277370ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- warning: unknown weapon `DogJaw` ┌─ tabbed:3:11 │ 3 │ Weapon: DogJaw │ ^^^^^^ the weapon warning: unknown condition `attack-cooldown` ┌─ tabbed:4:23 │ 4 │ ReloadingCondition: attack-cooldown │ ^^^^^^^^^^^^^^^ the condition warning: unknown field `Foo` ┌─ tabbed:5:2 │ 5 │ Foo: Bar │ ^^^ the field codespan-reporting-0.11.1/tests/snapshots/term__unicode__medium_no_color.snap000064400000000000000000000011540000000000000257410ustar 00000000000000--- 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`. codespan-reporting-0.11.1/tests/snapshots/term__unicode__rich_no_color.snap000064400000000000000000000013450000000000000254100ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- error[E0703]: invalid ABI: found `路濫狼á́́` ┌─ unicode.rs:1:8 │ 1 │ extern "路濫狼á́́" fn foo() {} │ ^^^^^^^^^ invalid ABI │ = 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`. codespan-reporting-0.11.1/tests/snapshots/term__unicode__short_no_color.snap000064400000000000000000000003100000000000000256110ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- unicode.rs:1:8: error[E0703]: invalid ABI: found `路濫狼á́́` error: aborting due to previous error codespan-reporting-0.11.1/tests/snapshots/term__unicode_spans__medium_no_color.snap000064400000000000000000000003630000000000000271460ustar 00000000000000--- 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 codespan-reporting-0.11.1/tests/snapshots/term__unicode_spans__rich_no_color.snap000064400000000000000000000014730000000000000266160ustar 00000000000000--- source: codespan-reporting/tests/term.rs expression: TEST_DATA.emit_no_color(&config) --- error[E01]: cow may not jump during new moon. ┌─ moon_jump.rs:1:1 │ 1 │ 🐄🌑🐄🌒🐄🌓🐄🌔🐄🌕🐄🌖🐄🌗🐄🌘🐄 │ ^^ Invalid jump note: invalid unicode range ┌─ moon_jump.rs:1:1 │ 1 │ 🐄🌑🐄🌒🐄🌓🐄🌔🐄🌕🐄🌖🐄🌗🐄🌘🐄 │ -- Cow range does not start at boundary. note: invalid unicode range ┌─ moon_jump.rs:1:3 │ 1 │ 🐄🌑🐄🌒🐄🌓🐄🌔🐄🌕🐄🌖🐄🌗🐄🌘🐄 │ -- Cow range does not end at boundary. note: invalid unicode range ┌─ moon_jump.rs:1:1 │ 1 │ 🐄🌑🐄🌒🐄🌓🐄🌔🐄🌕🐄🌖🐄🌗🐄🌘🐄 │ ------ Cow does not start or end at boundary. codespan-reporting-0.11.1/tests/snapshots/term__unicode_spans__short_no_color.snap000064400000000000000000000003630000000000000270250ustar 00000000000000--- 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 codespan-reporting-0.11.1/tests/support/color_buffer.rs000064400000000000000000000066530000000000000213710ustar 00000000000000use std::io; use std::io::prelude::*; use termcolor::{ColorSpec, WriteColor}; // Color tester from: // https://github.com/wycats/language-reporting/blob/b021c87e0d4916b5f32756151bf215c220eee52d/crates/render-tree/src/stylesheet/accumulator.rs /// A facility for creating visually inspectable representations of colored output /// so they can be easily tested. /// /// A new color is represented as `{style}` and a reset is represented by `{/}`. /// /// Attributes are printed in this order: /// /// - Foreground color as `fg:Color` /// - Background color as `bg:Color` /// - Bold as `bold` /// - Underline as `underline` /// - Intense as `bright` /// /// For example, the style "intense, bold red foreground" would be printed as: /// /// ```text /// {fg:Red bold intense} /// ``` /// /// Since this implementation attempts to make it possible to faithfully /// understand what real WriteColor implementations would do, it tries /// to approximate the contract in the WriteColor trait: "Subsequent /// writes to this write will use these settings until either reset is /// called or new color settings are set.") /// /// - If set_color is called with a style, `{...}` is emitted containing the /// color attributes. /// - If set_color is called with no style, `{/}` is emitted /// - If reset is called, `{/}` is emitted. pub struct ColorBuffer { buf: Vec, color: ColorSpec, } impl ColorBuffer { pub fn new() -> ColorBuffer { ColorBuffer { buf: Vec::new(), color: ColorSpec::new(), } } pub fn into_string(self) -> String { String::from_utf8(self.buf).unwrap() } } impl io::Write for ColorBuffer { fn write(&mut self, buf: &[u8]) -> io::Result { self.buf.extend(buf); Ok(buf.len()) } fn flush(&mut self) -> io::Result<()> { Ok(()) } } impl WriteColor for ColorBuffer { fn supports_color(&self) -> bool { true } fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> { #![allow(unused_assignments)] if self.color == *spec { return Ok(()); } else { self.color = spec.clone(); } if spec.is_none() { write!(self, "{{/}}")?; return Ok(()); } else { write!(self, "{{")?; } let mut first = true; fn write_first(first: bool, write: &mut ColorBuffer) -> io::Result { if !first { write!(write, " ")?; } Ok(false) }; if let Some(fg) = spec.fg() { first = write_first(first, self)?; write!(self, "fg:{:?}", fg)?; } if let Some(bg) = spec.bg() { first = write_first(first, self)?; write!(self, "bg:{:?}", bg)?; } if spec.bold() { first = write_first(first, self)?; write!(self, "bold")?; } if spec.underline() { first = write_first(first, self)?; write!(self, "underline")?; } if spec.intense() { first = write_first(first, self)?; write!(self, "bright")?; } write!(self, "}}")?; Ok(()) } fn reset(&mut self) -> io::Result<()> { let color = self.color.clone(); if color != ColorSpec::new() { write!(self, "{{/}}")?; self.color = ColorSpec::new(); } Ok(()) } } codespan-reporting-0.11.1/tests/support/mod.rs000064400000000000000000000017040000000000000174710ustar 00000000000000use codespan_reporting::diagnostic::Diagnostic; use codespan_reporting::files::Files; use codespan_reporting::term::{emit, Config}; use termcolor::{Buffer, WriteColor}; mod color_buffer; use self::color_buffer::ColorBuffer; pub struct TestData<'files, F: Files<'files>> { pub files: F, pub diagnostics: Vec>, } impl<'files, F: Files<'files>> TestData<'files, F> { fn emit(&'files self, mut writer: W, config: &Config) -> W { for diagnostic in &self.diagnostics { emit(&mut writer, config, &self.files, &diagnostic).unwrap(); } writer } pub fn emit_color(&'files self, config: &Config) -> String { self.emit(ColorBuffer::new(), &config).into_string() } pub fn emit_no_color(&'files self, config: &Config) -> String { let buffer = self.emit(Buffer::no_color(), &config); String::from_utf8_lossy(buffer.as_slice()).into_owned() } } codespan-reporting-0.11.1/tests/term.rs000064400000000000000000001130320000000000000161430ustar 00000000000000use codespan_reporting::diagnostic::{Diagnostic, Label}; use codespan_reporting::files::{SimpleFile, SimpleFiles}; use codespan_reporting::term::{termcolor::Color, Chars, Config, DisplayStyle, Styles}; mod support; use self::support::TestData; lazy_static::lazy_static! { static ref TEST_CONFIG: Config = Config { // Always use blue so tests are consistent across platforms styles: Styles::with_blue(Color::Blue), ..Config::default() }; } macro_rules! test_emit { (rich_color) => { #[test] fn rich_color() { let config = Config { display_style: DisplayStyle::Rich, ..TEST_CONFIG.clone() }; 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() { let config = Config { display_style: DisplayStyle::Short, ..TEST_CONFIG.clone() }; insta::assert_snapshot!(TEST_DATA.emit_color(&config)); } }; (rich_no_color) => { #[test] fn rich_no_color() { let config = Config { display_style: DisplayStyle::Rich, ..TEST_CONFIG.clone() }; 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() { let config = Config { display_style: DisplayStyle::Short, ..TEST_CONFIG.clone() }; insta::assert_snapshot!(TEST_DATA.emit_no_color(&config)); } }; (rich_ascii_no_color) => { #[test] fn rich_ascii_no_color() { let config = Config { display_style: DisplayStyle::Rich, chars: Chars::ascii(), ..TEST_CONFIG.clone() }; insta::assert_snapshot!(TEST_DATA.emit_no_color(&config)); } }; } mod empty { 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::bug(), Diagnostic::error(), Diagnostic::warning(), Diagnostic::note(), Diagnostic::help(), Diagnostic::bug(), ]; TestData { files, diagnostics } }; } 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); test_emit!(rich_ascii_no_color); } /// Based on: /// - https://github.com/rust-lang/rust/blob/c20d7eecbc0928b57da8fe30b2ef8528e2bdd5be/src/test/ui/codemap_tests/one_line.stderr mod same_line { use super::*; lazy_static::lazy_static! { static ref TEST_DATA: TestData<'static, SimpleFiles<&'static str, String>> = { let mut files = SimpleFiles::new(); let file_id1 = files.add( "one_line.rs", unindent::unindent(r#" fn main() { let mut v = vec![Some("foo"), Some("bar")]; v.push(v.pop().unwrap()); } "#), ); let diagnostics = vec![ Diagnostic::error() .with_code("E0499") .with_message("cannot borrow `v` as mutable more than once at a time") .with_labels(vec![ Label::primary(file_id1, 71..72) .with_message("second mutable borrow occurs here"), Label::secondary(file_id1, 64..65) .with_message("first borrow later used by call"), Label::secondary(file_id1, 66..70) .with_message("first mutable borrow occurs here"), ]), Diagnostic::error() .with_message("aborting due to previous error") .with_notes(vec![ "For more information about this error, try `rustc --explain E0499`.".to_owned(), ]), ]; TestData { files, diagnostics } }; } 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); test_emit!(rich_ascii_no_color); } /// Based on: /// - https://github.com/rust-lang/rust/blob/c20d7eecbc0928b57da8fe30b2ef8528e2bdd5be/src/test/ui/nested_impl_trait.stderr /// - https://github.com/rust-lang/rust/blob/c20d7eecbc0928b57da8fe30b2ef8528e2bdd5be/src/test/ui/typeck/typeck_type_placeholder_item.stderr /// - https://github.com/rust-lang/rust/blob/c20d7eecbc0928b57da8fe30b2ef8528e2bdd5be/src/test/ui/no_send_res_ports.stderr mod overlapping { use super::*; lazy_static::lazy_static! { static ref TEST_DATA: TestData<'static, SimpleFiles<&'static str, String>> = { let mut files = SimpleFiles::new(); let file_id1 = files.add( "nested_impl_trait.rs", unindent::unindent(r#" use std::fmt::Debug; fn fine(x: impl Into) -> impl Into { x } fn bad_in_ret_position(x: impl Into) -> impl Into { x } "#), ); let file_id2 = files.add( "typeck_type_placeholder_item.rs", unindent::unindent(r#" fn fn_test1() -> _ { 5 } fn fn_test2(x: i32) -> (_, _) { (x, x) } "#), ); let file_id3 = files.add( "libstd/thread/mod.rs", unindent::unindent(r#" #[stable(feature = "rust1", since = "1.0.0")] pub fn spawn(self, f: F) -> io::Result> where F: FnOnce() -> T, F: Send + 'static, T: Send + 'static, { unsafe { self.spawn_unchecked(f) } } "#), ); let file_id4 = files.add( "no_send_res_ports.rs", unindent::unindent(r#" use std::thread; use std::rc::Rc; #[derive(Debug)] struct Port(Rc); fn main() { #[derive(Debug)] struct Foo { _x: Port<()>, } impl Drop for Foo { fn drop(&mut self) {} } fn foo(x: Port<()>) -> Foo { Foo { _x: x } } let x = foo(Port(Rc::new(()))); thread::spawn(move|| { let y = x; println!("{:?}", y); }); } "#), ); let diagnostics = vec![ Diagnostic::error() .with_code("E0666") .with_message("nested `impl Trait` is not allowed") .with_labels(vec![ Label::primary(file_id1, 129..139) .with_message("nested `impl Trait` here"), Label::secondary(file_id1, 119..140) .with_message("outer `impl Trait`"), ]), Diagnostic::error() .with_code("E0121") .with_message("the type placeholder `_` is not allowed within types on item signatures") .with_labels(vec![ Label::primary(file_id2, 17..18) .with_message("not allowed in type signatures"), Label::secondary(file_id2, 17..18) .with_message("help: replace with the correct return type: `i32`"), ]), Diagnostic::error() .with_code("E0121") .with_message("the type placeholder `_` is not allowed within types on item signatures") .with_labels(vec![ Label::primary(file_id2, 49..50) .with_message("not allowed in type signatures"), Label::primary(file_id2, 52..53) .with_message("not allowed in type signatures"), Label::secondary(file_id2, 48..54) .with_message("help: replace with the correct return type: `(i32, i32)`"), ]), Diagnostic::error() .with_code("E0277") .with_message("`std::rc::Rc<()>` cannot be sent between threads safely") .with_labels(vec![ Label::primary(file_id4, 339..352) .with_message("`std::rc::Rc<()>` cannot be sent between threads safely"), Label::secondary(file_id4, 353..416) .with_message("within this `[closure@no_send_res_ports.rs:29:19: 33:6 x:main::Foo]`"), Label::secondary(file_id3, 141..145) .with_message("required by this bound in `std::thread::spawn`"), ]) .with_notes(vec![ "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<()>`".to_owned(), "note: required because it appears within the type `Port<()>`".to_owned(), "note: required because it appears within the type `main::Foo`".to_owned(), "note: required because it appears within the type `[closure@no_send_res_ports.rs:29:19: 33:6 x:main::Foo]`".to_owned(), ]), Diagnostic::error() .with_message("aborting due 5 previous errors") .with_notes(vec![ "Some errors have detailed explanations: E0121, E0277, E0666.".to_owned(), "For more information about an error, try `rustc --explain E0121`.".to_owned(), ]), ]; TestData { files, diagnostics } }; } 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); test_emit!(rich_ascii_no_color); } mod message { 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"), Diagnostic::warning().with_message("a message"), Diagnostic::note().with_message("a message"), Diagnostic::help().with_message("a message"), ]; TestData { files, diagnostics } }; } 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); test_emit!(rich_ascii_no_color); } mod message_and_notes { 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_notes(vec!["a note".to_owned()]), Diagnostic::warning().with_message("a message").with_notes(vec!["a note".to_owned()]), Diagnostic::note().with_message("a message").with_notes(vec!["a note".to_owned()]), Diagnostic::help().with_message("a message").with_notes(vec!["a note".to_owned()]), ]; TestData { files, diagnostics } }; } 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); test_emit!(rich_ascii_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); test_emit!(rich_ascii_no_color); } mod empty_ranges { use super::*; lazy_static::lazy_static! { static ref TEST_DATA: TestData<'static, SimpleFile<&'static str, &'static str>> = { let file = SimpleFile::new("hello", "Hello world!\nBye world!\n "); let eof = file.source().len(); let diagnostics = vec![ Diagnostic::note() .with_message("middle") .with_labels(vec![Label::primary((), 6..6).with_message("middle")]), Diagnostic::note() .with_message("end of line") .with_labels(vec![Label::primary((), 12..12).with_message("end of line")]), Diagnostic::note() .with_message("end of line") .with_labels(vec![Label::primary((), 23..23).with_message("end of line")]), Diagnostic::note() .with_message("end of file") .with_labels(vec![Label::primary((), eof..eof).with_message("end of file")]), ]; TestData { files: file, diagnostics } }; } 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); test_emit!(rich_ascii_no_color); } mod same_ranges { use super::*; lazy_static::lazy_static! { static ref TEST_DATA: TestData<'static, SimpleFile<&'static str, &'static str>> = { let file = SimpleFile::new("same_range", "::S { }"); let diagnostics = vec![ Diagnostic::error() .with_message("Unexpected token") .with_labels(vec![ Label::primary((), 4..4).with_message("Unexpected '{'"), Label::secondary((), 4..4).with_message("Expected '('"), ]), ]; TestData { files: file, diagnostics } }; } 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); test_emit!(rich_ascii_no_color); } mod multifile { use super::*; lazy_static::lazy_static! { static ref TEST_DATA: TestData<'static, SimpleFiles<&'static str, String>> = { let mut files = SimpleFiles::new(); let file_id1 = files.add( "Data/Nat.fun", unindent::unindent( " module Data.Nat where data Nat : Type where zero : Nat succ : Nat → Nat {-# BUILTIN NATRAL Nat #-} infixl 6 _+_ _-_ _+_ : Nat → Nat → Nat zero + n₂ = n₂ succ n₁ + n₂ = succ (n₁ + n₂) _-_ : Nat → Nat → Nat n₁ - zero = n₁ zero - succ n₂ = zero succ n₁ - succ n₂ = n₁ - n₂ ", ), ); let file_id2 = files.add( "Test.fun", unindent::unindent( r#" module Test where _ : Nat _ = 123 + "hello" "#, ), ); let diagnostics = vec![ // Unknown builtin error Diagnostic::error() .with_message("unknown builtin: `NATRAL`") .with_labels(vec![Label::primary(file_id1, 96..102).with_message("unknown builtin")]) .with_notes(vec![ "there is a builtin with a similar name: `NATURAL`".to_owned(), ]), // Unused parameter warning Diagnostic::warning() .with_message("unused parameter pattern: `n₂`") .with_labels(vec![Label::primary(file_id1, 285..289).with_message("unused parameter")]) .with_notes(vec!["consider using a wildcard pattern: `_`".to_owned()]), // Unexpected type error Diagnostic::error() .with_message("unexpected type in application of `_+_`") .with_code("E0001") .with_labels(vec![ Label::primary(file_id2, 37..44).with_message("expected `Nat`, found `String`"), Label::secondary(file_id1, 130..155).with_message("based on the definition of `_+_`"), ]) .with_notes(vec![unindent::unindent( " expected type `Nat` found type `String` ", )]), ]; TestData { files, diagnostics } }; } 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); test_emit!(rich_ascii_no_color); } mod fizz_buzz { use super::*; lazy_static::lazy_static! { static ref TEST_DATA: TestData<'static, SimpleFiles<&'static str, String>> = { let mut files = SimpleFiles::new(); let file_id = files.add( "FizzBuzz.fun", unindent::unindent( r#" module FizzBuzz where fizz₁ : Nat → String fizz₁ num = case (mod num 5) (mod num 3) of 0 0 => "FizzBuzz" 0 _ => "Fizz" _ 0 => "Buzz" _ _ => num fizz₂ : Nat → String fizz₂ num = case (mod num 5) (mod num 3) of 0 0 => "FizzBuzz" 0 _ => "Fizz" _ 0 => "Buzz" _ _ => num "#, ), ); let diagnostics = vec![ // Incompatible match clause error Diagnostic::error() .with_message("`case` clauses have incompatible types") .with_code("E0308") .with_labels(vec![ Label::primary(file_id, 163..166).with_message("expected `String`, found `Nat`"), Label::secondary(file_id, 62..166).with_message("`case` clauses have incompatible types"), Label::secondary(file_id, 41..47).with_message("expected type `String` found here"), ]) .with_notes(vec![unindent::unindent( " expected type `String` found type `Nat` ", )]), // Incompatible match clause error Diagnostic::error() .with_message("`case` clauses have incompatible types") .with_code("E0308") .with_labels(vec![ Label::primary(file_id, 328..331).with_message("expected `String`, found `Nat`"), Label::secondary(file_id, 211..331).with_message("`case` clauses have incompatible types"), Label::secondary(file_id, 258..268).with_message("this is found to be of type `String`"), Label::secondary(file_id, 284..290).with_message("this is found to be of type `String`"), Label::secondary(file_id, 306..312).with_message("this is found to be of type `String`"), Label::secondary(file_id, 186..192).with_message("expected type `String` found here"), ]) .with_notes(vec![unindent::unindent( " expected type `String` found type `Nat` ", )]), ]; TestData { files, diagnostics } }; } 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); test_emit!(rich_ascii_no_color); } mod multiline_overlapping { use super::*; lazy_static::lazy_static! { static ref TEST_DATA: TestData<'static, SimpleFile<&'static str, String>> = { let file = SimpleFile::new( "codespan/src/file.rs", [ " match line_index.compare(self.last_line_index()) {", " Ordering::Less => Ok(self.line_starts()[line_index.to_usize()]),", " Ordering::Equal => Ok(self.source_span().end()),", " Ordering::Greater => LineIndexOutOfBoundsError {", " given: line_index,", " max: self.last_line_index(),", " },", " }", ].join("\n"), ); let diagnostics = vec![ Diagnostic::error() .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`"), 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((), 167..195).with_message("this is found to be of type `Result`"), ]) .with_notes(vec![unindent::unindent( " expected type `Result` found type `LineIndexOutOfBoundsError` ", )]), ]; TestData { files: file, diagnostics } }; } 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); test_emit!(rich_ascii_no_color); } mod tabbed { use super::*; lazy_static::lazy_static! { static ref TEST_DATA: TestData<'static, SimpleFiles<&'static str, String>> = { let mut files = SimpleFiles::new(); let file_id = files.add( "tabbed", [ "Entity:", "\tArmament:", "\t\tWeapon: DogJaw", "\t\tReloadingCondition:\tattack-cooldown", "\tFoo: Bar", ] .join("\n"), ); let diagnostics = vec![ Diagnostic::warning() .with_message("unknown weapon `DogJaw`") .with_labels(vec![Label::primary(file_id, 29..35).with_message("the weapon")]), Diagnostic::warning() .with_message("unknown condition `attack-cooldown`") .with_labels(vec![Label::primary(file_id, 58..73).with_message("the condition")]), Diagnostic::warning() .with_message("unknown field `Foo`") .with_labels(vec![Label::primary(file_id, 75..78).with_message("the field")]), ]; TestData { files, diagnostics } }; } #[test] fn tab_width_default_no_color() { let config = TEST_CONFIG.clone(); insta::assert_snapshot!(TEST_DATA.emit_no_color(&config)); } #[test] fn tab_width_3_no_color() { let config = Config { tab_width: 3, ..TEST_CONFIG.clone() }; insta::assert_snapshot!(TEST_DATA.emit_no_color(&config)); } #[test] fn tab_width_6_no_color() { let config = Config { tab_width: 6, ..TEST_CONFIG.clone() }; insta::assert_snapshot!(TEST_DATA.emit_no_color(&config)); } } mod tab_columns { use super::*; lazy_static::lazy_static! { static ref TEST_DATA: TestData<'static, SimpleFiles<&'static str, String>> = { let mut files = SimpleFiles::new(); let source = [ "\thello", "∙\thello", "∙∙\thello", "∙∙∙\thello", "∙∙∙∙\thello", "∙∙∙∙∙\thello", "∙∙∙∙∙∙\thello", ].join("\n"); let hello_ranges = source .match_indices("hello") .map(|(start, hello)| start..(start+hello.len())) .collect::>(); let file_id = files.add("tab_columns", source); let diagnostics = vec![ Diagnostic::warning() .with_message("tab test") .with_labels( hello_ranges .into_iter() .map(|range| Label::primary(file_id, range)) .collect(), ), ]; TestData { files, diagnostics } }; } #[test] fn tab_width_default_no_color() { let config = TEST_CONFIG.clone(); insta::assert_snapshot!(TEST_DATA.emit_no_color(&config)); } #[test] fn tab_width_2_no_color() { let config = Config { tab_width: 2, ..TEST_CONFIG.clone() }; insta::assert_snapshot!(TEST_DATA.emit_no_color(&config)); } #[test] fn tab_width_3_no_color() { let config = Config { tab_width: 3, ..TEST_CONFIG.clone() }; insta::assert_snapshot!(TEST_DATA.emit_no_color(&config)); } #[test] fn tab_width_6_no_color() { let config = Config { tab_width: 6, ..TEST_CONFIG.clone() }; insta::assert_snapshot!(TEST_DATA.emit_no_color(&config)); } } /// Based on: /// - https://github.com/TheSamsa/rust/blob/75cf41afb468152611212271bae026948cd3ba46/src/test/ui/codemap_tests/unicode.stderr mod unicode { use super::*; lazy_static::lazy_static! { static ref TEST_DATA: TestData<'static, SimpleFile<&'static str, String>> = { let prefix = r#"extern "#; let abi = r#""路濫狼á́́""#; let suffix = r#" fn foo() {}"#; let file = SimpleFile::new( "unicode.rs", format!("{}{}{}", prefix, abi, suffix), ); let diagnostics = vec![ Diagnostic::error() .with_code("E0703") .with_message("invalid ABI: found `路濫狼á́́`") .with_labels(vec![ Label::primary((), prefix.len()..(prefix.len() + abi.len())) .with_message("invalid ABI"), ]) .with_notes(vec![unindent::unindent( " 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 ", )]), Diagnostic::error() .with_message("aborting due to previous error") .with_notes(vec![ "For more information about this error, try `rustc --explain E0703`.".to_owned(), ]), ]; TestData { files: file, diagnostics } }; } test_emit!(rich_no_color); test_emit!(medium_no_color); test_emit!(short_no_color); } mod unicode_spans { use super::*; lazy_static::lazy_static! { static ref TEST_DATA: TestData<'static, SimpleFile<&'static str, String>> = { let moon_phases = format!("{}", r#"🐄🌑🐄🌒🐄🌓🐄🌔🐄🌕🐄🌖🐄🌗🐄🌘🐄"#); let invalid_start = 1; let invalid_end = "🐄".len() - 1; assert_eq!(moon_phases.is_char_boundary(invalid_start), false); assert_eq!(moon_phases.is_char_boundary(invalid_end), false); assert_eq!("🐄".len(), 4); let file = SimpleFile::new( "moon_jump.rs", moon_phases, ); let diagnostics = vec![ Diagnostic::error() .with_code("E01") .with_message("cow may not jump during new moon.") .with_labels(vec![ Label::primary((), invalid_start..invalid_end) .with_message("Invalid jump"), ]), Diagnostic::note() .with_message("invalid unicode range") .with_labels(vec![ Label::secondary((), invalid_start.."🐄".len()) .with_message("Cow range does not start at boundary."), ]), Diagnostic::note() .with_message("invalid unicode range") .with_labels(vec![ Label::secondary((), "🐄🌑".len().."🐄🌑🐄".len() - 1) .with_message("Cow range does not end at boundary."), ]), Diagnostic::note() .with_message("invalid unicode range") .with_labels(vec![ Label::secondary((), invalid_start.."🐄🌑🐄".len() - 1) .with_message("Cow does not start or end at boundary."), ]), ]; TestData{files: file, diagnostics } }; } 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); test_emit!(rich_ascii_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); }