Created Started Cancelled
Say each of the three things once A diagnostic prints three pieces of text: the finding message as the error headline, the rule text as the label under the marker, and the rule why as a note. Every rule was answering the same question in all three. A reader stopped by an `Eq` finding got: ``` error[HsNoCustomEq]: This Eq instance is written out. Derive it instead, so that what it compares is the fields of the type. │ ^^^^^^^^^^^^^^^^^^^^^ Eq is derived. = note: If you need a custom equality operation, use a separate function, not the Eq instance. ``` "Derive it instead", "Eq is derived", and then the argument for deriving a third time. Nine of the sixteen finding messages carried a remedy sentence that the marker two lines below already said. This gives each field one job. **The finding message names what was found here, and only that.** Where the rule knows which one it found, it now says so, because that is what varies between two findings of one rule and what a reader scanning a list of them needs: | | before | after | |---|---|---| | `HsNoCustomEq` | This Eq instance is written out. Derive it instead, so that what it compares is the fields of the type. | `Eq User is written out.` | | `HsNoCustomShowRead` | This Show instance is written out. Derive it instead, or discard what it is given if the point is to hide the value. | `Show Secret is written out, and uses the value.` | | `TestNoTestHelpers` | A top-level binding in a test file, beside spec. | `A top-level binding beside spec: resourceDir.` | | `HsAppOnlyMain` | A declaration in an executable's own source, beside main. Nothing here can be imported or tested, so move it into the library. | `A declaration beside main: twice.` | | `HsGenValidInGenPackage` | A GenValid instance outside a -gen package. | `A GenValid instance in thing's library.` | | `CommentBareTodo` | A bare TODO. Reference an issue or a URL, or do it. | `A TODO with no issue and no URL.` | | `HsNoFilePath` | The type FilePath. Say what the path is with Path from path. | `The type FilePath.` | The names come off facts that were already there: `instanceFactType` for the four instance rules, the decl name for the two that report a declaration, the package name for the generator rule. **The rule text is the standard, in the one line the marker has room for.** Six were two sentences or a clause chain where the marker fits a noun phrase. `HsNoFilePath` went from "Say what a path is with path's Path, rather than with FilePath." to "A path is a Path, not a FilePath."; `TestJsonSpecPerJsonType` from 26 words to "ToJSON and FromJSON oblige jsonSpec @T in the gen package's test suite." **The rule why is the argument for the rule.** It stays general to the rule and stops when it has made it. `HsNoFilePath` went 130 words to 43, `TestJsonSpecPerJsonType` 110 to 38, `HsNoCustomShowRead` 105 to 40, `HsAppOnlyMain` 85 to 32, `CommentBareTodo` 80 to 20. Two exceptions were worth their sentence and stayed: `toFilePath` at the edge is not what `HsNoFilePath` reports, and a `Show` that ignores the value is how a secret stays out of the logs. `HsNoSemigroupOnText`'s nine-word why was already the benchmark and is untouched. `ExampleNoShouting` in `hopinion-gen` is left alone. It exists to show a repository adding a rule of its own, and its why is about that rather than about shouting. Goldens reset. 496 tests pass, `nix flake check` passes.