Skip to content

Commit

Permalink
0.2.12
Browse files Browse the repository at this point in the history
  • Loading branch information
jodersky committed Apr 1, 2021
1 parent f01d6e1 commit e72bc82
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 48 deletions.
6 changes: 3 additions & 3 deletions build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import de.tobiasroeser.mill.vcs.version.VcsVersion

val dottyVersions = sys.props.get("dottyVersion").toList

val scalaVersions = "2.11.12" :: "2.12.13" :: "2.13.4" :: "3.0.0-RC1" :: dottyVersions
val scalaVersions = "2.11.12" :: "2.12.13" :: "2.13.4" :: "3.0.0-RC2" :: dottyVersions
val scala2Versions = scalaVersions.filter(_.startsWith("2."))

val scalaJSVersions = for {
Expand Down Expand Up @@ -39,7 +39,7 @@ trait FansiModule extends PublishModule {
}
trait FansiMainModule extends CrossScalaModule {
def millSourcePath = super.millSourcePath / offset
def ivyDeps = Agg(ivy"com.lihaoyi::sourcecode::0.2.4")
def ivyDeps = Agg(ivy"com.lihaoyi::sourcecode::0.2.5")
def offset: os.RelPath = os.rel
def sources = T.sources(
super.sources()
Expand All @@ -56,7 +56,7 @@ trait FansiMainModule extends CrossScalaModule {
trait FansiTestModule extends ScalaModule with TestModule {
def crossScalaVersion: String
def testFrameworks = Seq("utest.runner.Framework")
def ivyDeps = Agg(ivy"com.lihaoyi::utest::0.7.7")
def ivyDeps = Agg(ivy"com.lihaoyi::utest::0.7.8")
def offset: os.RelPath = os.rel
def millSourcePath = super.millSourcePath / os.up

Expand Down
99 changes: 54 additions & 45 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ Fansi 0.2.10 [![Gitter Chat]][gitter-url] [![Build Status]][travis-url] [![Patre
"com.lihaoyi" %%% "fansi" % "0.2.10" // Scala.js or Scala-Native
```

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

While "normal" use of Ansi escapes with `java.lang.String`, you find yourself
While "normal" use of Ansi escapes with `java.lang.String`, you find yourself
concatenating colors:

```scala
Expand All @@ -37,35 +37,35 @@ this approach. For example,
val colored: 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.
// 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 length
val length = ???
val length = ???

// 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
// 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?
val blueWorld = ???
val blueWorld = ???

// What if I want to underline "World" instead of changing it's color, while
// still preserving the original color?
val underlinedWorld = ???

// What if I want to apply underlines to "World" and the two characters on
// What if I want to apply underlines to "World" and the two characters on
// either side, after I had already turned "World" blue?
val underlinedBlue = ???
```

While simple to describe, these tasks are all error-prone and difficult to
do using normal `java.lang.String`s containing Ansi color codes. This is
do using normal `java.lang.String`s containing Ansi color codes. This is
especially so if, unlike the toy example above, `colored` is coming from some
other part of your program and you're not sure what or how-many Ansi color
codes it already contains.
other part of your program and you're not sure what or how-many Ansi color
codes it already contains.

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

```scala
val colored: fansi.Str = fansi.Color.Red("Hello World Ansi!")
// Or fansi.Str("Hello World Ansi!").overlay(fansi.Color.Red)
// Or fansi.Str("Hello World Ansi!").overlay(fansi.Color.Red)

val length = colored.length // Fast and returns the non-colored length of string

Expand Down Expand Up @@ -113,15 +113,15 @@ too much and stomp over colors that already exist:
![StringError](docs/StringError.png)

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

![FansiRocks](docs/FansiRocks.png)

Fansi is also very efficient: `fansi.Str` uses just 3x as much memory as
`java.lang.String` to hold all the additional formatting information.
Its operations are probably about the same factor slower, as they are all
implemented using fast `arraycopy`s and while-loops similar to
`java.lang.String`. That means that - unlike fiddling with Ansi-codes using
regexes - you generally do not need to worry about performance when dealing with
Its operations are probably about the same factor slower, as they are all
implemented using fast `arraycopy`s and while-loops similar to
`java.lang.String`. That means that - unlike fiddling with Ansi-codes using
regexes - you generally do not need to worry about performance when dealing with
`fansi.Str`s. Just treat them as you would `java.lang.String`s: splitting them,
`substring`ing them, and applying or removing colors or other styles at-will.

Expand All @@ -144,27 +144,27 @@ The main operations you need to know are:

![fansi.Str](docs/Str.png)

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

![fansi.Attr](docs/Attr.png)

- `fansi.Attrs` represents a group of zero or more `fansi.Attr`s.
These that can be passed around together, combined via `++` or applied
to `fansi.Str`s all at once. Any individual `fansi.Attr` can be used
when `fansi.Attrs` is required, as can `fansi.Attrs.empty`.
- `fansi.Attrs` represents a group of zero or more `fansi.Attr`s.
These that can be passed around together, combined via `++` or applied
to `fansi.Str`s all at once. Any individual `fansi.Attr` can be used
when `fansi.Attrs` is required, as can `fansi.Attrs.empty`.

![fansi.Attrs](docs/Attrs.png)

- Using any of the `fansi.Attr` or `fansi.Attrs` mentioned above, e.g.
`fansi.Color.Red`, using `fansi.Color.Red("hello world ansi!")` to create a
`fansi.Str` with that text and color, or
- Using any of the `fansi.Attr` or `fansi.Attrs` mentioned above, e.g.
`fansi.Color.Red`, using `fansi.Color.Red("hello world ansi!")` to create a
`fansi.Str` with that text and color, or
`fansi.Str("hello world ansi!").overlay(fansi.Color.Blue, 6, 11)`

- `.render` to convert a `fansi.Str` back into a `java.lang.String` with all
Expand All @@ -187,32 +187,32 @@ If you want to dig into deeper, there are a few more APIs you can use:


- `fansi.Str.join(args: fansi.Str*)` to conveniently join together multiple
`fansi.Str`s all at once, more efficient than `++` for large numbers of
`fansi.Str`s all at once, more efficient than `++` for large numbers of
inputs
- `getColors`/`getColor` and `getChars`/`getChar` methods on `fansi.Str` to
- `getColors`/`getColor` and `getChars`/`getChar` methods on `fansi.Str` to
extract the raw data for your own use
- `fansi.Str.fromArrays` to piece it back together
- `fansi.Str.fromArrays` to piece it back together

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

`fansi.Str` currently has a relatively skeletal API: it is slightly smaller
than what `java.lang.String` has, and definitely much less than what is
than what `java.lang.String` has, and definitely much less than what is
available on `scala.RichString`'s extension methods. Feel free to implement
your own custom operations using `fromArrays` if you can't find what you want
on `fansi.Str`, or send a patch if you think it's arguably general enough to
be included in Fansi itself.

- `fansi.Attrs.emitAnsiCodes` Lets you manually emit the different
- `fansi.Attrs.emitAnsiCodes` Lets you manually emit the different
`java.lang.String`s that correspond to changes in color in an Ansi string.

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

```scala
fansi.Attrs.emitAnsiCodes(0, fansi.Color.Red.applyMask) // "\u001b[31m"
Expand All @@ -235,7 +235,7 @@ You can also pass in an `errorMode` when parsing a string via `ansi.Str(...)`
to tell Fansi how to behave if it finds Ansi escapes it can't handle. You
have the options:

- `fansi.ErrorMode.Throw` is the default, to throw an exception and fail the
- `fansi.ErrorMode.Throw` is the default, to throw an exception and fail the
parse if it sees an Ansi escape it does not recognize.
- `fansi.ErrorMode.Sanitize` to remove the escape character but leave the
remnants of the escape-sequence in the result that people can see
Expand All @@ -250,6 +250,15 @@ Scaladoc
Changelog
---------

### 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
Expand Down Expand Up @@ -300,9 +309,9 @@ Changelog

### 0.1.2

- Removed infinite-loop if parsing strings with Ansi escapes that are not
- Removed infinite-loop if parsing strings with Ansi escapes that are not
recognized by Fansi
- Added `fansi.ErrorMode` parameter, to control behavior when un-recognized
- Added `fansi.ErrorMode` parameter, to control behavior when un-recognized
Ansi escapes are found.

### 0.1.1
Expand Down

0 comments on commit e72bc82

Please sign in to comment.