{"id":13800996,"url":"https://github.com/com-lihaoyi/fansi","last_synced_at":"2025-04-12T22:26:06.240Z","repository":{"id":43927960,"uuid":"59707695","full_name":"com-lihaoyi/fansi","owner":"com-lihaoyi","description":"Scala/Scala.js library for manipulating Fancy Ansi colored strings","archived":false,"fork":false,"pushed_at":"2024-05-17T14:20:59.000Z","size":1914,"stargazers_count":223,"open_issues_count":21,"forks_count":26,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-05-21T01:02:10.445Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/com-lihaoyi.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":"lihaoyi"}},"created_at":"2016-05-26T00:43:32.000Z","updated_at":"2024-08-04T00:05:49.279Z","dependencies_parsed_at":"2024-04-14T14:39:31.705Z","dependency_job_id":"bac13fdc-cc8a-4453-97b9-b98ad2c9fb77","html_url":"https://github.com/com-lihaoyi/fansi","commit_stats":null,"previous_names":["lihaoyi/fansi"],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/com-lihaoyi%2Ffansi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/com-lihaoyi%2Ffansi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/com-lihaoyi%2Ffansi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/com-lihaoyi%2Ffansi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/com-lihaoyi","download_url":"https://codeload.github.com/com-lihaoyi/fansi/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247103307,"owners_count":20884023,"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-04T00:01:18.369Z","updated_at":"2025-04-04T01:10:55.840Z","avatar_url":"https://github.com/com-lihaoyi.png","language":"Scala","funding_links":["https://github.com/sponsors/lihaoyi","https://www.patreon.com/lihaoyi"],"categories":["Table of Contents","Console"],"sub_categories":["Misc"],"readme":"Fansi 0.5.0 [![Gitter Chat]][gitter-url] [![Patreon][patreon-badge]][patreon-link]\n======================================================================\n[Gitter Chat]: https://badges.gitter.im/Join%20Chat.svg\n[gitter-url]: https://gitter.im/lihaoyi/fansi?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge\n[Build Status]: https://travis-ci.org/lihaoyi/fansi.svg\n\n[patreon-badge]: https://img.shields.io/badge/patreon-sponsor-ff69b4.svg\n[patreon-link]: https://www.patreon.com/lihaoyi\n\n![LandingExample](docs/LandingExample.png)\n\n```scala\n// SBT\n\"com.lihaoyi\" %% \"fansi\" % \"0.5.0\"\n\"com.lihaoyi\" %%% \"fansi\" % \"0.5.0\" // Scala.js or Scala-Native\n\n// Mill\nivy\"com.lihaoyi::fansi:0.5.0\"\nivy\"com.lihaoyi::fansi::0.5.0\" // Scala.js or Scala-Native\n```\n\nFansi is a Scala library to make it easy to deal with fancy colored Ansi\nstrings within your command-line programs.\n\nWhile \"normal\" use of Ansi escapes with `java.lang.String`, you find yourself\nconcatenating colors:\n\n```scala\nval colored = Console.RED + \"Hello World Ansi!\" + Console.RESET\n```\n\nTo build your colored string. This works the first time, but is error prone\non larger strings: e.g. did you remember to put a `Console.RESET` where it's\nnecessary? Do you need to end with one to avoid leaking the color to the entire\nconsole after printing it?\n\nFurthermore, some operations are fundamentally difficult or error-prone with\nthis approach. For example,\n\n```scala\nval colored: String = Console.RED + \"Hello World Ansi!\" + Console.RESET\n\n// How to efficiently get the length of this string on-screen? We could try\n// using regexes to remove and Ansi codes, but that's slow and inefficient.\n// And it's easy to accidentally call `colored.length` and get a invalid length\nval length = ???\n\n// How to make the word `World` blue, while preserving the coloring of the\n// `Ansi!` text after? What if the string came from somewhere else and you\n// don't know what color that text was originally?\nval blueWorld = ???\n\n// What if I want to underline \"World\" instead of changing it's color, while\n// still preserving the original color?\nval underlinedWorld = ???\n\n// What if I want to apply underlines to \"World\" and the two characters on\n// either side, after I had already turned \"World\" blue?\nval underlinedBlue = ???\n```\n\nWhile simple to describe, these tasks are all error-prone and difficult to\ndo using normal `java.lang.String`s containing Ansi color codes. This is\nespecially so if, unlike the toy example above, `colored` is coming from some\nother part of your program and you're not sure what or how-many Ansi color\ncodes it already contains.\n\nWith Fansi, doing all these tasks is simple, error-proof and efficient:\n\n```scala\nval colored: fansi.Str = fansi.Color.Red(\"Hello World Ansi!\")\n// Or fansi.Str(\"Hello World Ansi!\").overlay(fansi.Color.Red)\n\nval length = colored.length // Fast and returns the non-colored length of string\n\nval blueWorld = colored.overlay(fansi.Color.Blue, 6, 11)\n\nval underlinedWorld = colored.overlay(fansi.Underlined.On, 6, 11)\n\nval underlinedBlue = blueWorld.overlay(fansi.Underlined.On, 4, 13)\n```\n\nAnd it just works:\n\n![LandingExample](docs/LandingExample.png)\n\nWhy Fansi?\n----------\n\nUnlike normal `java.lang.String`s with Ansi escapes embedded inside,\n`fansi.Str` allows you to perform a range of operations in an efficient\nmanner:\n\n- Extracting the non-Ansi `plainText` version of the string\n\n- Get the non-Ansi `length`\n\n- Concatenate colored Ansi strings without worrying about leaking\n  colors between them\n\n- Applying colors to certain portions of an existing `fansi.Str`,\n  and ensuring that the newly-applied colors get properly terminated\n  while existing colors are unchanged\n\n- Splitting colored Ansi strings at a `plainText` index\n\n- Rendering to colored `java.lang.String`s with Ansi escapes embedded,\n  which can be passed around or concatenated without worrying about\n  leaking colors.\n\nThese are tasks which are possible to do with normal `java.lang.String`,\nbut are tedious, error-prone and typically inefficient. Often, you can get\nby with adding copious amounts of `Console.RESET`s when working with colored\n`java.lang.String`s, but even that easily results in errors when you `RESET`\ntoo much and stomp over colors that already exist:\n\n![StringError](docs/StringError.png)\n\n`fansi.Str` allows you to perform these tasks safely and easily:\n\n![FansiRocks](docs/FansiRocks.png)\n\nFansi is also very efficient: `fansi.Str` uses just 3x as much memory as\n`java.lang.String` to hold all the additional formatting information.\nIts operations are probably about the same factor slower, as they are all\nimplemented using fast `arraycopy`s and while-loops similar to\n`java.lang.String`. That means that - unlike fiddling with Ansi-codes using\nregexes - you generally do not need to worry about performance when dealing with\n`fansi.Str`s. Just treat them as you would `java.lang.String`s: splitting them,\n`substring`ing them, and applying or removing colors or other styles at-will.\n\nFansi was originally a part of the [Ammonite REPL](http://www.lihaoyi.com/Ammonite/),\nbut is now a standalone zero-dependency library anyone can use if they want\nto easily and efficiently deal with colored Ansi strings.\n\nUsing Fansi\n-----------\n\nThe main operations you need to know are:\n\n- `fansi.Str(raw: CharSequence): fansi.String`, to construct colored\n  Ansi strings from a `java.lang.String`, with or without existing Ansi\n  color codes inside it.\n\n- `fansi.Str`, the primary data-type that you will use to pass-around\n  colored Ansi strings and manipulate them: concatenating, splitting,\n  applying or removing colors, etc.\n\n![fansi.Str](docs/Str.png)\n\n- `fansi.Attr`s are the individual modifications you can make to an\n  `fansi.Str`'s formatting. Examples are:\n    - `fansi.Bold.{On, Off}`\n    - `fansi.Reversed.{On, Off}`\n    - `fansi.Underlined.{On, Off}`\n    - `fansi.Color.*`\n    - `fansi.Back.*`\n    - `fansi.Attr.Reset`\n\n![fansi.Attr](docs/Attr.png)\n\n- `fansi.Attrs` represents a group of zero or more `fansi.Attr`s.\n  These that can be passed around together, combined via `++` or applied\n  to `fansi.Str`s all at once. Any individual `fansi.Attr` can be used\n  when `fansi.Attrs` is required, as can `fansi.Attrs.empty`.\n\n![fansi.Attrs](docs/Attrs.png)\n\n- Using any of the `fansi.Attr` or `fansi.Attrs` mentioned above, e.g.\n  `fansi.Color.Red`, using `fansi.Color.Red(\"hello world ansi!\")` to create a\n  `fansi.Str` with that text and color, or\n  `fansi.Str(\"hello world ansi!\").overlay(fansi.Color.Blue, 6, 11)`\n\n- `.render` to convert a `fansi.Str` back into a `java.lang.String` with all\n  necessary Ansi color codes within it\n\nFansi also supports 8-bit 256-colors through `fansi.Color.Full` and\n`fansi.Back.Full`, as well as 24-bit 16-million-colors through\n`fansi.Color.True` and `fansi.Back.True`:\n\n![docs/TrueColor.png](docs/TrueColor.png)\n\nNote that Fansi only performs the rendering of the colors to an ANSI-encoded\nstring. Final rendering will depend on whichever terminal you print the string\nto, whether it is able to display these sets of colors or not.\n\nDigging Deeper\n--------------\n\nIf you want to dig into deeper, there are a few more APIs you can use:\n\n\n- `fansi.Str.apply(args: fansi.Str*)` or\n  `fansi.Str.join(args: Seq[fansi.Str], sep: fansi.Str = fansi.Str(\"\"))`\n  to conveniently join together multiple `fansi.Str`s all at once, more efficient\n  than `++` for large numbers of inputs\n- `fansi.Str.{Sanitize, Strip, Throw}` for constructing `fansi.Str`s while\n  specifying how to handle errors\n- `getColors`/`getColor` and `getChars`/`getChar` methods on `fansi.Str` to\n  extract the raw data for your own use\n- `fansi.Str.fromArrays` to piece it back together\n\nThis allows you to perform fast, mutable array operations on the\ncolor/character arrays if you know what you're doing and want to perform\noperations that are inconvenient or slow to do through `fansi.Str`'s immutable\nAPI. For example, if you want to do a bunch of work with colored strings and\nthen at-the-end render everything to HTML, you can manually walk over the\ncolor/character arrays yourself and decide where to print HTML tags to give\nthe text colors.\n\n`fansi.Str` currently has a relatively skeletal API: it is slightly smaller\nthan what `java.lang.String` has, and definitely much less than what is\navailable on `scala.RichString`'s extension methods. Feel free to implement\nyour own custom operations using `fromArrays` if you can't find what you want\non `fansi.Str`, or send a patch if you think it's arguably general enough to\nbe included in Fansi itself.\n\n- `fansi.Attrs.emitAnsiCodes` Lets you manually emit the different\n  `java.lang.String`s that correspond to changes in color in an Ansi string.\n\nFor example, if you want to emit the Ansi codes that correspond to the\ntransition from \"No Color\" to \"Red\", you can use\n\n```scala\nfansi.Attrs.emitAnsiCodes(0, fansi.Color.Red.applyMask) // \"\\u001b[31m\"\n```\n\nOr the Ansi codes from \"Red\" to \"No Color\"\n\n```scala\nfansi.Attrs.emitAnsiCodes(fansi.Color.Red.applyMask, 0) // \"\\u001b[39m\"\n```\n\nOr for any other combination of attributes\n\n```scala\nval attrs = fansi.Color.Red ++ fansi.Back.Blue ++ fansi.Underlined.On\nfansi.Attrs.emitAnsiCodes(0, attrs.applyMask) // \"\\u001b[31m\\u001b[44m\\u001b[4m\"\n```\n\nYou can also pass in an `errorMode` when parsing a string via `ansi.Str(...)`\nto tell Fansi how to behave if it finds Ansi escapes it can't handle. You\nhave the options:\n\n- `fansi.ErrorMode.Throw` is the default, to throw an exception and fail the\n  parse if it sees an Ansi escape it does not recognize.\n- `fansi.ErrorMode.Sanitize` to remove the escape character but leave the\n  remnants of the escape-sequence in the result that people can see\n- `fansi.ErrorMode.Strip` to remove those escape sequences entirely so that\n  no trace of them remains in the final result\n\nScaladoc\n--------\n\n- [0.2.0](http://lihaoyi.github.io/fansi/api)\n\nChangelog\n---------\n\n### 0.5.0\n\n- Support for Scala-Native 0.5.0\n- Dropped support for Scala 2.11.x\n- Minimum version of Scala 3 increased to 3.3.1\n\n### 0.4.0\n\n- Dropped support for Scala.js 0.6\n- Bumped Scala.js to 1.10 (minimum version supported is 1.8)\n- Bumped Scala versions to latest (2.12.16, 2.13.8, 3.1.3)\n\n### 0.3.0\n\n- Added shorthands for constructing `fansi.Str` with various error modes via\n  `fansi.Str.Throw`, `fansi.Str.Sanitize`, `fansi.Str.Strip`\n- Renamed `fansi.Str.join` to `fansi.Str.apply`, added a new\n  `fansi.Str.join(args: Seq[fansi.Str], sep: fansi.Str = fansi.Str(\"\"))` method\n  in its place\n\n\n### 0.2.14\n\n- Support for Scala 3.0.0\n\n### 0.2.13\n\n- Support for Scala 3.0.0-RC3\n\n### 0.2.12\n\n- Support for Scala 3.0.0-RC2\n\n### 0.2.11\n\n- Support for Scala 3.0.0-RC1\n- Support for ScalaJS on Scala 3\n\n### 0.2.10\n\n- Support for Scala Native 0.4\n- Support for Scala 3.0.0-M3\n\n### 0.2.7\n\n- Support for Scala 2.13.0 final\n\n### 0.2.5\n\n- Support for Scala-Native\n\n### 0.2.4\n\n- Added `fansi.Str.join`, `fansi.Str#getChar`, `fansi.Str#getColor`\n- Created a [Patreon Page][patreon-link]\n  to raise money to try and fund the development of Fansi, PPrint, Ammonite and my other\n  open-source libraries. If you've use these libraries in the past and enjoyed doing so,\n  please [chip in][patreon-link] to support development!\n\n\n### 0.2.3\n\n- Publish for Scala 2.12\n\n### 0.2.2\n\n- Reduce memory usage by 134mb by not initializing huge lookup tables to\n  parse truecolor colors.\n\n### 0.2.1\n\n- Fix #7: Parsing of true colors broken\n\n### 0.2.0\n\n- Added the `fansi.Color.True` and `fansi.Back.True` colors, allowing you to\n  specify `Attr`s that represent the 24-bit 16-million-color \"True Color\"\n  range.\n\n### 0.1.3\n\n- Fixed a bug in `substring` that incorrectly threw an out of bounds exception\n  for `end == length`\n- Exposed the `fansi.Attrs.emitAnsiCodes` function\n- Renamed `Attrs.empty` to `Attrs.Empty` for consistency with all the others\n\n### 0.1.2\n\n- Removed infinite-loop if parsing strings with Ansi escapes that are not\n  recognized by Fansi\n- Added `fansi.ErrorMode` parameter, to control behavior when un-recognized\n  Ansi escapes are found.\n\n### 0.1.1\n\n- Doubled the speed of the `.render` operation\n- Doubled the speed of the `.overlay` operation\n- Added the `.overlayAll` method on `fansi.Str`, to allow you to quickly apply\n  multiple overlays onto the same string\n\n### 0.1.0\n\n- First release\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcom-lihaoyi%2Ffansi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcom-lihaoyi%2Ffansi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcom-lihaoyi%2Ffansi/lists"}