1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
//! # Spannify
//!
//! This crate provides functionality to produce nice-looking graphs that represent your
//! callstack. It is designed to help developers trace and understand the execution flow of their
//! programs, making it easier to debug and optimize their code.
//!
//! ## Overview
//!
//! The core functionality of this crate revolves around creating spans that represent different
//! sections of your code. These spans are organized hierarchically, and the crate generates
//! messages to visualize when you enter and exit each span. The generated messages can be
//! customized to suit your preferences using a variety of configuration options.
//!
//! ## Modules
//!
//! - [`config`]: Contains the configuration structures and options for customizing the appearance
//! and behavior of the callstack visualization.
//! - [`core`]: Contains the core functionality for managing spans, generating messages, and
//! handling the callstack visualization logic.
//! - [`level`]: Contains the levels of spans, which determines if the span should be outputted or not
//!
//! ## Example
//!
//! ```rust
//! use spannify::{config::Config, core::StdoutSpanner, spf};
//! use std::sync::LazyLock;
//!
//! static SPANNER: LazyLock<StdoutSpanner> =
//! LazyLock::new(|| StdoutSpanner::new().with_config(Config::new().with_skip(1)));
//!
//! fn fib(n: usize) -> usize {
//! let _span = spf!(SPANNER, "fib({n})");
//! match n {
//! 0 => 0,
//! 1 | 2 => 1,
//! _ => fib(n - 1) + fib(n - 2),
//! }
//! }
//!
//! fn main() {
//! fib(5);
//! }
//!
//! ```
//! ### Output
//!
//! ```text
//!┌fib(5)
//!| fib(4)
//!| ┌fib(3)
//!| ┆ fib(2)
//!| ┆ fib(2)
//!| ┆ fib(1)
//!| ┆ fib(1)
//!| └fib(3)
//!| ┌fib(2)
//!| └fib(2)
//!| fib(4)
//!| fib(3)
//!| ┌fib(2)
//!| └fib(2)
//!| ┌fib(1)
//!| └fib(1)
//!| fib(3)
//!└fib(5)
//! ```
//!
//! ## Usage
//!
//! To use this crate, you typically start by creating a `spannify` instance with a desired writer
//! and configuration. Then, you create spans by calling the `Span::enter` method, which tracks the
//! entry and exit points of different sections of your code.
//!
//! ```rust
//! use spannify::{config::Config, core::{StdoutSpanner}};
//! use std::io::stdout;
//!
//! // Create a configuration
//! let config = Config::default();
//!
//! // Create a spannify
//! let spanner = StdoutSpanner::new().with_config(config);
//!
//! // Create a span
//! {
//! let _span = spanner.enter_span("main");
//! // Your code here...
//! }
//! // The span is automatically dropped here, and the exit message is generated
//! ```
//!
//! ## Configuration
//!
//! The [`config`] module provides various options to customize the appearance and behavior of the
//! callstack visualization. This includes settings for indentation, depth display, and message
//! formatting. You can create a custom configuration by modifying the default values.
//!
//! ```rust
//! use spannify::config::Config;
//!
//! let mut config = Config::default();
//! config.tabwidth = 4;
//! config.skip = 2;
//! config.depthmap = |depth| if depth % 2 == 0 { '|' } else { '^' };
//!
//! // Use this configuration when creating a spannify
//! ```
//!
//! ## License
//!
//! This crate is licensed under the MIT License. See the LICENSE file for more details.
//!
//! ## Contributing
//!
//! Contributions are welcome! Please open an issue or submit a pull request