{"id":14128284,"url":"https://github.com/ocaml-dune/pp","last_synced_at":"2025-04-30T07:31:54.308Z","repository":{"id":53473700,"uuid":"248205941","full_name":"ocaml-dune/pp","owner":"ocaml-dune","description":"Pretty printing library ","archived":false,"fork":false,"pushed_at":"2024-09-16T07:58:39.000Z","size":736,"stargazers_count":50,"open_issues_count":2,"forks_count":5,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-09-16T09:24:45.158Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://ocaml-dune.github.io/pp/","language":"OCaml","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ocaml-dune.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":null,"funding":null,"license":"LICENSE.md","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-03-18T10:53:19.000Z","updated_at":"2024-09-16T08:00:44.000Z","dependencies_parsed_at":"2023-02-15T14:20:43.886Z","dependency_job_id":"7e7a64c7-7e4f-4cf8-ad40-2646e4ee9020","html_url":"https://github.com/ocaml-dune/pp","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ocaml-dune%2Fpp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ocaml-dune%2Fpp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ocaml-dune%2Fpp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ocaml-dune%2Fpp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ocaml-dune","download_url":"https://codeload.github.com/ocaml-dune/pp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224201973,"owners_count":17272673,"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":[],"created_at":"2024-08-15T16:01:26.673Z","updated_at":"2024-11-12T01:31:48.321Z","avatar_url":"https://github.com/ocaml-dune.png","language":"OCaml","funding_links":[],"categories":["OCaml"],"sub_categories":[],"readme":"Pp - Pretty printing\n====================\n\n[![CI Status](https://github.com/ocaml-dune/pp/workflows/CI/badge.svg)](https://github.com/ocaml-dune/pp/actions/workflows/ci.yml)\n\nThis library provides a lean alternative to the [Format][format]\nmodule of the OCaml standard library. It aims to make it easy for\nusers to do the right thing. If you have tried `Format` before but\nfind its API complicated and difficult to use, then `Pp` might be a\ngood choice for you.\n\n`Pp` uses the same concepts of boxes and break hints, and the final\nrendering is done to formatter from the `Format` module. However it\ndefines its own algebra which I personaly find easier to work with and\nreason about. No previous knowledge is required to start using this\nlibrary, however the various guides for the `Format` module such as\n[this one][format-guide] should be applicable to `Pp` as well.\n\nExamples\n--------\n\n```ocaml\n# #require \"pp\";;\n# let print pp = Format.printf \"%a@.\" Pp.to_fmt pp;;\nval print : 'a Pp.t -\u003e unit = \u003cfun\u003e\n# print (Pp.enumerate (List.init 10 Fun.id) ~f:(Pp.textf \"%d\"));;\n- 0\n- 1\n- 2\n- 3\n- 4\n- 5\n- 6\n- 7\n- 8\n- 9\n# print (Pp.box ~indent:2 (Pp.text\n         \"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed \\\n          do eiusmod tempor incididunt ut labore et dolore magna \\\n          aliqua. Ut enim ad minim veniam, quis nostrud exercitation \\\n          ullamco laboris nisi ut aliquip ex ea commodo \\\n          consequat. Duis aute irure dolor in reprehenderit in \\\n          voluptate velit esse cillum dolore eu fugiat nulla \\\n          pariatur. Excepteur sint occaecat cupidatat non proident, \\\n          sunt in culpa qui officia deserunt mollit anim id est \\\n          laborum.\"));;\nLorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor\n  incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis\n  nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n  Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore\n  eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident,\n  sunt in culpa qui officia deserunt mollit anim id est laborum.\n- : unit = ()\n# print\n    (Pp.vbox\n       ( Pp.box (Pp.text \"Error: something went wrong!\")\n       ++ Pp.cut\n       ++ Pp.box (Pp.text \"Here are a few things you can do:\")\n       ++ Pp.cut\n       ++ Pp.enumerate ~f:Fun.id\n            [ Pp.text\n                \"read the documentation, double check the way you are using \\\n                 this software to make sure you are not doing something wrong, \\\n                 and hopefully fix the problem on your side and move on\"\n            ; Pp.text\n                \"strace furiously the program to try and understand why \\\n                 exactly it is trying to do what it is doing\"\n            ; Pp.text \"report an issue upstream\"\n            ; Pp.text \"if all else fails\"\n              ++ Pp.cut\n              ++ Pp.enumerate ~f:Pp.text\n                   [ \"scream loudly at your computer\"\n                   ; \"take a break from your keyboard\"\n                   ; \"clear your head and try again\"\n                   ]\n            ] ));;\nError: something went wrong!\nHere are a few things you can do:\n- read the documentation, double check the way you are using this software to\n  make sure you are not doing something wrong, and hopefully fix the problem on\n  your side and move on\n- strace furiously the program to try and understand why exactly it is trying\n  to do what it is doing\n- report an issue upstream\n- if all else fails\n  - scream loudly at your computer\n  - take a break from your keyboard\n  - clear your head and try again\n- : unit = ()\n```\n\nResources\n---------\n\nAs mentioned earlier, [this Format guide][format-guide] can be a good\nstarting point to understand the pretty-printing mechanics of `Pp`.\nAdditionally, [Format Unraveled][format-unraveled] is a great resource\nfor understanding the core mental model of `Format`. And since `Pp`\nuses the same concepts as `Format`, it can be a good resource for `Pp`\ntoo.\n\nNote that the Format Unraveled paper discuss some limitations of\n`Format` that are due to the fact that it never has the full document\nin-memory before rendering it. This does not apply to `Pp` since `Pp`\nclearly always construct the full document in-memory. However, since\nright now the only way to render a `Pp.t` is via the `Format` module,\nthe same limitations that apply to `Format` apply to `Pp` as well. We\nmight add another renderer in the future that does not have these\nlimitations if there is sufficient incentive to do so.\n\nHistory\n-------\n\nThis library comes from the [dune build system][dune]. Initially, to\nconstruct the various messages displayed to the user on the terminal,\ndune was mostly using the `Format` module, and in particular the\n`Format.fprintf` style format strings. The `Format` API, its concepts\nand printf-like format strings are quite complicated and not easy to\ngrasp at all.  It requires quite a bit of learning and practice before\none can be fluent with `Format`.\n\nWhat is more, it is well known that programmers absolutely \"love\"\nspending time writing good error messages. Hint: this is sarcastic.\n\nThe result of all this was terrible and most messages printed by DUne\nwhere badly formatted. So to remedy to the situation we introduced a\n`Pp` module in `stdune`, the mini-standard library inside Dune. `Pp`\nis completely detached from `Format`, and there is no mention of\n`formatter` until the rendering stage. While in the `Pp` world, all we\ndo is construct a document with various formatting hints.\n\nIn the end, the API of `Pp` just makes it easy for someone to do the\nright thing. And this makes all the difference. Since then, it has\nbeen easy to construct well formatted error messages for Dune and the\nformatting of existing error messages has generally improved.\n\nOnce `Pp` was mature enough, we extracted it into its own library so\nthat it can benefit others.\n\nInteroperability\n----------------\n\nIt is easy to integrate `Pp` with `Format`. For that, simply use the\n`Pp.to_fmt` function. For instance, if you have a value `pp` of type\n`_ Pp.t` you can do:\n\n```ocaml\nFormat.fprintf \"... %a ...\" Pp.to_fmt pp\n```\n\nIf you are familiar with the [fmt library][fmt], `Pp.to_fmt` basically\nallows you to go from a `'a Pp.t` to a `'a Fmt.t`. The opposite is not\npossible; it is not possible to inject arbitrary side-effecting\nformatting functions into a `Pp.t`.\n\nIf you want to convert `Pp` tags fot `Format` tags, you can use the\nfunction `Pp.to_fmt_with_tags`.\n\nComparison with other libraries\n-------------------------------\n\nThis is not an in-depth comparison as I haven't used these libraries\nmuch myself, so this is to be taken with a grain of salt. The below is\nbasically what I can tell from a quick look at their API. If you know\nmore and would like to contribute to this comparison, please do so by\nopening a PR :)\n\n### Comparison with fmt\n\nThe main difference with [fmt][fmt] is that `Fmt.t` is am alias for\n`Format.formatter -\u003e 'a -\u003e unit`, while `Pp.t` is an abstract type.\n\n### Comparison with easy-format\n\nThe [easy-format library][easy-format] looks much higher-level than\n`Pp`. `Pp` still works with boxes and break hints like the `Format`\nmodule, while `easy-format` works with atoms, lists and labelled\nnodes.\n\n[format]: https://caml.inria.fr/pub/docs/manual-ocaml/libref/Format.html\n[format-unraveled]: https://hal.archives-ouvertes.fr/hal-01503081/file/format-unraveled.pdf\n[dune]: https://dune.build\n[fmt]: https://erratique.ch/software/fmt\n[format-guide]: http://caml.inria.fr/resources/doc/guides/format.en.html\n[easy-format]: https://github.com/mjambon/easy-format\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Focaml-dune%2Fpp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Focaml-dune%2Fpp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Focaml-dune%2Fpp/lists"}