# How can I create a fancier REPL prompt with styled strings? (was: Make \`Base.textwidth\` ignore ANSI sequences)

**URL:** https://discourse.julialang.org/t/how-can-i-create-a-fancier-repl-prompt-with-styled-strings-was-make-base-textwidth-ignore-ansi-sequences/120782
**Category:** General Usage
**Tags:** strings, repl, colors
**Created:** [October 1, 2024, 11:32am UTC](https://discourse.julialang.org/t/how-can-i-create-a-fancier-repl-prompt-with-styled-strings-was-make-base-textwidth-ignore-ansi-sequences/120782 "2024-10-01T11:32:46Z")
**Posts on this page:** 13
**Page:** 1

<div class="post-metadata">

### Author: ![HanD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hand/32/213908_2.png) [@HanD](https://discourse.julialang.org/u/HanD)
#### Post date: [October 1, 2024, 11:32am UTC](https://discourse.julialang.org/t/how-can-i-create-a-fancier-repl-prompt-with-styled-strings-was-make-base-textwidth-ignore-ansi-sequences/120782/1 "2024-10-01T11:32:46Z")

</div>

I’m trying to spice up my Julia REPL prompt with ANSI color codes (not just one single color, but multiple colors in the same line). However, it messes up the cursor alignment, because the code in REPL.jl also counts the ANSI control sequences when it computes the length of the prompt. AFAICT, the “culprit” is `Base.textwidth`:

```julia
julia> print("\e[4munderlined\e[0m")
underlined

julia> textwidth("\e[4munderlined\e[0m")
16

```

16 is too much, it should return 11.

I was wondering if there was an easy workaround for this.

---

<div class="post-metadata">

### Author: ![nilshg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nilshg/32/2283_2.png) [@nilshg](https://discourse.julialang.org/u/nilshg)
#### Post date: [October 1, 2024, 12:40pm UTC](https://discourse.julialang.org/t/how-can-i-create-a-fancier-repl-prompt-with-styled-strings-was-make-base-textwidth-ignore-ansi-sequences/120782/2 "2024-10-01T12:40:02Z")

</div>

Are you maybe looking for

> **[Example Usage · Styled Strings](https://julialang.github.io/StyledStrings.jl/dev/examples/)**
>
> Documentation for Styled Strings.

---

<div class="post-metadata">

### Author: ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)
#### Post date: [October 1, 2024, 1:01pm UTC](https://discourse.julialang.org/t/how-can-i-create-a-fancier-repl-prompt-with-styled-strings-was-make-base-textwidth-ignore-ansi-sequences/120782/3 "2024-10-01T13:01:04Z")

</div>

The \e is already ignored, since it’s invisible, and this could arguably be considered a bug, to not ignore what follows and is interpreted for it, _and then get 10_. Not too important since (assume a similar feature for underlining):

```julia
julia> textwidth(styled"{yellow:hello} {blue:there}")
11

```

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [October 1, 2024, 1:03pm UTC](https://discourse.julialang.org/t/how-can-i-create-a-fancier-repl-prompt-with-styled-strings-was-make-base-textwidth-ignore-ansi-sequences/120782/4 "2024-10-01T13:03:58Z")

</div>

> [@HanD](#):
>
> I was wondering if there was an easy workaround for this.

You could strip out the ANSI escapes (which are not part of Unicode) before calling `textwidth`, e.g. [Strange characters in windows terminal - #4 by digital\_carver](https://discourse.julialang.org/t/strange-characters-in-windows-terminal/89355/4)

But probably better to use StyledStrings

---

<div class="post-metadata">

### Author: ![HanD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hand/32/213908_2.png) [@HanD](https://discourse.julialang.org/u/HanD)
#### Post date: [October 1, 2024, 1:44pm UTC](https://discourse.julialang.org/t/how-can-i-create-a-fancier-repl-prompt-with-styled-strings-was-make-base-textwidth-ignore-ansi-sequences/120782/5 "2024-10-01T13:44:37Z")

</div>

Yeah, `StyledStrings` could be the way to go, up from v1.11… I guess I’ll just have to wait (“mama said”).

> [@stevengj](#):
>
> You could strip out the ANSI escapes (which are not part of Unicode) before calling `textwidth`, e.g. [Strange characters in windows terminal - #4 by digital\_carver](https://discourse.julialang.org/t/strange-characters-in-windows-terminal/89355/4)

Nah, this whole thing is deep inside the REPL.jl library, I don’t want to mess with that.

---

<div class="post-metadata">

### Author: ![nilshg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nilshg/32/2283_2.png) [@nilshg](https://discourse.julialang.org/u/nilshg)
#### Post date: [October 1, 2024, 2:23pm UTC](https://discourse.julialang.org/t/how-can-i-create-a-fancier-repl-prompt-with-styled-strings-was-make-base-textwidth-ignore-ansi-sequences/120782/6 "2024-10-01T14:23:25Z")

</div>

See the package [readme](https://github.com/JuliaLang/StyledStrings.jl/blob/main/README.md):

> This is a standard library as of Julia 1.11. A version compatible with Julia 1.0 through to 1.10 has also been registered in General — allowing `StyledStrings` to be used anywhere without compromising compatibility.

---

<div class="post-metadata">

### Author: ![HanD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hand/32/213908_2.png) [@HanD](https://discourse.julialang.org/u/HanD)
#### Post date: [October 2, 2024, 7:00am UTC](https://discourse.julialang.org/t/how-can-i-create-a-fancier-repl-prompt-with-styled-strings-was-make-base-textwidth-ignore-ansi-sequences/120782/7 "2024-10-02T07:00:28Z")

</div>

Well, StyledString.jl might be backported to earlier Julia versions, but the support is limited. First and foremost, the REPL prompt doesn’t expect AnnotatedStrings, and it throws a typeasset.

```julia
TypeError: in typeassert, expected String, got a value of type StyledStrings.AnnotatedStrings.AnnotatedString{String}
    Stacktrace:
      [1] write_prompt(terminal::IO, s::Union{AbstractString, Function}, color::Bool)
        @ REPL.LineEdit ~/.local/share/mise/installs/julia/1.10.5/share/julia/stdlib/v1.10/REPL/src/LineEdit.jl:1525

```

(On a related note, in Julia 1.10, concatenating StyledStrings seems to be a PITA, regular `join` and `*` return plain Strings. The documentation says otherwise. I also can’t get it to load my `faces.toml` file on startup. Odd.)

---

<div class="post-metadata">

### Author: ![tecosaur](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tecosaur/32/23206_2.png) [@tecosaur](https://discourse.julialang.org/u/tecosaur)
#### Post date: [October 2, 2024, 7:29am UTC](https://discourse.julialang.org/t/how-can-i-create-a-fancier-repl-prompt-with-styled-strings-was-make-base-textwidth-ignore-ansi-sequences/120782/8 "2024-10-02T07:29:04Z")

</div>

> [@HanD](#):
>
> (On a related note, in Julia 1.10, concatenating StyledStrings seems to be a PITA, regular `join` and `*` return plain Strings. The documentation says otherwise. I also can’t get it to load my `faces.toml` file on startup. Odd.)

`join` and `*` were originally supported, but had to be reluctantly dropped due to a huge latency cost (tons of invalidations). They’ll have to be 1.11+.

Documentation needs to be updated.

Loading `faces.toml` on startup should work? Things to try:

- Set a custom face in your `faces.toml`
- Verify that your `faces.toml` is located at `joinpath(first(DEPOT_PATH), "config", "faces.toml")`
- See if it’s loaded after `using StyledStrings` by trying something like `styled"{my_custom_face:test test}"`.

---

<div class="post-metadata">

### Author: ![HanD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hand/32/213908_2.png) [@HanD](https://discourse.julialang.org/u/HanD)
#### Post date: [October 2, 2024, 7:38am UTC](https://discourse.julialang.org/t/how-can-i-create-a-fancier-repl-prompt-with-styled-strings-was-make-base-textwidth-ignore-ansi-sequences/120782/9 "2024-10-02T07:38:40Z")

</div>

> [@tecosaur](#):
>
> `join` and `*` were originally supported, but had to be reluctantly dropped due to a huge latency cost (tons of invalidations). They’ll have to be 1.11+.
> 
> Documentation needs to be updated.

Thanks for the heads up, good to know.

> [@tecosaur](#):
>
> Loading `faces.toml` on startup should work? Things to try:
> 
> - Set a custom face in your `faces.toml`
> - Verify that your `faces.toml` is located at `joinpath(first(DEPOT_PATH), "config", "faces.toml")`
> - See if it’s loaded after `using StyledStrings` by trying something like `styled"{my_custom_face:test test}"`.

I have a very simple `~/.julia/config/faces.toml`:

```julia
[my_custom_face]
background = '#444444'
foreground = '#949494'

```

Then:

```julia
julia> using StyledStrings

julia> styled"{my_custom_face:test test}"
"test test" # this is not visibly styled

julia> StyledStrings.load_customisations!(force=true)

julia> styled"{my_custom_face:test test}"
"test test" # this is visibly styled

```

![image](https://global.discourse-cdn.com/julialang/original/3X/e/d/ed4d4e4170404b74cdea6b1badf2a37307dab0d3.png)

This happens both with 1.10.5 and 1.11.0-rc4. Using `--startup-file=no` doesn’t help, either, so its not my local setup. But we are digressing, perhaps this could be continued in an issue reported to the StyledStrings.jl repo.

---

<div class="post-metadata">

### Author: ![tecosaur](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tecosaur/32/23206_2.png) [@tecosaur](https://discourse.julialang.org/u/tecosaur)
#### Post date: [October 2, 2024, 7:48am UTC](https://discourse.julialang.org/t/how-can-i-create-a-fancier-repl-prompt-with-styled-strings-was-make-base-textwidth-ignore-ansi-sequences/120782/10 "2024-10-02T07:48:39Z")

</div>

> [@HanD](#):
>
> This happens both with 1.10.5 and 1.11.0-rc4. Using `--startup-file=no` doesn’t help, either, so its not my local setup. But we are digressing, perhaps this could be continued in an issue reported to the [StyledStrings.jl](https://juliahub.com/ui/Packages/General/StyledStrings) repo.

Ah, I suspect this could be from an issue resulting from precompiling that I recently fixed.

---

<div class="post-metadata">

### Author: ![HanD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hand/32/213908_2.png) [@HanD](https://discourse.julialang.org/u/HanD)
#### Post date: [October 8, 2024, 7:32am UTC](https://discourse.julialang.org/t/how-can-i-create-a-fancier-repl-prompt-with-styled-strings-was-make-base-textwidth-ignore-ansi-sequences/120782/11 "2024-10-08T07:32:45Z")

</div>

> [@HanD](#):
>
> Well, [StyledString.jl](https://juliahub.com/ui/Packages/General/StyledString) might be backported to earlier Julia versions, but the support is limited. First and foremost, the REPL prompt doesn’t expect AnnotatedStrings, and it throws a typeasset.

I tried this on Julia v1.11-rc4. Sadly, it seems that this issue, i.e., that the REPL prompt doesn’t accept `AnnotatedString`s, holds for v1.11 as well, which makes such strings unusable in the prompt:

```julia
Unhandled Task ERROR: TypeError: in typeassert, expected String, got a value of type Base.AnnotatedString{String}
Stacktrace:
  [1] write_prompt(terminal::IO, s::Union{AbstractString, Function}, color::Bool)
    @ REPL.LineEdit ~/.local/share/mise/installs/julia/1.11.0-rc4/share/julia/stdlib/v1.11/REPL/src/LineEdit.jl:1618

```

It seems that the type spec on line 1618 is too strong:

```julia
    promptstr = prompt_string(s)::String

```

Too bad. Can I hope that this gets fixed before the release of v1.11?

---

<div class="post-metadata">

### Author: ![tecosaur](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tecosaur/32/23206_2.png) [@tecosaur](https://discourse.julialang.org/u/tecosaur)
#### Post date: [October 8, 2024, 8:05am UTC](https://discourse.julialang.org/t/how-can-i-create-a-fancier-repl-prompt-with-styled-strings-was-make-base-textwidth-ignore-ansi-sequences/120782/12 "2024-10-08T08:05:00Z")

</div>

1.11 is out now, so that’s not happening unfortunately. @caleb-allen did spin up a PR a while back looking at this: [Use `StyledStrings` for REPL prompt styling by caleb-allen · Pull Request #51887 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/pull/51887), but I think we’ve both been nerd-sniped since then by the attraction that is the prospect of nicer REPL code.

The fix I mentioned earlier will have to come in 1.11.1, since StyledStrings wasn’t bumped between rc4 and 1.11.0, unfortunately. It’s been suggested to me I should be more willing to merge my own PRs about AnnotatedStrings/StyledStrings, but it feels dodgy to me 😅.

---

<div class="post-metadata">

### Author: ![caleb-allen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/caleb-allen/32/14054_2.png) [@caleb-allen](https://discourse.julialang.org/u/caleb-allen)
#### Post date: [October 8, 2024, 11:18am UTC](https://discourse.julialang.org/t/how-can-i-create-a-fancier-repl-prompt-with-styled-strings-was-make-base-textwidth-ignore-ansi-sequences/120782/13 "2024-10-08T11:18:51Z")

</div>

May have some time to revisit that PR next week, would love to follow through on that
