{"id":15652964,"url":"https://github.com/skellock/crappyprint","last_synced_at":"2025-07-10T10:32:43.714Z","repository":{"id":150230747,"uuid":"166704185","full_name":"skellock/crappyprint","owner":"skellock","description":"A composable string \u0026 terminal printing library for nim.","archived":false,"fork":false,"pushed_at":"2020-05-09T02:13:51.000Z","size":162,"stargazers_count":11,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-09T16:17:54.437Z","etag":null,"topics":["dsl","nim","printing","terminal"],"latest_commit_sha":null,"homepage":"","language":"Nim","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/skellock.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":"2019-01-20T20:09:03.000Z","updated_at":"2025-01-26T21:51:47.000Z","dependencies_parsed_at":"2023-06-15T05:15:10.785Z","dependency_job_id":null,"html_url":"https://github.com/skellock/crappyprint","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skellock%2Fcrappyprint","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skellock%2Fcrappyprint/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skellock%2Fcrappyprint/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skellock%2Fcrappyprint/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/skellock","download_url":"https://codeload.github.com/skellock/crappyprint/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248065281,"owners_count":21041872,"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":["dsl","nim","printing","terminal"],"created_at":"2024-10-03T12:44:21.489Z","updated_at":"2025-04-09T16:18:01.814Z","avatar_url":"https://github.com/skellock.png","language":"Nim","funding_links":[],"categories":[],"sub_categories":[],"readme":"# What is `crappyprint`?\n\n\nA [`nim`](https://nim-lang.org) library to build your own printing DSLs. You can target a `File`, `StringStream` or a `string`.\n\nUse it for:\n\n1. code generators\n2. CLIs with a lot of styled text\n\n\u003cimg src=\"./images/rick.png\" width=578 alt=\"Example\" /\u003e\n\nYou can find the source code for ↑ that image ↑ in `./examples/rick.nim`.\n\n# Basic string example\n\n```nim\nimport crappyprint\n\nvar print = newStringPrint()\n  .text(\"Hello\")\n  .enter()\n  .text(\"World\")\n  .enter()\n\necho $print\n\n# seems like a crappy way to concat strings eh? ;P\n```\n\n# Basic terminal example\n\n```nim\nimport terminal, crappyprint\n\nnewFilePrint()                        # spin it up \u0026 start chaining...\n  .text(\"We're \")                     # normal text\n  .text(\"no \", style={styleBright})   # different styles\n  .text(\"strangers to \")\n  .text(\"love\", fg=fgWhite, bg=bgRed) # different colours\n  .text(\".\")\n  .enter()                            # next line\n```\n\nOr the same thing using the `std/with` available since Nim 1.2.\n\n```nim\nimport terminal, crappyprint, std/with\n\nwith newFilePrint():\n  text \"We're \"\n  text \"no \", style={styleBright}\n  text \"strangers to \"\n  text \"love\", fg=fgWhite, bg=bgRed\n  text \".\"\n  enter\n```\n\nNothing too exciting here, eh?\n\n# Stateful Example\n\nYou can make changes to colors, styles, or indentation.\n\n```nim\nimport terminal, crappyprint\n\nnewFilePrint(spacesPerIndent = 4)\n  .bright()              # any text will now be bold\n  .fg(fgYellow)          # and yellow\n  .text(\"Never gonna:\")\n  .enter()\n  .bright(false)         # text will no longer be bold\n  .fg(fgDefault)         # text will be the default terminal color\n\n  .indent()  # \u003c-- from now on, new lines will be indented by 4 spaces\n\n  .text(\"give you up\").enter()\n  .text(\"let you down\").enter()\n  .text(\"run around and desert you\").enter(2)\n\n  .unindent() # \u003c-- restores original indentation\n```\n\n# Composition Example\n\nThe previous example is pretty messy right?\n\nLet's clean that up by making 2 functions; `title()` and `bullet()`:\n\n```nim\nimport terminal, crappyprint\n\nproc title(print: Print, text: string): Print =\n  ## Make the list title reusable.\n  print\n    .text(text, style={styleBright}, fg=fgYellow)\n    .text(\":\", style={styleDim})\n    .enter()\n    .indent()\n\nproc bullet(print: Print, text: string): Print =\n  ## Make a bullet line reusable.\n  print\n    .text(\"* \", fg=fgGreen)\n    .text(text)\n    .enter()\n```\n\nWith those 2 functions in play, here's what the previous example looks like now...\n\n```nim\nnewFilePrint(spacesPerIndent=4)\n  .title(\"Never gonna\")\n  .bullet(\"give you up\")\n  .bullet(\"let you down\")\n  .bullet(\"run around and desert you\")\n  .enter()\n  .indent(0)\n```\n\nTo introduce your own chainable functions, you create a function whose first parameter is `Print` and the return value is also `Print`. I recommend adding the `{.discardable.}` pragma too. For example:\n\n```nim\nproc hr*(print: Print): Print {.discardable.} =\n  ## Prints a fancy line divider.\n  print\n    .text(\"-=-=-=-=-=-=-=-\", style={styleBright}, fg=fgBlue)\n    .enter()\n```\n\nSee [this code](examples/rick.nim) for a larger example.\n\n# Principles\n\n-   programs should make their own styling functions (like a style guide)\n-   don't reinvent colors and style from `terminal`\n-   terminal printing is already stateful; so embrace that\n\n# API\n\n### `newStringPrint(initialValue = \"\", spacesPerIndent = 4)`\n\nReturns a `Print` object used to chain styling functions. This kind of `Print` is good\nfor writing code generators.\n\n| argument       | type     | description                                                      | default |\n| -------------- | -------- | ---------------------------------------------------------------- | ------- |\n| intialValue    | `string` | optional: the starting value to use                              | `\"\"`    |\n| spacePerIndent | `int`    | optional: how many spaces are printed for each indentation level | `4`     |\n\n```nim\nlet print = newStringPrint()\n```\n\n### `newFilePrint(target = stdout, spacesPerIndent = 4)`\n\nReturns a `Print` object used to chain styling functions. This kind of `Print` is good\nfor writing to the terminal.\n\n| argument       | type   | description                                                      | default  |\n| -------------- | ------ | ---------------------------------------------------------------- | -------- |\n| target         | `File` | optional: where to write to                                      | `stdout` |\n| spacePerIndent | `int`  | optional: how many spaces are printed for each indentation level | `4`      |\n\n```nim\nlet print = newFilePrint()\n```\n\n### `newStreamPrint(target = StringStream, spacesPerIndent = 4)`\n\nReturns a `Print` object used to chain styling functions. This kind of `Print` is good\nfor streaming if you're building a massive string.\n\n| argument       | type           | description                                                      | default  |\n| -------------- | -------------- | ---------------------------------------------------------------- | -------- |\n| target         | `StringStream` | optional: where to write to                                      | `stdout` |\n| spacePerIndent | `int`          | optional: how many spaces are printed for each indentation level | `4`      |\n\n```nim\nvar ss = newStringStream()\nlet print = newStreamPrint(ss)\n```\n\n### `.text(value = \"\", fg = fgDefault, bg = bgDefault, style = {}, indentBy = 0)`\n\nPrints text. You'll be using this one frequently.\n\nNote that only `Print` created with `newFilePrint()` supports terminal styling colours.\n\n| argument | type              | description                                                                  | default     |\n| -------- | ----------------- | ---------------------------------------------------------------------------- | ----------- |\n| value    | `string`          | the text to print                                                            | `\"\"`        |\n| fg       | `ForegroundColor` | optional: applies a foreground color to the text                             | `fgDefault` |\n| bg       | `BackgroundColor` | optional: applies a background color to the text                             | `bgDefault` |\n| style    | `set[Style]`      | optional: applies styling (`styleBright` for example) to the text            | `{}`        |\n| indentBy | `int`             | optional: overrides the current indentation with a specific number of spaces | `0`         |\n\n```nim\nnewFilePrint()\n  .text(\"Say \")\n  .text(\"hello \", style = {styleBold})\n  .text(\"to my\", fg = bgGreen)\n  .text(\" little friend!\", bg = bgBlue, fg = fgWhite)\n```\n\n### `.fg(color)`\n\nChanges the foreground color for `File`-based `Print`ers.\n\n| argument  | type              | description                                                  |\n| --------- | ----------------- | ------------------------------------------------------------ |\n| **color** | `ForegroundColor` | applies a foreground color to any text written in the future |\n\n```nim\nnewFilePrint()\n  .text(\"Days since last accident: \")\n  .fg(fgRed)     # \u003c-- red text\n  .text(\"0\")\n  .fg(fgDefault) # \u003c-- normal text\n  .text(\".\")\n```\n\n### `.bg(color)`\n\nChanges the background color for `File`-based `Print`ers.\n\n| argument  | type              | description                                                  |\n| --------- | ----------------- | ------------------------------------------------------------ |\n| **color** | `BackgroundColor` | applies a background color to any text written in the future |\n\n```nim\nnewFilePrint()\n  .text(\"Don't cry for me, Argentina.\").enter(2)\n  .bg(bgCyan)  # \u003c-- cyan\n  .text(\"           \").enter()\n  .bg(bgWhite) # \u003c-- then white\n  .fg(fgYellow)\n  .bright()\n  .text(\"     *     \").enter()\n  .bg(bgCyan)  # \u003c-- then back to cyan\n  .text(\"           \").enter()\n```\n\n### `.indent(level)`\n\nChanges the indentation level so text will be inset from the left on each line.\n\n| argument  | type  | description                         | default |\n| --------- | ----- | ----------------------------------- | ------- |\n| **level** | `int` | how many levels we should move over | `1`     |\n\n```nim\nnewStringPrint()\n  .text(\"Dear Diary,\").enter(2)\n  .indent() # \u003c-- move future text to the right (4 spaces by default)\n  .text(\"I love nim.\").enter(2)\n  .indent(-1) # \u003c-- sets the indentation back\n  .text(\"Love, \").enter(2)\n  .text(\"Steve\")\n```\n\n### `.unindent(level)`\n\nThis is the opposite of `.indent()`.\n\n| argument  | type  | description                         | default |\n| --------- | ----- | ----------------------------------- | ------- |\n| **level** | `int` | how many levels we should move back | `1`     |\n\n```nim\nnewStringPrint()\n  .text(\"Dear Diary,\").enter(2)\n  .indent() # \u003c-- move future text to the right\n  .text(\"I love nim.\").enter(2)\n  .unindent() # \u003c-- sets the indentation back\n  .text(\"Love, \").enter(2)\n  .text(\"Steve\")\n```\n\n### `.space(count)`\n\nAdds horizontal whitespace.\n\n| argument  | type  | description                 | default |\n| --------- | ----- | --------------------------- | ------- |\n| **count** | `int` | the number of spaces to add | `1`     |\n\n```nim\nnewStringPrint()\n  .space(81) # \u003c-- adds some spaces\n  .text(\"the forbidden zone!\")\n```\n\n### `.enter(count)`\n\nMoves to the next line.\n\n| argument  | type  | description                | default |\n| --------- | ----- | -------------------------- | ------- |\n| **count** | `int` | the number of lines to add | `1`     |\n\n```nim\nnewStringPrint()\n  .text(\"Patience...\")\n  .enter(4000) # \u003c-- RIP your terminal\n  .text(\"is a virtue.\")\n```\n\n### `.bright(on)`\n\nMakes subsequent text be bright/bold for `File`-based `Print`ers.\n\n| argument | type   | description                      | default |\n| -------- | ------ | -------------------------------- | ------- |\n| **on**   | `bool` | should this style setting be on? | `true`  |\n\nYou can turn this off again with `.bright(off)`.\n\n```nim\nnewFilePrint()\n  .bright()      # \u003c-- on\n  .text(\"twinkle twinkle\")\n  .bright(false) # \u003c-- off\n  .text(\"little star\")\n```\n\n### `.dim(on)`\n\nMakes subsequent text be dim for `File`-based `Print`ers.\n\n| argument | type   | description                      | default |\n| -------- | ------ | -------------------------------- | ------- |\n| **on**   | `bool` | should this style setting be on? | `true`  |\n\nYou can turn this off again with `.dim(off)`.\n\n```nim\nnewFilePrint()\n  .text(\"867-5309\")\n  .dim()      # \u003c-- on\n  .text(\"/ Jenny\")\n  .dim(false) # \u003c-- off\n```\n\n# Why not use this?\n\n-   your program doesn't print much\n-   the `terminal` module is already great for styled printing\n-   because I wrote this\n\n# Changelog\n\n#### `0.2.0` - Oct 26, 2019\n\n-   Fixes issues with style overrides.\n-   Adds support for targeting streams and strings.\n-   Adds `unindent(x)` which is simply `indent(-x)`\n-   Removes the quit proc for resetting the terminal because it prevented piping output as text.\n\n#### `0.1.0` - Jan 21, 2019\n\n-   Initial Release.\n\n# Requirements\n\n-   Nim 1.x\n\n# Installing\n\n`nimble install https://github.com/skellock/crappyprint#v0.1.0`\n\n( NOTE: I haven't submitted this to `nimble` just yet. )\n\n# TODOs\n\n-   [x] make CI work\n-   [x] in `text()`, make `fg`, `bg`, and `style` changes independent from each other\n-   [x] finish testing all functions\n-   [ ] support windows (not sure what's involved)\n-   [ ] show more examples of control flow\n-   [ ] change name of library?\n-   [ ] submit to nimble\n\n# License\n\nMIT.\n\n# Contributing\n\nFork it. Pull it. Patch it. Push it.\n\nSend a PR, that should do it.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskellock%2Fcrappyprint","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fskellock%2Fcrappyprint","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskellock%2Fcrappyprint/lists"}