Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/CTBase.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ import DocStringExtensions: TYPEDEF, TYPEDSIGNATURES
# MODULAR ORGANIZATION
# ============================================================================ #

# Exceptions module - enhanced error handling system (must load first)
include(joinpath(@__DIR__, "Exceptions", "Exceptions.jl"))
using .Exceptions

# Core module - fundamental types and utilities
# Core module - fundamental types and utilities (must load first)
include(joinpath(@__DIR__, "Core", "Core.jl"))
using .Core

# Exceptions module - enhanced error handling system
include(joinpath(@__DIR__, "Exceptions", "Exceptions.jl"))
using .Exceptions

# Unicode module - Unicode character utilities
include(joinpath(@__DIR__, "Unicode", "Unicode.jl"))
using .Unicode
Expand Down
2 changes: 2 additions & 0 deletions src/Core/Core.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ module Core
import DocStringExtensions: TYPEDEF, TYPEDSIGNATURES

include("types.jl")
include("tags.jl")
include("default.jl")

# Private utilities
Expand All @@ -19,6 +20,7 @@ include("macros.jl")

# Public utilities
include("matrix_utils.jl")
include("display.jl")

# Export public API
export ctNumber, matrix2vec, to_out_of_place, @ensure
Expand Down
131 changes: 131 additions & 0 deletions src/Core/display.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
"""
_apply_ansi(s, code, io::IO)

Apply ANSI escape codes to a string if color is enabled in the IO context.

# Arguments
- `s::AbstractString`: The string to style.
- `code::String`: The ANSI code (e.g., `"2"` for dim, `"1"` for bold, `"1;31"` for red).
- `io::IO`: Output stream to check for color support.

# Returns
- `String`: The string wrapped in ANSI escape codes if `get(io, :color, false)` is true,
otherwise the plain string.
"""
_apply_ansi(s, code, io::IO) = get(io, :color, false) ? "\033[$(code)m$(s)\033[0m" : s

"""
$(TYPEDSIGNATURES)

Apply dimmed (faint) ANSI styling to a string.

# Arguments
- `s::AbstractString`: The string to style.
- `io::IO`: Output stream to check for color support.

# Returns
- `String`: The string wrapped in dim ANSI escape codes if color is enabled.
"""
_dim(s, io::IO) = _apply_ansi(s, "2", io)

"""
$(TYPEDSIGNATURES)

Apply bold ANSI styling to a string.

# Arguments
- `s::AbstractString`: The string to style.
- `io::IO`: Output stream to check for color support.

# Returns
- `String`: The string wrapped in bold ANSI escape codes if color is enabled.
"""
_bold(s, io::IO) = _apply_ansi(s, "1", io)

"""
$(TYPEDSIGNATURES)

Apply red ANSI styling to a string.

# Arguments
- `s::AbstractString`: The string to style.
- `io::IO`: Output stream to check for color support.

# Returns
- `String`: The string wrapped in red ANSI escape codes if color is enabled.
"""
_red(s, io::IO) = _apply_ansi(s, "1;31", io)

"""
$(TYPEDSIGNATURES)

Apply yellow ANSI styling to a string.

# Arguments
- `s::AbstractString`: The string to style.
- `io::IO`: Output stream to check for color support.

# Returns
- `String`: The string wrapped in yellow ANSI escape codes if color is enabled.
"""
_yellow(s, io::IO) = _apply_ansi(s, "33", io)

"""
$(TYPEDSIGNATURES)

Apply green ANSI styling to a string.

# Arguments
- `s::AbstractString`: The string to style.
- `io::IO`: Output stream to check for color support.

# Returns
- `String`: The string wrapped in green ANSI escape codes if color is enabled.
"""
_green(s, io::IO) = _apply_ansi(s, "32", io)

"""
get_format_codes(io::IO) -> NamedTuple

Get ANSI formatting codes based on terminal color support.

Returns a NamedTuple with formatting codes for consistent display across all show() methods.

# Fields
- `bold`: Bold text
- `reset`: Reset all formatting
- `name`: Bold blue for names (options, types, etc.)
- `type`: Cyan for types
- `value`: Green for values
- `keyword`: Yellow for keywords/aliases
- `count`: Magenta for counts
- `label`: Gray for labels/descriptions

# Example
```julia
fmt = get_format_codes(io)
print(io, fmt.name, "option_name", fmt.reset, "::", fmt.type, "Int", fmt.reset)
```

# Notes
- Automatically detects color support via `get(io, :color, false)`
- Returns empty strings for all codes if colors are not supported
- Ensures consistent color scheme across the entire package
"""
function get_format_codes(io::IO)
supports_color = get(io, :color, false)

return (
# Text formatting
bold=supports_color ? "\033[1m" : "",
reset=supports_color ? "\033[0m" : "",

# Colors for different semantic elements
name=supports_color ? "\033[1m\033[34m" : "", # Bold blue for names
type=supports_color ? "\033[36m" : "", # Cyan for types
value=supports_color ? "\033[32m" : "", # Green for values
keyword=supports_color ? "\033[33m" : "", # Yellow for keywords/aliases
count=supports_color ? "\033[35m" : "", # Magenta for counts
label=supports_color ? "\033[90m" : "", # Gray for labels
)
end
20 changes: 20 additions & 0 deletions src/Core/tags.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"""
AbstractTag

Abstract type for tag dispatch pattern used to handle extension-dependent implementations.

This type is used for multiple dispatch in validation functions and other contexts
where behavior depends on loaded extensions (e.g., Enzyme, Zygote, CUDA).

# Example
```julia
struct MyTag <: AbstractTag end

function validate_backend(tag::MyTag, backend::Symbol)
# Tag-specific validation logic
end
```

See also: Extension-based validation patterns in extension modules
"""
abstract type AbstractTag end
1 change: 1 addition & 0 deletions src/Exceptions/Exceptions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ The Exceptions module is organized into thematic files:
module Exceptions

import DocStringExtensions: TYPEDEF, TYPEDSIGNATURES
using ..Core: Core

# Type definitions
include("types.jl")
Expand Down
115 changes: 13 additions & 102 deletions src/Exceptions/display.jl
Original file line number Diff line number Diff line change
@@ -1,92 +1,3 @@
# Custom display functions for user-friendly error messages

# ANSI formatting primitives
"""
_apply_ansi(s, code, io::IO)

Apply ANSI escape codes to a string if color is enabled in the IO context.

# Arguments
- `s::AbstractString`: The string to style.
- `code::String`: The ANSI code (e.g., "2" for dim, "1" for bold, "1;31" for red).
- `io::IO`: Output stream to check for color support.

# Returns
- `String`: The string wrapped in ANSI escape codes if `get(io, :color, false)` is true,
otherwise the plain string.
"""
_apply_ansi(s, code, io::IO) = get(io, :color, false) ? "\033[$(code)m$(s)\033[0m" : s

"""
$(TYPEDSIGNATURES)

Apply dimmed (faint) ANSI styling to a string.

# Arguments
- `s::AbstractString`: The string to style.
- `io::IO`: Output stream to check for color support.

# Returns
- `String`: The string wrapped in dim ANSI escape codes if color is enabled.
"""
_dim(s, io::IO) = _apply_ansi(s, "2", io)

"""
$(TYPEDSIGNATURES)

Apply bold ANSI styling to a string.

# Arguments
- `s::AbstractString`: The string to style.
- `io::IO`: Output stream to check for color support.

# Returns
- `String`: The string wrapped in bold ANSI escape codes if color is enabled.
"""
_bold(s, io::IO) = _apply_ansi(s, "1", io)

"""
$(TYPEDSIGNATURES)

Apply red ANSI styling to a string.

# Arguments
- `s::AbstractString`: The string to style.
- `io::IO`: Output stream to check for color support.

# Returns
- `String`: The string wrapped in red ANSI escape codes if color is enabled.
"""
_red(s, io::IO) = _apply_ansi(s, "1;31", io)

"""
$(TYPEDSIGNATURES)

Apply yellow ANSI styling to a string.

# Arguments
- `s::AbstractString`: The string to style.
- `io::IO`: Output stream to check for color support.

# Returns
- `String`: The string wrapped in yellow ANSI escape codes if color is enabled.
"""
_yellow(s, io::IO) = _apply_ansi(s, "33", io)

"""
$(TYPEDSIGNATURES)

Apply green ANSI styling to a string.

# Arguments
- `s::AbstractString`: The string to style.
- `io::IO`: Output stream to check for color support.

# Returns
- `String`: The string wrapped in green ANSI escape codes if color is enabled.
"""
_green(s, io::IO) = _apply_ansi(s, "32", io)

"""
extract_user_frames(st::Vector)

Expand Down Expand Up @@ -360,16 +271,16 @@ function _print_pipe_field(io, label::String, value, max_len::Int, color::Symbol
# Multi-line case: AmbiguousDescription.candidates
for (i, v) in enumerate(value)
if i == 1
print(io, _dim("│", io), " ", _bold(rpad(label, max_len), io), " ")
print(io, Core._dim("│", io), " ", Core._bold(rpad(label, max_len), io), " ")
_print_colored(io, string(v), color)
println(io)
else
println(io, _dim("│", io), " ", " "^max_len, " ", string(v))
println(io, Core._dim("│", io), " ", " "^max_len, " ", string(v))
end
end
else
# Single value
print(io, _dim("│", io), " ", _bold(rpad(label, max_len), io), " ")
print(io, Core._dim("│", io), " ", Core._bold(rpad(label, max_len), io), " ")
_print_colored(io, string(value), color)
println(io)
end
Expand All @@ -390,9 +301,9 @@ Print colored text based on a color symbol.
"""
function _print_colored(io, text, color::Symbol)
if color == :yellow
print(io, _yellow(text, io))
print(io, Core._yellow(text, io))
elseif color == :green
print(io, _green(text, io))
print(io, Core._green(text, io))
else
print(io, text)
end
Expand All @@ -413,22 +324,22 @@ function _format_user_friendly_error(io::IO, e::CTException)
frame = isempty(user_frames) ? nothing : user_frames[1]

type_name = string(nameof(typeof(e)))
print(io, _red(type_name, io))
print(io, Core._red(type_name, io))

if !isnothing(frame)
func_name = string(frame.func)
file_name = basename(string(frame.file))
line_num = frame.line
print(io, " ", _dim("→", io), " ", _bold(func_name, io), " ")
print(io, _yellow("$(file_name):$(line_num)", io))
print(io, " ", Core._dim("→", io), " ", Core._bold(func_name, io), " ")
print(io, Core._yellow("$(file_name):$(line_num)", io))
end
println(io)

# Blank pipe separator
println(io, _dim("│", io))
println(io, Core._dim("│", io))

# Message
println(io, _dim("│", io), " ", _bold(e.msg, io))
println(io, Core._dim("│", io), " ", Core._bold(e.msg, io))

# Build field pairs
primary_pairs = _build_primary_pairs(e)
Expand All @@ -440,7 +351,7 @@ function _format_user_friendly_error(io::IO, e::CTException)
max_len = maximum(length(p[1]) for p in all_pairs)

# Blank pipe separator
println(io, _dim("│", io))
println(io, Core._dim("│", io))

# Primary fields
for p in primary_pairs
Expand All @@ -449,7 +360,7 @@ function _format_user_friendly_error(io::IO, e::CTException)

# Separator between primary and secondary
if !isempty(primary_pairs) && !isempty(secondary_pairs)
println(io, _dim("│", io))
println(io, Core._dim("│", io))
end

# Secondary fields
Expand All @@ -459,7 +370,7 @@ function _format_user_friendly_error(io::IO, e::CTException)
end

# Closing visual
return println(io, _dim("└─", io))
return println(io, Core._dim("└─", io))
end

"""
Expand Down
Loading
Loading