{"id":32183806,"url":"https://github.com/cgrand/packed-printer","last_synced_at":"2025-10-21T23:07:45.929Z","repository":{"id":57317822,"uuid":"111840357","full_name":"cgrand/packed-printer","owner":"cgrand","description":"Compact pretty printer","archived":false,"fork":false,"pushed_at":"2017-11-29T13:07:04.000Z","size":27,"stargazers_count":39,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-21T23:07:10.003Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cgrand.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}},"created_at":"2017-11-23T18:35:10.000Z","updated_at":"2025-03-08T16:52:08.000Z","dependencies_parsed_at":"2022-08-25T21:12:13.915Z","dependency_job_id":null,"html_url":"https://github.com/cgrand/packed-printer","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/cgrand/packed-printer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cgrand%2Fpacked-printer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cgrand%2Fpacked-printer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cgrand%2Fpacked-printer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cgrand%2Fpacked-printer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cgrand","download_url":"https://codeload.github.com/cgrand/packed-printer/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cgrand%2Fpacked-printer/sbom","scorecard":{"id":272563,"data":{"date":"2025-08-11","repo":{"name":"github.com/cgrand/packed-printer","commit":"598d55d5b93790c3838e48ac8707d96d984ffea0"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Code-Review","score":0,"reason":"Found 0/11 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Eclipse Public License 1.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-17T13:44:30.021Z","repository_id":57317822,"created_at":"2025-08-17T13:44:30.021Z","updated_at":"2025-08-17T13:44:30.021Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280348072,"owners_count":26315370,"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","status":"online","status_checked_at":"2025-10-21T02:00:06.614Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":"2025-10-21T23:03:39.241Z","updated_at":"2025-10-21T23:07:45.920Z","avatar_url":"https://github.com/cgrand.png","language":"Clojure","funding_links":[],"categories":["Debugging"],"sub_categories":[],"readme":"# packed-printer\n\nA Clojure and Clojurescript library to pretty print data in a packed manner.\n\n*This printer likes rectangular shapes (the wider the better) and despises staircases.*\n\nIt's an adaptation of [minimum raggedness](https://en.wikipedia.org/wiki/Line_wrap_and_word_wrap#Minimum_raggedness) (used by TeX for non-justified text) to data.\n\n## Packed printer in one sentence\n\n## Usage\n\nCoordinates `[net.cgrand/packed-printer \"0.2.1\"]`.\n\n```clj\n(require '[net.cgrand.packed-printer :refer [pprint]])\n```\n\nRelaxed mode:\n```clj\n=\u003e (pprint (partition 10 (range 50)) :width 15)\n;...5....0....5\n((0 1 2 3 4\n  5 6 7 8 9)\n (10 11 12 13 14\n  15 16 17 18 19)\n (20 21 22 23 24\n  25 26 27 28 29)\n (30 31 32 33 34\n  35 36 37 38 39)\n (40 41 42 43 44\n  45 46 47 48 49))\n```\n\nStrict mode:\n```clj\n=\u003e (pprint (partition 10 (range 50)) :width 15 :strict true)\n;...5....0....5\n((0 1 2 3 4\n  5 6 7 8 9)\n (10 11 12\n  13 14 15 16\n  17 18 19)\n (20 21 22\n  23 24 25 26\n  27 28 29)\n (30 31 32\n  33 34 35 36\n  37 38 39)\n (40 41 42\n  43 44 45 46\n  47 48 49))\n```\n\nOn code (not intended for that):\n```clj\n=\u003e (pprint '(defn render [lines]\n     (doseq [{:keys [indent] [head \u0026 spans] :spans} lines]\n       (prsp indent) (prsp (leading-spaces head true)) (print (str head))\n       (doseq [span spans]  (prsp (leading-spaces span false)) (print (str span)))\n       (newline)))\n     :coll-indents {\"(\" 2})\n(defn render [lines]\n  (doseq [{:keys [indent],  [head \u0026 spans] :spans} lines]\n    (prsp indent) (prsp (leading-spaces head true)) (print (str head))\n    (doseq [span spans] (prsp (leading-spaces span false))\n      (print (str span)))\n    (newline)))\n```\n\nValues are indented when they can't be set on the same line:\n\n```clj\n=\u003e (pprint '{:foo :bar :baz :quux} :width 10)\n{:foo :bar,\n :baz :quux}\n=\u003e (pprint '{:foo :bar :baz :quux} :width 6)\n{:foo\n   :bar,\n :baz\n   :quux}\n```\n\n## Comparison\n\n### clojure.pprint\n```clj\n=\u003e (binding [clojure.pprint/*print-right-margin* 30]\n     (clojure.pprint/pprint {:a :b :c {:e :f :g :h :i :j :k :l} :m :n :o {:p {:q :r :s :t}}}))\n\n;        1    1    2    2    3\n;...5....0....5....0....5....0\n{:a :b,\n :c\n {:e :f,\n  :g :h,\n  :i :j,\n  :k :l},\n :m :n,\n :o {:p {:q :r, :s :t}}}\n```\n\n### zprint\n```clj\n=\u003e (czprint {:a :b :c {:e :f :g :h :i :j :k :l} :m :n :o {:p {:q :r :s :t}}} 30 {:map {:nl-separator? true}})\n\n;        1    1    2    2    3\n;...5....0....5....0....5....0\n{:a :b,\n :c {:e :f,\n     :g :h,\n     :i :j,\n     :k :l},\n :m :n,\n :o {:p {:q :r, :s :t}}}\n ```\n\n### packed-printer \n```clj\n=\u003e (pprint {:a :b :c {:e :f :g :h :i :j :k :l} :m :n :o {:p {:q :r :s :t}}} :width 30)\n\n;        1    1    2    2    3\n;...5....0....5....0....5....0\n{:a :b, :c {:e :f, :g :h,\n            :i :j, :k :l},\n :m :n, :o {:p {:q :r, :s :t}}}\n```\n\nAnd in strict mode:\n\n```clj\n=\u003e (pprint {:a :b :c {:e :f :g :h :i :j :k :l} :m :n :o {:p {:q :r :s :t}}} :width 30 :strict true)\n\n;        1    1    2    2    3\n;...5....0....5....0....5....0\n{:a :b, :c {:e :f, :g :h,\n            :i :j, :k :l},\n :m :n, :o {:p {:q :r,\n                :s :t}}}\n```\n\nAnd in between:\n\n```clj\n=\u003e (pprint {:a :b :c {:e :f :g :h :i :j :k :l} :m :n :o {:p {:q :r :s :t}}} :width 30 :strict 1)\n\n;        1    1    2    2    3\n;...5....0....5....0....5....0\n{:a :b, :c {:e :f, :g :h, :i :j, :k :l},\n :m :n, :o {:p {:q :r, :s :t}}}\n```\n\n## Stages\n\nThere are three stages: `spans` (which converts data into spans), `layout` (which finds the optimal layout), and `render` (which turns the layout in side effects).\n\nThe main stage in `layout` and is fixed. `core/spans` and `core/render` are multimethods and thus can be extended. Dispatch occurs based on the values of options `:to` (the target, defaults is `:text` and `:as` the input format (default `:edn`). `core/spans` dispatches on the pair `[to as]` while `core/render` dispatches only on `to`.\n\n### `core/spans`\n\nIt must returns a sequences of spans (see protocol `core/Span`).\n\n### `core/render`\n\nIt takes a sequence of lines, a line being a map with keys `:indent` (the amount of whitespace by which to indent the line) and `:spans` a sequence of spans.\n\nWhen `:to` is `:text`, spans must implement the `text/Text` protocol. \n\n## Implementation\n\nComplexity is `O(n * w^3)` where n is the length (in spans) of the data to layout and w is the desired width.\n\nThe `w^3` may be frightening but it's just an upper bound: dynamic programming is used, giving a cache size of `O(n * w^3)` but in practice this cache is very sparsely populated. Binding `core/*print-stats*` to true causes the actual value for `w^3` to be printed out.\n\n### Minimum raggedness\n\nThe usual algorithm found for minimum raggedness is `O(n^2)` and uses dynamic programming.\n\nHowever if you are laying out things on a grid whose number of columns is low then `O(n*w)` is possible. The key insight is that the cost of a layout depends only of the position in the list of words/spans to layout and the position in the current line -- hence the `n*w`.\n\n### Adaptation for data\n\nTo layout data, two parameters are added: current indentation and next line indentation. Both are bounded by `w`. Well, they are bounded by `w` only when `:strict true`.\n\nIn relaxed mode, how far in the margin can things be printed is bounded in practice by the cost function. Making the cost function more punitive (increasing strictness) will result in less margin prints.\n\n## License\n\nCopyright © 2017 Christophe Grand\n\nDistributed under the Eclipse Public License either version 1.0 or (at\nyour option) any later version.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcgrand%2Fpacked-printer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcgrand%2Fpacked-printer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcgrand%2Fpacked-printer/lists"}