ratatui_ruby 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.builds/ruby-3.2.yml +1 -1
- data/.builds/ruby-3.3.yml +1 -1
- data/.builds/ruby-3.4.yml +1 -1
- data/.builds/ruby-4.0.0.yml +1 -1
- data/CHANGELOG.md +13 -0
- data/doc/async.md +160 -0
- data/doc/debugging.md +71 -0
- data/ext/ratatui_ruby/Cargo.lock +1 -1
- data/ext/ratatui_ruby/Cargo.toml +1 -1
- data/ext/ratatui_ruby/src/style.rs +25 -9
- data/lib/ratatui_ruby/version.rb +1 -1
- data/tasks/bump/changelog.rb +8 -0
- data/tasks/bump/ruby_gem.rb +12 -0
- data/tasks/bump/unreleased_section.rb +16 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4fc5e88c5e6146ec1aeae7816aeb8bea73926aaf90d5b2df75fa58d5c6490ab0
|
|
4
|
+
data.tar.gz: 90ec60b887d797c1cd8b8f06ca41506dbf8a463abc554c20b7caab8ec537b496
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3d6fdbb5c4c2970210f70cb0f16c0f40eca871afd6cc115cc5e744e9b85aed01b2c7209baabbb4b2e7129f6ddf460f1add31a6612070a8ef239fbb1e5e2893bd
|
|
7
|
+
data.tar.gz: ffef16474856ead4d0754dcd6f26104b795a6c2d8aac962df73d7f6c468d4fc6ad7c769a68bb97c1ad3fecc487973afbb50764c555f0a8385addf14864d5c22c
|
data/.builds/ruby-3.2.yml
CHANGED
data/.builds/ruby-3.3.yml
CHANGED
data/.builds/ruby-3.4.yml
CHANGED
data/.builds/ruby-4.0.0.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -18,6 +18,18 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
18
18
|
|
|
19
19
|
### Removed
|
|
20
20
|
|
|
21
|
+
## [0.7.1] - 2026-01-03
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- **Block Title Styling**: `Block` title `content` now correctly renders `Text::Line` objects with styled spans. Previously, passing a styled `Line` as title content displayed its Ruby inspect representation (e.g., `#<data RatatuiRuby::Text::Line...>`) instead of the styled text.
|
|
30
|
+
|
|
31
|
+
### Removed
|
|
32
|
+
|
|
21
33
|
## [0.7.0] - 2026-01-03
|
|
22
34
|
|
|
23
35
|
> [!WARNING]
|
|
@@ -356,6 +368,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
356
368
|
- **Testing Support**: Included `RatatuiRuby::TestHelper` and RSpec integration to make testing your TUI applications possible.
|
|
357
369
|
|
|
358
370
|
[Unreleased]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/HEAD
|
|
371
|
+
[0.7.1]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/v0.7.1
|
|
359
372
|
[0.7.0]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/v0.7.0
|
|
360
373
|
[0.6.0]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/v0.6.0
|
|
361
374
|
[0.5.0]: https://git.sr.ht/~kerrick/ratatui_ruby/refs/v0.5.0
|
data/doc/async.md
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
3
|
+
SPDX-License-Identifier: AGPL-3.0-or-later
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
# Async Operations in TUI Applications
|
|
7
|
+
|
|
8
|
+
TUI applications fetch data from APIs, run shell commands, and query databases. These operations take time. Blocking the render loop freezes the interface.
|
|
9
|
+
|
|
10
|
+
You want responsive UIs. The checklist shows "Loading..." while data arrives. The interface never hangs.
|
|
11
|
+
|
|
12
|
+
This guide explains async patterns that work with raw terminal mode.
|
|
13
|
+
|
|
14
|
+
## The Raw Terminal Problem
|
|
15
|
+
|
|
16
|
+
`RatatuiRuby.run` enters raw terminal mode:
|
|
17
|
+
|
|
18
|
+
- stdin reconfigures for character-by-character input
|
|
19
|
+
- stdout carries terminal escape sequences
|
|
20
|
+
- External commands expecting normal terminal I/O fail
|
|
21
|
+
|
|
22
|
+
### What Breaks
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
# These fail inside a Thread during raw mode:
|
|
26
|
+
`git ls-remote --tags origin` # Returns empty or hangs
|
|
27
|
+
IO.popen(["git", "ls-remote", ...]) # Same
|
|
28
|
+
Open3.capture2("git", "ls-remote", ...) # Same
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The commands succeed synchronously. They fail asynchronously. The difference: thread context inherits the parent's raw terminal state.
|
|
32
|
+
|
|
33
|
+
### Why Threads Fail
|
|
34
|
+
|
|
35
|
+
Ruby's GIL releases during I/O. But:
|
|
36
|
+
|
|
37
|
+
1. Subprocesses inherit the parent's terminal state.
|
|
38
|
+
2. Git/SSH try to read credentials from raw-mode stdin.
|
|
39
|
+
3. The read blocks forever. Or returns empty.
|
|
40
|
+
|
|
41
|
+
`GIT_TERMINAL_PROMPT=0` prevents prompts. Auth fails silently instead of hanging.
|
|
42
|
+
|
|
43
|
+
## Solutions
|
|
44
|
+
|
|
45
|
+
### Pre-Check Before Raw Mode
|
|
46
|
+
|
|
47
|
+
Run slow operations before entering the TUI:
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
def initialize
|
|
51
|
+
@data = fetch_data # Runs before RatatuiRuby.run
|
|
52
|
+
end
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Trade-off**: Delays startup.
|
|
56
|
+
|
|
57
|
+
### Process.spawn with File Output
|
|
58
|
+
|
|
59
|
+
Spawn a separate process before entering raw mode. Write results to a temp file. Poll for completion:
|
|
60
|
+
|
|
61
|
+
```ruby
|
|
62
|
+
class AsyncChecker
|
|
63
|
+
CACHE_FILE = File.join(Dir.tmpdir, "my_check_result.txt")
|
|
64
|
+
|
|
65
|
+
def initialize
|
|
66
|
+
@loading = true
|
|
67
|
+
@result = nil
|
|
68
|
+
@pid = Process.spawn("my-command > #{CACHE_FILE}")
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def loading?
|
|
72
|
+
return false unless @loading
|
|
73
|
+
|
|
74
|
+
# Non-blocking poll
|
|
75
|
+
_pid, status = Process.waitpid2(@pid, Process::WNOHANG)
|
|
76
|
+
if status
|
|
77
|
+
@result = File.read(CACHE_FILE).strip
|
|
78
|
+
@loading = false
|
|
79
|
+
end
|
|
80
|
+
@loading
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Key points**:
|
|
86
|
+
|
|
87
|
+
- `Process.spawn` returns immediately.
|
|
88
|
+
- The command runs in a separate process, not a thread.
|
|
89
|
+
- Results pass through a temp file. Avoids pipe/terminal issues.
|
|
90
|
+
- `Process::WNOHANG` polls without blocking.
|
|
91
|
+
|
|
92
|
+
### Thread for CPU-Bound Work
|
|
93
|
+
|
|
94
|
+
Ruby threads work for pure computation:
|
|
95
|
+
|
|
96
|
+
```ruby
|
|
97
|
+
Thread.new { @result = expensive_calculation }
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Avoid threads for shell commands.
|
|
101
|
+
|
|
102
|
+
## Ractors
|
|
103
|
+
|
|
104
|
+
Ractors provide true parallelism. Trade-offs:
|
|
105
|
+
|
|
106
|
+
- No mutable shared state.
|
|
107
|
+
- Limited to Ractor-safe values.
|
|
108
|
+
- Terminal I/O issues remain.
|
|
109
|
+
|
|
110
|
+
For TUI async, `Process.spawn` solves the problem cleanly.
|
|
111
|
+
|
|
112
|
+
## Pattern Summary
|
|
113
|
+
|
|
114
|
+
| Approach | Use Case | Raw Mode Safe? |
|
|
115
|
+
|----------|----------|----------------|
|
|
116
|
+
| Sync before TUI | Fast checks (<100ms) | Yes |
|
|
117
|
+
| Process.spawn + file | Shell commands, network | Yes |
|
|
118
|
+
| Thread | CPU-bound Ruby code | Yes |
|
|
119
|
+
| Thread + shell | Shell commands | **No** |
|
|
120
|
+
|
|
121
|
+
## Real Example: Git Tag Check
|
|
122
|
+
|
|
123
|
+
Check if a tag exists on the remote:
|
|
124
|
+
|
|
125
|
+
```ruby
|
|
126
|
+
class GitRepo
|
|
127
|
+
CACHE_FILE = File.join(Dir.tmpdir, "git_tag_pushed.txt")
|
|
128
|
+
|
|
129
|
+
def initialize
|
|
130
|
+
@version = `git describe --tags --abbrev=0`.strip
|
|
131
|
+
@tag_pushed = nil
|
|
132
|
+
@loading = true
|
|
133
|
+
@pid = Process.spawn(
|
|
134
|
+
"git ls-remote --tags origin | grep -q '#{@version}' " \
|
|
135
|
+
"&& echo true > #{CACHE_FILE} || echo false > #{CACHE_FILE}"
|
|
136
|
+
)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def loading?
|
|
140
|
+
return false unless @loading
|
|
141
|
+
|
|
142
|
+
_pid, status = Process.waitpid2(@pid, Process::WNOHANG)
|
|
143
|
+
if status
|
|
144
|
+
@tag_pushed = File.read(CACHE_FILE).strip == "true"
|
|
145
|
+
@loading = false
|
|
146
|
+
end
|
|
147
|
+
@loading
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def refresh
|
|
151
|
+
# Sync version for manual refresh (user presses 'r')
|
|
152
|
+
@loading = true
|
|
153
|
+
remote_tags = `git ls-remote --tags origin`.strip
|
|
154
|
+
@tag_pushed = remote_tags.include?(@version)
|
|
155
|
+
@loading = false
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
The TUI starts instantly. The tag check runs in the background. The checklist updates when the result arrives.
|
data/doc/debugging.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
3
|
+
SPDX-License-Identifier: AGPL-3.0-or-later
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
# Debugging TUI Applications
|
|
7
|
+
|
|
8
|
+
TUI applications run in raw terminal mode. stderr and stdout carry terminal escape sequences. Using `puts` or `warn` inside the render loop corrupts the display.
|
|
9
|
+
|
|
10
|
+
This creates a problem: how do you inspect variables and trace execution?
|
|
11
|
+
|
|
12
|
+
Write debug output to files. Tail them in a separate terminal.
|
|
13
|
+
|
|
14
|
+
## File-Based Logging
|
|
15
|
+
|
|
16
|
+
Create timestamped log files to avoid overwrites:
|
|
17
|
+
|
|
18
|
+
```ruby
|
|
19
|
+
FileUtils.mkdir_p(File.join(Dir.tmpdir, "my_debug"))
|
|
20
|
+
timestamp = Time.now.strftime('%Y%m%d_%H%M%S_%N')
|
|
21
|
+
File.write(
|
|
22
|
+
File.join(Dir.tmpdir, "my_debug", "#{timestamp}.log"),
|
|
23
|
+
"variable=#{value.inspect}\n"
|
|
24
|
+
)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Or append to a single file:
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
File.write("/tmp/debug.log", "#{Time.now}: #{message}\n", mode: "a")
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Tail the logs in a separate terminal:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Single file
|
|
37
|
+
tail -f /tmp/debug.log
|
|
38
|
+
|
|
39
|
+
# Directory of timestamped files
|
|
40
|
+
watch -n 0.5 'ls -la /tmp/my_debug/ && cat /tmp/my_debug/*.log'
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## REPL Debugging with `__FILE__` Guards
|
|
44
|
+
|
|
45
|
+
Unit tests verify correctness. But during exploratory debugging, you want to poke at objects interactively. Loading the full TUI just to inspect one object is slow.
|
|
46
|
+
|
|
47
|
+
Wrap your main execution in a guard:
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
if __FILE__ == $PROGRAM_NAME
|
|
51
|
+
MyApp.new.run
|
|
52
|
+
end
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Now load the file and interact with classes directly:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
ruby -e 'load "./bin/my_tui"; obj = MyClass.new; sleep 1; puts obj.result'
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
This exercises domain logic without entering raw terminal mode. Use it for exploratory debugging. Write tests using the [TestHelper](application_testing.md) for regression coverage.
|
|
62
|
+
|
|
63
|
+
## Isolating Terminal Issues
|
|
64
|
+
|
|
65
|
+
Something works in a `ruby -e` script but fails in the TUI. Common causes:
|
|
66
|
+
|
|
67
|
+
1. **Thread context.** Ruby threads share the process's terminal state.
|
|
68
|
+
2. **Raw mode.** External commands fail when stdin/stdout are reconfigured.
|
|
69
|
+
3. **SSH/Git auth.** Commands that prompt for credentials hang or return empty.
|
|
70
|
+
|
|
71
|
+
See [Async Operations](async.md) for solutions.
|
data/ext/ratatui_ruby/Cargo.lock
CHANGED
data/ext/ratatui_ruby/Cargo.toml
CHANGED
|
@@ -12,6 +12,8 @@ use ratatui::{
|
|
|
12
12
|
widgets::{Block, BorderType, Borders, Padding},
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
use crate::text::parse_line;
|
|
16
|
+
|
|
15
17
|
pub fn parse_color(color_str: &str) -> Option<Color> {
|
|
16
18
|
// Try standard ratatui parsing first (named colors, indexed, etc.)
|
|
17
19
|
if let Ok(color) = color_str.parse::<Color>() {
|
|
@@ -274,15 +276,22 @@ fn parse_titles(block_val: Value, mut block: Block<'_>) -> Result<Block<'_>, Err
|
|
|
274
276
|
let index = isize::try_from(i)
|
|
275
277
|
.map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
|
|
276
278
|
let title_item: Value = titles_array.entry(index)?;
|
|
277
|
-
let mut content = String::new();
|
|
278
279
|
let mut alignment = Alignment::Left;
|
|
279
280
|
let mut is_bottom = false;
|
|
280
281
|
let mut style = Style::default();
|
|
282
|
+
let mut line: Option<Line<'static>> = None;
|
|
281
283
|
|
|
282
284
|
if let Some(hash) = magnus::RHash::from_value(title_item) {
|
|
283
285
|
if let Ok(v) = hash.lookup::<_, Value>(ruby.to_symbol("content")) {
|
|
284
286
|
if !v.is_nil() {
|
|
285
|
-
|
|
287
|
+
// First, try to parse as a Line object (preserves styling)
|
|
288
|
+
if let Ok(parsed_line) = parse_line(v) {
|
|
289
|
+
line = Some(parsed_line);
|
|
290
|
+
} else {
|
|
291
|
+
// Fallback to string
|
|
292
|
+
let content: String = v.funcall("to_s", ())?;
|
|
293
|
+
line = Some(Line::from(content));
|
|
294
|
+
}
|
|
286
295
|
}
|
|
287
296
|
}
|
|
288
297
|
if let Ok(v) = hash.lookup::<_, Value>(ruby.to_symbol("alignment")) {
|
|
@@ -307,15 +316,22 @@ fn parse_titles(block_val: Value, mut block: Block<'_>) -> Result<Block<'_>, Err
|
|
|
307
316
|
}
|
|
308
317
|
}
|
|
309
318
|
} else {
|
|
310
|
-
content = title_item.funcall("to_s", ())?;
|
|
319
|
+
let content: String = title_item.funcall("to_s", ())?;
|
|
320
|
+
line = Some(Line::from(content));
|
|
311
321
|
}
|
|
312
322
|
|
|
313
|
-
let
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
323
|
+
if let Some(mut l) = line {
|
|
324
|
+
l = l.alignment(alignment);
|
|
325
|
+
// Only apply style if the line doesn't already have styled spans
|
|
326
|
+
if style != Style::default() {
|
|
327
|
+
l = l.style(style);
|
|
328
|
+
}
|
|
329
|
+
block = if is_bottom {
|
|
330
|
+
block.title_bottom(l)
|
|
331
|
+
} else {
|
|
332
|
+
block.title_top(l)
|
|
333
|
+
};
|
|
334
|
+
}
|
|
319
335
|
}
|
|
320
336
|
}
|
|
321
337
|
}
|
data/lib/ratatui_ruby/version.rb
CHANGED
data/tasks/bump/changelog.rb
CHANGED
|
@@ -34,4 +34,12 @@ class Changelog
|
|
|
34
34
|
File.write(@path, "#{header}#{UnreleasedSection.fresh}\n\n#{history}\n#{links}")
|
|
35
35
|
nil
|
|
36
36
|
end
|
|
37
|
+
|
|
38
|
+
def commit_message(version)
|
|
39
|
+
content = File.read(@path)
|
|
40
|
+
unreleased = UnreleasedSection.parse(content)
|
|
41
|
+
return nil unless unreleased
|
|
42
|
+
|
|
43
|
+
"chore: release v#{version}\n\n#{unreleased.commit_body}"
|
|
44
|
+
end
|
|
37
45
|
end
|
data/tasks/bump/ruby_gem.rb
CHANGED
|
@@ -17,19 +17,31 @@ class RubyGem
|
|
|
17
17
|
|
|
18
18
|
def bump(segment)
|
|
19
19
|
target = version.next(segment)
|
|
20
|
+
commit_message = @changelog.commit_message(target)
|
|
20
21
|
|
|
21
22
|
puts "Bumping #{segment}: #{version} -> #{target}"
|
|
22
23
|
@changelog.release(target)
|
|
23
24
|
@manifests.each { |manifest| manifest.write(target) }
|
|
24
25
|
@lockfile.refresh
|
|
26
|
+
|
|
27
|
+
puts_commit_message(commit_message)
|
|
25
28
|
end
|
|
26
29
|
|
|
27
30
|
def set(version_string)
|
|
28
31
|
target = SemVer.parse(version_string)
|
|
32
|
+
commit_message = @changelog.commit_message(target)
|
|
29
33
|
|
|
30
34
|
puts "Setting version: #{version} -> #{target}"
|
|
31
35
|
@changelog.release(target)
|
|
32
36
|
@manifests.each { |manifest| manifest.write(target) }
|
|
33
37
|
@lockfile.refresh
|
|
38
|
+
|
|
39
|
+
puts_commit_message(commit_message)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private def puts_commit_message(message)
|
|
43
|
+
puts "=" * 80
|
|
44
|
+
puts message
|
|
45
|
+
puts "=" * 80
|
|
34
46
|
end
|
|
35
47
|
end
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
5
|
|
|
6
6
|
require "date"
|
|
7
|
+
require "rdoc"
|
|
7
8
|
|
|
8
9
|
# UnreleasedSection manages the [Unreleased] section of the changelog.
|
|
9
10
|
class UnreleasedSection
|
|
@@ -35,4 +36,19 @@ class UnreleasedSection
|
|
|
35
36
|
def to_s
|
|
36
37
|
@content
|
|
37
38
|
end
|
|
39
|
+
|
|
40
|
+
def commit_body
|
|
41
|
+
formatter = Class.new { include RDoc::Text }.new
|
|
42
|
+
@content
|
|
43
|
+
.sub(/^## \[Unreleased\].*$/, "")
|
|
44
|
+
.gsub(/^### (Added|Changed|Fixed|Removed)\n*$/, "")
|
|
45
|
+
.gsub(/^- \*\*([^*]+)\*\*:/, '\1:')
|
|
46
|
+
.gsub(/`([^`]+)`/, '\1')
|
|
47
|
+
.strip
|
|
48
|
+
.lines
|
|
49
|
+
.map { |line| line.gsub(/^- /, "").strip }
|
|
50
|
+
.reject(&:empty?)
|
|
51
|
+
.map { |line| formatter.wrap(line, 72) }
|
|
52
|
+
.join("\n\n")
|
|
53
|
+
end
|
|
38
54
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ratatui_ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.7.
|
|
4
|
+
version: 0.7.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kerrick Long
|
|
@@ -107,6 +107,7 @@ files:
|
|
|
107
107
|
- Rakefile
|
|
108
108
|
- doc/application_architecture.md
|
|
109
109
|
- doc/application_testing.md
|
|
110
|
+
- doc/async.md
|
|
110
111
|
- doc/contributors/architectural_overhaul/chat_conversations.md
|
|
111
112
|
- doc/contributors/architectural_overhaul/implementation_plan.md
|
|
112
113
|
- doc/contributors/architectural_overhaul/task.md
|
|
@@ -118,6 +119,7 @@ files:
|
|
|
118
119
|
- doc/contributors/index.md
|
|
119
120
|
- doc/contributors/v1.0.0_blockers.md
|
|
120
121
|
- doc/custom.css
|
|
122
|
+
- doc/debugging.md
|
|
121
123
|
- doc/event_handling.md
|
|
122
124
|
- doc/images/app_all_events.png
|
|
123
125
|
- doc/images/app_color_picker.png
|