Liking cljdoc? Tell your friends :D

bling

Rich text in the console.

bling on Clojars

Features  •  Setup  •  Basic Usage  •  Blocks  •  Templates



The same example as above, in a terminal emulator with a dark background.

Features

  • Works great for Clojure, ClojureScript, and Babashka.

  • Supports both terminal emulators and browser consoles.

  • Simple, accessibility-focused, 11-color pallette.

  • All colors provide reasonable contrast on both light and dark backgrounds.

  • Simple and intuitive hiccup-like markup syntax.

  • Sensible templates for warning and error callouts.


Setup

Add as a dependency to your project:

[io.github.paintparty/bling "0.4.0"]

Import into your namespace:

(ns myns.core
  (:require
    [bling.core :refer [bling callout point-of-interest]]))

;; In ClojureScript, you may also want :refer bling.core/print-bling.

Basic Usage

Note that if you are reading this on github in a light-mode theme, the dark-mode samples in the sections below will appear to have lower contrast than they actually do if you were viewing them in dark-mode.

bling.core/bling takes any number of arguments and returns a string of text decorated with tags for colorization, italics, and boldness:

(println (bling [:bold "bold"]
                ", "
                [:italic "italic"]
                ", or "
                [:blue "colored"]))


In ClojureScript, bling returns a js object that needs to be printed like this:
(.apply js/console.log js/console (goog.object/get o "consoleArray")).

To avoid typing all this out, you can use bling.core/print-bling to print the array returned from bling:

(print-bling (bling [:bold "bold"]
                    ", "
                    [:italic "italic"]
                    ", or "
                    [:blue "colored"]))

By default, in ClojureScript, bling.core/print-bling prints with js/console.log. However, if you would like to print with either js.console/warn, or js/console.error, you can pass either as a second argument.

(print-bling (bling [:bold "bold"]
                    ", "
                    [:italic "italic"]
                    ", or "
                    [:blue "colored"])
             js/console.warn)

Combo styles

You can add multiple decorations with hiccup-style tags (a keyword with dot separators). The order of the things separated by dots doesn't matter.

(println (bling [:bold.italic "bold & italic"]
                ", "
                [:italic.blue "italic & colored"]
                ", "
                [:bold.italic.white.blue-bg
                 "bold & italic & colored & colored-bg"]
                ", "
                [:bold.italic.blue.underline
                 "bold & italic & colored & underline"]
                ", "
                [:bold.italic.blue.strikethrough
                 "bold & italic & colored & strikethrough"]))


You can also pass a map (instead of a hiccup-style tag) to style the text:

(bling [{:color            :green
         :background-color :black
         :font-style       :italic
         :font-weight      :bold}
        "bold italic green text on black background"])

Note that all the arguments to bling.core/bling must satisfy this predicate:

(every? (fn [x]
          (or (and (vector? x)
                   (= 2 (count x))
                   (-> x
                       (nth 0)
                       (maybe #(or (keyword? %)
                                   (map? %)))))
              (not (coll? x))))
        args)

In other words, every one of the arguments to bling.core/bling must be either:

  • A two-element vector, with the first element being a keyword or map.
  • A value which is not a collection.

If, for example, you wanted to print [1 2 3] in red, you will need to stringify the vector:

(bling [:red (str [1 2 3])])

The Bling pallette

Eleven carefully selected colors, from the xterm range 16-255, are available for use (shown in bold). All of these colors should display consistantly across most consoles on the end-user side. Don't expect all of the colors to pass the strictest APCA contrast criterion, but you can be sure of reasonably visibility on both light and dark backgrounds:

(println (bling [:bold.red "Red"]
                ", "
                [:bold.orange "Orange"]
                ", "
                [:bold.yellow "Yellow"]
                ", "
                [:bold.green "Olive"]
                ", "
                [:bold.green "Green"]
                ", "
                [:bold.blue "Blue"]
                ", "
                [:bold.blue "Purple"]
                ", "
                [:bold.magenta "Magenta"]
                ", "
                [:bold.gray "Gray"]
                ", "
                [:bold.black "Black"]
                ", "
                [:bold.white "White"] ))


Color aliases

You can use the following semantic aliases for some colors (shown in bold):

(println (bling [:bold.negative "Negative"]
                ", "
                [:bold.error "Error"]
                ", "
                [:bold.warning "Warning"]
                ", "
                [:bold.positive "Positive"]
                ", "
                [:bold.info "Info"]
                ", "
                [:bold.subtle "Subtle"]
                ", "
[:bold.neutral "Neutral"]))


Using system colors

Bling also supports named color aliases for system colors (Xterm colors 0-16). Please note that these will not display consistantly across user spaces, as the actual color is dictated by the theme the user has selected in their particular terminal emulator. If your terminal emulator theme is totally dialed-in to your liking and you are using Bling to provide errors, warnings, and messages for code that only you will ever see, then system colors might be preferrable.

(println (bling [:system-black "black (SYSTEM)"]))
(println (bling [:system-maroon "maroon (SYSTEM)"]))
(println (bling [:system-green "green (SYSTEM)"]))
(println (bling [:system-olive "olive (SYSTEM)"]))
(println (bling [:system-navy "navy (SYSTEM)"]))
(println (bling [:system-purple "purple (SYSTEM)"]))
(println (bling [:system-teal "teal (SYSTEM)"]))
(println (bling [:system-silver "silver (SYSTEM)"]))
(println (bling [:system-grey "grey (SYSTEM)"]))
(println (bling [:system-red "red (SYSTEM)"]))
(println (bling [:system-lime "lime (SYSTEM)"]))
(println (bling [:system-yellow "yellow (SYSTEM)"]))
(println (bling [:system-blue "blue (SYSTEM)"]))
(println (bling [:system-fuchsia "fuchsia (SYSTEM)"]))
(println (bling [:system-aqua "aqua (SYSTEM)"]))
(println (bling [:system-white "white (SYSTEM)"]))

Using arbitrary colors

Bling also supports arbitrary colors in the xTerm 0-256 range. If you are using arbitrary colors to construct messages to stdout that other people might have to read, you may want to test the appearance with both light and dark terminal themes. They must be provided as integers, so you will need to use an options map instead of a hiccup-style keyword:

(println (bling [{:color 180} "xTerm color 180, aka Tan"]))


Printing formatted blocks

bling.core/callout will print a message "block" to the console with a colored bounding border in the inline-start position.

(callout {:type :info}
         "Example callout, with :type of :info")

(callout {:type  :info
          :label "My custom label"}
         "Example callout, with :type of :info and custom :label")

(callout {:type :warning}
         "Example callout, with :type of :warning")

(callout {:type :error}
         "Example callout, with :type of :error")

(callout {:type  :positive
          :label "SUCCESS!"}
         "Example callout, with :type of :positive, and custom :label")

(callout {:type :subtle}
         "Example callout, with :type of :subtle (or :gray)")

(callout {:type :magenta}
         "Example callout, with :type of :magenta")

(callout "Example callout, default")

The above calls would render the following in your favorite terminal emulator:

bling.core/callout takes one or two arguments. If two arguments are supplied, the first should be a map with 0 or more of following entries:

KeyPredDescription
:labelany?
Labels the callout. In a terminal emulator context, the value will be cast to a string. In a browser context, the label can be an instance of bling.core/Enriched, or any other value (which will be cast to a string).
In the case of a callout :type of :warning, :error, or :info, the value of the label will default to "WARNING", "ERROR", or "INFO", respectively.

:typekeyword? or string?
Controls the color of the border and label.
Should be one of: :error, :warning , :info , :positive, or :subtle.
Can also be any one of the pallete colors such as :magenta, :green, :negative, :neutral, etc.

:border-weightkeyword? or string?
Controls the weight of the border. Can be one of :medium, :heavy, or :light. Defaults to :light, which renders default border with standard unicode, single-line box-drawing character.

:padding-topint?
Amount of padding (in lines) at top of callout (inside callout block).
Defaults to 0.

:padding-bottomint?
Amount of padding (in lines) at bottom of callout (inside callout block).
Defaults to 0. In browser console, defaults to 1 in the case of callouts of type :warning or :error.

:padding-leftint?
Amount of padding (in lines) at left of callout (inside callout block).
In console emulator, defaults to 1 when :border-weight is :light, and 2 when :border-weight is :medium or :heavy. In browser console, defaults to 0.

:margin-topint?
Amount of margin (in lines) at top of callout (outside callout block).
Defaults to 1. Only applies to terminal emulator printing.

:margin-bottomint?
Amount of margin (in lines) at bottom of callout (outside callout block).
Defaults to 0. Only applies to terminal emulator printing.

:data?boolean?
Returns a data representation of result instead of printing it.



Templates for errors and warnings

bling.core/callout, paired with bling.core/point-of-interest is perfect for creating your own custom error or warning messages.

Here is an example of creating a custom callout for an error message. You must provide the relevant :file, :line, :column, and :form values.

(defn example-custom-callout
  [{:keys [point-of-interest-opts callout-opts]}]
  (let [poi-opts     (merge {:header "Your header message goes here."
                             :body   (str "The body of your message goes here."
                                          "\n"
                                          "Another line of copy."
                                          "\n"
                                          "Another line."
                                          )}
                            point-of-interest-opts)
        message      (point-of-interest poi-opts)
        callout-opts (merge callout-opts
                            {:padding-top 1})]
    (callout callout-opts message)))

(example-custom-callout
 {:point-of-interest-opts {:type   :error
                           :file   "example.ns.core"
                           :line   11
                           :column 1
                           :form   '(+ 1 true)}
  :callout-opts           {:type :error}})

The above callout would render like this your terminal emulator:

bling.core/point-of-interest takes a single map with the following options:

KeyPredDescription
:filestring?
File or namespace

:lineinteger?
Line number

:columninteger?
Column number

:formany?
The form to draw attention to. Will be cast to string and truncated at 33 chars

:typekeyword or string?
Controls the color of the squiggly underline. Should be one of: :error :warning, or :neutral. Defaults to :neutral

:headerany?
Typically, a string composed with newlines as desired. In a browser context, can be an instance of bling.core/Enriched (produced by using bling.core/bling)

:bodyany?
Typically, a string composed with newlines as desired. In a browser context, can be an instance of bling.core/Enriched (produced by using bling.core/bling)

:margin-blockint?
Controls the number of blank lines above and below the diagram.
Defaults to 1.



Go heavy

If you want to place more emphasis on your callouts you can pass bling.core/callout a :border-weight option with a value of :medium or :heavy. Here is an example using the example-custom-callout function we defined above:

(example-custom-callout
 {:file          "example.ns.core"
  :line          11
  :column        1
  :form          '(+ 1 true)
  :type          :error
  :border-weight :heavy})

Example of a value of :medium for :border-weight:

(example-custom-callout
 {:file          "example.ns.core"
  :line          11
  :column        1
  :form          '(+ 1 true)
  :type          :error
  :border-weight :medium})

More callout examples of :heavy for :border-weight:

More callout examples of :medium for :border-weight:


Status / Roadmap

Alpha, subject to change. Issues welcome, see contributing.


Contributing

Issues for bugs, improvements, or features are very welcome. Please file an issue for discussion before starting or issuing a PR.



Can you improve this documentation?Edit on GitHub

cljdoc is a website building & hosting documentation for Clojure/Script libraries

× close