tui-td 0.1.3 → 0.2.0
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/CHANGELOG.md +8 -0
- data/README.md +29 -6
- data/lib/tui_td/ansi_parser.rb +4 -2
- data/lib/tui_td/cli.rb +41 -1
- data/lib/tui_td/test_runner.rb +20 -1
- data/lib/tui_td/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b8ebaa8989019a8cd573f682a538ca76a21a17daee810f29a1f178f8f35f0008
|
|
4
|
+
data.tar.gz: 52fecfc7d59143648f450e71612ac7b7b6839e1b697d03056cb80e0a0dd067ac
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9563af163f07bbaae4ea0427120785cc814c444289f7a6bc75b527d9a2e2a5a29785b99f40fa7c31c807c10708693f7f1a5cb5d9c39fea40b82a31e8d8c56964
|
|
7
|
+
data.tar.gz: 6912a0399394405e8678e33b13b1c95a7575ce5ef7f7731c23a514d2f55c720724c1f4d17bcb73be654a58461bade34d03adfcfd7e615509d1244c53ac8a8673
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
- Live debug modes for `tui-td test`: `-v` (verbose), `-l` (live screen-refresh), `-s` (step-by-step pause)
|
|
6
|
+
- Fix: skip DEC private mode sequences (`\e[?1049h` alternate screen, `\e[?25h` cursor visibility, etc.)
|
|
7
|
+
- TestRunner `on_step` callback API for programmatic step-by-step observation
|
|
8
|
+
- Vim interaction test example: type, yank, paste, substitute
|
|
9
|
+
- Removed aruba dev dependency from Gemfile
|
|
10
|
+
|
|
3
11
|
## 0.1.3
|
|
4
12
|
|
|
5
13
|
- UTF-8 multi-byte character support in ANSI parser (`_utf8_char_at`)
|
data/README.md
CHANGED
|
@@ -98,22 +98,45 @@ Usage: tui-td <command> [options]
|
|
|
98
98
|
|
|
99
99
|
Commands:
|
|
100
100
|
serve Start MCP server (JSON-RPC over stdio)
|
|
101
|
-
test <file> Run JSON test file
|
|
102
|
-
run <command> Run a TUI app and show live output
|
|
103
|
-
drive <command> Drive a TUI with structured state output
|
|
104
101
|
capture <command> Run once, capture and display state
|
|
102
|
+
drive <command> Drive a TUI interactively
|
|
103
|
+
run <command> Run a TUI app and show live output
|
|
104
|
+
test <file.json> Run JSON test file
|
|
105
|
+
help [topic] Show this help, or help test / help rspec
|
|
106
|
+
|
|
107
|
+
Examples:
|
|
108
|
+
tui-td capture "ls -la"
|
|
109
|
+
tui-td --screenshot out.png capture "htop" --timeout 5
|
|
110
|
+
tui-td --html out.html capture "glow README.md"
|
|
111
|
+
tui-td -C /my/project capture "make test"
|
|
112
|
+
tui-td drive "vim file.txt" --rows 24 --cols 80
|
|
113
|
+
tui-td test examples/echo_test.json
|
|
114
|
+
tui-td -vl test examples/vim_hello_world.json
|
|
115
|
+
tui-td serve
|
|
116
|
+
|
|
117
|
+
Interactive commands (drive mode):
|
|
118
|
+
state Show terminal state as pretty JSON
|
|
119
|
+
raw Show raw ANSI output
|
|
120
|
+
key <name> Send keystroke (enter, tab, escape, up, down, left, right,
|
|
121
|
+
backspace, ctrl_c, ctrl_d)
|
|
122
|
+
<text> Send text to the TUI
|
|
123
|
+
exit Quit drive mode
|
|
105
124
|
|
|
106
125
|
Global options:
|
|
107
126
|
-r, --rows N Terminal rows (default: 40)
|
|
108
127
|
-c, --cols N Terminal cols (default: 120)
|
|
109
|
-
-C, --chdir PATH Working directory for the command
|
|
110
128
|
-t, --timeout N Timeout in seconds (default: 30)
|
|
129
|
+
-C, --chdir PATH Working directory for the command
|
|
111
130
|
--screenshot PATH Save PNG screenshot
|
|
112
131
|
--html PATH Save HTML render for browser viewing
|
|
113
132
|
--json Output state as compact JSON (includes raw ANSI)
|
|
114
133
|
--pretty Output state as pretty JSON
|
|
115
|
-
--text Output state as plain text table
|
|
116
|
-
-
|
|
134
|
+
--text Output state as plain text table
|
|
135
|
+
-v, --verbose Show each test step as it runs
|
|
136
|
+
-l, --live Show terminal state after each test step (screen-refresh)
|
|
137
|
+
-s, --step Pause after each test step for confirmation
|
|
138
|
+
--version Show version
|
|
139
|
+
-h, --help Show complete reference
|
|
117
140
|
```
|
|
118
141
|
|
|
119
142
|
`tui-td --help` serves as the full CLI reference. `tui-td help test` shows all JSON test
|
data/lib/tui_td/ansi_parser.rb
CHANGED
|
@@ -103,7 +103,7 @@ module TUITD
|
|
|
103
103
|
if processed[i] == "\e" && processed[i + 1] == "["
|
|
104
104
|
# Find end of CSI sequence
|
|
105
105
|
j = i + 2
|
|
106
|
-
j += 1 while j < processed.length && !processed[j].match?(/[A-HJ-KP-SX@`
|
|
106
|
+
j += 1 while j < processed.length && !processed[j].match?(/[A-HJ-KP-SX@`fhlmnR]/)
|
|
107
107
|
seq = processed[i..j]
|
|
108
108
|
|
|
109
109
|
dsr = _apply_csi(seq, cursor, attrs, grid, rows, cols)
|
|
@@ -214,7 +214,7 @@ module TUITD
|
|
|
214
214
|
def self._apply_csi(seq, cursor, attrs, grid, rows, cols)
|
|
215
215
|
# Strip leading escape char if present
|
|
216
216
|
cleaned = seq.sub(/^\e/, "")
|
|
217
|
-
match = cleaned.match(/^\[([\d;]*)([A-HJ-KP-SX@`
|
|
217
|
+
match = cleaned.match(/^\[([\d;]*)([A-HJ-KP-SX@`fhlmnR])$/)
|
|
218
218
|
return unless match
|
|
219
219
|
|
|
220
220
|
params = match[1].split(";").map(&:to_i)
|
|
@@ -270,6 +270,8 @@ module TUITD
|
|
|
270
270
|
next unless cursor[:row] < rows && cursor[:col] + i < cols
|
|
271
271
|
grid[cursor[:row]][cursor[:col] + i][:char] = " "
|
|
272
272
|
end
|
|
273
|
+
when "h", "l" # DEC private mode set/reset — skip (alternate screen, cursor show/hide, etc.)
|
|
274
|
+
nil
|
|
273
275
|
when "n" # DSR — Device Status Report request
|
|
274
276
|
# \e[6n = request cursor position → caller must respond with \e[row;colR
|
|
275
277
|
return params[0] == 6
|
data/lib/tui_td/cli.rb
CHANGED
|
@@ -32,6 +32,7 @@ module TUITD
|
|
|
32
32
|
opts.separator " tui-td -C /my/project capture \"make test\""
|
|
33
33
|
opts.separator " tui-td drive \"vim file.txt\" --rows 24 --cols 80"
|
|
34
34
|
opts.separator " tui-td test examples/echo_test.json"
|
|
35
|
+
opts.separator " tui-td -vl test examples/vim_hello_world.json"
|
|
35
36
|
opts.separator " tui-td serve"
|
|
36
37
|
opts.separator ""
|
|
37
38
|
opts.separator "Interactive commands (drive mode):"
|
|
@@ -71,6 +72,15 @@ module TUITD
|
|
|
71
72
|
opts.on("--text", "Output state as plain text table") do |_|
|
|
72
73
|
global_opts[:format] = :text
|
|
73
74
|
end
|
|
75
|
+
opts.on("-v", "--verbose", "Show each test step as it runs") do |_|
|
|
76
|
+
global_opts[:verbose] = true
|
|
77
|
+
end
|
|
78
|
+
opts.on("-l", "--live", "Show terminal state after each step (screen-refresh)") do |_|
|
|
79
|
+
global_opts[:live] = true
|
|
80
|
+
end
|
|
81
|
+
opts.on("-s", "--step", "Pause after each test step for confirmation") do |_|
|
|
82
|
+
global_opts[:step_mode] = true
|
|
83
|
+
end
|
|
74
84
|
opts.on("--version", "Show version") do
|
|
75
85
|
puts "tui-td #{TUITD::VERSION}"
|
|
76
86
|
exit 0
|
|
@@ -228,9 +238,35 @@ module TUITD
|
|
|
228
238
|
path = args.first
|
|
229
239
|
abort "File not found: #{path}" unless File.exist?(path)
|
|
230
240
|
|
|
241
|
+
verbose = globals[:verbose]
|
|
242
|
+
live = globals[:live]
|
|
243
|
+
step_mode = globals[:step_mode]
|
|
244
|
+
|
|
245
|
+
on_step = if verbose || live || step_mode
|
|
246
|
+
lambda do |info|
|
|
247
|
+
if live && info[:driver]
|
|
248
|
+
info[:driver].wait_for_stable(stable_ms: 200)
|
|
249
|
+
end
|
|
250
|
+
if verbose
|
|
251
|
+
status = info[:result].passed ? "PASS" : "FAIL"
|
|
252
|
+
puts "[#{info[:index] + 1}/#{info[:total]}] #{info[:action]}: #{info[:result].message}"
|
|
253
|
+
puts " → #{status}"
|
|
254
|
+
end
|
|
255
|
+
if live && info[:driver]
|
|
256
|
+
print "\e[2J\e[H" # clear screen, home cursor
|
|
257
|
+
_render_text(info[:driver].state_data)
|
|
258
|
+
end
|
|
259
|
+
if step_mode
|
|
260
|
+
print "\n[Enter=weiter, q=abbruch] "
|
|
261
|
+
input = $stdin.gets
|
|
262
|
+
exit 1 if input&.chomp == "q"
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
|
|
231
267
|
require "json"
|
|
232
268
|
plan = JSON.parse(File.read(path), symbolize_names: true)
|
|
233
|
-
runner = TestRunner.new(plan)
|
|
269
|
+
runner = TestRunner.new(plan, on_step: on_step)
|
|
234
270
|
result = runner.run
|
|
235
271
|
|
|
236
272
|
puts
|
|
@@ -277,6 +313,10 @@ module TUITD
|
|
|
277
313
|
Run from CLI:
|
|
278
314
|
|
|
279
315
|
tui-td test examples/echo_test.json
|
|
316
|
+
tui-td -v test examples/echo_test.json (verbose: show each step)
|
|
317
|
+
tui-td -vl test examples/echo_test.json (verbose + live terminal view)
|
|
318
|
+
tui-td -vs test examples/echo_test.json (verbose + pause after each step)
|
|
319
|
+
tui-td -vls test examples/vim_hello_world.json (all three: watch vim edit live)
|
|
280
320
|
|
|
281
321
|
Or from Ruby code:
|
|
282
322
|
|
data/lib/tui_td/test_runner.rb
CHANGED
|
@@ -26,10 +26,11 @@ module TUITD
|
|
|
26
26
|
class TestRunner
|
|
27
27
|
Result = Struct.new(:step, :passed, :message, keyword_init: true)
|
|
28
28
|
|
|
29
|
-
def initialize(source)
|
|
29
|
+
def initialize(source, on_step: nil)
|
|
30
30
|
raw = source.is_a?(String) ? JSON.parse(source) : source
|
|
31
31
|
@plan = raw.transform_keys(&:to_sym)
|
|
32
32
|
@plan[:steps] = @plan[:steps].map { |s| s.transform_keys(&:to_sym) }
|
|
33
|
+
@on_step = on_step
|
|
33
34
|
end
|
|
34
35
|
|
|
35
36
|
def run
|
|
@@ -150,6 +151,24 @@ module TUITD
|
|
|
150
151
|
|
|
151
152
|
results << r
|
|
152
153
|
all_passed &&= r.passed
|
|
154
|
+
|
|
155
|
+
if @on_step
|
|
156
|
+
state_data = nil
|
|
157
|
+
begin
|
|
158
|
+
state_data = driver.state_data if driver
|
|
159
|
+
rescue StandardError
|
|
160
|
+
# ignore — state retrieval is best-effort
|
|
161
|
+
end
|
|
162
|
+
@on_step.call(
|
|
163
|
+
index: results.size - 1,
|
|
164
|
+
total: @plan[:steps].size,
|
|
165
|
+
action: action,
|
|
166
|
+
value: value,
|
|
167
|
+
result: r,
|
|
168
|
+
driver: driver,
|
|
169
|
+
state_data: state_data
|
|
170
|
+
)
|
|
171
|
+
end
|
|
153
172
|
end
|
|
154
173
|
|
|
155
174
|
driver&.close
|
data/lib/tui_td/version.rb
CHANGED