Make `Base.textwidth` ignore ANSI sequences

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> 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.

Are you maybe looking for

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> textwidth(styled"{yellow:hello} {blue:there}")
11
1 Like

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

But probably better to use StyledStrings

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

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

See the package readme:

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.

1 Like

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.

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.)

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}".

Thanks for the heads up, good to know.

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

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

Then:

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

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.

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

1 Like