Skip to content

Commit

Permalink
printing with styled/non-unit-textwidth-character contents (#443)
Browse files Browse the repository at this point in the history
Previously, BlockArrays with elements that used styling would throw off
the printing, because the textwidth computation didn't account for the
fact that some contents might have a different `length` relative to how
much space they take up when printed.

This fixes that by using the `ANSIIterator` from Base, ala
JuliaLang/julia#47430. Unfortunately,
`ANSIIterator` isn't exported at the moment - but the alternative is to
depend on StringManipulations.jl or copy over the Base implementation.

I added a test that shows the problem. Previously, it displayed as:

![image](https://github.com/user-attachments/assets/722037b0-aeb1-4aca-b8aa-2c603290cf02)
With this, it displays as:

![image](https://github.com/user-attachments/assets/a0d5098d-8d5a-4019-a733-2a1acbcdaa4a)
  • Loading branch information
thchr authored Jan 12, 2025
1 parent 4d386cf commit 6e54660
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ function _blockarray_print_matrix_row(io::IO,
print(io, l, prettysx, r)

# Jump forward
n_chars += length(l) + length(prettysx) + length(r) + 2
n_chars += length(l) + textwidth(Base.ANSIIterator(prettysx)) + length(r) + 2

cumul += 1
if ndims(X) == 2
Expand Down
29 changes: 29 additions & 0 deletions test/test_blocks.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,35 @@ using Test, BlockArrays
@test blocks(mortar(matrix_blocks)) === matrix_blocks
end

@testset "blocks::BlockMatrix{::MyString}" begin
# test printing with ANSI escape sequences & textwidth(::Char) ≠ 1
struct MyString
s::String
end
function Base.show(io::IO, x::MyString)
if all(isnumeric, x.s)
printstyled(io, x.s; bold=true, color=:green)
elseif all(isascii, x.s)
printstyled(io, x.s, color=:red)
print(io, " ascii!")
else
print(io, x.s)
end
end

B = BlockArray(undef_blocks, Matrix{MyString}, [1,2], [1,2])
B[Block(1), Block(1)] = [MyString("abc");;]
B[Block(1), Block(2)] = [MyString("123") MyString("γ");]
B[Block(2), Block(1)] = [MyString("γ"); MyString("1");;]
B[Block(2), Block(2)] = [MyString("⛵⛵⛵⛵⛵") MyString("x"); MyString("⛵⛵⛵") MyString("4")]

strip_ansi(s) = reduce(*, filter(c->!(c isa Base.ANSIDelimiter),
map(last, Base.ANSIIterator(s))))
reference_str = "2×2-blocked 3×3 BlockMatrix{$(@__MODULE__).MyString}:\n \e[31mabc\e[39m ascii! │ \e[32m\e[1m123\e[22m\e[39m γ \n ────────────┼──────────────────────\n γ │ ⛵⛵⛵⛵⛵ \e[31mx\e[39m ascii!\n \e[32m\e[1m1\e[22m\e[39m │ ⛵⛵⛵ \e[32m\e[1m4\e[22m\e[39m "
@test strip_ansi(sprint(show, "text/plain", B; context=stdout)) == strip_ansi(reference_str)
@test strip_ansi(sprint(show, "text/plain", B)) == strip_ansi(reference_str)
end

@testset "blocks(::BlockedVector)" begin
v0 = rand(3)
vb = BlockedArray(v0, [1, 2])
Expand Down

0 comments on commit 6e54660

Please sign in to comment.