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.__ate... ───╯

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.__ate... ───╯

easy!

But wait, there's more!

termshow(termshow)  # or any other function
   ╭──── Function: termshow ──────────────────────────────────────────────╮
                                                                         
    (1)  termshow(io::IO, e::Expr; kwargs...)                            
    (2)                                                                  
    (3)  termshow(io::IO, obj::AbstractDict; kwargs...)                  
    (4)                                                                  
    (5)  termshow(io::IO, mtx::AbstractMatrix; kwargs...)                
    (6)                                                                  
    (7)  termshow(io::IO, vec::Union {Tuple, AbstractVecto               
        r} ; kwargs...)                                                  
    (8)                                                                  
    (9)  termshow(io::IO, arr::AbstractArray; kwargs...)                 
    (10)                                                                 
                                                                         
   ╰─────────────────────────────────────────────────────── 18 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 by 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 = false,                                          
          padding::Union{{Nothing,Padding,NTuple}} = nothing,         
          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 terminal's width,         
      it will                                                             
      get trimmed                                                         
      to avoid overflow, unless `trim=false` is given.                    
    ╰──────────────────────────────────────────────────────────────────────╯

    ┌──────────────────────────────────────────────────────────────────┐
      Panel(                                                          
          content::Union{{AbstractString,AbstractRenderable}},        
          ::Val{{false}},                                             
          padding::Padding;                                           
20 lines omitted...

and in general you can display almost any object

termshow(Dict(:x => 1, :y => 2))
termshow(zeros(3, 3))
╭──── Dict   ──────╮
                                 
      y => 2      
      x => 1      
                                 
                                 
╰─────────────────────────────────╯
╭──── Matrix  ... ─╮
                           
                           
         (1)   (2)   (3)   
                           
   (1)   0.0   0.0   0.0   
   (2)   0.0   0.0   0.0   
   (3)   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 = false,                                          
          padding::Union{{Nothing,Padding,NTuple}} = nothing,         
          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 terminal's width,         
      it will                                                             
      get trimmed                                                         
      to avoid overflow, unless `trim=false` is given.                    
    ╰──────────────────────────────────────────────────────────────────────╯

    ┌──────────────────────────────────────────────────────────────────┐
      Panel(                                                          
          content::Union{{AbstractString,AbstractRenderable}},        
          ::Val{{false}},                                             
          padding::Padding;                                           
20 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, sprint_no_color(x))                                 
  end                                                               
└────────────────────────────────────────────────────────────────────┘
                   /home/runner/work/Term.jl/Term.jl/src/tprint.jl:41

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:31

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:31

    ╭──── all methods ─────────────────────────────────────────────────────────╮
                                                                              
        (1)  tprint(io::IO, x::AbstractString; highlight)                     
        (2)                                                                   
        (3)  tprint(io::IO, x::Term.Renderables.AbstractRender                
            able; highlight)                                                  
        (4)                                                                   
        (5)  tprint(io::IO, md::Markdown.MD; kwargs...)                       
        (6)                                                                   
        (7)  tprint(io::IO, x; highlight)                                     
        (8)                                                                   
        (9)  tprint(io::IO, args...; highlight)                               
        (10)                                                                  
        (11)  tprint(md::Markdown.MD; kwargs...)                              
        (12)                                                                  
        (13)  tprint(x; highlight)                                            
        (14)                                                                  
        (15)  tprint(args...; highlight)                                      
        (16)                                                                  
                                                                              
    ╰──────────────────────────────────────────────────────────────────────────╯

Enjoy.