Term Repr

Note: by repr here we refer generically to how information about an object is represented in the terminal, not the repr function in Julia.

Type REPR

You can use Term.jl to create a styled type display in your console.

The easiest way to explain it is by way of example. Let's say you define a type, and create an instance of it:

struct myType
    name::String
    height::Int
    width::Int
    mass::Float64
end


obj = myType("Rocket", 10, 10, 99.9)
Main.myType("Rocket", 10, 10, 99.9)

as you can see the default way to represent your object in the console is not very exciting. But we can improve that with a simple macro!

using Term.Repr

@with_repr struct myFancyType
    name::String
    height::Int
    width::Int
    mass::Float64
end


obj = myFancyType("Rocket", 10, 10, 99.9)
╭─────────────────────────╮
   name::String Rocket  
  height::Int64 10      
   width::Int64 10      
  mass::Float64 99.9    
╰─ Main.__atexample... ───╯

now every time we display an instance of myFancyType in the console, we get a nice representation (note that that's not true for print(obj)!).

Docs display

Ooopss... it looks like the Panel display in the example above is not working out in the Docs. It will look fine in your REPL though!

Termshow

Very nice, but what if I don't have access to where the types are created (perhaps they are in another package) but still want to have the nice display? One way is to use termshow:

dullobj = myType("Rocket", 10, 10, 99.9)
termshow(dullobj)
╭─────────────────────────╮
   name::String Rocket  
  height::Int64 10      
   width::Int64 10      
  mass::Float64 99.9    
╰─ Main.__atexample... ───╯

easy!

But wait, there's more!

termshow(termshow)  # or any other function
   ╭──── Function: termshow ──────────────────────────╮
   │                                                  
     (1)  termshow(io::IO, e::Expr; kwargs...)       
     (2)  termshow(io::IO, obj::AbstractDict;        
         kwargs...)                                  
     (3)  termshow(io::IO, mtx::AbstractMatrix;      
         kwargs...)                                  
     (4)  termshow(io::IO, vec::Union; kwargs...)    
     (5)  termshow(io::IO, arr::AbstractArray;       
         kwargs...)                                  
     (6)  termshow(io::IO, obj::DataType;            
         kwargs...)                                  
     (7)  termshow(io::IO, fun::Function; width)     
     (8)  termshow(io::IO, obj)                      
     (9)  termshow(obj; kwargs...)                   
                                                     
   ╰──────────────────────────────────── 9 methods ───╯
━━━━━━━━━━━━━━━━━━━━━━ Docstring ━━━━━━━━━━━━━━━━━━━━━━
       ┌─────────────────────────────────────┐
         termshow                           
       └─────────────────────────────────────┘

   Styled string representation of any object.

   `termshow` prints to stdout (or any other IO) a
   styled representation of the object. Dedicated
   methods create displays for specify types such as
   `Dict` or `Vector`.

   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

       ┌─────────────────────────────────────┐
         termshow(io::IO, obj)              
       └─────────────────────────────────────┘

   Generic method for any object not caught my
   dedicated methods. Creates a `Panel` with the
   object's fields and contents.

   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

       ┌─────────────────────────────────────┐
         termshow(io::IO, e::Expr;          
         kwargs...)                         
       └─────────────────────────────────────┘

   Show an expression's head and arguments.

   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

       ┌─────────────────────────────────────┐
         termshow(io::IO, d::Dict;          
         kwargs...)                         
       └─────────────────────────────────────┘

   Show a dictionary's keys and values and their data
   types.

   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

       ┌─────────────────────────────────────┐
         termshow(io::IO,                   
         mtx::AbstractMatrix; kwargs...)    
       └─────────────────────────────────────┘

   Show a matrix content as a 2D table visualization.

   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

       ┌─────────────────────────────────────┐
         termshow(io::IO, vec::Union{Tuple,AbstractVector};   
         kwargs...)                         
       └─────────────────────────────────────┘

   Show a vector's content as a 1D table
   visualization.

   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

       ┌─────────────────────────────────────┐
         termshow(io::IO,                   
         arr::AbstractArray; kwargs...)     
       └─────────────────────────────────────┘

   Show the content of a multidimensional array as a
   series of 2D slices.

   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

       ┌─────────────────────────────────────┐
         termshow(io::IO, obj::DataType;    
         kwargs...)                         
       └─────────────────────────────────────┘

   Show a type's arguments, constructors and
   docstring.

   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

       ┌─────────────────────────────────────┐
         termshow(io::IO, fun::Function;    
         kwargs...)                         
       └─────────────────────────────────────┘

   Show a function's methods and docstring.

Fancy right? It shows the function, various methods for it and it's docstrings (by parsing the Markdown). It works with types too

import Term: Panel
termshow(Panel)
    ╭─────────────────────────────────────────────────────╮
                                                         
             Panel <: Term.Panels.AbstractPanel          
               segments ::Vector                        
                measure ::Term.Measures.Measure         
                                                         
    ╰─────────────────────────────────────────────────────╯
━━━━━━━━━━━━━━━━━━━━━━━━━ Docstring ━━━━━━━━━━━━━━━━━━━━━━━━
    ┌──────────────────────────────────────────────┐
      Panel                                       
    └──────────────────────────────────────────────┘

`Renderable` with a panel surrounding some content:

    ┌──────────────────────────────────────────────┐
          ╭──────────╮                            
          │ my panel │                            
          ╰──────────╯                            
    └──────────────────────────────────────────────┘

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
━━━━

When constructing a Panel, several keyword arguments can
be
used to set its appearance:

box::Symbol sets the `Box` type for the Panel's border
style::String  sets the box's style (e.g., color)
title::Union  sets the Panel's title
title_style::Union sets the title's style
title_justify::Symbol     sets the location of the
title
subtitle::Union  sets the Panel's subtitle
subtitle_style::Union  sets the subtitle's style
subtitle_justify::Symbol  sets the location of the
subtitle
justify::Symbol sets text's alignment (:left, :rigth,
:center, :justify)


━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
━━━━

    ┌──────────────────────────────────────────────┐
      Panel(;                                     
          fit::Bool = false,                      
          height::Int = 2,                        
          width::Int = 80,                        
          padding::Union{Vector,Padding,NTuple} = Padding(0, 0, 0, 0),  
          kwargs...,                              
      )                                           
    └──────────────────────────────────────────────┘

Construct a `Panel` with no content.

                          Examples

    ┌──────────────────────────────────────────────┐
      julia> Panel(height=5, width=10)            
      ╭────────╮                                  
      │        │                                  
      │        │                                  
      │        │                                  
      ╰────────╯                                  
                                                  
      julia> Panel(height=3, width=5)             
      ╭───╮                                       
      │   │                                       
      ╰───╯                                       
    └──────────────────────────────────────────────┘

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
━━━━

    ┌──────────────────────────────────────────────┐
      Panel(                                      
          content::Union{AbstractString,AbstractRenderable};  
          fit::Bool = true,                       
          padding::Union{Padding,NTuple} = Padding(2, 2, 0, 0),  
          kwargs...,                              
      )                                           
    └──────────────────────────────────────────────┘

Construct a `Panel` around an `AbstractRenderable` or
`AbstractString`.

This is the main Panel-creating function, it dispatches to
other methods based on the value of `fit` to either fith
the `Panel` to its content or vice versa.

`kwargs` can be used to set various aspects of the
`Panel`'s appearance like the presence and style of
titles,
box type etc... see render (@ref) below.

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
━━━━

    ┌──────────────────────────────────────────────┐
      Panel(                                      
          content::Union{AbstractString,AbstractRenderable},  
          ::Val{true},                            
          padding::Padding;                       
          height::Union{Nothing,Int} = nothing,   
          width::Union{Nothing,Int} = nothing,    
          trim::Bool = true,                      
          kwargs...,                              
      )                                           
    └──────────────────────────────────────────────┘

Construct a `Panel` fitting the content's width.

    ╭──── Warning ─────────────────────────────────────╮
      If the content is larger than the console       
37 lines omitted...

and in general you can display almost any object

termshow(Dict(:x => 1, :y => 2))
termshow(zeros(3, 3))
╭──── Dict {Symbol, Int64}  ──────╮
│                                 
   {Symbol}  y => 2  {Int64}   
   {Symbol}  x => 1  {Int64}   
                                 
╰───────────────────── 2 items ───╯
╭──── Matrix {Float64}  ─────────────────────────╮
│                                                
                     (1)  (2)  (3)              
               (1)                              
               (2)   0.0  0.0  0.0              
               (3)   0.0  0.0  0.0              
                     0.0  0.0  0.0              
                                                
╰───────────────────────────────────── 3 × 3  ───╯

install term repr

Okay, termshow is pretty cool (even if I say so myself), but we need to call it every time we need to display something. I just want to type a variable name in the REPL (devs are lazy you know). Well, there's a solution for that too of course:

install_term_repr()
Panel
    ╭─────────────────────────────────────────────────────╮
                                                         
             Panel <: Term.Panels.AbstractPanel          
               segments ::Vector                        
                measure ::Term.Measures.Measure         
                                                         
    ╰─────────────────────────────────────────────────────╯
━━━━━━━━━━━━━━━━━━━━━━━━━ Docstring ━━━━━━━━━━━━━━━━━━━━━━━━
    ┌──────────────────────────────────────────────┐        
      Panel                                               
    └──────────────────────────────────────────────┘        
                                                            
`Renderable` with a panel surrounding some content:         
                                                            
    ┌──────────────────────────────────────────────┐        
          ╭──────────╮                                    
          │ my panel │                                    
          ╰──────────╯                                    
    └──────────────────────────────────────────────┘        
                                                            
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━    
━━━━                                                        
                                                            
When constructing a Panel, several keyword arguments can    
be                                                          
used to set its appearance:                                 
                                                            
box::Symbol sets the `Box` type for the Panel's border  
style::String  sets the box's style (e.g., color)       
title::Union  sets the Panel's title                    
title_style::Union sets the title's style               
title_justify::Symbol     sets the location of the      
title                                                       
subtitle::Union  sets the Panel's subtitle              
subtitle_style::Union  sets the subtitle's style        
subtitle_justify::Symbol  sets the location of the      
subtitle                                                    
justify::Symbol sets text's alignment (:left, :rigth,   
:center, :justify)                                          
                                                            
                                                            
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━    
━━━━                                                        
                                                            
    ┌──────────────────────────────────────────────┐        
      Panel(;                                             
          fit::Bool = false,                              
          height::Int = 2,                                
          width::Int = 80,                                
          padding::Union{Vector,Padding,NTuple} = Padding(0, 0, 0, 0),  
          kwargs...,                                      
      )                                                   
    └──────────────────────────────────────────────┘        
                                                            
Construct a `Panel` with no content.                        
                                                            
                          Examples                                                         
                                                            
    ┌──────────────────────────────────────────────┐        
      julia> Panel(height=5, width=10)                    
      ╭────────╮                                          
      │        │                                          
      │        │                                          
      │        │                                          
      ╰────────╯                                          
                                                          
      julia> Panel(height=3, width=5)                     
      ╭───╮                                               
      │   │                                               
      ╰───╯                                               
    └──────────────────────────────────────────────┘        
                                                            
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━    
━━━━                                                        
                                                            
    ┌──────────────────────────────────────────────┐        
      Panel(                                              
          content::Union{AbstractString,AbstractRenderable};  
          fit::Bool = true,                               
          padding::Union{Padding,NTuple} = Padding(2, 2, 0, 0),  
          kwargs...,                                      
      )                                                   
    └──────────────────────────────────────────────┘        
                                                            
Construct a `Panel` around an `AbstractRenderable` or       
`AbstractString`.                                           
                                                            
This is the main Panel-creating function, it dispatches to  
other methods based on the value of `fit` to either fith    
the `Panel` to its content or vice versa.                   
                                                            
`kwargs` can be used to set various aspects of the          
`Panel`'s appearance like the presence and style of         
titles,                                                     
box type etc... see render (@ref) below.                    
                                                            
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━    
━━━━                                                        
                                                            
    ┌──────────────────────────────────────────────┐        
      Panel(                                              
          content::Union{AbstractString,AbstractRenderable},  
          ::Val{true},                                    
          padding::Padding;                               
          height::Union{Nothing,Int} = nothing,           
          width::Union{Nothing,Int} = nothing,            
          trim::Bool = true,                              
          kwargs...,                                      
      )                                                   
    └──────────────────────────────────────────────┘        
                                                            
Construct a `Panel` fitting the content's width.            
                                                            
    ╭──── Warning ─────────────────────────────────────╮    
      If the content is larger than the console           
37 lines omitted...                                         

now showing anything in the REPL goes through termshow

Not for developers!!!

If you're writing code just for yourself, go ahead and use install_term_repr. Enjoy it. But, if the code you're writing is intended for others you should really avoid doing that. It will modify the behavior of the REPL for them too and that's confusing and possibly error prone.

@showme

One of Julia's most loved features is multiple dispatch. However, sometimes it can be hard to know which method gets called by your code and what that method is doing. There's lots of tools out there to help with this, including some built in in Julia's base code. Here we show a nifty little macro that builds upon CodeTracking by Tim Holy to directly show you the method your code is calling:

import Term.Repr: @showme

@showme tprint(stdout, "this is TERM")  # which method is being called?
────────────────────────────────────────────────────────────
    ╭──── @showme ─────────────────────────────────────╮
      Showing definition for method called by:        
      `tprint(stdout, "this is TERM")`                
    ╰──────────────────────────────────────────────────╯

Arguments
      stdout::Symbol
      "this is TERM"::String

Method definition
 ┌────────────────────────────────────────────────┐
   function tprint(io::IO, x::AbstractString;    
   highlight = true)                             
       x = (highlight ? apply_style             
   highlighter : apply_style)(x)                 
                                                 
       x =                                       
           Measure(x).w <= console_width(io)     
   ? x :                                         
           string(RenderableText(string(x),      
   width = console_width(io)))                   
       print(io, x)                              
   end                                           
 └────────────────────────────────────────────────┘
/home/runner/work/Term.jl/Term.jl/src/tprint.jl:37

as you can see, it shows the source code of the particular tprint method being called by the combination of arguments, for different arguments different methods will be invoked:

@showme tprint("this is also TERM")  # different method
────────────────────────────────────────────────────────────
    ╭──── @showme ─────────────────────────────────────╮
      Showing definition for method called by:        
      `tprint("this is also TERM")`                   
    ╰──────────────────────────────────────────────────╯

Arguments
      "this is also TERM"::String

Method definition
 ┌────────────────────────────────────────────────┐
   tprint(x; highlight = true) =                 
   tprint(stdout, x; highlight = highlight)      
 └────────────────────────────────────────────────┘
/home/runner/work/Term.jl/Term.jl/src/tprint.jl:24

You can also list all methods for the function you're calling, should you wish to do so

@showme tprint("still TERM") show_all_methods=true
────────────────────────────────────────────────────────────
    ╭──── @showme ─────────────────────────────────────╮
      Showing definition for method called by:        
      `tprint("still TERM")`                          
    ╰──────────────────────────────────────────────────╯

Arguments
      "still TERM"::String

Method definition
 ┌────────────────────────────────────────────────┐
   tprint(x; highlight = true) =                 
   tprint(stdout, x; highlight = highlight)      
 └────────────────────────────────────────────────┘
/home/runner/work/Term.jl/Term.jl/src/tprint.jl:24

    ╭──── all methods ─────────────────────────────────────╮
    │                                                      
        (1)  tprint(io::IO,                               
            ::MIME{Symbol("text/html")}, x;               
            highlight)                                    
        (2)  tprint(io::IO, x::AbstractString;            
            highlight)                                    
        (3)  tprint(io::IO,                               
            x::Term.Renderables.A                         
            bstractRenderable; highlight)                 
        (4)  tprint(io::IO, md::Markdown.MD;              
            kwargs...)                                    
        (5)  tprint(io::IO, x; highlight)                 
        (6)  tprint(io::IO, args...)                      
        (7)  tprint(md::Markdown.MD; kwargs...)           
        (8)  tprint(x; highlight)                         
        (9)  tprint(args...; highlight)                   
                                                          
    ╰──────────────────────────────────────────────────────╯

Enjoy.