Git Product home page Git Product logo

yvette's Introduction

yvette

CI codecov Maven Central javadoc License

A diagnostic reporting library for Java, ported from the Rust library miette.

An example of a graphical error message produced by this library is shown. The error message text is preceded by a red cross symbol. This is followed by the message "Mismatched type! Expected: Int, Actual: Tree[A]". Following the error message a source code snippet is printed, headed by a hyperlink pointing to the underlying file and line number that is in error. Line numbers are shown in the margin indicating the location of the snippet in the underlying source file. The specific term in the source code that is in error is underlined using a blue line.

Installation

yvette is published for Java 8 and above.

Gradle (build.gradle / build.gradle.kts):

implementation("com.opencastsoftware:yvette:0.2.0")

Maven (pom.xml):

<dependency>
    <groupId>com.opencastsoftware</groupId>
    <artifactId>yvette</artifactId>
    <version>0.2.0</version>
</dependency>

To use the GraphicalReportHandler and other features of the package com.opencastsoftware.yvette.handlers.graphical, the jansi library is also needed:

Gradle (build.gradle / build.gradle.kts):

implementation("org.fusesource.jansi:jansi:2.4.0")

Maven (pom.xml):

<dependency>
    <groupId>org.fusesource.jansi</groupId>
    <artifactId>jansi</artifactId>
    <version>2.4.0</version>
</dependency>

Displaying diagnostics

In order to display diagnostics with yvette, your application's error messages must implement the abstract class Diagnostic. All of the methods of this class may return null, but bear in mind that your diagnostics may not be very helpful without a message.

A BasicDiagnostic implementation is provided, which can be used to wrap exceptions:

Diagnostic err = new BasicDiagnostic(e.getMessage(), e.getCause());

You can then implement a ReportHandler to display your diagnostics using the Appendable instance you wish to use for output, for example System.out, System.err or a StringBuilder.

yvette provides a GraphicalReportHandler which produces output like the screenshot above. You can create one of these using the GraphicalReportHandler.builder() static method:

ReportHandler reportHandler = GraphicalReportHandler.builder()
    .withRgbColours(RgbColours.PREFERRED)
    .buildFor(System.err);

There are some terminal feature detection features in yvette. If you wish to bypass these, use the withColours, withTerminalWidth and withUnicode methods of the builder to enable or disable those features explicitly. However, please bear in mind that using withColours to force enable colour output will override the NO_COLOR detection implemented by this library.

Once you have a ReportHandler, it can be used to output diagnostics:

Diagnostic diagnostic = ???; // A diagnostic from your application
reportHandler.display(diagnostic, System.err);

Uncaught exception handler

yvette provides an implementation of Thread.UncaughtExceptionHandler which can be used to replace the default handler for all threads.

import com.opencastsoftware.yvette.UncaughtExceptionHandler;

ReportHandler handler = ???; // Your report handler, obtained as described above

try {
    UncaughtExceptionHandler.install(handler, System.err); // Installs the new handler
} finally {
    UncaughtExceptionHandler.uninstall(); // Restores the default handler
}

The setup above will print diagnostics to STDERR:

new Thread(() -> {
    Throwable exc = new FileNotFoundException("Couldn't find the file BadFile.java");
    exc.initCause(new AccessDeniedException("Access denied to file BadFile.java"));
    throw new RuntimeException("Whoops!", exc);
}).start();

/*
Uncaught exception in thread Thread-5:
    x Whoops!
    |-> Couldn't find the file BadFile.java
    `-> Access denied to file BadFile.java

java.lang.RuntimeException: Whoops!
    at com.opencastsoftware.yvette.UncaughtExceptionHandlerTest.lambda$replacesThreadPoolHandler$2(UncaughtExceptionHandlerTest.java:87)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:750)
Caused by: java.io.FileNotFoundException: Couldn't find the file BadFile.java
    at com.opencastsoftware.yvette.UncaughtExceptionHandlerTest.lambda$replacesThreadPoolHandler$2(UncaughtExceptionHandlerTest.java:85)
    ... 3 more
Caused by: java.nio.file.AccessDeniedException: Access denied to file BadFile.java
    at com.opencastsoftware.yvette.UncaughtExceptionHandlerTest.lambda$replacesThreadPoolHandler$2(UncaughtExceptionHandlerTest.java:86)
    ... 3 more
*/

It can also be set as the uncaught exception handler for new threads in a thread pool by using a ThreadFactory:

Thread.UncaughtExceptionHandler excHandler = UncaughtExceptionHandler.create(handler, System.err);

ThreadFactory threadFactory = runnable -> {
    Thread thread = new Thread(runnable);
    thread.setUncaughtExceptionHandler(excHandler);
    thread.setDaemon(true);
    return newThread;
};

Deviations and Limitations

This is not an exact port of miette - there are some differences and unported features:

  • Where miette and the Language Server Protocol's definitions deviate, we have erred on the side of alignment with LSP. This is for ease of integrating yvette with language server applications. For example, miette uses SourceSpan to keep track of the byte offset and length of a span within a source file. However, yvette's equivalent of SourceSpan is called Range, and specifies a start and end Position, each of which refers to a zero-indexed line and character position within a document. The upside of this is alignment with LSP, but the downside is that we can no longer efficiently read arbitrary offsets of a source file in order to get the span contents.
  • Only the GraphicalReportHandler and ToStringReportHandler are currently implemented, there is no NarratableReportHandler or JSONReportHandler as yet.
  • There is no special handling of tab characters or unicode character width in yvette yet, which may mean that your highlights are misaligned with the source code they are supposed to underline.
  • Related diagnostics are not currently implemented in yvette, since the definition of DiagnosticRelatedInformation is sufficiently different in the Language Server Protocol that we haven't decided how to implement it yet.

Acknowlegements

This project wouldn't exist without the work of zkat and the other miette contributors.

License

All code in this repository is licensed under the Apache License, Version 2.0. See LICENSE.

yvette's People

Contributors

davidgregory084 avatar renovate[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar

Forkers

bigdaz

yvette's Issues

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

This repository currently has no open or pending branches.

Detected dependencies

github-actions
.github/workflows/ci.yml
  • actions/checkout v3
  • gradle/wrapper-validation-action v1
  • typelevel/download-java v2
  • actions/setup-java v3.11.0
  • gradle/gradle-build-action v2.6.1
  • codecov/codecov-action v3
  • actions/upload-artifact v3
  • gradle/gradle-build-action v2.6.1
.github/workflows/test-report.yml
  • dawidd6/action-download-artifact v2
  • mikepenz/action-junit-report v3
gradle
settings.gradle.kts
build.gradle.kts
gradle/libs.versions.toml
  • org.apache.commons:commons-lang3 3.12.0
  • org.apache.commons:commons-text 1.10.0
  • nl.jqno.equalsverifier:equalsverifier 3.15
  • org.hamcrest:hamcrest 2.2
  • org.fusesource.jansi:jansi 2.4.0
  • net.jqwik:jqwik 1.7.4
  • org.junit.jupiter:junit-jupiter 5.10.0
  • com.jparams:to-string-verifier 1.4.8
  • com.opencastsoftware.gradle.java-conventions 0.1.4
gradle-wrapper
gradle/wrapper/gradle-wrapper.properties
  • gradle 8.2.1

  • Check this box to trigger a request for Renovate to run again on this repository

Integration with prettier4j

At present the messages in this library are broken over lines by using the WordUtils.wrap methods of Apache Commons Text.

This is perfectly fine for most purposes, but it doesn't offer the user much control over how messages are laid out.

Since we already have a pretty printing library in https://github.com/opencastsoftware/prettier4j, it would be nice if we could make use of that library's Doc to lay out messages.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.