# Coming from slice-ansi

> A slice-ansi alternative with a drop-in path: import sliceAnsi from linegauge/slice, graded 15 / 15 by slice-ansi's own test suite, including the OSC 8 hyperlink case slice-ansi marks as failing — then zero dependencies, grapheme clusters never halved, and one style stack shared with wrap.

Source: https://linegauge.interlace.tools/docs/coming-from/slice-ansi

**linegauge** is a **slice-ansi alternative** you adopt by changing one import.
`linegauge/slice`'s default export is `slice`, call-compatible with slice-ansi's default, and
slice-ansi's own test suite is the grade.

## Migrate from slice-ansi in one import

```diff
- import sliceAnsi from 'slice-ansi';
+ import sliceAnsi from 'linegauge/slice';
```

The call is slice-ansi's — `sliceAnsi(string, start, end)`, in display columns, `end`
optional. The same function is also the named export `slice`, from `linegauge/slice` or from
`linegauge`.

It also answers the questions slice-ansi's neighbours do, one subpath each:

| Incumbent | linegauge path |
| :-- | :-- |
| `string-width` | `linegauge` (the default export) |
| `strip-ansi` | `linegauge/strip` |
| `wrap-ansi` | `linegauge/wrap` |
| `slice-ansi` | `linegauge/slice` |

## Is linegauge compatible with slice-ansi?

Graded, not claimed. slice-ansi's own suite, vendored at 7.1.2 and unmodified apart from the
import specifier, runs against `linegauge/slice` beside a control that runs it against the
real slice-ansi:

| | passing | rate |
| :-- | --: | --: |
| `linegauge/slice` | 15 / 15 | 100.0% |
| slice-ansi itself (control) | 15 / 15 | 100.0% |

From [Compatibility](https://burgee.interlace.tools/docs/compatibility), which `npm run compat:page` generates from the
oracle's last run; that page is the authority. One of the fifteen, `slice links`, is marked
`test.failing()` in slice-ansi's own suite — the incumbent cannot round-trip an `OSC 8`
hyperlink and says so. linegauge can, so the assertion passes; the runner reports an
unexpected pass as `not ok`, and the grader counts it as the pass it is and marks it on the
page rather than letting it look like the fourteen beside it.

The suite is pinned at 7.1.2, not at slice-ansi's current major: the control grades against
the slice-ansi this workspace installs, which is 7, and grading 9's suite against a 7 control
would publish the gap between two of the incumbent's own majors as linegauge's.

The same page grades `linegauge` against string-width (229 / 229), `linegauge/strip` against
strip-ansi (8 / 8) and `linegauge/wrap` against wrap-ansi (80 / 80).

## What you gain over slice-ansi

slice-ansi 7.1.2 depends on `ansi-styles` and `is-fullwidth-code-point`. `linegauge/slice`
depends on nothing, and it is pure: nothing in linegauge reads `process`, so the same input
slices the same way on a pipe, under `--json` and in a test.

- **Hyperlinks survive the cut.** An `OSC 8` link open at `start` is re-emitted at the front
  of the slice and closed at its end — the case slice-ansi's own suite marks as one it fails.
- **A cluster is never halved.** Columns come from the same `width` that passes
  string-width's suite 229 / 229, and cluster boundaries from the platform's own
  `Intl.Segmenter`. A cluster that straddles the boundary is included whole, so a slice can be
  one column wider than asked but never returns half a family emoji or one letter of a flag.
- **One style stack, not two.** slice-ansi and wrap-ansi each carry their own copy of
  open/close/reopen, and they disagree at the edges. `linegauge/slice` and `linegauge/wrap`
  share one, so slicing and wrapping the same styled string agree.
- **The family measures with it.** burgee, caique and flagstaff build on linegauge, so what
  they write for a pipe or an agent is cut the same way.

## When to switch from slice-ansi

- Your output carries terminal hyperlinks, and a slice of it has to keep them.
- Your dependency tree carries slice-ansi beside string-width, strip-ansi or wrap-ansi, and
  you would rather it carried one package with no dependencies.

The API and the design notes are on [linegauge](/docs); the width path is on
[Coming from string-width](/docs/coming-from/string-width).
