Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

Scala/Scala.js library for manipulating Fancy Ansi colored strings

License

NotificationsYou must be signed in to change notification settings

com-lihaoyi/fansi

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LandingExample

// SBT"com.lihaoyi"%%"fansi"%"0.5.0""com.lihaoyi"%%%"fansi"%"0.5.0"// Scala.js or Scala-Native// Millivy"com.lihaoyi::fansi:0.5.0"ivy"com.lihaoyi::fansi::0.5.0"// Scala.js or Scala-Native

Fansi is a Scala library to make it easy to deal with fancy colored Ansistrings within your command-line programs.

While "normal" use of Ansi escapes withjava.lang.String, you find yourselfconcatenating colors:

valcolored=Console.RED+"Hello World Ansi!"+Console.RESET

To build your colored string. This works the first time, but is error proneon larger strings: e.g. did you remember to put aConsole.RESET where it'snecessary? Do you need to end with one to avoid leaking the color to the entireconsole after printing it?

Furthermore, some operations are fundamentally difficult or error-prone withthis approach. For example,

valcolored:String=Console.RED+"Hello World Ansi!"+Console.RESET// How to efficiently get the length of this string on-screen? We could try// using regexes to remove and Ansi codes, but that's slow and inefficient.// And it's easy to accidentally call `colored.length` and get a invalid lengthvallength=???// How to make the word `World` blue, while preserving the coloring of the// `Ansi!` text after? What if the string came from somewhere else and you// don't know what color that text was originally?valblueWorld=???// What if I want to underline "World" instead of changing it's color, while// still preserving the original color?valunderlinedWorld=???// What if I want to apply underlines to "World" and the two characters on// either side, after I had already turned "World" blue?valunderlinedBlue=???

While simple to describe, these tasks are all error-prone and difficult todo using normaljava.lang.Strings containing Ansi color codes. This isespecially so if, unlike the toy example above,colored is coming from someother part of your program and you're not sure what or how-many Ansi colorcodes it already contains.

With Fansi, doing all these tasks is simple, error-proof and efficient:

valcolored: fansi.Str= fansi.Color.Red("Hello World Ansi!")// Or fansi.Str("Hello World Ansi!").overlay(fansi.Color.Red)vallength= colored.length// Fast and returns the non-colored length of stringvalblueWorld= colored.overlay(fansi.Color.Blue,6,11)valunderlinedWorld= colored.overlay(fansi.Underlined.On,6,11)valunderlinedBlue= blueWorld.overlay(fansi.Underlined.On,4,13)

And it just works:

LandingExample

Why Fansi?

Unlike normaljava.lang.Strings with Ansi escapes embedded inside,fansi.Str allows you to perform a range of operations in an efficientmanner:

  • Extracting the non-AnsiplainText version of the string

  • Get the non-Ansilength

  • Concatenate colored Ansi strings without worrying about leakingcolors between them

  • Applying colors to certain portions of an existingfansi.Str,and ensuring that the newly-applied colors get properly terminatedwhile existing colors are unchanged

  • Splitting colored Ansi strings at aplainText index

  • Rendering to coloredjava.lang.Strings with Ansi escapes embedded,which can be passed around or concatenated without worrying aboutleaking colors.

These are tasks which are possible to do with normaljava.lang.String,but are tedious, error-prone and typically inefficient. Often, you can getby with adding copious amounts ofConsole.RESETs when working with coloredjava.lang.Strings, but even that easily results in errors when youRESETtoo much and stomp over colors that already exist:

StringError

fansi.Str allows you to perform these tasks safely and easily:

FansiRocks

Fansi is also very efficient:fansi.Str uses just 3x as much memory asjava.lang.String to hold all the additional formatting information.Its operations are probably about the same factor slower, as they are allimplemented using fastarraycopys and while-loops similar tojava.lang.String. That means that - unlike fiddling with Ansi-codes usingregexes - you generally do not need to worry about performance when dealing withfansi.Strs. Just treat them as you wouldjava.lang.Strings: splitting them,substringing them, and applying or removing colors or other styles at-will.

Fansi was originally a part of theAmmonite REPL,but is now a standalone zero-dependency library anyone can use if they wantto easily and efficiently deal with colored Ansi strings.

Using Fansi

The main operations you need to know are:

  • fansi.Str(raw: CharSequence): fansi.String, to construct coloredAnsi strings from ajava.lang.String, with or without existing Ansicolor codes inside it.

  • fansi.Str, the primary data-type that you will use to pass-aroundcolored Ansi strings and manipulate them: concatenating, splitting,applying or removing colors, etc.

fansi.Str

  • fansi.Attrs are the individual modifications you can make to anfansi.Str's formatting. Examples are:
    • fansi.Bold.{On, Off}
    • fansi.Reversed.{On, Off}
    • fansi.Underlined.{On, Off}
    • fansi.Color.*
    • fansi.Back.*
    • fansi.Attr.Reset

fansi.Attr

  • fansi.Attrs represents a group of zero or morefansi.Attrs.These that can be passed around together, combined via++ or appliedtofansi.Strs all at once. Any individualfansi.Attr can be usedwhenfansi.Attrs is required, as canfansi.Attrs.empty.

fansi.Attrs

  • Using any of thefansi.Attr orfansi.Attrs mentioned above, e.g.fansi.Color.Red, usingfansi.Color.Red("hello world ansi!") to create afansi.Str with that text and color, orfansi.Str("hello world ansi!").overlay(fansi.Color.Blue, 6, 11)

  • .render to convert afansi.Str back into ajava.lang.String with allnecessary Ansi color codes within it

Fansi also supports 8-bit 256-colors throughfansi.Color.Full andfansi.Back.Full, as well as 24-bit 16-million-colors throughfansi.Color.True andfansi.Back.True:

docs/TrueColor.png

Note that Fansi only performs the rendering of the colors to an ANSI-encodedstring. Final rendering will depend on whichever terminal you print the stringto, whether it is able to display these sets of colors or not.

Digging Deeper

If you want to dig into deeper, there are a few more APIs you can use:

  • fansi.Str.apply(args: fansi.Str*) orfansi.Str.join(args: Seq[fansi.Str], sep: fansi.Str = fansi.Str(""))to conveniently join together multiplefansi.Strs all at once, more efficientthan++ for large numbers of inputs
  • fansi.Str.{Sanitize, Strip, Throw} for constructingfansi.Strs whilespecifying how to handle errors
  • getColors/getColor andgetChars/getChar methods onfansi.Str toextract the raw data for your own use
  • fansi.Str.fromArrays to piece it back together

This allows you to perform fast, mutable array operations on thecolor/character arrays if you know what you're doing and want to performoperations that are inconvenient or slow to do throughfansi.Str's immutableAPI. For example, if you want to do a bunch of work with colored strings andthen at-the-end render everything to HTML, you can manually walk over thecolor/character arrays yourself and decide where to print HTML tags to givethe text colors.

fansi.Str currently has a relatively skeletal API: it is slightly smallerthan whatjava.lang.String has, and definitely much less than what isavailable onscala.RichString's extension methods. Feel free to implementyour own custom operations usingfromArrays if you can't find what you wantonfansi.Str, or send a patch if you think it's arguably general enough tobe included in Fansi itself.

  • fansi.Attrs.emitAnsiCodes Lets you manually emit the differentjava.lang.Strings that correspond to changes in color in an Ansi string.

For example, if you want to emit the Ansi codes that correspond to thetransition from "No Color" to "Red", you can use

fansi.Attrs.emitAnsiCodes(0, fansi.Color.Red.applyMask)// "\u001b[31m"

Or the Ansi codes from "Red" to "No Color"

fansi.Attrs.emitAnsiCodes(fansi.Color.Red.applyMask,0)// "\u001b[39m"

Or for any other combination of attributes

valattrs= fansi.Color.Red++ fansi.Back.Blue++ fansi.Underlined.Onfansi.Attrs.emitAnsiCodes(0, attrs.applyMask)// "\u001b[31m\u001b[44m\u001b[4m"

You can also pass in anerrorMode when parsing a string viaansi.Str(...)to tell Fansi how to behave if it finds Ansi escapes it can't handle. Youhave the options:

  • fansi.ErrorMode.Throw is the default, to throw an exception and fail theparse if it sees an Ansi escape it does not recognize.
  • fansi.ErrorMode.Sanitize to remove the escape character but leave theremnants of the escape-sequence in the result that people can see
  • fansi.ErrorMode.Strip to remove those escape sequences entirely so thatno trace of them remains in the final result

Scaladoc

Changelog

0.5.0

  • Support for Scala-Native 0.5.0
  • Dropped support for Scala 2.11.x
  • Minimum version of Scala 3 increased to 3.3.1

0.4.0

  • Dropped support for Scala.js 0.6
  • Bumped Scala.js to 1.10 (minimum version supported is 1.8)
  • Bumped Scala versions to latest (2.12.16, 2.13.8, 3.1.3)

0.3.0

  • Added shorthands for constructingfansi.Str with various error modes viafansi.Str.Throw,fansi.Str.Sanitize,fansi.Str.Strip
  • Renamedfansi.Str.join tofansi.Str.apply, added a newfansi.Str.join(args: Seq[fansi.Str], sep: fansi.Str = fansi.Str("")) methodin its place

0.2.14

  • Support for Scala 3.0.0

0.2.13

  • Support for Scala 3.0.0-RC3

0.2.12

  • Support for Scala 3.0.0-RC2

0.2.11

  • Support for Scala 3.0.0-RC1
  • Support for ScalaJS on Scala 3

0.2.10

  • Support for Scala Native 0.4
  • Support for Scala 3.0.0-M3

0.2.7

  • Support for Scala 2.13.0 final

0.2.5

  • Support for Scala-Native

0.2.4

  • Addedfansi.Str.join,fansi.Str#getChar,fansi.Str#getColor
  • Created aPatreon Pageto raise money to try and fund the development of Fansi, PPrint, Ammonite and my otheropen-source libraries. If you've use these libraries in the past and enjoyed doing so,pleasechip in to support development!

0.2.3

  • Publish for Scala 2.12

0.2.2

  • Reduce memory usage by 134mb by not initializing huge lookup tables toparse truecolor colors.

0.2.1

  • Fix #7: Parsing of true colors broken

0.2.0

  • Added thefansi.Color.True andfansi.Back.True colors, allowing you tospecifyAttrs that represent the 24-bit 16-million-color "True Color"range.

0.1.3

  • Fixed a bug insubstring that incorrectly threw an out of bounds exceptionforend == length
  • Exposed thefansi.Attrs.emitAnsiCodes function
  • RenamedAttrs.empty toAttrs.Empty for consistency with all the others

0.1.2

  • Removed infinite-loop if parsing strings with Ansi escapes that are notrecognized by Fansi
  • Addedfansi.ErrorMode parameter, to control behavior when un-recognizedAnsi escapes are found.

0.1.1

  • Doubled the speed of the.render operation
  • Doubled the speed of the.overlay operation
  • Added the.overlayAll method onfansi.Str, to allow you to quickly applymultiple overlays onto the same string

0.1.0

  • First release

About

Scala/Scala.js library for manipulating Fancy Ansi colored strings

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Packages

No packages published

[8]ページ先頭

©2009-2025 Movatter.jp