{"id":23403164,"url":"https://github.com/tahabasri/take-a-hint","last_synced_at":"2025-04-08T22:29:58.879Z","repository":{"id":132504269,"uuid":"262800170","full_name":"tahabasri/take-a-hint","owner":"tahabasri","description":"Give your final users hints when getting error messages without the need of documentation.","archived":false,"fork":false,"pushed_at":"2020-07-02T17:11:40.000Z","size":360,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-02-14T17:51:51.012Z","etag":null,"topics":["cli","command-line","emoji","error-handling","error-messages","exception-handler","exceptions","java","uncaught-exception-handler","uncaught-exceptions"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tahabasri.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-05-10T14:04:29.000Z","updated_at":"2023-12-05T09:03:19.000Z","dependencies_parsed_at":null,"dependency_job_id":"29eee0c0-c2e2-492e-bc92-3c3cbf8de3ef","html_url":"https://github.com/tahabasri/take-a-hint","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tahabasri%2Ftake-a-hint","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tahabasri%2Ftake-a-hint/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tahabasri%2Ftake-a-hint/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tahabasri%2Ftake-a-hint/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tahabasri","download_url":"https://codeload.github.com/tahabasri/take-a-hint/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247939210,"owners_count":21021693,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","command-line","emoji","error-handling","error-messages","exception-handler","exceptions","java","uncaught-exception-handler","uncaught-exceptions"],"created_at":"2024-12-22T12:46:22.957Z","updated_at":"2025-04-08T22:29:58.873Z","avatar_url":"https://github.com/tahabasri.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cimg src=\"docs/images/logo/logo-with-title.png\" alt=\"take-a-hint\" height=\"200px\"\u003e\n\n[![Build Status](https://travis-ci.org/tahabasri/take-a-hint.svg?branch=master)](https://travis-ci.org/github/tahabasri/take-a-hint)\n[![codecov](https://codecov.io/gh/tahabasri/take-a-hint/branch/master/graph/badge.svg)](https://codecov.io/gh/tahabasri/take-a-hint)\n[![Follow @TheTahaBasri](https://img.shields.io/twitter/follow/TheTahaBasri.svg?style=social)](https://twitter.com/intent/follow?screen_name=TheTahaBasri) \n\n\n# take-a-hint\nGive final users hints when getting error messages without the need for documentation.\n\n## Introduction\nWouldn't be beneficial to give users hints about what went wrong with a \nfailing command right away, without the need to open any documentation ?\n\ntake-a-hint (a.k.a. Hint) is a tiny framework to change the look-and-feel of Java error messages. \nGiving the possibility to add hints on top of error message, final user can take-a-hint as quick as possible.\n\n## How it works\nGiven the following example:\n```java\npublic class Spaceship {\n    public static void main(String[] args) {\n        Spaceship main = new Spaceship();\n        main.goToMars();\n    }\n\n    private void goToMars() {\n        throw new IllegalStateException(\"Oxygen leak detected !\");\n    }\n}\n```\nTypically, executing this will result in the stacktrace we are all familiar with:\n\n\u003cimg src=\"docs/images/demo.hint.before.png\" width=\"600\"\u003e\n\nAdding Hint is as simple as initializing a Hint object using your main class:\n```java\npublic class Spaceship {\n    public static void main(String[] args) {\n        Spaceship main = new Spaceship();\n        new HintCommand(main).init();\n        main.goToMars();\n    }\n    // ...\n}\n```\nExecuting the new program, we get a new look for our error message.\n\n\u003cimg src=\"docs/images/demo.hint.after.png\" width=\"600\"\u003e\n\nBy default, take-a-hint shows the essential part of the error which is the error message.\nYou can customize your final look further more and obtain something like:\n\n\u003cimg src=\"docs/images/demo.hint.after.extra.png\" width=\"750\"\u003e\n\n### Customization\n\ntake-a-hint comes with pre-defined look-and-feel for your Java error messages. Still, you can -and should- customize final messages depending on your needs.\n\ntake-a-hint offers a set of properties you can customize in code to configure final error messages.\n\n| Property                 | Default value                         | Description |\n| ---------                 | -------------                         | ----------- |\n| showStackTrace            | false                                 | shows or hides stacktrace in final output |\n| showHints                 | true                                  | shows or hides hints messages in final output |\n| defaultExceptionMessage   | 'Application failed with exception :'   | default message for exceptions without custom error message |\n| defaultDocsMessage        | 'See the docs for details : '           | default message for notes about documentations |\n| defaultExitCode           | 1                                     | default exit code to be used by your program when an uncaught exception gets thrown |\n| hintPrefix                | '✅ hints:'                             | default prefix to be used for each line in hints messages |\n| errorPrefix               | '❌ error:'                             | default prefix to be used for each line in error messages |\n| stackPrefix               | '⛔ stack:'                             | default prefix to be used for each line in stacktrace |\n| docsPrefix                | ❔ usage:                             | default prefix to be used for each line in usage messages (docs) |\n| defaultDocsSeparator      | '---'                                   | default separator to be used before showing documentation message |\n| defaultSeparator          | \\t                                    | default separator to be used between each token in final output (e.g between error prefix and message) |\n| docsUrl                   |                                       | global documentation url, if unset, documentation help message won't show up on your final output |\n\nIn order to configure how error messages appear, you can use following options:\n\n- via programmatic API:\n```java\nclass Spaceship{\n    public static void main(String[] args){\n        new HintCommand(new Spaceship())\n                .errorPrefix(\"[ERROR] :\")\n                .showStackTrace(true)\n                .docsUrl(\"https://github.com/tahabasri/take-a-hint\")\n                .init();\n    }\n}\n```\n\n- via annotations:\n```java\n@Hint(\n        errorPrefix = \"[ERROR] :\",\n        showStackTrace = true,\n        docsUrl = \"https://github.com/tahabasri/take-a-hint\"\n)\nclass Spaceship{\n    public static void main(String[] args){\n        new HintCommand(new Spaceship()).init();\n    }\n}\n```\n\nWhen mixing annotation and programmatic API, take-a-hint will opt for configuration by programmatic API.\n\n### Provide easy hints for final users\n\nIt's much better when the final user can get hints on how to fix errors at failure time. take-a-hint offers custom Exception classes to help you communicate hints easily.\n\nIf you have already a code block that throws an exception, you can wrap it inside `HintException` or `HintRuntimeException`. This will let you personalize final error messages depending on your needs. Here are some examples:\n\n```java\nclass Spaceship {\n    private void goToMars() {\n        throw HintRuntimeException.of(\n            new IllegalStateException(\"Oxygen leak !!!\"), // this is your regular exception\n            \"Check your equipments !\" // you can set a custom hint message to be shown to final user\n        );\n    }\n}\n```\n\nWhen the error gets thrown, the final user will get the following message (depending on configuration):\n\n```\n❌ error:\tApplication failed with exception : java.lang.IllegalStateException: Oxygen leak !!!\n\n✅ hints:\tCheck your equipments !\n```\n\nYou can work with checked exceptions while using take-a-hint via the custom exception class `HintException` :\n\n```java\nclass Spaceship {\n    private void goToMars() throws HintException {\n        throw HintException.of(new IllegalStateException(\"Oxygen leak !!!\"), \"Check your equipments !\");\n    }\n}\n// ...\ntry {\n    new Spaceship().goToMars();\n} catch (HintException ex) { // HintException is a checked exception, should be thrown\n    System.out.println(\"Custom error : \" + ex.getHintsMsg()); // use exception instance as you want\n}\n\n```\n\nAnother cool thing you can do with take-a-hint is set a global hint message for method or class. Let's say you have a method that may throw an exception in multiple occasions, and you want to provide a single hint message for the whole method. Then, you can use the annotation `@HintMessage` to do that.\n\n```java\n@Hint\nclass Spaceship {\n    @HintMessage(\"Check your equipments\")\n    private void goToMars(int x) {\n        if(x==-1){\n            throw new IllegalStateException(\"Crash !\");\n        }else if(x==0){\n            throw new IllegalStateException(\"Boom !\");\n        }else{\n            // go\n        }\n    }\n}\n```\n\nFor each exception thrown within the method `goToMars`, take-a-hint will display (depending on the configuration) the custom hint message provided by the annotation `@HintMessage`.\n\nYou can use the same annotation with the parent class. In that case, the provided message in the class will be shown whenever an exception gets thrown within a method of that class. Each method with its own annotation will override the class custom message.\n\n```java\n@Hint\n@HintMessage(\"Check your equipments !\")\nclass Spaceship {\n    @HintMessage(\"What about heat ?\") // this message will override the one in parent class\n    private void goToTheSun(int x) {\n        throw new IllegalStateException(\"Burned !\");\n    }\n\n    // will use parent message\n    private void goToMars() {\n        throw new IllegalStateException(\"Boom !\");\n    }\n}\n```\n\n### Use with Picocli\n\n[Picocli](https://picocli.info/) is a one-file framework for creating Java command line applications with almost zero code.\n\nIn order to add take-a-hint features to your Picocli application, you need to use Hint custom handlers.\n```java\n@CommandLine.Command\n@Hint // this is optional\npublic class PicocliWithHint implements Runnable {\n\n    @CommandLine.Parameters\n    int apiRating;\n\n    public static void main(String[] args) {\n        PicocliWithHint picocliWithHint = new PicocliWithHint();\n        CommandLine cmd = new CommandLine(picocliWithHint);\n        HintCommand hintCmd = new HintCommand(picocliWithHint);\n        // add custom handler for parameter exceptions\n        cmd.setParameterExceptionHandler(new PicocliParameterExceptionHandler(hintCmd));\n        // add custom handler for all other exceptions\n        cmd.setExecutionExceptionHandler(new PicocliExecutionExceptionHandler(hintCmd));\n        System.exit(cmd.execute(args));\n    }\n\n    @Override\n    public void run() {\n        if (apiRating \u003c 3) {\n            throw new RuntimeException(\"Not cool !\");\n        }\n    }\n}\n```\n\nAfter wiring take-a-hint with Picocli, exceptions will be shown with Hint style.\n\n- When running Picocli program without required parameter `apiRating`, we get:\n\n\u003cimg src=\"docs/images/demo.picocli.noparam.png\" width=\"600\"\u003e\n\n- When running Picocli with incompatible parameter for `apiRating`, we get:\n\n\u003cimg src=\"docs/images/demo.picocli.wrongparam.png\" width=\"900\"\u003e\n\n### How to use your own Emoji characters in your Java command-line application\n\ntake-a-hint comes with pre-defined messages with a set of Emojis, you can change yours via the configuration:\n\n- via programmatic API, you can set your default prefix for error messages like this :\n```java\nclass Spaceship{\n    public static void main(String[] args){\n      new HintCommand(new Spaceship()).errorPrefix(\"\\u26D4 error :\").init();\n    }\n}\n```\n\nYour final message will be :\n```\n⛔ error :   Spaceship is no longer a ship!\n```\n\n- via annotations, you can achieve the same result via the following method :\n```java\n@Hint(errorPrefix = \"\\u26D4 error :\")\nclass Spaceship{\n    new HintCommand(new Spaceship()).init();\n}\n```\n\nTo use a new Emoji, you can follow the steps bellow:\n- Visit [Full Emoji List, v13.0](https://unicode.org/emoji/charts/full-emoji-list.html) and find emoji to use.\n- Copy the code in `Code` column and make a search in \n[fileformat.info](http://www.fileformat.info/info/unicode/char/search.htm) using the copied code as query string.\n- Click on the returned result (end of page) and copy the value for column `C/C++/Java source code`.\n- Put the value in your prefix string and recompile your program, it should show the new Emoji.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftahabasri%2Ftake-a-hint","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftahabasri%2Ftake-a-hint","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftahabasri%2Ftake-a-hint/lists"}