An open API service indexing awesome lists of open source software.

https://github.com/gnl/debux

A trace-based debugging library for Clojure and ClojureScript.
https://github.com/gnl/debux

Last synced: 3 months ago
JSON representation

A trace-based debugging library for Clojure and ClojureScript.

Awesome Lists containing this project

README

          

# Debux
:source-language: clojure
:source-highlighter: coderay
:sectnums:
:imagesdir: ./doc/img
:toc:

*Debux* is a simple but useful library for debugging Clojure and ClojureScript. I wrote
this library to debug my own Clojure(Script) code and to analyze other developer's one.

* Clojars repository: link:https://clojars.org/philoskim/debux[]

## Prerequisites

* clojure 1.8.0 or later
* clojurescript 1.10.238 or later

[[two-libraries]]
## Two libraries

*In development*, use the `philoskim/debux` library. When you use *debux* macros and
functions from this library, it will emit debugging messages to the REPL window or the
Chrome DevTools' console.

*In production*, use the `philoskim/debux-stubs`
(link:https://github.com/philoskim/debux-stubs[]) library. This has the same public API as
`philoskim/debux` but the macros simply expand only to the given original form itself.

With this setup

* *in production*, your use of *debux* macros will have zero run-time and compile-time
cost,

* *in development*, *debux* macros are able to be turned off too via the `set-debug-mode!`
function.

WARNING: Never use `philoskim/debux` library in production because it will impose too much
overhead on the peformance, especially in using `dbgn` and `clogn`, even though
`(set-debug-mode! false)` is run.

## Installation

First, please be sure to read the "Two libraries" section immediately above for background.

To include `debux` in your project for development, simply add the following to your
`project.clj` *development* dependencies:

[source]
....
[philoskim/debux "0.8.3"]
....

and this to your *production* dependencies.

[source]
....
[philoskim/debux-stubs "0.8.3"]
....

## Recent change logs

NOTE: You can see _All change logs since v0.3.0_
https://github.com/philoskim/debux/tree/master/doc/change-logs.adoc[here].

* v0.8.3
** link:https://github.com/hyperfiddle/electric[Electric] support added. See the details
<>.

* v0.8.2
** A bug fixed: pull request link:https://github.com/philoskim/debux/pull/26[#26]

* v0.8.1
** `dbgt` and `clogt` macro bugs fixed.

* v0.8.0
** `dbgt` and `clogt` macros for debugging transducers added. See the details
<>.
** `set-debug-level!` removed. Instead, use `with-level` macro. See the details
<>.

* v0.7.9
** `set-debug-level!` and `:level` option added. See the details <>.
** `set-line-bullet!` added. See the details <>.

* v0.7.8
** `set-cljs-devtools!` added. See the details <>.
** `cljs-devtools` dependency removed. _Debux_ no longer includes `cljs-devtools`
dependency.

* v0.7.5
** `set-source-info-mode!` added. See <> for the details.

* v0.7.3
** `pass:q[some->]` and `pass:q[some->>]` support in `dbg` and `clog` added. See
<> for the details.
** `pass:q[cond->]` and `pass:q[cond->>]` support in `dbg` and `clog` added. See
<> for the details.

* v0.7.1
** The temporal _turn-off_ version of Debux macros added. See <>
for the details.
** The safe debugging in multi-threads now supported. See
<> for the example.

** The `:msg` (or `:m`) option added for dynamic message creation. See <> for the details.

* v0.7.0
** Tagged literals (`#d/dbg`, `#d/dbgn`, `#d/clog`, `#d/clogn`) added. So you don't have
to wrap the form by the parentheses any more, if you want. See <> for the details.

## How to use

In Clojure, the following line should be included in your file.

[source]
....
(use 'debux.core)
....

In ClojureScript, the following `(:require pass:q[...])` line has to be included in your
file.

[source]
.examples/core.cljs
....
(ns examples.core
(:require [debux.cs.core :as d :refer-macros [clog clogn dbg dbgn break
clog_ clogn_ dbg_ dbgn_ break_]]))
....

{empty} +

[cols="^1m,^1m,^1m,^1m,^1m,^1m", options="header"]
.Debugging API use

|===

| | dbg | dbgn | clog | clogn | break

| Clojure REPL | O | O | X | X | X
| ClojureScript REPL | O | O | X | X | X
| ClojureScript Browser console | O | O | O | O | O

|===

* Legend: `O` (supported), `X` (not supported)

//-

. `dbg`/`dbgn` can be used in Clojure REPL.

. `dbg`/`dbgn` can be used in ClojureScript REPL like
link:https://github.com/tomjakubowski/weasel[weasel] or
https://github.com/bhauman/lein-figwheel[figwheel].

** Refer to <> for Browser REPL usage.

. `dbg`/`dbgn` , `clog`/`clogn` and `break` can be used in the browser console window
like Chrome DevTools.
+
TIP: I recommend that you should use `clog`/`clogn` instead of `dbg`/`dbgn` in the browser
console window, because `clog`/`clogn` uses the `console.log` function of browser's
developer tools to style the form. You can see its effect <>.

## `dbg` examples

NOTE: You can see every example source code of this document in
https://github.com/philoskim/debux/tree/master/examples[examples] folder.

### Basic usage

NOTE: The features of `clog` are almost the same as those of `dbg`.

The macro `dbg` prints an original form and pretty-prints the evaluated value on the REPL
window. Then it returns the value without interrupting the code evaluation.

[source]
....
(* 2 (dbg (+ 10 20)))
; => 60
....

[listing]
.REPL output
----
{:ns examples.demo, :line 8}
dbg: (+ 10 20) =>
| 30
----

[#eval-multiple-forms]
Sometimes you need to see multiple forms evaluated. To do so, a literal vector
form can be used like this.

[source]
....
(defn my-fun
[a {:keys [b c d] :or {d 10 b 20 c 30}} [e f g & h]]
(dbg [a b c d e f g h]))

(my-fun (take 5 (range)) {:c 50 :d 100} ["a" "b" "c" "d" "e"])
; => [(0 1 2 3 4) 20 50 100 "a" "b" "c" ("d" "e")]
....

[listing]
.REPL output
----
{:ns examples.demo, :line 11}
dbg: [a b c d e f g h] =>
| [(0 1 2 3 4) 20 50 100 "a" "b" "c" ("d" "e")]
----

[#eval-multiple-forms-with-dbgn]
You can use `dbgn` for better results as well. See the detalis for `dbgn` <>.

[source]
....
(defn my-fun2
[a {:keys [b c d] :or {d 10 b 20 c 30}} [e f g & h]]
(dbgn [a b c d e f g h]))

(my-fun2 (take 5 (range)) {:c 50 :d 100} ["a" "b" "c" "d" "e"])
; => [(0 1 2 3 4) 20 50 100 "a" "b" "c" ("d" "e")]
....

[listing]
.REPL output
----
{:ns examples.demo, :line 15}
dbgn: [a b c d e f g h] =>
| a =>
| (0 1 2 3 4)
| b =>
| 20
| c =>
| 50
| d =>
| 100
| e =>
| "a"
| f =>
| "b"
| g =>
| "c"
| h =>
| ("d" "e")
| [a b c d e f g h] =>
| [(0 1 2 3 4) 20 50 100 "a" "b" "c" ("d" "e")]
----

Generally, `dbg` prints the evaluated result of the outermost form except for the
following eight special cases (`pass:q[->]`, `pass:q[->>]`, `pass:q[some->]`,
`pass:q[some->>]`, `pass:q[cond->]`, `pass:q[cond->>]`, `let`, `comp`).

### Debugging the thread macro `pass:q[->]` or `pass:q[->>]`

#### Using outside the thread macros

When debugging the thread-first macro `pass:q[->]` or thread-last macro `pass:q[->>]`,
`dbg` prints every expression in the thread macros.

This is an example of thread-first macro `pass:q[->]`.

[source]
....
(dbg (-> "a b c d"
.toUpperCase
(.replace "A" "X")
(.split " ")
first))
;=> "X"
....

.REPL output
[listing]
----
{:ns examples.demo, :line 18}
dbg: (-> "a b c d" .toUpperCase (.replace "A" "X") (.split " ") first) =>
| "a b c d" =>
| "a b c d"
| .toUpperCase =>
| "A B C D"
| (.replace "A" "X") =>
| "X B C D"
| (.split " ") =>
| ["X", "B", "C", "D"]
| first =>
| "X"
----

Another example.

[source]
....
(def person
{:name "Mark Volkmann"
:address {:street "644 Glen Summit"
:city "St. Charles"
:state "Missouri"
:zip 63304}
:employer {:name "Object Computing, Inc."
:address {:street "12140 Woodcrest Dr."
:city "Creve Coeur"
:state "Missouri"
:zip 63141}}})

(dbg (-> person :employer :address :city))
; => "Creve Coeur"
....

.REPL output
....
{:ns examples.demo, :line 37}
dbg: (-> person :employer :address :city) =>
| person =>
| {:name "Mark Volkmann",
| :address
| {:street "644 Glen Summit",
| :city "St. Charles",
| :state "Missouri",
| :zip 63304},
| :employer
| {:name "Object Computing, Inc.",
| :address
| {:street "12140 Woodcrest Dr.",
| :city "Creve Coeur",
| :state "Missouri",
| :zip 63141}}}
| :employer =>
| {:name "Object Computing, Inc.",
| :address
| {:street "12140 Woodcrest Dr.",
| :city "Creve Coeur",
| :state "Missouri",
| :zip 63141}}
| :address =>
| {:street "12140 Woodcrest Dr.",
| :city "Creve Coeur",
| :state "Missouri",
| :zip 63141}
| :city =>
| "Creve Coeur"
....

This is an example of thread-last macro `pass:q[->>]`.

[source]
....
(def c 5)

(dbg (->> c (+ 3) (/ 2) (- 1)))
; => 3/4
....

.REPL output
....
{:ns examples.demo, :line 42}
dbg: (->> c (+ 3) (/ 2) (- 1)) =>
| c =>
| 5
| (+ 3) =>
| 8
| (/ 2) =>
| 1/4
| (- 1) =>
| 3/4
....

#### Using inside the thread macros

If you want to debug one of the expressions within the thread macro `pass:q[->]` or
`pass:q[->>]`, don't do it like this.

[source]
....
(-> {:a [1 2]}
(dbg (get :a))
(conj 3))
; => java.lang.IllegalArgumentException
; Don't know how to create ISeq from: java.lang.Long
....

You will have some exception. Instead, do it like this.

[source]
....
(-> {:a [1 2]}
(get :a)
dbg
(conj 3))
; => [1 2 3]
....

.REPL output
....
{:ns examples.demo}
dbg: (get {:a [1 2]} :a) =>
| [1 2]
....

Another example.

[source]
....
(->> [-1 0 1 2]
(filter pos?)
(map inc)
dbg
(map str))
; => ("2" "3")
....

.REPL output
....
{:ns examples.demo}
dbg: (map inc (filter pos? [-1 0 1 2])) =>
| (2 3)
....

NOTE: In the above examples, `dbg` doesn't get the `:line` number information from the
Clojure compiler, so it is omitted. I don't know why the Clojure compiler doesn't
provide the line number informaton through the code of `(:line (meta &form))` inside
the thread macros pass:q[`->`] or pass:q[`->>`] in this situation. If anyone knows
about it, please let me know.

See more examples <>.

[[some-threading-macros]]
### Debugging the thread macro `pass:q[some->]` or `pass:q[some->>]`

The thread macro `pass:q[some->]` and `pass:q[some->>]` are supported in `dbg` and `clog`.

[source]
.Example 1
....
(dbg (some-> {:a 10}
:b
inc))
....

[listing]
.REPL output
----
{:ns examples.lab, :line 54}
dbg: (some-> {:a 10} :b inc) =>
| {:a 10} =>
| {:a 10}
| :b =>
| nil
----

---

[source]
.Example 2
....
(dbg (some->> {:x 5 :y 10}
:y
(- 30)))
....

[listing]
.REPL output
----
{:ns examples.lab, :line 56}
dbg: (some->> {:x 5 :y 10} :y (- 30)) =>
| {:x 5 :y 10} =>
| {:x 5 :y 10}
| :y =>
| 10
| (- 30) =>
| 20
----

[[cond-threading-macros]]
### Debugging the thread macro `pass:q[cond->]` or `pass:q[cond->>]`

The thread macro `pass:q[cond->]` and `pass:q[cond->>]` are supported in `dbg` and `clog`.

[source]
.Example 1
....
(def a 10)

(dbg (cond-> a
(even? a) inc
(= a 20) (* 42)
(= 5 5) (* 3)))
....

[source]
.REPL output
....
{:ns examples.lab, :line 60}
dbg: (cond-> a (even? a) inc (= a 20) (* 42) (= 5 5) (* 3)) =>
| a =>
| 10
| (even? a) =>
| true
| inc =>
| 11
| (= a 20) =>
| false
| (= 5 5) =>
| true
| (* 3) =>
| 33
....

[source]
.Example 2
....
(def b 10)

(dbg (cond->> b
(even? b) inc
(= b 20) (- 42)
(= 2 2) (- 30)))
....

[source]
.REPL output
....
{:ns examples.lab, :line 65}
dbg: (cond->> b (even? b) inc (= b 20) (- 42) (= 5 5) (- 30)) =>
| b =>
| 10
| (even? b) =>
| true
| inc =>
| 11
| (= b 20) =>
| false
| (= 5 5) =>
| true
| (- 30) =>
| 19
....

### Debugging `let` or `comp` form

When debugging `let` form,

[source]
....
(dbg (let [a (take 5 (range))
{:keys [b c d] :or {d 10 b 20 c 30}} {:c 50 :d 100}
[e f g & h] ["a" "b" "c" "d" "e"]]
[a b c d e f g h]))
; => [(0 1 2 3 4) 20 50 100 "a" "b" "c" ("d" "e")]
....

each binding will be printed like this.

.REPL output
....
{:ns examples.demo, :line 58}
dbg: (let [a (take 5 (range)) {:keys [b c d], :or {d 10, b 20, c 30}} {:c 5 ... =>
| a =>
| (0 1 2 3 4)
| {:keys [b c d], :or {d 10, b 20, c 30}} =>
| {:keys [20 50 100], :or {100 10, 20 20, 50 30}}
| [e f g & h] =>
| ["a" "b" "c" & ("d" "e")]
....

When debugging `comp` form,

[source]
....
(def c (dbg (comp inc inc +)))

(c 10 20)
; => 32
....
the result of each function will be printed like this.

.REPL output
....
{:ns examples.demo, :line 64}
dbg: (comp inc inc +) =>
| + =>
| 30
| inc =>
| 31
| inc =>
| 32
....

[[dbgn-examples]]
## `dbgn` examples

NOTE: The features of `clogn` are almost the same as those of `dbgn`.

The macro `dbgn` is for Clojure/CloujureScript REPL and the macro `clogn` is for
ClojureScript browser console only. The appended *n* to these two macro names means
**N**ested forms. You can debug every nested form without interrupting code
evaluations. This feature is very useful, especially when you analyze other developer's
source code.

### Simple example

[source]
....
(dbgn (defn foo [a b & [c]]
(if c
(* a b c)
(* a b 100))))

(foo 2 3)
; => 600

(foo 2 3 10)
; => 60
....

[listing]
.REPL output
----
{:ns examples.demo, :line 72}
dbgn: (defn foo [a b & [c]] (if c (* a b c) (* a b 100))) =>

| c =>
| nil
| a =>
| 2
| b =>
| 3
| (* a b 100) =>
| 600
| (if c (* a b c) (* a b 100)) =>
| 600

| c =>
| 10
| a =>
| 2
| b =>
| 3
| (* a b c) =>
| 60
| (if c (* a b c) (* a b 100)) =>
| 60
----

### Detailed examples

* `dbgn`/`clogn` don't have any problem in handling functions.

* `dbgn`/`clogn`, however, can have some problem in case of macros and special forms.

** Some macros such as `when` don't have any problem when used in `dbgn`/`clogn`.

** Other macros such as `defn` which has a binding vector can have problem because they
have binding symbols which must not be evaluated in `dbgn`/`clogn` macros. In case of
special forms and those macros in `clojure.core` namespace, `degn`/`clogn` can handle
them appropriately.

** In some cases, Clojure developers can write their own macros which `dbgn`/`clogn` cannot
handle appporiately. So I categorized those macros in `clojure.core` namespace as the
following table and you can register your own macros according to the macro types in
the table. I will explain it in <>.

[#macro-type-table, cols="^3m,<7m", options="header"]
.Categorized 19 types of macros in `dbgn`/`clogn`
|===

| Macro types | Macros in `clojure.core` and special forms
| :def-type | def defonce
| :defn-type | defn defn-
| :fn-type | fn fn*
| :let-type | binding dotimes let when-first when-let when-some with-in-str
with-local-vars with-open with-out-str with-redefs
| :if-let-type | if-let if-some
| :letfn-type | letfn
| :loop-type | loop
| :for-type | for doseq
| :case-type | case
| :skip-arg-1-type | set! with-precision
| :skip-arg-2-type | pass:q[as->]
| :skip-arg-1-2-type |
| :skip-arg-1-3-type | defmethod
| :skip-arg-2-3-type | amap areduce
| :skip-arg-1-2-3-type |
| :skip-all-args-type | declare defmacro defmulti defstruct extend extend-protocol
extend-type import memfn new ns proxy proxy-super quote
refer-clojure reify sync var
| :skip-form-itself-type | catch definline definterface defprotocol defrecord deftype finally
| :expand-type | pass:q[.. -> ->> doto cond-> cond->> condp import some-> some->>]
| :dot-type | .

|===

#### `:def-type` example

This type of macros have the first argument which must not be evaluated and can have
optional `doc-string` argument.

[source]
....
(dbgn (def my-function "my-function doc string"
(fn [x] (* x x x))))

(my-function 10)
; => 1000
....

[listing]
.REPL output
----
{:ns examples.demo, :line 85}
dbgn: (def my-function "my-function doc string" (fn [x] (* x x x))) =>
| (fn [x] (* x x x)) =>
| #function[example.core/eval24554/result--24229--auto----24555]
| (def my-function "my-function doc string" (fn [x] (* x x x))) =>
| #'example.core/my-function

| x =>
| 10
| (* x x x) =>
| 1000
----

#### `:defn-type` example

This type of macros have the binding vector argument which must not be evaluated and can
have optional `doc-string`, `attr-map`, or `prepost-map` arguments.

[source]
....
(dbgn (defn add
"add doc string"
[a b]
(+ a b)))

(add 10 20)
; => 30
....

[listing]
.REPL output
----
{:ns examples.demo, :line 92}
dbgn: (defn add "add doc string" [a b] (+ a b)) =>

| a =>
| 10
| b =>
| 20
| (+ a b) =>
| 30
----

{empty} +

You can debug multiple-arity functions as well.

[source]
....
(dbgn (defn my-add
"my-add doc string"
([] 0)
([a] a)
([a b] (+ a b))
([a b & more] (apply + a b more))))

; The function body in this case doesn't have any symbol to evaluate,
; so no output will be printed.
(my-add)
; => 0

(my-add 10)
; => 10

(my-add 10 20)
; => 30

(my-add 10 20 30 40)
; => 100
....

[listing]
.REPL output
----
{:ns examples.demo, :line 100}
dbgn: (defn my-add "my-add doc string" ([] 0) ([a] a) ([a b] (+ a b)) ([a b ... =>

| a =>
| 10

| a =>
| 10
| b =>
| 20
| (+ a b) =>
| 30

| + =>
| #function[clojure.core/+]
| a =>
| 10
| b =>
| 20
| more =>
| (30 40)
| (apply + a b more) =>
| 100
----

{empty} +

You can have multiple `dbgn`/``clogn``s.

[source]
....
(dbgn (defn calc1 [a1 a2] (+ a1 a2)))
(dbgn (defn calc2 [s1 s2] (- 100 (calc1 s1 s2))))
(dbgn (defn calc3 [m1 m2] (* 10 (calc2 m1 m2))))

(calc3 2 5)
; => 760
....

[listing]
.REPL output
----
{:ns examples.demo, :line 113}
dbgn: (defn calc1 [a1 a2] (+ a1 a2)) =>

{:ns examples.demo, :line 114}
dbgn: (defn calc2 [s1 s2] (- 100 (calc1 s1 s2))) =>

{:ns examples.demo, :line 115}
dbgn: (defn calc3 [m1 m2] (* 10 (calc2 m1 m2))) =>

| m1 =>
| 2
| m2 =>
| 5

|| s1 =>
|| 2
|| s2 =>
|| 5

||| a1 =>
||| 2
||| a2 =>
||| 5
||| (+ a1 a2) =>
||| 7
|| (calc1 s1 s2) =>
|| 7
|| (- 100 (calc1 s1 s2)) =>
|| 93
| (calc2 m1 m2) =>
| 93
| (* 10 (calc2 m1 m2)) =>
| 930
----

#### `:fn-type` example

This type of macros have the binding vector argument which must not be evaluated and can
have optional function name. So it is a little different from `:defn-type` macros.

[[enhanced-readability]]
[source]
....
(dbgn (reduce (fn [acc i] (+ acc i)) 0 [1 5 9]))
; => 15
....

[listing]
.REPL output
----
{:ns examples.demo, :line 121}
dbgn: (reduce (fn [acc i] (+ acc i)) 0 [1 5 9]) =>
| (fn [acc i] (+ acc i)) =>
| #function[example.core/eval25034/result--24229--auto----25035]
| [1 5 9] =>
| [1 5 9]

|| acc =>
|| 0
|| i =>
|| 1
|| (+ acc i) =>
|| 1

|| acc =>
|| 1
|| i =>
|| 5
|| (+ acc i) =>
|| 6

|| acc =>
|| 6
|| i =>
|| 9
|| (+ acc i) =>
|| 15
| (reduce (fn [acc i] (clojure.core/binding [debux.common.util/*indent-l ... =>
| 15
----

{empty} +

[source]
.Another example
....
(dbgn (map #(* % 10) [1 5 9]))
; => (10 50 90)
....

[listing]
.REPL output
----
{:ns examples.demo, :line 123}
dbgn: (map (fn* [p1__2514#] (* p1__2514# 10)) [1 5 9]) =>
| (fn* [p1__13193#] (try (clojure.core/reset! (:evals +debux-dbg-opts+) ... =>
| #object[example.dbgn$eval13194$result__4709__auto____13195 0x1b58788a "example.dbgn$eval13194$result__4709__auto____13195@1b58788a"]
| [1 5 9] =>
| [1 5 9]

|| p1__13583# =>
|| 1
|| (* p1__13583# 10) =>
|| 10

|| p1__13583# =>
|| 5
|| (* p1__13583# 10) =>
|| 50

|| p1__13583# =>
|| 9
|| (* p1__13583# 10) =>
|| 90
| (map (fn* [p1__13583#] (clojure.core/binding [debux.common.util/*inden ... =>
| (10 50 90)
----

#### `:let-type` example

This type of macros have the binding vector argument which must not be evaluated.

[source]
....
(dbgn (let [a (+ 1 2)
[b c] [(+ a 10) (* a 2)]]
(- (+ a b) c)))
; => 10
....

[listing]
.REPL output
----
{:ns examples.demo, :line 127}
dbgn: (let [a (+ 1 2) [b c] [(+ a 10) (* a 2)]] (- (+ a b) c)) =>
| (+ 1 2) =>
| 3
| a =>
| 3
| (+ a 10) =>
| 13
| (* a 2) =>
| 6
| [(+ a 10) (* a 2)] =>
| [13 6]

| b =>
| 13
| (+ a b) =>
| 16
| c =>
| 6
| (- (+ a b) c) =>
| 10
| (let [a (+ 1 2) [b c] [(+ a 10) (* a 2)]] (- (+ a b) c)) =>
| 10
----

#### `:if-let-type` example

This type of macros are a little different from `:let-type` macros in that they need only
one or two forms in their bodies.

[source]
....
(def a* 10)

(dbgn (if-let [s a*]
(+ s 100)
false))
; => 110
....

[listing]
.REPL output
----
{:ns examples.demo, :line 135}
dbgn: (if-let [s a*] (+ s 100) false) =>
| a* =>
| 10
| s =>
| 10
| (+ s 100) =>
| 110
| (if-let [s a*] (+ s 100) false) =>
| 110
----

#### `:letfn-type` example

This type of macro has the special binding vector syntax which is a bit different from
`:fn-type`.

[source]
....
(dbgn (letfn [(twice [x]
(* x 2))
(six-times [y]
(* (twice y) 3))]
(six-times 15)))
; => 90
....

[listing]
.REPL output
----
{:ns examples.demo, :line 141}
dbgn: (letfn [(twice [x] (* x 2)) (six-times [y] (* (twice y) 3))] (six-time ... =>
| y =>
| 15
| x =>
| 15
| (* x 2) =>
| 30
| (twice y) =>
| 30
| (* (twice y) 3) =>
| 90
| (six-times 15) =>
| 90
| (letfn [(twice [x] (* x 2)) (six-times [y] (* (twice y) 3))] (six-time ... =>
| 90
----

#### `:loop-type` example

This type of macro is similiar to `:let-type` but has a significant difference because the `recur` has to be placed at the tail positon with the `loop` form. So it needs a special handling in the implementation of `dbgn`/`clogn`. Refer to <> for details.

#### `:for-type` example

This type of macros have a little different syntax from `:let-type` macros, because it
can have `:let`, `:when`, or `:while` clause.

[source]
....
(dbgn (for [x [0 1 2 3 4 5]
:let [y (* x 3)]
:when (even? y)]
y))
; => (0 6 12)
....

[listing]
.REPL output
----
{:ns examples.demo, :line 149}
dbgn: (for [x [0 1 2 3 4 5] :let [y (* x 3)] :when (even? y)] y) =>
| [0 1 2 3 4 5] =>
| [0 1 2 3 4 5]
| x =>
| 0
| (* x 3) =>
| 0
| y =>
| 0
| (even? y) =>
| true

| x =>
| 1
| (* x 3) =>
| 3
| y =>
| 3
| (even? y) =>
| false

| x =>
| 2
| (* x 3) =>
| 6
| y =>
| 6
| (even? y) =>
| true

| x =>
| 3
| (* x 3) =>
| 9
| y =>
| 9
| (even? y) =>
| false

| x =>
| 4
| (* x 3) =>
| 12
| y =>
| 12
| (even? y) =>
| true

| x =>
| 5
| (* x 3) =>
| 15
| y =>
| 15
| (even? y) =>
| false
| (for [x [0 1 2 3 4 5] :let [y (* x 3)] :when (even? y)] (do (debux.com ... =>
| (0 6 12)
----

#### `:case-type` example

This type of macro has the special syntax. Refer to the details
https://clojuredocs.org/clojure.core/case[here].

[source]
....
(dbgn (let [mystr "hello"]
(case mystr
"" 0
"hello" (count mystr))))
; => 5
....

[listing]
.REPL output
----
{:ns examples.demo, :line 156}
dbgn: (let [mystr "hello"] (case mystr "" 0 "hello" (count mystr))) =>
| mystr =>
| "hello"
| (count mystr) =>
| 5
| (case mystr "" 0 "hello" (count mystr)) =>
| 5
| (let [mystr "hello"] (case mystr "" 0 "hello" (count mystr))) =>
| 5
----

{empty} +

[source]
.Another example
....
(dbgn (case 'a
(x y z) "x, y, or z"
"default"))
; => "default"
....

[listing]
.REPL output
----
{:ns examples.demo, :line 161}
dbgn: (case (quote a) (x y z) "x, y, or z" "default") =>
| (case (quote a) (x y z) "x, y, or z" "default") =>
| "default"
----

#### `:skip-arg-1-type` example

This type of macros have the first argument which must not be evaluated. So `dbgn`/`clogn`
internally skips the evaluation of this argument.

[source]
....
(dbgn (with-precision 10 (/ 1M 6)))
; => 0.1666666667M
....

[listing]
.REPL output
----
{:ns examples.demo, :line 167}
dbgn: (with-precision 10 (/ 1M 6)) =>
| (/ 1M 6) =>
| 0.1666666667M
| (with-precision 10 (/ 1M 6)) =>
| 0.1666666667M
----

#### `:skip-arg-2-type` example

This type of macros have the second argument which must not be evaluated. So `dbgn`/`clogn`
internally skips the evaluation of this argument.

[source]
....
(dbgn (as-> 0 n
(inc n)
(inc n)))
; => 2
....

[listing]
.REPL output
----
{:ns examples.demo, :line 171}
dbgn: (as-> 0 n (inc n) (inc n)) =>
| n =>
| 0
| (inc n) =>
| 1
| n =>
| 1
| (inc n) =>
| 2
| (as-> 0 n (inc n) (inc n)) =>
| 2
----

#### `:skip-arg-1-2-type` example

This type of macros have the first and second arguments which must not be evaluated. So
`dbgn`/`clogn` internally skips the evaluation of those arguments. However, I can't find this
type of macros in `clojure.core` namespace but add this type for completeness and the
future possibilities of this type of macros.

#### `:skip-arg-1-3-type` example

This type of macros have the first and third arguments which must not be evaluated. So
`dbgn`/`clogn` internally skips the evaluation of those arguments.

[source]
....
(defmulti greeting
(fn [x] (:language x)))

(dbgn (defmethod greeting :english [map]
(str "English greeting: " (:greeting map))))

(dbgn (defmethod greeting :french [map]
(str "French greeting: " (:greeting map))))

(def english-map {:language :english :greeting "Hello!"})
(def french-map {:language :french :greeting "Bonjour!"})

(greeting english-map)
; => "English greeting: Hello!"

(greeting french-map)
; => "French greeting: Bonjour!"
....

[listing]
.REPL output
----
{:ns examples.demo, :line 180}
dbgn: (defmethod greeting :english [map] (str "English greeting: " (:greetin ... =>
| (defmethod greeting :english [map] (str "English greeting: " (:greetin ... =>
| #object[clojure.lang.MultiFn 0x193bb809 "clojure.lang.MultiFn@193bb809"]

{:ns examples.demo, :line 183}
dbgn: (defmethod greeting :french [map] (str "French greeting: " (:greeting ... =>
| (defmethod greeting :french [map] (str "French greeting: " (:greeting ... =>
| #object[clojure.lang.MultiFn 0x193bb809 "clojure.lang.MultiFn@193bb809"]

| map =>
| {:language :english, :greeting "Hello!"}
| (:greeting map) =>
| "Hello!"
| (str "English greeting: " (:greeting map)) =>
| "English greeting: Hello!"

| map =>
| {:language :french, :greeting "Bonjour!"}
| (:greeting map) =>
| "Bonjour!"
| (str "French greeting: " (:greeting map)) =>
| "French greeting: Bonjour!"
----

#### `:skip-arg-2-3-type` example

This type of macros have the second and third arguments which must not be evaluated. So
`dbgn`/`clogn` internally skips the evaluation of those arguments.

[source]
....
(let [xs (float-array [1 2 3])]
(dbgn (areduce xs i ret (float 0)
(+ ret (aget xs i)))))
; => 6.0
....

[listing]
.REPL output
----
{:ns examples.demo, :line 195}
dbgn: (areduce xs i ret (float 0) (+ ret (aget xs i))) =>
| xs =>
| [1.0, 2.0, 3.0]
| (float 0) =>
| 0.0
| ret =>
| 0.0
| i =>
| 0
| (aget xs i) =>
| 1.0
| (+ ret (aget xs i)) =>
| 1.0
| ret =>
| 1.0
| i =>
| 1
| (aget xs i) =>
| 2.0
| (+ ret (aget xs i)) =>
| 3.0
| ret =>
| 3.0
| i =>
| 2
| (aget xs i) =>
| 3.0
| (+ ret (aget xs i)) =>
| 6.0
| (areduce xs i ret (float 0) (+ ret (aget xs i))) =>
| 6.0
----

#### `:skip-arg-1-2-3-type` example

This type of macros have the first, second and third arguments which must not be evaluated. So
`dbgn`/`clogn` internally skips the evaluation of those arguments. However, I can't find this
type of macros in `clojure.core` namespace but add this type for completeness and the
future possibilities of this type of macros.

#### `:skip-all-args-type` example

This type of macros ignores all the arguments and prints the outermost form and its
result.

[source]
....
(dbgn (defmacro unless [pred a b]
`(if (not ~pred) ~a ~b)))
....

[listing]
.REPL output
----
{:ns examples.demo, :line 200}
dbgn: (defmacro unless [pred a b] (clojure.core/seq (clojure.core/concat (cl ... =>
| (defmacro unless [pred a b] (clojure.core/seq (clojure.core/concat (cl ... =>
| #'user/unless
----

#### `:skip-form-itself-type` example

This type of macros ignores the form itself and prints nothing.

[source]
....
(dbgn (try
(/ 1 0)
(catch ArithmeticException e (str "caught exception: " (.getMessage e)))))
....

[listing]
.REPL output
----
{:ns examples.demo, :line 205}
dbgn: (try (/ 1 0) (catch ArithmeticException e (str "caught exception: " (. ... =>
| (try (/ 1 0) (catch ArithmeticException e (str "caught exception: " (. ... =>
| "caught exception: Divide by zero"
----

NOTE: The evaluated resuts of the `catch` form are not printed in the above example.

#### `:expand-type` example

This type of macros will be expanded and then the output will be printed.

[source]
....
(dbgn (-> "a b c d"
.toUpperCase
(.replace "A" "X")
(.split " ")
first))
; => "X"
....

[listing]
.REPL output
----
{:ns examples.demo, :line 211}
dbgn: (-> "a b c d" .toUpperCase (.replace "A" "X") (.split " ") first) =>
| (.toUpperCase "a b c d") =>
| "A B C D"
| (.replace (.toUpperCase "a b c d") "A" "X") =>
| "X B C D"
| (.split (.replace (.toUpperCase "a b c d") "A" "X") " ") =>
| ["X", "B", "C", "D"]
| (first (.split (.replace (.toUpperCase "a b c d") "A" "X") " ")) =>
| "X"
----

{empty} +

[source]
.Another example
....
(dbgn (.. "fooBAR" toLowerCase (contains "ooba")))
; => true
....

[listing]
.REPL output
----
{:ns examples.demo, :line 217}
dbgn: (.. "fooBAR" toLowerCase (contains "ooba")) =>
| (. "fooBAR" toLowerCase) =>
| "foobar"
| (. (. "fooBAR" toLowerCase) (contains "ooba")) =>
| true
----

{empty} +

[source]
.Yet another example
....
(let [x 1 y 2]
(dbgn (cond-> []
(odd? x) (conj "x is odd")
(zero? (rem y 3)) (conj "y is divisible by 3")
(even? y) (conj "y is even"))))
; => ["x is odd" "y is even"]
....

[listing]
.REPL output
----
{:ns examples.demo, :line 220}
dbgn: (cond-> [] (odd? x) (conj "x is odd") (zero? (rem y 3)) (conj "y is di ... =>
| [] =>
| []
| x =>
| 1
| (odd? x) =>
| true
| G__14051 =>
| []
| (conj G__14051 "x is odd") =>
| ["x is odd"]
| (if (odd? x) (conj G__14051 "x is odd") G__14051) =>
| ["x is odd"]
| y =>
| 2
| (rem y 3) =>
| 2
| (zero? (rem y 3)) =>
| false
| G__14051 =>
| ["x is odd"]
| (if (zero? (rem y 3)) (conj G__14051 "y is divisible by 3") G__14051) =>
| ["x is odd"]

| (even? y) =>
| true
| (conj G__14051 "y is even") =>
| ["x is odd" "y is even"]
| (if (even? y) (conj G__14051 "y is even") G__14051) =>
| ["x is odd" "y is even"]
| (clojure.core/let [G__14051 [] G__14051 (if (odd? x) (conj G__14051 "x ... =>
| ["x is odd" "y is even"]
----

#### `:dot-type` example

[source]
....
(dbgn (. (java.util.Date.) getMonth))
; => 5
....

[listing]
.REPL output
----
{:ns examples.demo, :line 227}
dbgn: (. (java.util.Date.) getMonth) =>
| (java.util.Date.) =>
| #inst "2017-06-27T08:04:46.480-00:00"
| (. (java.util.Date.) getMonth) =>
| 5
----

[#recur-support]
### Limited support for the form including `recur`

[cols="^1m,^1m,^1m", options="header"]
.The forms including `recur`
|===

| | dbgn | clogn
| loop ~ recur | O | O
| defn/defn-/fn ~ recur | △ | △

|===

* Legend: `O` (supported), `△` (limitedly supported)

#### `loop` ~ `recur`

You can see the evaluated results of the form which incldues `loop` ~ `recur` by using
`dbgn` in Clojure and ClojureScript.

[source]
....
(dbgn (loop [acc 1 n 3]
(if (zero? n)
acc
(recur (* acc n) (dec n)))))
; => 6
....

.REPL output
[listing]
----
{:ns examples.demo, :line 233}
dbgn: (loop [acc 1 n 3] (if (zero? n) acc (recur (* acc n) (dec n)))) =>

| n =>
| 3
| (zero? n) =>
| false
| acc =>
| 1
| (* acc n) =>
| 3
| (dec n) =>
| 2

| n =>
| 2
| acc =>
| 3
| (* acc n) =>
| 6
| (dec n) =>
| 1

| n =>
| 1
| acc =>
| 6
| (dec n) =>
| 0

| n =>
| 0
| (zero? n) =>
| true
| (loop [acc 1 n 3] (debux.common.util/insert-blank-line) (if (zero? n) ... =>
| 6
----

{empty} +

[source]
.Another example
....
(dbgn (defn fact [num]
(loop [acc 1 n num]
(if (zero? n)
acc
(recur (* acc n) (dec n))))))

(fact 3)
; => 6
....

[listing]
.REPL output
----
{:ns examples.demo, :line 239}
dbgn: (defn fact [num] (loop [acc 1 n num] (if (zero? n) acc (recur (* acc n ... =>

| num =>
| 3

| n =>
| 3
| (zero? n) =>
| false
| acc =>
| 1
| (* acc n) =>
| 3
| (dec n) =>
| 2

| n =>
| 2
| acc =>
| 3
| (* acc n) =>
| 6
| (dec n) =>
| 1

| n =>
| 1
| acc =>
| 6
| (dec n) =>
| 0

| n =>
| 0
| (zero? n) =>
| true
| (loop [acc 1 n num] (debux.common.util/insert-blank-line) (if (zero? n ... =>
| 6
----

#### `defn`/`defn-`/`fn` ~ `recur` without `loop`

IMPORTANT: If you use `dbgn` in `defn`/`defn-`/`fn` ~ `recur` form without `loop`, you
will have the following exception. I am sorry about it, but this is inevitable due to the
implementation restriction.

[source]
....
(dbgn (defn factorial [acc n]
(if (zero? n)
acc
(recur (* acc n) (dec n)))))
....

.REPL output
[listing]
----
1. Caused by java.lang.UnsupportedOperationException
Cannot recur across try
----

{empty} +

TIP: However, if you *temporarily* replace `recur` with `function name` itself, you can
debug the form as follows. *Be careful* not to forget to recover `function name` itself to
`recur` after debugging.

[source]
....
(dbgn (defn factorial [acc n]
(if (zero? n)
acc
(factorial (* acc n) (dec n)))))

(factorial 1 3)
; => 6
....

.REPL output
[listing]
----
{:ns examples.demo, :line 248}
dbgn: (defn factorial [acc n] (if (zero? n) acc (factorial (* acc n) (dec n) ... =>

| n =>
| 3
| (zero? n) =>
| false
| acc =>
| 1
| (* acc n) =>
| 3
| (dec n) =>
| 2

|| n =>
|| 2
|| (zero? n) =>
|| false
|| acc =>
|| 3
|| (* acc n) =>
|| 6
|| (dec n) =>
|| 1

||| n =>
||| 1
||| (zero? n) =>
||| false
||| acc =>
||| 6
||| (* acc n) =>
||| 6
||| (dec n) =>
||| 0

|||| n =>
|||| 0
|||| (zero? n) =>
|||| true
|||| acc =>
|||| 6
|||| (if (zero? n) acc (factorial (* acc n) (dec n))) =>
|||| 6
||| (factorial (* acc n) (dec n)) =>
||| 6
----

[#register-macros]
### How to register your own macros in using `dbgn`/`clogn`

* If you have some error when analyzing some source code using `dbgn`/`clogn`, first
of all, you have to figure out what type of macro (refer to <>) caused
the error and then register the macro by using `register-macros!`.

* You can see the registered macros by using `show-macros`.

[source]
.API format
....
(register-macros! macro-type macros)

(show-macros)
(show-macros macro-type)
....

#### Clojure example

[source]
.example/core.clj
....
(defmacro my-let [bindings & body]
`(let ~bindings ~@body))

;; Registering your own macro
(register-macros! :let-type [my-let])

(dbg (show-macros :let-type))
(dbg (show-macros))

(dbgn (my-let [a 10 b (+ a 10)] (+ a b)))
....

[listing]
.REPL output
----
{:ns examples.demo, :line 261}
dbg: (show-macros :let-type) =>
| {:let-type
| #{clojure.core/when-let example.dbgn/my-let clojure.core/let
| clojure.core/with-local-vars clojure.core/when-some clojure.core/dotimes
| clojure.core/with-open clojure.core/with-redefs clojure.core/binding
| clojure.core/with-in-str clojure.core/with-out-str clojure.core/when-first}}

{:ns examples.demo, :line 262}
dbg: (show-macros) =>
| {:fn-type #{clojure.core/fn fn*},
| :skip-arg-1-2-3-type #{},
| :skip-form-itself-type
| #{clojure.core/definterface clojure.core/defrecord clojure.core/deftype
| finally clojure.core/gen-class clojure.core/definline catch
| clojure.core/gen-interface clojure.core/defprotocol},
| :case-type #{clojure.core/case},
| :skip-arg-2-3-type #{clojure.core/areduce clojure.core/amap},
| :skip-arg-1-type #{clojure.core/with-precision set!},
| :let-type
| #{clojure.core/when-let example.dbgn/my-let clojure.core/let
| clojure.core/with-local-vars clojure.core/when-some
| clojure.core/dotimes clojure.core/with-open clojure.core/with-redefs
| clojure.core/binding clojure.core/with-in-str
| clojure.core/with-out-str clojure.core/when-first},
| :skip-arg-2-type #{clojure.core/as->},
| :defn-type #{clojure.core/defn clojure.core/defn-},
| :loop-type #{clojure.core.async/go-loop clojure.core/loop},
| :for-type #{clojure.core/for clojure.core/doseq},
| :def-type #{clojure.core/defonce def},
| :if-let-type #{clojure.core/if-let clojure.core/if-some},
| :letfn-type #{clojure.core/letfn},
| :dot-type #{.},
| :skip-arg-1-2-type #{},
| :skip-all-args-type
| #{clojure.core/proxy-super clojure.core/defmacro clojure.core/sync
| clojure.core/declare clojure.core/refer-clojure clojure.core/memfn
| clojure.core/extend-type new clojure.core/defstruct
| clojure.core/defmulti clojure.core/ns clojure.core/proxy
| clojure.core/extend clojure.core/extend-protocol var quote
| clojure.core/reify clojure.core/import},
| :expand-type
| #{clojure.core/doto clojure.core/->> clojure.core/some->>
| clojure.core/.. clojure.core/-> clojure.core/some->
| clojure.core/cond-> clojure.core/condp clojure.core/import
| clojure.core/cond->>},
| :skip-arg-1-3-type #{clojure.core/defmethod}}

{:ns examples.demo, :line 264}
dbgn: (my-let [a 10 b (+ a 10)] (+ a b)) =>
| a =>
| 10
| (+ a 10) =>
| 20

| b =>
| 20
| (+ a b) =>
| 30
| (my-let [a 10 b (+ a 10)] (debux.common.util/insert-blank-line) (+ a b ... =>
| 30
----

#### ClojureScript example

[source]
.example/macro.clj
....
(ns example.macro)

(defmacro my-let [bindings & body]
`(let ~bindings ~@body))
....

[source]
.example/core.cljs
....
(ns examples.demo
(:require [debux.cs.core :as d :refer-macros [clog clogn dbg dbgn break]])
(:require-macros [examples.macro :refer [my-let]]))

;; Registering your own macro
(d/register-macros! :let-type [my-let])

(dbg (d/show-macros :let-type))
(dbg (d/show-macros))

(clogn (my-let [a 10 b (+ a 10)] (+ a b)))
....

[listing]
.Output
----
{:ns examples.demo, :line 261}
dbg: (d/show-macros :let-type) =>
| {:let-type
| #{example.macro/my-let cljs.core/with-redefs cljs.core/binding
| cljs.core/when-first cljs.core/let cljs.core/with-out-str
| cljs.core/when-let cljs.core/when-some cljs.core/dotimes}}

{:ns examples.demo, :line 262}
dbg: (d/show-macros) =>
| {:fn-type #{fn* cljs.core/fn},
| :skip-arg-1-2-3-type #{},
| :skip-form-itself-type
| #{finally cljs.core/defprotocol cljs.core/defrecord cljs.core/deftype
| cljs.core/js-comment cljs.core/js-inline-comment catch},
| :case-type #{cljs.core/case},
| :skip-arg-2-3-type #{cljs.core/amap cljs.core/areduce},
| :skip-arg-1-type #{set! cljs.core/this-as},
| :let-type
| #{example.macro/my-let cljs.core/with-redefs cljs.core/binding
| cljs.core/when-first cljs.core/let cljs.core/with-out-str
| cljs.core/when-let cljs.core/when-some cljs.core/dotimes},
| :skip-arg-2-type #{cljs.core/as->},
| :defn-type #{cljs.core/defn- cljs.core/defn},
| :loop-type #{cljs.core/loop},
| :for-type #{cljs.core/doseq cljs.core/for},
| :def-type #{cljs.core/defonce def},
| :if-let-type #{cljs.core/if-some cljs.core/if-let},
| :letfn-type #{cljs.core/letfn},
| :dot-type #{.},
| :skip-arg-1-2-type #{},
| :skip-all-args-type
| #{cljs.core/simple-benchmark cljs.core/defmulti cljs.core/specify!
| cljs.core/goog-define cljs.core/import-macros cljs.core/specify
| cljs.core/use cljs.core/use-macros cljs.core/extend-protocol new
| cljs.core/import cljs.core/declare cljs.core/reify cljs.core/require
| cljs.core/comment cljs.core/memfn cljs.core/require-macros var
| quote cljs.core/refer-clojure cljs.core/extend-type cljs.core/defmacro},
| :expand-type
| #{cljs.core/.. cljs.core/some-> cljs.core/-> cljs.core/cond->>
| cljs.core/import cljs.core/doto cljs.core/condp cljs.core/cond->
| cljs.core/some->> cljs.core/->>},
| :skip-arg-1-3-type #{cljs.core/defmethod}}
----

image::register-macros.png[title="register-macros! example", width=750]

[#multiple-use]
## Multiple use of `dbg` and `dbgn`

NOTE: This feature applies to the multiple use of `clog` and `clogn` as well.

### `dbg` inside `dbgn` or vice versa

`dbg` can be used inside `dbgn` or vice versa. For example, if you want to see the printed
results of pass:q[`->`], pass:q[`->>`], `let` or `comp` of `dbg` in more compact way than
only using `dbgn`, do it like this.

[source]
....
(defn my-fun [a b c]
(dbgn (+ a b c
(dbg (->> (range (- b a))
(map #(* % %))
(filter even?)
(take a)
(reduce +))))))

(my-fun 10 20 100)
; => 250
....

[listing]
.REPL output:
----
{:ns examples.demo, :line 271}
dbgn: (+ a b c (->> (range (- b a)) (map (fn* [p1__3949#] (* p1__3949# ... =>
| a =>
| 10
| b =>
| 20
| c =>
| 100

|{:ns examples.demo, :line 272}
|dbg: (->> (range (- b a)) (map (fn* [p1__41#] (* p1__41# p1__41#))) (filter ... =>
|| (range (- b a)) =>
|| (0 1 2 3 4 5 6 7 8 9)
|| (map (fn* [p1__41#] (* p1__41# p1__41#))) =>
|| (0 1 4 9 16 25 36 49 64 81)
|| (filter even?) =>
|| (0 4 16 36 64)
|| (take a) =>
|| (0 4 16 36 64)
|| (reduce +) =>
|| 120
| (+ a b c (->> (range (- b a)) (map (fn* [p1__41#] (* p1__41# p1__ ... =>
| 250
----

In other words, `dbg` can be used selectively inside `dbgn` like this, if you want to
avoid printing a deeply nested structure inside `dbgn`.

[source]
....
(let [a 10 b 9 c 8 d 7 e 6 f 5 g 4 h 3]
(dbgn (* a b (dbg (+ c d (- e f (* g h)))))))
; => 360
....

The above `dbg` will prevent `dbgn` from printing `(+ c d (- e f (* g h))))` recursively.

[listing]
.REPL output
----
{:ns example.demo, :line 15}
dbgn: (* a b (+ c d (- e f (* g h)))) =>
| a =>
| 10
| b =>
| 9

|{:ns example.demo, :line 15}
|dbg: (+ c d (- e f (* g h))) =>
|| 4
| (* a b (dbg (+ c d (- e f (* g h))))) =>
| 360
----

### Multiple `dbgn` and `dbg`

You can use multiple `dbgn` or `dbg`.

[source]
.Example 1
....
(def n 10)

(defn add [a b]
(dbgn (+ a b)))

(defn mul [a b]
(dbgn (* a b)))

(dbgn (+ n (mul 3 4) (add 10 20)))
; => 52
....

[listing]
.REPL output
----
{:ns examples.demo, :line 290}
dbgn: (+ n (mul 3 4) (add 10 20)) =>
| n =>
| 10

|{:ns examples.demo, :line 288}
|dbgn: (* a b) =>
|| a =>
|| 3
|| b =>
|| 4
|| (* a b) =>
|| 12
| (mul 3 4) =>
| 12

|{:ns examples.demo, :line 285}
|dbgn: (+ a b) =>
|| a =>
|| 10
|| b =>
|| 20
|| (+ a b) =>
|| 30
| (add 10 20) =>
| 30
| (+ n (mul 3 4) (add 10 20)) =>
| 52
----

{empty} +

[source]
.Example 2
....
(def n 10)

(defn add2 [a b]
(dbg (+ a b)))

(defn mul2 [a b]
(dbg (* a b)))

(dbgn (+ n (mul2 3 4) (add2 10 20)))
; => 52
....

[listing]
.REPL output
----
{:ns examples.demo, :line 299}
dbgn: (+ n (mul2 3 4) (add2 10 20)) =>
| n =>
| 10

|{:ns examples.demo, :line 297}
|dbg: (* a b) =>
|| 12
| (mul2 3 4) =>
| 12

|{:ns examples.demo, :line 294}
|dbg: (+ a b) =>
|| 30
| (add2 10 20) =>
| 30
| (+ n (mul2 3 4) (add2 10 20)) =>
| 52
----

[[safe-debugging-in-multi-threads]]
### Safe debugging in multi-threads programming.

The Debux macros `dbg`, `dbgn`, `dbg-last` in Clojure support the safe debugging in
multi-threads since the version 0.7.1.

The following example shows that the messages produced by the `dbg` are printed in their
own separate units, not mixed by one another.

[source]
....
(defn my-fn [thread-no]
(dbg (-> "a b c d"
.toUpperCase
(.replace "A" "X")
(.split " ")
first)
:msg (str "thread-no: " thread-no)))

(future
(Thread/sleep 1000)
(my-fn 1))

(future
(Thread/sleep 1000)
(my-fn 2))

(future
(Thread/sleep 1000)
(my-fn 3))

(dbg (* 2 5))

(shutdown-agents)
....

[listing]
.REPL output
----
{:ns examples.lab, :line 45}
dbg: (* 2 5) =>
| 10

{:ns examples.lab, :line 26}
dbg: (-> "a b c d" .toUpperCase (.replace "A" "X") (.split " ") first) =>
| "a b c d" =>
| "a b c d"
| .toUpperCase =>
| "A B C D"
| (.replace "A" "X") =>
| "X B C D"
| (.split " ") =>
| ["X", "B", "C", "D"]
| first =>
| "X"

{:ns examples.lab, :line 26}
dbg: (-> "a b c d" .toUpperCase (.replace "A" "X") (.split " ") first) =>
| "a b c d" =>
| "a b c d"
| .toUpperCase =>
| "A B C D"
| (.replace "A" "X") =>
| "X B C D"
| (.split " ") =>
| ["X", "B", "C", "D"]
| first =>
| "X"

{:ns examples.lab, :line 26}
dbg: (-> "a b c d" .toUpperCase (.replace "A" "X") (.split " ") first) =>
| "a b c d" =>
| "a b c d"
| .toUpperCase =>
| "A B C D"
| (.replace "A" "X") =>
| "X B C D"
| (.split " ") =>
| ["X", "B", "C", "D"]
| first =>
| "X"
----

[[dbgt]]
## `dbgt` examples

NOTE: The features of `clogt` are almost the same as those of `dbgt`.

`dbgt` and `clogt` macros are for debugging transducers.

Special thanks to
link:https://github.com/green-coder/transducer-exercises/blob/master/solution/debug.clj[Vincent
Cantin] for the idea and inspiration for my writing these macros.

### Debugging a single transducer

[source]
.Example
....
(transduce (dbgt (filter odd?))
conj (range 5))
....

[listing]
.REPL output
----
{:ns examples.lab, :line 5}
dbgt: (filter odd?)
|> 0
|< []

|> 1
|< [1]

|> 2
|< [1]

|> 3
|< [1 3]

|> 4
|< [1 3]
----

### Debugging composed transducers

[source]
.Example
....
(transduce (dbgt (comp (map inc) (filter odd?)))
conj (range 5))
....

[listing]
.REPL output
----
{:ns examples.lab, :line 8}
dbgt: (comp (map inc) (filter odd?))
|> 0
||> 1
||< [1]
|< [1]

|> 1
||> 2
||< [1]
|< [1]

|> 2
||> 3
||< [1 3]
|< [1 3]

|> 3
||> 4
||< [1 3]
|< [1 3]

|> 4
||> 5
||< [1 3 5]
|< [1 3 5]
----

## Various options

* The various options can be added and combined in any order after the form.

[cols="^1m,^1m,^1m,^1m,^1m,^1m,^1m,^1m", options="header"]
.*debux* macro options
|===

| Optio ns | dbg | dbgn | clog | clogn | dbgt | clogt | break

| string | O | O | O | O | O | O | O
| :msg or :m | O | O | O | O | O | O | X
| number | O | O | O | O | O | O | X
| :if | O | O | O | O | O | O | O
| :locals or :l | O | O | O | O | O | O | X
| :print or :p | O | X | O | X | X | X | X
| :dup | X | 0 | X | 0 | X | X | X
| :level | O | O | O | O | O | O | X
| :style or :s | X | X | O | O | X | O | X
| :once or :o | X | X | O | X | X | X | X
| :js | X | X | O | O | X | X | X

|===

* Legend: `O` (supported), `X` (not supported)

### String option

You can add your own message in a string and it will be printed between less-than and
more-than signs like this.

[source]
....
(dbg (repeat 5 "x") "5 times repeat"))
; => ("x" "x" "x" "x" "x")
....

.REPL output
....
{:ns examples.demo, :line 305}
dbg: (repeat 5 "x") <5 times repeat> =>
| ("x" "x" "x" "x" "x")
....

[[msg-option]]
### `:msg (or :m)` option

Sometimes you need to create the message dynamically. This option can be useful in the
multi-threads programming like this.

[source]
....

(defn my-fn2 [thread-no]
(dbg (* thread-no (+ 10 20)) :msg (str "thread-no: " thread-no)))

(future
(Thread/sleep 3000)
(my-fn2 1))

(future
(Thread/sleep 1000)
(my-fn2 2))

(future
(Thread/sleep 2000)
(my-fn2 3))

(dbg (* 10 5))

(shutdown-agents)
....

[listing]
.REPL output
----
{:ns examples.lab, :line 20}
dbg: (* 10 5) =>
| 50

{:ns examples.lab, :line 6}
dbg: (* thread-no (+ 10 20)) =>
| 60

{:ns examples.lab, :line 6}
dbg: (* thread-no (+ 10 20)) =>
| 90

{:ns examples.lab, :line 6}
dbg: (* thread-no (+ 10 20)) =>
| 30
----

If the above `String` option and this `:msg` option both exist, the `:msg` option has the
higher precedence.

[[number-option]]
### Number option

If you don't specify a number after the form returning the `coll` data type, *debux*
macros will print the default 100 items.

[source]
....
(dbgn (count (range 200)))
; => 200
....

.REPL output
[listing]
----
{:ns examples.demo, :line 309}
dbgn: (count (range 200)) =>
| (range 200) =>
| (0 1 2 ...... 99 ...)
| (count (range 200)) =>
| 200
----

So, if you want to print less or more than default 100 items, specify the number
explicitly like this.

....
(dbgn (count (range 200)) 200)
; => 200
....

.REPL output
[listing]
----
{:ns examples.demo, :line 311}
dbgn: (count (range 200)) =>
| (range 200) =>
| (0 1 2 ...... 199)
| (count (range 200)) =>
| 200
----

The same rule applies to the case of evaluating an *infinite lazy-seq*. If you omit the
number in evaluating an *infinite lazy-seq*, in the same manner it will print default 100
elements to prevent `OutOfMemoryError`.

[source]
....
(dbgn (take 5 (range)))
; => (0 1 2 3 4)
....

.REPL output
....
{:ns examples.demo, :line 313}
dbgn: (take 5 (range)) =>
| (range) =>
| (0 1 2 ...... 99 ...)
| (take 5 (range)) =>
| (0 1 2 3 4)
....

[[nested-coll]]
The elements of the nested `coll` types will be printed as much as specified numbers.

[source]
....
(def m
{:list (range)
:vector (vec (range 100))
:map (zipmap (range 100) (cycle [:a :b :c]))
:set (set (range 100))})

(dbgn (count m) 5)
; => 4
....

[listing]
.REPL output
----
{:ns examples.demo, :line 328}
dbgn: (count m) =>
| m =>
| {:list (0 1 2 3 4 ...),
| :vector [0 1 2 3 4 ...],
| :map {0 :a, 65 :c, 70 :b, 62 :c, 74 :c, ...},
| :set #{0 65 70 62 74 ...}}
| (count m) =>
| 4
----

NOTE: The Clojure source codes are the Clojure data structures as well, which is known as
_homoiconcity_. When the debux macros traverse the Clojure source code trees, they
enter the lists or vectors within the trees but don't enter the maps or sets within
the trees. So the codes themselves within the above map `m` aren't printed in the
middle of the evaluated results, because they are wrapped inside the map `m`.

[[set-print-length]]
If you want to change the default number globally, use `set-print-length!` function
like this.

[source]
....
;; in Clojure
(set-print-length! 10)

(dbgn (take 5 (range)))
; => (0 1 2 3 4)
....

[listing]
.REPL output
----
{:ns examples.demo, :line 318}
dbgn: (take 5 (range)) =>
| (range) =>
| (0 1 2 3 4 5 6 7 8 9 ...)
| (take 5 (range)) =>
| (0 1 2 3 4)
----

[source]
....
;; in ClojureScript
(ns example.core
(:require [debux.cs.core :as d :refer-macros [clog clogn dbg dbgn break]]))

(d/set-print-length! 10)

(clogn (take 5 (range)))
....

### `:if` option

You can set `:if` option like this.

[source]
....
(doseq [i (range 10)]
(dbg i :if (even? i)))
; => (0 1 2 3 4 5 6 7 8 9)
....

.REPL output
....
{:ns examples.demo, :line 333}
dbg: i =>
| 0

{:ns examples.demo, :line 333}
dbg: i =>
| 2

{:ns examples.demo, :line 333}
dbg: i =>
| 4

{:ns examples.demo, :line 333}
dbg: i =>
| 6

{:ns examples.demo, :line 333}
dbg: i =>
| 8
....

[[local-option]]
### `:locals` (or `:l`) option

The `:locals` option is added, according to the request
link:https://github.com/philoskim/debux/issues/19[#issue 19].

[source]
....
(let [x 10 y 20]
(dbg (+ x y) :locals)
(dbg (-> 100 inc inc) :l)

(dbgn (-> 200 inc inc) :l))
....

[source]
.REPL output
....
{:ns examples.lab, :line 11}
dbg: (+ x y) =>
| :locals =>
| {x 10, y 20}

| 30

{:ns examples.lab, :line 12}
dbg: (-> 100 inc inc) =>
| :locals =>
| {x 10, y 20}

| 100 =>
| 100
| inc =>
| 101
| inc =>
| 102

{:ns examples.lab, :line 14}
dbgn: (-> 200 inc inc) =>
| :locals =>
| {x 10, y 20}

| (inc 200) =>
| 201
| (inc (inc 200)) =>
| 202
....

[[print-option]]
### `:print` (or `:p`) option

IMPORTANT: The `:print` (or `:p` in brief) option applies only to `dbg`/`clog`.

If you don't want to see the evaluated result itself but the result applied to another
operations, use '`:print one-arg-fn`' (or '`:p one-arg-fn`') option like this.

[source]
....
(+ 10 (dbg (* 20 30) :print #(type %)))
; => 610

;; equivalent to the above
(+ 10 (dbg (* 20 30) :print type))
; => 610
....

[listing]
.REPL output
----
{:ns examples.demo, :line 337}
dbg: (* 20 30) =>
| java.lang.Long
----

The above example prints `java.lang.Long`, not `600`

[source]
....
(def person
{:name "Mark Volkmann"
:address {:street "644 Glen Summit"
:city "St. Charles"
:state "Missouri"
:zip 63304}
:employer {:name "Object Computing, Inc."
:address {:street "12140 Woodcrest Dr."
:city "Creve Coeur"
:state "Missouri"
:zip 63141}}})

(dbg person :p #(get-in % [:employer :address :city]))
....

[listing]
.REPL output
----
{:ns examples.demo, :line 339}
dbg: person =>
| "Creve Coeur"
----

The above example prints the most inner `:city` part, not `person` itself.

[#dup-option]
### `:dup` option

The same duplicate evaluated results are not printed by default as follows.

[source]
....
(dbgn (def my-function "my-function doc string"
(fn [x] (* x x x))))

(my-function 10)
; => 1000
....

[listing]
.REPL output
----
{:ns examples.demo, :line 343}
dbgn: (def my-function "my-function doc string" (fn [x] (* x x x))) =>
| (fn [x] (* x x x)) =>
| #function[example.core/eval24554/result--24229--auto----24555]
| (def my-function "my-function doc string" (fn [x] (* x x x))) =>
| #'example.core/my-function

| x =>
| 10
| (* x x x) =>
| 1000
----

However, you can print the same duplicate evaluated values by `:dup` option.

[source]
....
(dbgn (def my-function "my-function doc string"
(fn [x] (* x x x))) :dup)

(my-function 10)
; => 1000
....

[listing]
.REPL output
----
{:ns examples.demo, :line 349}
dbgn: (def my-function "my-function doc string" (fn [x] (* x x x))) =>
| (fn [x] (* x x x)) =>
| #function[example.core/eval24554/result--24229--auto----24555]
| (def my-function "my-function doc string" (fn [x] (* x x x))) =>
| #'example.core/my-function

| x =>
| 10
| x =>
| 10
| x =>
| 10
| (* x x x) =>
| 1000
----

You will sometimes need to print every duplicate evaluated value to see exactly what's
going on.

Compare the results of the next two examples.

[source]
....
(dbgn (loop [acc 1 n 3]
(if (zero? n)
acc
(recur (* acc n) (dec n)))))
; => 6

(dbgn (loop [acc 1 n 3]
(if (zero? n)
acc
(recur (* acc n) (dec n)))) :dup)
; => 6
....

[listing]
.REPL output
----
{:ns examples.demo, :line 355}
dbgn: (loop [acc 1 n 3] (if (zero? n) acc (recur (* acc n) (dec n)))) =>

| n =>
| 3
| (zero? n) =>
| false
| acc =>
| 1
| (* acc n) =>
| 3
| (dec n) =>
| 2

| n =>
| 2
| acc =>
| 3
| (* acc n) =>
| 6
| (dec n) =>
| 1

| n =>
| 1
| acc =>
| 6
| (dec n) =>
| 0

| n =>
| 0
| (zero? n) =>
| true
| (loop [acc 1 n 3] (debux.common.util/insert-blank-line) (if (zero? n) ... =>
| 6

{:ns examples.demo, :line 360}
dbgn: (loop [acc 1 n 3] (if (zero? n) acc (recur (* acc n) (dec n)))) =>

| n =>
| 3
| (zero? n) =>
| false
| acc =>
| 1
| n =>
| 3
| (* acc n) =>
| 3
| n =>
| 3
| (dec n) =>
| 2

| n =>
| 2
| (zero? n) =>
| false
| acc =>
| 3
| n =>
| 2
| (* acc n) =>
| 6
| n =>
| 2
| (dec n) =>
| 1

| n =>
| 1
| (zero? n) =>
| false
| acc =>
| 6
| n =>
| 1
| (* acc n) =>
| 6
| n =>
| 1
| (dec n) =>
| 0

| n =>
| 0
| (zero? n) =>
| true
| acc =>
| 6
| (loop [acc 1 n 3] (debux.common.util/insert-blank-line) (if (zero? n) ... =>
| 6
----

[[with-level]]
### `:level` option

You can set the debug level by using `with-level` macro and specify `:level` option as
follows. You can specify the debug levels with any positive numbers including the floating
point numbers. The `with-level` macro uses a dynamic var of Clojure internally, so you can
nest `with-level` macros to whatever level you want.

[source]
.Example 1
....
;; The default debug level is 0.
(dbg (+ 10 20))
(dbg (+ 10 20 3) :level 3)
(dbg (+ 10 20 5) :level 5)
....

[listing]
.REPL output
----
{:ns examples.lab, :line 18}
dbg: (+ 10 20) =>
| 30

{:ns examples.lab, :line 19}
dbg: (+ 10 20 3) =>
| 33

{:ns examples.lab, :line 20}
dbg: (+ 10 20 5) =>
| 35
----

[source]
.Example 2
....
(with-level 3
(dbg (+ 10 20))
(dbg (+ 10 20 3) :level 3)
(dbg (+ 10 20 5) :level 5))
....

[listing]
.REPL output
----
{:ns examples.lab, :line 12}
dbg: (+ 10 20 3) =>
| 33

{:ns examples.lab, :line 13}
dbg: (+ 10 20 5) =>
| 35
----

[source]
.Example 3
....
(defn my-add [a b]
(dbg (+ a b) :level 2))

(defn my-sub [a b]
(dbg (- a b) :level 3))

(with-level 3
(dbg (my-add 10 20))
(dbg (my-sub 100 10))

(with-level 0
(dbg (* 10 2))))
....

[listing]
.REPL output
----
{:ns examples.lab, :line 20}
dbg: (- a b) =>
| 90

{:ns examples.lab, :line 27}
dbg: (* 10 2) =>
| 20
----

[[style-option]]
### `:style` (or `:s`) option (CSS Styling: CLJS only)

The following is the example of using `clog` and `clogn` in Chrome browser.

[source]
.example/core.cljs
....
(ns example.core
(:require [debux.cs.core :as d :refer-macros [clog clogn dbg dbgn break]]))

(clog (repeat 5 "x") "5 times repeat")
(clogn (repeat 5 (repeat 5 "x")) "25 times repeat")
....

image::clog.png[title="clog and clogn example", width=650]

#### Predefined style keywords

You can style the form, using the following predefined keywords.

[cols="^,^", options="header", width="30"]
|===

| keyword | abbreviation
| :style | :s
| :error | :e
| :warn | :w
| :info | :i
| :debug | :d

|===

....
(clog (+ 10 20) :style :error "error style")
(clog (+ 10 20) :style :warn "warn style")
(clog (+ 10 20) :style :info "info style")
(clog (+ 10 20) :style :debug "debug style")
(clog (+ 10 20) "debug style is default")
....

Or in brief

....
(clog (+ 10 20) :s :e "error style")
(clog (+ 10 20) :s :w "warn style")
(clog (+ 10 20) :s :i "info style")
(clog (+ 10 20) :s :d "debug style")
(clog (+ 10 20) "debug style is default")
....

image::clog-style.png[title="Predefined style example", width=700]

#### User-defined style

You can redefine the predefined styles or define your own new style by using
`merge-styles` like this.

[source]
....
(d/merge-styles {:warn "background: #9400D3; color: white"
:love "background: #FF1493; color: white"})

(clog (+ 10 20) :style :warn "warn style changed")
(clog (+ 10 20) :style :love "love style")

;; You can style the form directly in string format in any way you want.
(clog (+ 10 20) :style "color:orange; background:blue; font-size: 14pt")
....

image::clog-style-user.png[title="User-defined style example", width=650]

### `:once` (or `:o`) option (CLJS only)

If you add `:once` (or `:o` in brief) option after the form, the same evaluated value will
not be printed. This is a very useful feature, when you are debugging a game programming,
where successive multiple frames usually have the same evaluated value.

[source]
....
(def a (atom 10))

; This will be printed.
(clog @a :once)

; This will not be printed,
; because the evaluated value is the same as before.
(clog @a :once)

(reset! a 20)

; This will be printed,
; because the evaluated value is not the same as before.
(clog @a :once)

; This will not be printed,
; because the evaluated value is the same as before.
(clog @a :once)
....

image::clog-once.png[title=":once option example", width=700]

NOTE: `(:once mode)` string is appended after the form header to remind you of `:once`
mode.

### `:js` option (CLJS only)

If `:js` option is added after the form, the JavaScript object will be printed as well, so
you can inspect the internal structures of ClojureScript data types or the JavaScript
objects returned by JavaScript interops in ClojureScript.

....
(clog {:a 10 :b 20} :js)
....

image::clog-js.png[title=":js option example", width=800]

[[tagged-literals]]
## Tagged literals: `#d/dbg`, `#d/dbgn`, `#d/dbgt`,`#d/clog`, `#d/clogn`, `#d/clogt`

If you don't use the above options at all, you can use the tagged literals: `#d/dbg`, `#d/dbgn`, `#d/dbgt`,`#d/clog`, `#d/clogn`, `#d/clogt`. They behave exactly in the same way as their
counterparts `dbg`, `dbgn`, `clog`, `clogn`. So in the _no options_ case, you don't have
to wrap the form by the parentheses any more, if you want.

[source]
.Example 1
....
#d/dbg (+ 1 2 #d/dbg (* 3 4))
....

[source]
.REPL output
....
{:ns examples.lab, :line 5}
dbg: (+ 1 2 (* 3 4)) =>

|{:ns examples.lab, :line 5}
|dbg: (* 3 4) =>
|| 12
| 15
....

---

[source]
.Example 2
....
#d/dbgn (+ (* 2 5) #d/dbg (+ 10 (* 3 4)))
....

[source]
.REPL output
....
{:ns examples.lab, :line 7}
dbgn: (+ (* 2 5) (+ 10 (* 3 4))) =>
| (* 2 5) =>
| 10

|{:ns examples.lab, :line 7}
|dbg: (+ 10 (* 3 4)) =>
|| 22
| (+ (* 2 5) (+ 10 (* 3 4))) =>
| 32
....

---

[source]
.Example 3
....
#d/dbg (+ (* 2 5) #d/dbgn (+ 10 (* 3 4)))
....

[source]
.REPL output
....
{:ns examples.lab, :line 9}
dbg: (+ (* 2 5) (+ 10 (* 3 4))) =>

|{:ns examples.lab, :line 9}
|dbgn: (+ 10 (* 3 4)) =>
|| (* 3 4) =>
|| 12
|| (+ 10 (* 3 4)) =>
|| 22
| 32
....

[TIP]
--
You can comment out the tagged literals temporarily, by appending `_` after `#` like this.

[source]
....
#d/dbg (+ 1 2 #_d/dbg (* 3 4))
....

[source]
.REPL output
....
{:ns examples.lab, :line 5}
dbg: (+ 1 2 (* 3 4)) =>
| 15
....
--

[#dbg-last]
## `dbg-last`: Debugging inside the thread-last macro pass:q[`->>`]

IMPORTANT: The `dbg-last`/`clog-last` macros must be used inside the thread-last macro
pass:q[`->>`]

NOTE: The options of `dbg-last`/`clog-last` macros are the same as those of `dbg`/`clog`.

If you want to use `dbg` macro _with its options_ inside the thread-last macro
pass:q[`->>`] like this, you will have an exception.

[source]
....
(->> (range 10)
(filter odd?)
(dbg 5 "after filter")
(map inc))
; >> 1. Unhandled java.lang.IllegalArgumentException
; Don't know how to create ISeq from: java.lang.Long
....

The `dbg-last` macro is to the rescue of this case.

[source]
....
(->> (range 20)
(filter odd?)
(dbg-last 5 "after filter")
(map inc))
; => (2 4 6 8 10 12 14 16 18 20)
....

[listing]
.REPL output
----
{:ns examples.demo}
dbg: (filter odd? (range 20)) =>
| (1 3 5 7 9)
----

There is no problem in case of the `dbg` macro _with its options_ inside the thread-first
macro pass:q[`->`].

[source]
....
(-> (range 10)
(conj 100)
(dbg 5 "after conj")
vec)
; => [100 0 1 2 3 4 5 6 7 8 9]
....

[listing]
----
{:ns examples.demo, :line 374}
dbg: (conj (range 10) 100) =>
| (100 0 1 2 3)
----

[[dbg-prn]]
## `dbg-prn`: Debugging the macros for ClojureScript at the macro-expansion time.

CAUTION: The function `dbg-prn` doesn't follow the usage employed in `dbg`/`clog`. It is just
another name of `println` which can be used at the macro-expansion time.

NOTE: `dbg-prn` can be used inside the macros for Clojure.

See the detailed explaination link:doc/macro-debugging-in-clojurescript.adoc[here].

[[cljs-devtools]]
## Support for `cljs-devtools` added

* The `clog`/`clogn` of `debux` supports
link:https://github.com/binaryage/cljs-devtools[cljs-devtools] since the version
`0.5.9`.
+
image::cljs-devtools.png[title="cljs-devtools printing example", width=700]

[[set-cljs-devtools]]
* If you want to use `cljs-devtools` printing in _debux_,

** firstly, call the `set-cljs-devtools!` function in your source code explicitly like
this.
+
[source]
....
(debux.cs.core/set-cljs-devtools! true) ;; the default value is false
....

** secondly, install `cljs-devtools` via `:preloads` cljs compiler option like this,
following
link:https://github.com/binaryage/cljs-devtools/blob/master/docs/installation.md[cljs-devtools
installition guide].
+
[listing]
.project.clj
----
(defproject your-project "0.1.0"
:dependencies [[binaryage/devtools "1.0.2"]
,,,,,,]
,,,,,,
:cljsbuild {:builds [{:compiler {:preloads [devtools.preload]
,,,,,,}}]})
----
+
Or install it manually like this.
+
[listing]
----
(ns your-project.devtools
(:require [devtools.core :as devtools]))

(devtools/install!)
----

* Don't forget to to turn on the Chrome DevTools' [Settings -- Preferences -- Console --
Enable custom formatters], before using `cljs-devtools` printing.
+
image::chrome-devtools-settings.png[title="Enable custom formatters on Chrome DevTools", width=850]

* You should read
link:https://github.com/binaryage/cljs-devtools/blob/master/docs/faq.md#why-some-custom-formatters-were-not-rendered[Why
some custom formatters were not rendered?] before using cljs-devtools printing.

* You can confiugre `cljs-devtools` in various ways as you like. See the details in
link:https://github.com/binaryage/cljs-devtools/blob/master/docs/configuration.md[cljs-devtools
configuration].

[[electric]]
## Support for `Electric` added

* link:https://github.com/hyperfiddle/electric[Electric] has some problems on expanding
the user-defined macros. See
link:https://github.com/hyperfiddle/electric/issues/38[here] for the related issue.

* So according to the advice of dustingetz, the author of _Electric_, I created the new
namespaces and wrote some macros for _Electric_ in _Debux_ as follows.
+
[listing]
----
;;; The server side macros for Electric
debux.electric namespace:
dbg, dbgn, dbgt, dbg-last, dbg_, dbgn_, dbgt_, dbg-last_

;;; The client side macros for Electric
debux.cs.electric namespace:
clog, clogn, clogt, clog-last, clog_, clogn_, clogt_, clog-last_
dbg, dbgn, dbgt, dbg-last, dbg_, dbgn_, dbgt_, dbg-last_
----

* The following is the examples for Electric.
+
[source]
....
(ns user.demo-toggle
(:require [hyperfiddle.electric :as e]
[hyperfiddle.electric-dom2 :as dom]
[hyperfiddle.electric-ui4 :as ui]
#?(:cljs [debux.cs.electric :refer-macros [clog clogn clogt clog-last
clog_ clogn_ clogt_ clog-last_
dbg dbgn dbgt dbg-last
dbg_ dbgn_ dbgt_ dbg-last_]]) ))

#?(:clj (use 'debux.electric))

#?(:clj (defonce !x (atom true))) ; server state
(e/def x (e/server (e/watch !x))) ; reactive signal derived from atom

(e/defn Toggle []
(e/client
(dom/h1 (dom/text "Toggle Client/Server"))

(dom/div
(dom/text "number type here is: "
(case x
true (e/client (clogn (pr-str (type 1)))) ;; <-- Here
false (e/server (dbgn (pr-str (type 1))) )))) ;; <-- Here

(dom/div (dom/text "current site: "
(case x
true "ClojureScript (client)"
false "Clojure (server)")))

(ui/button (e/fn []
(e/server
(swap! !x not)))
(dom/text "toggle client/server"))))
....

## `break` examples (CLJS only)

### `break` options

You can use `break` to set the breakpoint in the source code like this. You can add string
option for message, or `:if` option for conditional break.

[source]
....
(break)
(break "hello world")
(break :if (> 10 20) "this will not be printed")
(break :if (< 10 20) "10 is less than 20")
....

You can see the message in DevTools' console window.

image:break-1.png[title="break examples", width=650]

### Callstack, locals, etc

After setting the breakpoint, you can inspect the callstack, locals, etc. in the browser's
DevTools window.

[source]
....
(defn my-fun2
[a {:keys [b c d] :or {d 10 b 20 c 30}} [e f g & h]]
(break "in my-fun2")
(clog [a b c d e f g h]))

(my-fun2 (take 5 (range)) {:c 50 :d 100} ["a" "b" "c" "d" "e"])
....

You can see the message in DevTools' console window.

image:break-2.png[width=750]

### `:if` option example

When using `break`, you can use `:if` like this.

[source]
....
(defn my-fun3 []
(let [a 10
b 20]
(dotimes [i 1000]
(break :if (= i 999) "in my-fun3"))))

(my-fun3)
....

image:break-4.png[]

[[source-info-mode]]
## Turning off the source info line printing

If you want to turn off the source info line printing in the `debux` macros, use
`(set-source-info-mode! false)`. The `:ns` and `:line` source info line will not be
printed.

[source]
....
(set-source-info-mode! false)

(dbg (+ 2 3))
(dbgn (* 10 (+ 2 3)))

(set-source-info-mode! true)

(dbg (+ 20 30))
(dbgn (* 10 (+ 2 3)))
....

[listing]
.REPL output
----
dbg: (+ 2 3) =>
| 5

dbgn: (* 10 (+ 2 3)) =>
| (+ 2 3) =>
| 5
| (* 10 (+ 2 3)) =>
| 50

{:ns examples.lab, :line 11}
dbg: (+ 20 30) =>
| 50

{:ns examples.lab, :line 12}
dbgn: (* 10 (+ 2 3)) =>
| (+ 2 3) =>
| 5
| (* 10 (+ 2 3)) =>
| 50
----

[[set-line-bullet]]
## Setting the line bullet

You can change the default line bullet "`|`" by using `set-line-bullet!` as follows.

[source]
....
(set-line-bullet! ";")
(dbg (+ 20 30))
(dbgn (* 10 (+ 2 3)))

(set-line-bullet! " ")
(dbg (+ 20 30))
(dbgn (* 10 (+ 2 3)))
....

[listing]
.REPL output
----
{:ns examples.lab, :line 11}
dbg: (+ 20 30) =>
; 50

{:ns examples.lab, :line 12}
dbgn: (* 10 (+ 2 3)) =>
; (+ 2 3) =>
; 5
; (* 10 (+ 2 3)) =>
; 50

{:ns examples.lab, :line 17}
dbg: (+ 20 30) =>
50

{:ns examples.lab, :line 18}
dbgn: (* 10 (+ 2 3)) =>
(+ 2 3) =>
5
(* 10 (+ 2 3)) =>
50
----

[[temporal-turn-off]]
## Turning off the debux macros temporarily

You can temporarily turn off the debux macros by appending `pass:q[_]` after the existing
debux macro names or turn off the tagged literals by appending `pass:q[_]` after `#`.

[cols="m,m,m,m", options="header", width=75%]
|===

^| Macros ^| turning-off ^| Tagged literals ^| turning-off

| dbg | dbg_ | #d/dbg | #_d/dbg
| dbgn | dbgn_ | #d/dbgn | #_d/dbgn
| dbgt | dbgt_ | #d/dbgt | #_d/dbgt
| dbg-prn | dbg-prn_ | |
| dbg-last | dbg-last_ | |

| clog | clog_ | #d/clog | #_d/clog
| clogn | clogn_ | #d/clogn | #_d/clogn
| clogt | clogt_ | #d/clogt | #_d/clogt
| clog-last | clog-last_ | |

| break | break_ | |

|===

[[debux-config]]
## How to configure the namespaces to debug

* When `(set-debug-mode! false)` is run, the effects of `set-ns-whitelist!` and
`set-ns-blacklist!` will be ignored.
+
[source]
....
(set-debug-mode! false)

;; The folowings take no effect at all.
(set-ns-whitelist! ["my-app.*" ])
(set-ns-blacklist! ["my-app.foo" "my-app.bar.*"])
....

* When `set-ns-whitelist!` and `set-ns-blaklist!` are both run like this, all `my-app.*`
except `my-app.foo` will be run.
+
[source]
....
(set-ns-whitelist! ["my-app.*" ])
(set-ns-blacklist! ["my-app.foo" "my-app.bar.*"])
....

The following (in https://github.com/philoskim/debux/tree/master/examples[examples] folder)
is an example.

### in Clojure

[listing]
.examples/project.clj
----
(defproject examples
,,,,,,
:main examples.core
,,,,,,)
----

[source]
.examples/src/clj/examples/core.clj
....
(ns examples.core
(:require [debux.core :as d])
(:gen-class))

(defn -main []
(println "\nRunning debux examples...\n")

;(d/set-debug-mode! false)
(d/set-ns-whitelist! ["examples.dbg*"])
(d/set-ns-blacklist! ["examples.dbgn"])

;; You should require dynamically the namespaces that you want to load.
(require 'examples.dbg)
(require 'examples.options)
(require 'examples.dbgn))
....

### in ClojureScript

[listing]
.examples/project.clj
----
(defproject examples
,,,,,,
:cljsbuild {:builds [{,,,,,,
:compiler {,,,,,,
:preloads [examples.preload]
,,,,,,}}]})
----

[source]
.examples/src/cljs/examples/preload.cljs
....
(ns examples.preload
(:require [debux.cs.core :as d]))

;(d/set-debug-mode! false)
(d/set-ns-whitelist! ["examples.clog*"])
(d/set-ns-blacklist! ["examples.clogn"])
....

## Using *debux* macros on Node.js

You had better use `dbg`/`dbgn` instead of `clog`/`clogn` on Node.js JavaScript
console, because Node.js doesn't support colors in its `console.log` function. The
following shows the example.

[source]
.example.node
....
(ns examples.node
(:require [cljs.nodejs :as nodejs]
[debux.cs.core :refer-macros [clog clogn dbg dbgn]] ))

(defn -main [& args]
(dbgn (+ 2 (* 3 4)))
(clogn (+ 2 (* 3 4))))

(set! *main-cli-fn* -main)
....

[listing]
.JavaScript console output on Node.js
----
{:ns examples.node :line 6}
dbgn: (+ 2 (* 3 4)) =>
| (* 3 4) =>
| 12
| (+ 2 (* 3 4)) =>
| 14

{:ns examples.node :line 7}
%cclogn: %c (+ 2 (* 3 4)) %c => color: #8b008b background: #ffc125; color: black color: black =>
| %c (* 3 4) %c => background: #ffc125; color: black color: black =>
| 12
| %c (+ 2 (* 3 4)) %c => background: #ffc125; color: black color: black =>
| 14
----

Of course, you should use the `clog`/`clogn` instead of `dbg`/`dbgn` in
link:https://electronjs.org/[Electron] apps on Node.js, because Electron supports colors
in its `console.log` function.

[#browser-repl]
## Usage in ClojureScript on Browser REPL

You can use both `dbg`/`dbgn` and `clog`/`clogn` on the browser REPL. The following is
an example about running the link:https://github.com/bhauman/lein-figwheel[figwheel].

[source]
.project.clj
....
(defproject examples "0.1.0-SNAPSHOT"
:dependencies [[org.clojure/clojure "1.8.0"]
[org.clojure/clojurescript "1.10.238"]
[philoskim/debux "0.8.3"]]
:plugins [[lein-cljsbuild "1.1.6"]
[lein-figwheel "0.5.10"]]
:source-paths ["src/clj"]
:clean-targets ^{:protect false}
["resources/public/js/app.js"
"resources/public/js/app.js.map"]
:cljsbuild {:builds [{:id "dev"
:source-paths ["src/cljs"]
:figwheel true
:compiler {:main examples.core
:asset-path "js/out"
:output-to "resources/public/js/app.js"
:output-dir "resources/public/js/out"
:source-map true
:optimizations :none} }]})
....

And then run figwheel like this on terminal window.

[listing]
----
$ lein figwheel
Figwheel: Cutting some fruit, just a sec ...
Figwheel: Validating the configuration found in project.clj
Figwheel: Configuration Valid :)
Figwheel: Starting server at http://0.0.0.0:3449
Figwheel: Watching build - dev
Compiling "resources/public/js/app.js" from ["src/cljs"]...
Successfully compiled "resources/public/js/app.js" in 2.14 seconds.
Launching ClojureScript REPL for build: dev
Figwheel Controls:
(stop-autobuild) ;; stops Figwheel autobuilder
(start-autobuild [id ...]) ;; starts autobuilder focused on optional ids
(switch-to-build id ...) ;; switches autobuilder to different build
(reset-autobuild) ;; stops, cleans, and starts autobuilder
(reload-config) ;; reloads build config and resets autobuild
(build-once [id ...]) ;; builds source one time
(clean-builds [id ..]) ;; deletes compiled cljs target files
(print-config [id ...]) ;; prints out build configurations
(fig-status) ;; displays current state of system
(figwheel.client/set-autoload false) ;; will turn autoloading off
(figwheel.client/set-repl-pprint false) ;; will turn pretty printing off
Switch REPL build focus:
:cljs/quit ;; allows you to switch REPL to another build
Docs: (doc function-name-here)
Exit: Control+C or :cljs/quit
Results: Stored in vars *1, *2, *3, *e holds last exception object
Prompt will show when Figwheel connects to your application
----

After that, connect to `http://localhost:3449` on your browser.

[listing]
----
To quit, type: :cljs/quit
cljs.user=> (require '[debux.cs.core :refer-macros [clog clogn dbg dbgn break]])
nil

cljs.user=> (dbg (+ 1 2))

{:ns cljs.user :line 4}
dbg: (+ 1 2) =>
| 3
3

cljs.user=>
----

Now you can do anything in this browser REPL as in the Clojure REPL. When you evaluate
`dbg`/`dbgn` in your ClojureScript source code, the result will go to both the REPL window
and the browser's console window. When you evaluate `clog`/`clogn` in your ClojureScript
source code, the result will go only to your browser's console window.

## `debux.el` for Emacs CIDER user

Inserting or deleting `dbg`/`dbgn`/`clog`/`clogn` manually is very painful. As Emacs user
I wrote `debux.el` for Emacs CIDER for my convenience. I think it's not perfect but better
than nothing. If you find it useful, append the following `debux.el` (which is in project
root folder) to the `~/.emacs.d/init.el`.

### `debux.el`

Refer to the source code of `debux.el`
https://github.com/philoskim/debux/blob/master/debux.el[here].

### How to use

* If you are editing on `\*.clj` or `*.cljc` files, pass:q[`(dbg ...)`] or pass:q[`(dbgn
...)`] will be inserted or deleted.

* If you are editing on `*.cljs` files, pass:q[`(clog ...)`] or pass:q[`(clogn ...)`] will
be inserted or deleted.

#### Inserting pass:q[`dbg`/`clog`] or pass:q[`dbgn`/`clogn`]

When you double-click the left mouse button on one of the open parentheses and the
following string is not `dbg` or `clog`, it will be inserted.

* The `v` of the following examples marks the cursor position.

[source]
....
;; before
;; v
(let [a 1 b 2]
(+ a b))

;; after
(dbg (let [a 1 b 2]
(+ a b)))
....

When you double-click on a symbol, `dbg` or `clog` will be inserted as well.

[source]
....
;; before
; v
(+ a b)

;; after
(+ (dbg a) b)
....

When you double-click on one of the open parentheses while pressing `` key and the
following string is not `dbgn` or `clogn`, it will be inserted.

[source]
....
;; before
;; v
(defn foo [a b c]
(* a b c))

;; after
(dbgn (defn foo [a b c]
(* a b c)))
....

#### Deleting pass:q[`dbg`/`clog`/`dbgn`/`clogn`]

When you double-click on one of the open parentheses and the following string is `dbg`,
`clog`, `dbgn` or `clogn`, it will be deleted.

[source]
....
;; before
;; v
(dbg (let [a 1 b 2]
(+ a b)))

;; after
(let [a 1 b 2]
(+ a b))

;; before
;; v
(dbgn (defn foo [a b c]
(* a b c)))

;; after
(defn foo [a b c]
(* a b c))
....

## License
Copyright © 2015--2023 Young Tae Kim

Distributed under the Eclipse Public License either version 1.0 or any later version.