Skip to content

Commit

Permalink
add tests and docs
Browse files Browse the repository at this point in the history
  • Loading branch information
mcy committed Oct 2, 2024
1 parent 6018d89 commit b8c45fd
Show file tree
Hide file tree
Showing 34 changed files with 2,080 additions and 4,322 deletions.
40 changes: 0 additions & 40 deletions experimental/report/debug.go

This file was deleted.

110 changes: 110 additions & 0 deletions experimental/report/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Copyright 2020-2024 Buf Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/*
package report provides a robust diagnostics framework. It offers diagnostic
construction, interchange, and ASCII art rendering functionality.
Diagnostics are collected into a [Report], which is a helpful builder over
a slice of [Diagnostic]s. Each [Diagnostic] consists of a Go error plus
metadata for rendering, such as source code spans, notes, and suggestions.
This package takes after Rust's diagnostic philosophy: diagnostics should
be pleasant to read, provide rich information about the error, and come in
a standard, machine-readable format.
Reports can be rendered using a [Renderer], which provides several options
for how to render the result to the user.
A Report can be converted into a Protobuf using [Report.ToProto]. This can
be serialized to e.g. JSON as an alternative error output.
The [IndexedFile] type is a generic utility for converting file offsets into
text editor coordinates. E.g., given a byte offset, what is the user-visible
line and column number? package report expects the caller to construct this
information themselves, to avoid recomputing it unnecessarily.
# Defining Diagnostics
Generally, to definite a diagnostic, you should define a new Go error type,
and then make it implement [Diagnose]. This has two benefits:
1. When someone using your tool as a library looks through a Report, they
can type assert Diagnostic.Err to programmatically determine the nature
of a diagnostic.
2. When emitting the diagnostic in different places you get the same UX.
This means you should do this even if the error type will be unexported.
Sometimes, (2) is not enough of a benefit, in which case you can just use
Report.Errorf() and friends.
# Diagnostics Style Guide
Diagnostics created with package report expect to be written in a certain
way. The following guidelines are taken, mostly verbatim, from the Rust
Project's diagnostics style guide.
https:github.com/rust-lang/rustc-dev-guide/blob/master/src/diagnostics.md
The golden rule: Users will see diagnostics when they are frustrated. Do not
make them more frustrated. Do not make them feel like your tool does not
respect their intelligence.
1. Errors are for semantic constraint violations, i.e., the compiler will
not produce valid output. Warnings are for when the compiler notices
something not strictly forbidden but probably bad. Remarks are
essentially warnings that are not shown to the user by default.
Diagnostic notes are for factual information that adds context to why the
diagnostic was shown. Diagnostic help is for prose suggestions to the
user. Diagnostic debugs are never shown to normal users, and are for
compiler debugging only.
2. Diagnostics should be written in plain, friendly English. Your message
will appear on many surfaces, such as terminals and LSP plugin insets.
The golden standard is that the error message should be readable and
understandable by an inexperienced, hung-over programmer whose native
language is not European, displayed on a dirty budget smartphone screen.
3. Diagnostic messages do not begin with a capital letter and do not end in
punctuation. The compiler does not ask questions. The words "error",
"warning", "remark", "help", and "note" are NEVER capitalized. Never
refer to "a diagnostic"; prefer something more specific, like "compiler
error".
4. Error messages should succinct: short and sweet, keeping in mind (1).
Users will see these messages many, many times.
5. The word "illegal" is illegal. We use this term inside the compiler, but
the word may have negative connotations for some people. "Forbidden" is
also forbidden. Prefer "invalid", "not allowed", etc.
6. The first span in a diagnostic (the primary span) should be precisely
the code that resulted in the error. Try to avoid more than three spans
in an error. Try to pick the smallest spans you can: instead of
highlighting a whole type definition, try highlighting just its name.
7. Try not to emit multiple diagnostics for the same error. This requires
more work in the compiler, but it is worth it for the UX.
8. If your tool does not have enough information to emit a good diagnostic,
that is a bug in either your tool, or in the language your tool operates
on (in both cases, it is the tool's job to acquire this information).
9. When talking about your tool, call it "the compiler", "the linter", etc.
Your tool is a machine, not a person; therefore it does not speak in
first person. When referring to a programming language's semantics,
rather than the compiler's, use that language's name. For example,
"Go does not support...", "... is not valid Protobuf", "this is a
limitation of C++".
*/
package report
Loading

0 comments on commit b8c45fd

Please sign in to comment.