asciinema_win 0.1.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 +7 -0
- data/README.md +575 -0
- data/exe/asciinema_win +17 -0
- data/lib/asciinema_win/ansi_parser.rb +437 -0
- data/lib/asciinema_win/asciicast.rb +537 -0
- data/lib/asciinema_win/cli.rb +591 -0
- data/lib/asciinema_win/export.rb +780 -0
- data/lib/asciinema_win/output_organizer.rb +276 -0
- data/lib/asciinema_win/player.rb +348 -0
- data/lib/asciinema_win/recorder.rb +480 -0
- data/lib/asciinema_win/screen_buffer.rb +375 -0
- data/lib/asciinema_win/themes.rb +334 -0
- data/lib/asciinema_win/version.rb +6 -0
- data/lib/asciinema_win.rb +153 -0
- data/lib/rich/_palettes.rb +148 -0
- data/lib/rich/box.rb +342 -0
- data/lib/rich/cells.rb +512 -0
- data/lib/rich/color.rb +628 -0
- data/lib/rich/color_triplet.rb +220 -0
- data/lib/rich/console.rb +549 -0
- data/lib/rich/control.rb +332 -0
- data/lib/rich/json.rb +254 -0
- data/lib/rich/layout.rb +314 -0
- data/lib/rich/markdown.rb +509 -0
- data/lib/rich/markup.rb +175 -0
- data/lib/rich/panel.rb +311 -0
- data/lib/rich/progress.rb +430 -0
- data/lib/rich/segment.rb +387 -0
- data/lib/rich/style.rb +433 -0
- data/lib/rich/syntax.rb +1145 -0
- data/lib/rich/table.rb +525 -0
- data/lib/rich/terminal_theme.rb +126 -0
- data/lib/rich/text.rb +433 -0
- data/lib/rich/tree.rb +220 -0
- data/lib/rich/version.rb +5 -0
- data/lib/rich/win32_console.rb +859 -0
- data/lib/rich.rb +108 -0
- metadata +123 -0
|
@@ -0,0 +1,591 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AsciinemaWin
|
|
4
|
+
# Command-line interface for asciinema-win
|
|
5
|
+
#
|
|
6
|
+
# Provides commands for recording, playing back, and inspecting
|
|
7
|
+
# terminal recordings. Uses only Ruby standard library for argument
|
|
8
|
+
# parsing (no external gems).
|
|
9
|
+
#
|
|
10
|
+
# @example Run the CLI
|
|
11
|
+
# AsciinemaWin::CLI.run(ARGV)
|
|
12
|
+
class CLI
|
|
13
|
+
# Available commands
|
|
14
|
+
COMMANDS = %w[rec play cat info export help version].freeze
|
|
15
|
+
|
|
16
|
+
# ANSI color codes for output
|
|
17
|
+
module Colors
|
|
18
|
+
RESET = "\e[0m"
|
|
19
|
+
BOLD = "\e[1m"
|
|
20
|
+
RED = "\e[31m"
|
|
21
|
+
GREEN = "\e[32m"
|
|
22
|
+
YELLOW = "\e[33m"
|
|
23
|
+
BLUE = "\e[34m"
|
|
24
|
+
CYAN = "\e[36m"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Run the CLI with the given arguments
|
|
28
|
+
#
|
|
29
|
+
# @param args [Array<String>] Command-line arguments
|
|
30
|
+
# @return [Integer] Exit code
|
|
31
|
+
def self.run(args)
|
|
32
|
+
new.run(args)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Run the CLI
|
|
36
|
+
#
|
|
37
|
+
# @param args [Array<String>] Command-line arguments
|
|
38
|
+
# @return [Integer] Exit code
|
|
39
|
+
def run(args)
|
|
40
|
+
if args.empty?
|
|
41
|
+
print_usage
|
|
42
|
+
return 0
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
command = args.shift
|
|
46
|
+
|
|
47
|
+
case command
|
|
48
|
+
when "rec", "record"
|
|
49
|
+
cmd_rec(args)
|
|
50
|
+
when "play"
|
|
51
|
+
cmd_play(args)
|
|
52
|
+
when "cat"
|
|
53
|
+
cmd_cat(args)
|
|
54
|
+
when "info"
|
|
55
|
+
cmd_info(args)
|
|
56
|
+
when "export"
|
|
57
|
+
cmd_export(args)
|
|
58
|
+
when "help", "-h", "--help"
|
|
59
|
+
cmd_help(args)
|
|
60
|
+
when "version", "-v", "--version"
|
|
61
|
+
cmd_version
|
|
62
|
+
else
|
|
63
|
+
error("Unknown command: #{command}")
|
|
64
|
+
print_usage
|
|
65
|
+
1
|
|
66
|
+
end
|
|
67
|
+
rescue StandardError => e
|
|
68
|
+
error(e.message)
|
|
69
|
+
error(e.backtrace.first(5).join("\n")) if ENV["DEBUG"]
|
|
70
|
+
1
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
# =========================================================================
|
|
76
|
+
# Commands
|
|
77
|
+
# =========================================================================
|
|
78
|
+
|
|
79
|
+
# Record command
|
|
80
|
+
#
|
|
81
|
+
# @param args [Array<String>] Command arguments
|
|
82
|
+
# @return [Integer] Exit code
|
|
83
|
+
def cmd_rec(args)
|
|
84
|
+
options = parse_options(args, {
|
|
85
|
+
"t" => :title,
|
|
86
|
+
"title" => :title,
|
|
87
|
+
"c" => :command,
|
|
88
|
+
"command" => :command,
|
|
89
|
+
"i" => :idle_time_limit,
|
|
90
|
+
"idle-time-limit" => :idle_time_limit,
|
|
91
|
+
"y" => :overwrite,
|
|
92
|
+
"overwrite" => :overwrite
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
output_path = args.shift
|
|
96
|
+
|
|
97
|
+
unless output_path
|
|
98
|
+
error("Missing output file path")
|
|
99
|
+
puts "Usage: asciinema_win rec [options] <filename>"
|
|
100
|
+
return 1
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Check if file exists and overwrite not set
|
|
104
|
+
if File.exist?(output_path) && !options[:overwrite]
|
|
105
|
+
error("File already exists: #{output_path}")
|
|
106
|
+
puts "Use -y or --overwrite to overwrite"
|
|
107
|
+
return 1
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Create recorder
|
|
111
|
+
recorder = Recorder.new(
|
|
112
|
+
title: options[:title],
|
|
113
|
+
command: options[:command],
|
|
114
|
+
idle_time_limit: options[:idle_time_limit]&.to_f || Recorder::DEFAULT_IDLE_TIME_LIMIT
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# Start recording
|
|
118
|
+
stats = recorder.record(output_path)
|
|
119
|
+
|
|
120
|
+
success("Recording saved to #{output_path}")
|
|
121
|
+
puts "Duration: #{format("%.2f", stats[:duration])}s"
|
|
122
|
+
puts "Events: #{stats[:event_count]}"
|
|
123
|
+
|
|
124
|
+
0
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Play command
|
|
128
|
+
#
|
|
129
|
+
# @param args [Array<String>] Command arguments
|
|
130
|
+
# @return [Integer] Exit code
|
|
131
|
+
def cmd_play(args)
|
|
132
|
+
options = parse_options(args, {
|
|
133
|
+
"s" => :speed,
|
|
134
|
+
"speed" => :speed,
|
|
135
|
+
"i" => :idle_time_limit,
|
|
136
|
+
"idle-time-limit" => :idle_time_limit,
|
|
137
|
+
"m" => :pause_on_markers,
|
|
138
|
+
"pause-on-markers" => :pause_on_markers
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
input_path = args.shift
|
|
142
|
+
|
|
143
|
+
unless input_path
|
|
144
|
+
error("Missing input file path")
|
|
145
|
+
puts "Usage: asciinema_win play [options] <filename>"
|
|
146
|
+
return 1
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
unless File.exist?(input_path)
|
|
150
|
+
error("File not found: #{input_path}")
|
|
151
|
+
return 1
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Create player
|
|
155
|
+
player = Player.new(
|
|
156
|
+
speed: options[:speed]&.to_f || 1.0,
|
|
157
|
+
idle_time_limit: options[:idle_time_limit]&.to_f,
|
|
158
|
+
pause_on_markers: !!options[:pause_on_markers]
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
# Start playback
|
|
162
|
+
player.play(input_path)
|
|
163
|
+
|
|
164
|
+
0
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Cat command (output without timing)
|
|
168
|
+
#
|
|
169
|
+
# @param args [Array<String>] Command arguments
|
|
170
|
+
# @return [Integer] Exit code
|
|
171
|
+
def cmd_cat(args)
|
|
172
|
+
input_path = args.shift
|
|
173
|
+
|
|
174
|
+
unless input_path
|
|
175
|
+
error("Missing input file path")
|
|
176
|
+
puts "Usage: asciinema_win cat <filename>"
|
|
177
|
+
return 1
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
unless File.exist?(input_path)
|
|
181
|
+
error("File not found: #{input_path}")
|
|
182
|
+
return 1
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Use raw player for immediate output
|
|
186
|
+
player = RawPlayer.new
|
|
187
|
+
player.play(input_path)
|
|
188
|
+
|
|
189
|
+
0
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Info command
|
|
193
|
+
#
|
|
194
|
+
# @param args [Array<String>] Command arguments
|
|
195
|
+
# @return [Integer] Exit code
|
|
196
|
+
def cmd_info(args)
|
|
197
|
+
input_path = args.shift
|
|
198
|
+
|
|
199
|
+
unless input_path
|
|
200
|
+
error("Missing input file path")
|
|
201
|
+
puts "Usage: asciinema_win info <filename>"
|
|
202
|
+
return 1
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
unless File.exist?(input_path)
|
|
206
|
+
error("File not found: #{input_path}")
|
|
207
|
+
return 1
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# Get info
|
|
211
|
+
info_data = Asciicast::Reader.info(input_path)
|
|
212
|
+
|
|
213
|
+
# Print info
|
|
214
|
+
puts "#{Colors::BOLD}File:#{Colors::RESET} #{input_path}"
|
|
215
|
+
puts "#{Colors::BOLD}Version:#{Colors::RESET} #{info_data[:version]}"
|
|
216
|
+
puts "#{Colors::BOLD}Size:#{Colors::RESET} #{info_data[:width]}x#{info_data[:height]}"
|
|
217
|
+
puts "#{Colors::BOLD}Duration:#{Colors::RESET} #{format("%.2f", info_data[:duration])}s"
|
|
218
|
+
puts "#{Colors::BOLD}Events:#{Colors::RESET} #{info_data[:event_count]}"
|
|
219
|
+
|
|
220
|
+
if info_data[:title]
|
|
221
|
+
puts "#{Colors::BOLD}Title:#{Colors::RESET} #{info_data[:title]}"
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
if info_data[:command]
|
|
225
|
+
puts "#{Colors::BOLD}Command:#{Colors::RESET} #{info_data[:command]}"
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
if info_data[:timestamp]
|
|
229
|
+
time = Time.at(info_data[:timestamp])
|
|
230
|
+
puts "#{Colors::BOLD}Recorded:#{Colors::RESET} #{time.strftime("%Y-%m-%d %H:%M:%S")}"
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
if info_data[:idle_time_limit]
|
|
234
|
+
puts "#{Colors::BOLD}Idle limit:#{Colors::RESET} #{info_data[:idle_time_limit]}s"
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
unless info_data[:env].empty?
|
|
238
|
+
puts "#{Colors::BOLD}Environment:#{Colors::RESET}"
|
|
239
|
+
info_data[:env].each do |key, value|
|
|
240
|
+
puts " #{key}=#{value}"
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
0
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# Export command
|
|
248
|
+
#
|
|
249
|
+
# @param args [Array<String>] Command arguments
|
|
250
|
+
# @return [Integer] Exit code
|
|
251
|
+
def cmd_export(args)
|
|
252
|
+
options = parse_options(args, {
|
|
253
|
+
"f" => :format,
|
|
254
|
+
"format" => :format,
|
|
255
|
+
"o" => :output,
|
|
256
|
+
"output" => :output,
|
|
257
|
+
"t" => :title,
|
|
258
|
+
"title" => :title
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
input_path = args.shift
|
|
262
|
+
|
|
263
|
+
unless input_path
|
|
264
|
+
error("Missing input file path")
|
|
265
|
+
puts "Usage: asciinema_win export [options] <input.cast> [-o output]"
|
|
266
|
+
return 1
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
unless File.exist?(input_path)
|
|
270
|
+
error("File not found: #{input_path}")
|
|
271
|
+
return 1
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
# Determine format from output extension or option
|
|
275
|
+
output_path = options[:output]
|
|
276
|
+
format = options[:format]&.to_sym
|
|
277
|
+
|
|
278
|
+
unless output_path
|
|
279
|
+
# Default output based on format
|
|
280
|
+
format ||= :html
|
|
281
|
+
ext = format == :text ? ".txt" : ".#{format}"
|
|
282
|
+
output_path = input_path.sub(/\.cast$/, ext)
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
unless format
|
|
286
|
+
# Infer from output extension
|
|
287
|
+
ext = File.extname(output_path).downcase
|
|
288
|
+
format = case ext
|
|
289
|
+
when ".html" then :html
|
|
290
|
+
when ".svg" then :svg
|
|
291
|
+
when ".txt" then :text
|
|
292
|
+
when ".json" then :json
|
|
293
|
+
when ".gif" then :gif
|
|
294
|
+
when ".mp4" then :mp4
|
|
295
|
+
when ".webm" then :webm
|
|
296
|
+
else :html
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
puts "Exporting #{input_path} to #{output_path} (#{format})..."
|
|
301
|
+
|
|
302
|
+
Export.export(input_path, output_path, format: format, title: options[:title])
|
|
303
|
+
|
|
304
|
+
success("Exported to #{output_path}")
|
|
305
|
+
0
|
|
306
|
+
rescue ExportError => e
|
|
307
|
+
error(e.message)
|
|
308
|
+
1
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
# Help command
|
|
312
|
+
#
|
|
313
|
+
# @param args [Array<String>] Command arguments
|
|
314
|
+
# @return [Integer] Exit code
|
|
315
|
+
def cmd_help(args)
|
|
316
|
+
command = args.shift
|
|
317
|
+
|
|
318
|
+
case command
|
|
319
|
+
when "rec", "record"
|
|
320
|
+
print_rec_help
|
|
321
|
+
when "play"
|
|
322
|
+
print_play_help
|
|
323
|
+
when "cat"
|
|
324
|
+
print_cat_help
|
|
325
|
+
when "info"
|
|
326
|
+
print_info_help
|
|
327
|
+
when "export"
|
|
328
|
+
print_export_help
|
|
329
|
+
else
|
|
330
|
+
print_usage
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
0
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
# Version command
|
|
337
|
+
#
|
|
338
|
+
# @return [Integer] Exit code
|
|
339
|
+
def cmd_version
|
|
340
|
+
puts "asciinema-win #{VERSION}"
|
|
341
|
+
puts "Ruby #{RUBY_VERSION} (#{RUBY_PLATFORM})"
|
|
342
|
+
0
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
# =========================================================================
|
|
346
|
+
# Option Parsing
|
|
347
|
+
# =========================================================================
|
|
348
|
+
|
|
349
|
+
# Parse command-line options
|
|
350
|
+
#
|
|
351
|
+
# @param args [Array<String>] Arguments (modified in place)
|
|
352
|
+
# @param valid_options [Hash] Map of option names to symbols
|
|
353
|
+
# @return [Hash] Parsed options
|
|
354
|
+
def parse_options(args, valid_options)
|
|
355
|
+
options = {}
|
|
356
|
+
remaining = []
|
|
357
|
+
|
|
358
|
+
i = 0
|
|
359
|
+
while i < args.length
|
|
360
|
+
arg = args[i]
|
|
361
|
+
|
|
362
|
+
if arg.start_with?("--")
|
|
363
|
+
# Long option
|
|
364
|
+
key = arg[2..]
|
|
365
|
+
if key.include?("=")
|
|
366
|
+
key, value = key.split("=", 2)
|
|
367
|
+
else
|
|
368
|
+
value = nil
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
sym = valid_options[key]
|
|
372
|
+
if sym
|
|
373
|
+
if value.nil? && i + 1 < args.length && !args[i + 1].start_with?("-")
|
|
374
|
+
i += 1
|
|
375
|
+
value = args[i]
|
|
376
|
+
end
|
|
377
|
+
options[sym] = value || true
|
|
378
|
+
else
|
|
379
|
+
remaining << arg
|
|
380
|
+
end
|
|
381
|
+
elsif arg.start_with?("-") && arg.length > 1
|
|
382
|
+
# Short option
|
|
383
|
+
key = arg[1]
|
|
384
|
+
value = arg.length > 2 ? arg[2..] : nil
|
|
385
|
+
|
|
386
|
+
sym = valid_options[key]
|
|
387
|
+
if sym
|
|
388
|
+
if value.nil? && i + 1 < args.length && !args[i + 1].start_with?("-")
|
|
389
|
+
i += 1
|
|
390
|
+
value = args[i]
|
|
391
|
+
end
|
|
392
|
+
options[sym] = value || true
|
|
393
|
+
else
|
|
394
|
+
remaining << arg
|
|
395
|
+
end
|
|
396
|
+
else
|
|
397
|
+
remaining << arg
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
i += 1
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
args.replace(remaining)
|
|
404
|
+
options
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
# =========================================================================
|
|
408
|
+
# Help Text
|
|
409
|
+
# =========================================================================
|
|
410
|
+
|
|
411
|
+
# Print main usage
|
|
412
|
+
def print_usage
|
|
413
|
+
puts <<~USAGE
|
|
414
|
+
#{Colors::BOLD}asciinema-win#{Colors::RESET} - Native Windows terminal recorder
|
|
415
|
+
|
|
416
|
+
#{Colors::BOLD}USAGE:#{Colors::RESET}
|
|
417
|
+
asciinema_win <command> [options]
|
|
418
|
+
|
|
419
|
+
#{Colors::BOLD}COMMANDS:#{Colors::RESET}
|
|
420
|
+
rec Record terminal session
|
|
421
|
+
play Play back a recording
|
|
422
|
+
cat Output recording to stdout (no timing)
|
|
423
|
+
info Show recording metadata
|
|
424
|
+
export Export to HTML, SVG, text, or video
|
|
425
|
+
help Show help for a command
|
|
426
|
+
version Show version information
|
|
427
|
+
|
|
428
|
+
#{Colors::BOLD}EXAMPLES:#{Colors::RESET}
|
|
429
|
+
asciinema_win rec session.cast
|
|
430
|
+
asciinema_win rec -c "dir /s" output.cast
|
|
431
|
+
asciinema_win play session.cast
|
|
432
|
+
asciinema_win play -s 2 session.cast
|
|
433
|
+
asciinema_win info session.cast
|
|
434
|
+
|
|
435
|
+
#{Colors::BOLD}OPTIONS:#{Colors::RESET}
|
|
436
|
+
-h, --help Show help
|
|
437
|
+
-v, --version Show version
|
|
438
|
+
|
|
439
|
+
Run 'asciinema_win help <command>' for command-specific help.
|
|
440
|
+
USAGE
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
# Print rec command help
|
|
444
|
+
def print_rec_help
|
|
445
|
+
puts <<~HELP
|
|
446
|
+
#{Colors::BOLD}asciinema_win rec#{Colors::RESET} - Record terminal session
|
|
447
|
+
|
|
448
|
+
#{Colors::BOLD}USAGE:#{Colors::RESET}
|
|
449
|
+
asciinema_win rec [options] <filename>
|
|
450
|
+
|
|
451
|
+
#{Colors::BOLD}DESCRIPTION:#{Colors::RESET}
|
|
452
|
+
Record terminal session and save it to a file. Press Ctrl+D to stop
|
|
453
|
+
recording. The recording is saved in asciicast v2 format, compatible
|
|
454
|
+
with asciinema.org.
|
|
455
|
+
|
|
456
|
+
#{Colors::BOLD}OPTIONS:#{Colors::RESET}
|
|
457
|
+
-t, --title <title> Recording title
|
|
458
|
+
-c, --command <cmd> Record specific command instead of interactive session
|
|
459
|
+
-i, --idle-time-limit Maximum idle time between events (default: 2.0s)
|
|
460
|
+
-y, --overwrite Overwrite existing file
|
|
461
|
+
|
|
462
|
+
#{Colors::BOLD}EXAMPLES:#{Colors::RESET}
|
|
463
|
+
asciinema_win rec demo.cast
|
|
464
|
+
asciinema_win rec -t "My Demo" demo.cast
|
|
465
|
+
asciinema_win rec -c "ping localhost" network.cast
|
|
466
|
+
asciinema_win rec -i 1.0 fast.cast
|
|
467
|
+
HELP
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
# Print play command help
|
|
471
|
+
def print_play_help
|
|
472
|
+
puts <<~HELP
|
|
473
|
+
#{Colors::BOLD}asciinema_win play#{Colors::RESET} - Play back a recording
|
|
474
|
+
|
|
475
|
+
#{Colors::BOLD}USAGE:#{Colors::RESET}
|
|
476
|
+
asciinema_win play [options] <filename>
|
|
477
|
+
|
|
478
|
+
#{Colors::BOLD}DESCRIPTION:#{Colors::RESET}
|
|
479
|
+
Play back a terminal recording with accurate timing. Press Ctrl+C
|
|
480
|
+
to stop playback.
|
|
481
|
+
|
|
482
|
+
#{Colors::BOLD}OPTIONS:#{Colors::RESET}
|
|
483
|
+
-s, --speed <factor> Playback speed (default: 1.0)
|
|
484
|
+
-i, --idle-time-limit <s> Max idle time between frames
|
|
485
|
+
-m, --pause-on-markers Pause at marker events
|
|
486
|
+
|
|
487
|
+
#{Colors::BOLD}EXAMPLES:#{Colors::RESET}
|
|
488
|
+
asciinema_win play demo.cast
|
|
489
|
+
asciinema_win play -s 2 demo.cast # 2x speed
|
|
490
|
+
asciinema_win play -s 0.5 demo.cast # Half speed
|
|
491
|
+
asciinema_win play -i 0.5 demo.cast # Max 0.5s idle
|
|
492
|
+
HELP
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
# Print cat command help
|
|
496
|
+
def print_cat_help
|
|
497
|
+
puts <<~HELP
|
|
498
|
+
#{Colors::BOLD}asciinema_win cat#{Colors::RESET} - Output recording to stdout
|
|
499
|
+
|
|
500
|
+
#{Colors::BOLD}USAGE:#{Colors::RESET}
|
|
501
|
+
asciinema_win cat <filename>
|
|
502
|
+
|
|
503
|
+
#{Colors::BOLD}DESCRIPTION:#{Colors::RESET}
|
|
504
|
+
Output the recording to stdout without timing. Useful for piping
|
|
505
|
+
to other tools or capturing the final output.
|
|
506
|
+
|
|
507
|
+
#{Colors::BOLD}EXAMPLES:#{Colors::RESET}
|
|
508
|
+
asciinema_win cat demo.cast
|
|
509
|
+
asciinema_win cat demo.cast | more
|
|
510
|
+
asciinema_win cat demo.cast > output.txt
|
|
511
|
+
HELP
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
# Print info command help
|
|
515
|
+
def print_info_help
|
|
516
|
+
puts <<~HELP
|
|
517
|
+
#{Colors::BOLD}asciinema_win info#{Colors::RESET} - Show recording metadata
|
|
518
|
+
|
|
519
|
+
#{Colors::BOLD}USAGE:#{Colors::RESET}
|
|
520
|
+
asciinema_win info <filename>
|
|
521
|
+
|
|
522
|
+
#{Colors::BOLD}DESCRIPTION:#{Colors::RESET}
|
|
523
|
+
Display metadata about a recording, including duration, dimensions,
|
|
524
|
+
title, and environment variables.
|
|
525
|
+
|
|
526
|
+
#{Colors::BOLD}EXAMPLES:#{Colors::RESET}
|
|
527
|
+
asciinema_win info demo.cast
|
|
528
|
+
HELP
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
# Print export command help
|
|
532
|
+
def print_export_help
|
|
533
|
+
puts <<~HELP
|
|
534
|
+
#{Colors::BOLD}asciinema_win export#{Colors::RESET} - Export recording to other formats
|
|
535
|
+
|
|
536
|
+
#{Colors::BOLD}USAGE:#{Colors::RESET}
|
|
537
|
+
asciinema_win export [options] <filename>
|
|
538
|
+
|
|
539
|
+
#{Colors::BOLD}DESCRIPTION:#{Colors::RESET}
|
|
540
|
+
Export a recording to different formats. Native formats (cast, HTML,
|
|
541
|
+
SVG, text, JSON) require no external dependencies. Video formats
|
|
542
|
+
(GIF, MP4, WebM) require FFmpeg to be installed.
|
|
543
|
+
|
|
544
|
+
#{Colors::BOLD}FORMATS:#{Colors::RESET}
|
|
545
|
+
cast asciicast v2 (copy or transform)
|
|
546
|
+
html Standalone HTML with embedded asciinema-player
|
|
547
|
+
svg SVG image (static snapshot)
|
|
548
|
+
txt Plain text (ANSI codes stripped)
|
|
549
|
+
json Normalized JSON format
|
|
550
|
+
gif Animated GIF (requires FFmpeg)
|
|
551
|
+
mp4 MP4 video (requires FFmpeg)
|
|
552
|
+
webm WebM video (requires FFmpeg)
|
|
553
|
+
|
|
554
|
+
#{Colors::BOLD}OPTIONS:#{Colors::RESET}
|
|
555
|
+
-f, --format <fmt> Output format (default: inferred from extension)
|
|
556
|
+
-o, --output <file> Output file path
|
|
557
|
+
-t, --title <title> Title for HTML export or cast transform
|
|
558
|
+
|
|
559
|
+
#{Colors::BOLD}EXAMPLES:#{Colors::RESET}
|
|
560
|
+
asciinema_win export demo.cast -o demo.html
|
|
561
|
+
asciinema_win export demo.cast -f svg -o preview.svg
|
|
562
|
+
asciinema_win export demo.cast -f cast -t "New Title" -o renamed.cast
|
|
563
|
+
HELP
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
# =========================================================================
|
|
567
|
+
# Output Helpers
|
|
568
|
+
# =========================================================================
|
|
569
|
+
|
|
570
|
+
# Print error message
|
|
571
|
+
#
|
|
572
|
+
# @param message [String] Error message
|
|
573
|
+
def error(message)
|
|
574
|
+
$stderr.puts "#{Colors::RED}Error:#{Colors::RESET} #{message}"
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
# Print success message
|
|
578
|
+
#
|
|
579
|
+
# @param message [String] Success message
|
|
580
|
+
def success(message)
|
|
581
|
+
puts "#{Colors::GREEN}#{message}#{Colors::RESET}"
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
# Print warning message
|
|
585
|
+
#
|
|
586
|
+
# @param message [String] Warning message
|
|
587
|
+
def warning(message)
|
|
588
|
+
puts "#{Colors::YELLOW}Warning:#{Colors::RESET} #{message}"
|
|
589
|
+
end
|
|
590
|
+
end
|
|
591
|
+
end
|