kaitai-struct-visualizer 0.5 → 0.11
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 +5 -5
- data/LICENSE +4 -4
- data/README.md +88 -28
- data/bin/ksdump +96 -0
- data/bin/ksv +53 -7
- data/lib/kaitai/console_ansi.rb +103 -98
- data/lib/kaitai/console_windows.rb +175 -230
- data/lib/kaitai/struct/visualizer/hex_viewer.rb +250 -241
- data/lib/kaitai/struct/visualizer/ks_error_matcher.rb +44 -0
- data/lib/kaitai/struct/visualizer/ksy_compiler.rb +243 -0
- data/lib/kaitai/struct/visualizer/node.rb +241 -225
- data/lib/kaitai/struct/visualizer/obj_to_h.rb +40 -0
- data/lib/kaitai/struct/visualizer/parser.rb +40 -0
- data/lib/kaitai/struct/visualizer/tree.rb +179 -198
- data/lib/kaitai/struct/visualizer/version.rb +3 -1
- data/lib/kaitai/struct/visualizer/visualizer.rb +10 -31
- data/lib/kaitai/struct/visualizer.rb +4 -1
- data/lib/kaitai/tui.rb +85 -94
- metadata +58 -27
- data/kaitai-struct-visualizer.gemspec +0 -37
- data/lib/kaitai/struct/visualizer/visualizer_main.rb +0 -42
- data/lib/kaitai/struct/visualizer/visualizer_ruby.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a4e2b67e9f53f3b692de0e98c7c46c9106c2c88e001ef228e0bd3351f83037d2
|
4
|
+
data.tar.gz: 623ee7e33ececcc081b5309746dd8ac9e557e5bc57ae52e3229e71e8ae5a94cf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b7ce146db58aab7d2a3c356263e4fde24a3f52517c729329beca1e6e1a26ae7d9b7ad4de84d0320d8b06f9c81054035a3d4a07dee5b61f6834f7f0adfc39c61a
|
7
|
+
data.tar.gz: '0867f535300fe5ae4d54bbd11562915249b35d51ff6cb57adae13a343c985c34d40cb916be25fe2baf3f111c9ca055bb2c9d5190ccd44bf640aa3b8df4e314fe'
|
data/LICENSE
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
GNU GENERAL PUBLIC LICENSE
|
2
2
|
Version 3, 29 June 2007
|
3
3
|
|
4
|
-
Copyright (C) 2007 Free Software Foundation, Inc. <
|
4
|
+
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
5
5
|
Everyone is permitted to copy and distribute verbatim copies
|
6
6
|
of this license document, but changing it is not allowed.
|
7
7
|
|
@@ -645,7 +645,7 @@ the "copyright" line and a pointer to where the full notice is found.
|
|
645
645
|
GNU General Public License for more details.
|
646
646
|
|
647
647
|
You should have received a copy of the GNU General Public License
|
648
|
-
along with this program. If not, see <
|
648
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
649
649
|
|
650
650
|
Also add information on how to contact you by electronic and paper mail.
|
651
651
|
|
@@ -664,11 +664,11 @@ might be different; for a GUI interface, you would use an "about box".
|
|
664
664
|
You should also get your employer (if you work as a programmer) or school,
|
665
665
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
666
666
|
For more information on this, and how to apply and follow the GNU GPL, see
|
667
|
-
<
|
667
|
+
<https://www.gnu.org/licenses/>.
|
668
668
|
|
669
669
|
The GNU General Public License does not permit incorporating your program
|
670
670
|
into proprietary programs. If your program is a subroutine library, you
|
671
671
|
may consider it more useful to permit linking proprietary applications with
|
672
672
|
the library. If this is what you want to do, use the GNU Lesser General
|
673
673
|
Public License instead of this License. But first, please read
|
674
|
-
<
|
674
|
+
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
data/README.md
CHANGED
@@ -1,65 +1,125 @@
|
|
1
1
|
# Kaitai Struct: visualizer
|
2
2
|
|
3
|
-
This is a
|
3
|
+
This is a console visualizer for the [Kaitai Struct](https://kaitai.io/) project.
|
4
|
+
|
5
|
+

|
4
6
|
|
5
7
|
Kaitai Struct is a declarative language used for describe various
|
6
8
|
binary data structures, laid out in files or in memory: i.e. binary
|
7
9
|
file formats, network stream packet formats, etc.
|
8
10
|
|
9
11
|
The main idea is that a particular format is described in Kaitai
|
10
|
-
Struct language (`.ksy`
|
11
|
-
|
12
|
-
languages. These modules will
|
13
|
-
that can read described data structure from a file / stream and
|
14
|
-
access to it
|
12
|
+
Struct language (`.ksy` file) and then can be compiled with
|
13
|
+
`ksc` into source files in one of the supported programming
|
14
|
+
languages. These modules will contain generated code for a parser
|
15
|
+
that can read the described data structure from a file / stream and provide
|
16
|
+
access to it using a nice, easy-to-understand API.
|
15
17
|
|
16
|
-
|
17
|
-
for details on `.ksy` files and general usage patterns.
|
18
|
+
See the [Kaitai Struct homepage](https://kaitai.io/) for details on `.ksy` files and general usage patterns.
|
18
19
|
|
19
20
|
## Downloading and installing
|
20
21
|
|
21
|
-
###
|
22
|
+
### Requirements
|
23
|
+
|
24
|
+
- [ksc](https://kaitai.io/#download) — `kaitai-struct-compiler`
|
25
|
+
- [Java](https://whichjdk.com/) (the latest LTS version 21 recommended, at least Java 8 required),
|
26
|
+
[JDK or JRE](https://whichjdk.com/#what-is-the-difference-between-jdk-and-jre) at your option
|
27
|
+
- [Ruby](https://www.ruby-lang.org/) (the latest Ruby 3.x recommended, at least Ruby 2.4 required)
|
28
|
+
|
29
|
+
### From the RubyGems repository
|
22
30
|
|
23
|
-
|
24
|
-
available
|
25
|
-
|
26
|
-
you'll need Ruby (RubyGems package manager comes bundled with Ruby
|
27
|
-
since v1.9) installed on your box, and then you can just run:
|
31
|
+
Kaitai Struct visualizer is written in [Ruby](https://www.ruby-lang.org/) and is
|
32
|
+
available [on RubyGems](https://rubygems.org/gems/kaitai-struct-visualizer). Thus,
|
33
|
+
you'll need Ruby installed on your box and then you can just run:
|
28
34
|
|
29
35
|
```shell
|
30
36
|
gem install kaitai-struct-visualizer
|
31
37
|
```
|
32
38
|
|
39
|
+
---
|
40
|
+
|
41
|
+
You can use `ksv --version` to check what versions of `ksv` and its dependencies are installed, for example:
|
42
|
+
|
43
|
+
```console
|
44
|
+
$ ksv --version
|
45
|
+
kaitai-struct-visualizer 0.11
|
46
|
+
kaitai-struct-compiler 0.11
|
47
|
+
kaitai-struct 0.11 (Kaitai Struct runtime library for Ruby)
|
48
|
+
```
|
49
|
+
|
50
|
+
The versions of `kaitai-struct-compiler` and `kaitai-struct` should match. If not, see https://kaitai.io/#download for instructions how to install the latest version of `kaitai-struct-compiler` and/or use `gem update kaitai-struct` to update the [kaitai-struct](https://rubygems.org/gems/kaitai-struct) gem if needed.
|
51
|
+
|
33
52
|
### Source code
|
34
53
|
|
35
54
|
If you're interested in developing the visualizer itself, you can check
|
36
|
-
out source code
|
55
|
+
out the source code from the [kaitai_struct_visualizer](https://github.com/kaitai-io/kaitai_struct_visualizer) GitHub repository:
|
37
56
|
|
38
|
-
|
57
|
+
```shell
|
58
|
+
git clone https://github.com/kaitai-io/kaitai_struct_visualizer.git
|
59
|
+
```
|
60
|
+
|
61
|
+
Then run `bundle install` to install dependencies. After that, you can run [`bin/ksv`](bin/ksv) or [`bin/ksdump`](bin/ksdump) right away (without having to install the `kaitai-struct-visualizer` gem first), which makes development easier.
|
39
62
|
|
40
63
|
## Usage
|
41
64
|
|
42
|
-
|
65
|
+
There are two executables provided by this package:
|
66
|
+
|
67
|
+
* `ksv` — interactive console visualizer with GUI
|
68
|
+
* `ksdump` — command-line tool for dumping parsed data in JSON, XML or YAML format to standard output (_stdout_)
|
69
|
+
|
70
|
+
The basic usage is similar for both programs:
|
71
|
+
|
72
|
+
```shell
|
73
|
+
ksv <file_to_parse.bin> <format.ksy>|<format.rb>
|
74
|
+
```
|
75
|
+
|
76
|
+
For `ksdump`, it may be useful to change the output format with the `-f` option (the default is `yaml`) and redirect the output to a file so that your terminal is not flooded with thousands of lines (for larger input files):
|
77
|
+
|
78
|
+
```shell
|
79
|
+
ksdump -f json <file_to_parse.bin> <format.ksy> > output.json
|
80
|
+
```
|
81
|
+
|
82
|
+
### Running with Docker
|
83
|
+
|
84
|
+
This project is also available via the [kaitai/ksv](https://hub.docker.com/r/kaitai/ksv) image on Docker Hub. The default entrypoint is `ksv` (the interactive visualizer):
|
85
|
+
|
86
|
+
```shell
|
87
|
+
docker run --rm -it -v "$(pwd):/share" kaitai/ksv <file_to_parse.bin> <format.ksy>
|
88
|
+
```
|
89
|
+
|
90
|
+
You can specify `ksdump` as the entrypoint like this (and note that we don't need the `-it` flags anymore because `ksdump` is not interactive — omitting them in fact allows you to distinguish the `ksdump`'s output to _stdout_ and _stderr_, see [this comment](https://github.com/kaitai-io/kaitai_struct_visualizer/issues/56#issuecomment-1666629764)):
|
91
|
+
|
92
|
+
```shell
|
93
|
+
docker run --rm -v "$(pwd):/share" --entrypoint ksdump kaitai/ksv -f json <file_to_parse.bin> <format.ksy> > output.json
|
94
|
+
```
|
95
|
+
|
96
|
+
---
|
97
|
+
|
98
|
+
Building the Docker image locally:
|
99
|
+
```shell
|
100
|
+
docker build . --tag docker.io/kaitai/ksv
|
101
|
+
```
|
43
102
|
|
44
103
|
## Licensing
|
45
104
|
|
46
|
-
Kaitai Struct visualizer
|
47
|
-
Project.
|
105
|
+
Kaitai Struct visualizer is copyright (C) 2015-2025 Kaitai Project.
|
48
106
|
|
49
107
|
This program is free software: you can redistribute it and/or modify
|
50
108
|
it under the terms of the GNU General Public License as published by
|
51
|
-
the Free Software Foundation, either version 3 of the License, or
|
52
|
-
your option) any later version.
|
109
|
+
the Free Software Foundation, either version 3 of the License, or
|
110
|
+
(at your option) any later version.
|
53
111
|
|
54
|
-
This program is distributed in the hope that it will be useful,
|
55
|
-
WITHOUT ANY WARRANTY; without even the implied warranty of
|
56
|
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
57
|
-
General Public License for more details.
|
112
|
+
This program is distributed in the hope that it will be useful,
|
113
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
114
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
115
|
+
GNU General Public License for more details.
|
58
116
|
|
59
117
|
You should have received a copy of the GNU General Public License
|
60
|
-
along with this program. If not, see <
|
118
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
119
|
+
|
120
|
+
---
|
61
121
|
|
62
|
-
Note that it applies only to
|
122
|
+
Note that it applies only to visualizer itself, not `.ksy` input files
|
63
123
|
that one supplies in normal process of compilation, nor to compiler's
|
64
|
-
output files — that
|
124
|
+
output files — that constitutes normal usage process and you obviously
|
65
125
|
keep copyright to both.
|
data/bin/ksdump
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
# Some additional magic to make it work right after repo checkout,
|
7
|
+
# without installation to proper Ruby library dirs
|
8
|
+
|
9
|
+
# The `__dir__` method is supposed to provide the real absolute path of the
|
10
|
+
# `bin/` directory (which this script is in), but it can technically return
|
11
|
+
# `nil` or a dot `"."` (in an "irb" session) instead. Normally, it shouldn't
|
12
|
+
# happen unless some very unusual startup method is used, but if it happens,
|
13
|
+
# we'll skip adding the dirs to $LOAD_PATH and wait for a miracle (which might
|
14
|
+
# be that the dependencies we need are already available via $LOAD_PATH because
|
15
|
+
# they are installed as gems, for example).
|
16
|
+
#
|
17
|
+
# See also
|
18
|
+
# * https://stackoverflow.com/a/2206731
|
19
|
+
# * https://makandracards.com/makandra/42122-ruby-__file__-__dir__-and-symlinks
|
20
|
+
script_dir = __dir__
|
21
|
+
unless script_dir.nil? || script_dir == '.'
|
22
|
+
$LOAD_PATH << File.expand_path('../lib', script_dir)
|
23
|
+
$LOAD_PATH << File.expand_path('../../runtime/ruby/lib', script_dir)
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'kaitai/struct/visualizer'
|
27
|
+
require 'kaitai/struct/visualizer/obj_to_h'
|
28
|
+
|
29
|
+
# ======================================================================
|
30
|
+
|
31
|
+
FORMATS = %w[json xml yaml].freeze
|
32
|
+
|
33
|
+
prog_name = File.basename($PROGRAM_NAME)
|
34
|
+
options = { format: 'yaml' }
|
35
|
+
parser = OptionParser.new do |opts|
|
36
|
+
opts.banner = "Usage: #{prog_name} [options] <file_to_parse.bin> <format.ksy>..."
|
37
|
+
opts.separator ''
|
38
|
+
|
39
|
+
opts.on('-I', '--import-path [DIRECTORIES]', '.ksy library search path(s) for imports (see also KSPATH env variable)') do |v|
|
40
|
+
options[:import_path] = v
|
41
|
+
end
|
42
|
+
|
43
|
+
opts.on('-f', '--format FORMAT', FORMATS, "choose dump format - #{FORMATS.join(', ')} (default: #{options[:format]})") do |v|
|
44
|
+
options[:format] = v
|
45
|
+
end
|
46
|
+
|
47
|
+
opts.on('--version', 'show versions of kaitai-struct-visualizer, kaitai-struct-compiler and kaitai-struct (Kaitai Struct runtime library for Ruby)') do |_v|
|
48
|
+
puts "kaitai-struct-visualizer #{Kaitai::Struct::Visualizer::VERSION}"
|
49
|
+
if system('kaitai-struct-compiler', '--version').nil?
|
50
|
+
$stderr.puts "#{prog_name}: unable to find and execute kaitai-struct-compiler in your PATH"
|
51
|
+
exit 1
|
52
|
+
end
|
53
|
+
require 'kaitai/struct/struct'
|
54
|
+
puts "kaitai-struct #{Kaitai::Struct::VERSION} (Kaitai Struct runtime library for Ruby)"
|
55
|
+
exit 0
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
begin
|
60
|
+
parser.parse!
|
61
|
+
rescue OptionParser::InvalidOption => e
|
62
|
+
puts e
|
63
|
+
puts parser
|
64
|
+
exit 1
|
65
|
+
end
|
66
|
+
|
67
|
+
if ARGV.size < 2
|
68
|
+
puts parser
|
69
|
+
exit 1
|
70
|
+
end
|
71
|
+
|
72
|
+
c = Kaitai::Struct::Visualizer::KSYCompiler.new(options, prog_name)
|
73
|
+
app = Kaitai::Struct::Visualizer::Parser.new(c, ARGV[0], ARGV[1..-1], options)
|
74
|
+
exc = app.load
|
75
|
+
raise exc if exc
|
76
|
+
|
77
|
+
# ======================================================================
|
78
|
+
|
79
|
+
tree = Kaitai::Struct::Visualizer.obj_to_h(app.data)
|
80
|
+
r = nil
|
81
|
+
|
82
|
+
case options[:format]
|
83
|
+
when 'json'
|
84
|
+
require 'json'
|
85
|
+
r = JSON.pretty_generate(tree)
|
86
|
+
when 'xml'
|
87
|
+
require 'active_support'
|
88
|
+
require 'active_support/core_ext'
|
89
|
+
r = tree.to_xml
|
90
|
+
when 'yaml'
|
91
|
+
require 'yaml'
|
92
|
+
r = tree.to_yaml
|
93
|
+
r = r[4..-1] if r[0..3] == "---\n"
|
94
|
+
end
|
95
|
+
|
96
|
+
puts r
|
data/bin/ksv
CHANGED
@@ -1,20 +1,66 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'optparse'
|
2
5
|
|
3
6
|
# Some additional magic to make it work right after repo checkout,
|
4
7
|
# without installation to proper Ruby library dirs
|
5
8
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
$LOAD_PATH <<
|
10
|
-
$LOAD_PATH <<
|
9
|
+
# See `bin/ksdump` for more comments
|
10
|
+
script_dir = __dir__
|
11
|
+
unless script_dir.nil? || script_dir == '.'
|
12
|
+
$LOAD_PATH << File.expand_path('../lib', script_dir)
|
13
|
+
$LOAD_PATH << File.expand_path('../../runtime/ruby/lib', script_dir)
|
14
|
+
end
|
11
15
|
|
12
16
|
require 'kaitai/struct/visualizer'
|
13
17
|
|
18
|
+
# ======================================================================
|
19
|
+
|
20
|
+
prog_name = File.basename($PROGRAM_NAME)
|
21
|
+
options = {}
|
22
|
+
parser = OptionParser.new do |opts|
|
23
|
+
opts.banner = "Usage: #{File.basename($PROGRAM_NAME)} [options] <file_to_parse.bin> <format.ksy>...|<format.rb>"
|
24
|
+
opts.separator ''
|
25
|
+
|
26
|
+
opts.on('-I', '--import-path [DIRECTORIES]', '.ksy library search path(s) for imports (see also KSPATH env variable)') do |v|
|
27
|
+
options[:import_path] = v
|
28
|
+
end
|
29
|
+
|
30
|
+
opts.on('--opaque-types [BOOLEAN]', 'opaque types allowed, default: false') do |v|
|
31
|
+
options[:opaque_types] = v
|
32
|
+
end
|
33
|
+
|
34
|
+
opts.on('-r', '--require [PATH]', 'load ("require") .rb file into Ruby process') do |v|
|
35
|
+
$LOAD_PATH << '.' unless $LOAD_PATH.include?('.')
|
36
|
+
require v
|
37
|
+
end
|
38
|
+
|
39
|
+
opts.on('--version', 'show versions of kaitai-struct-visualizer, kaitai-struct-compiler and kaitai-struct (Kaitai Struct runtime library for Ruby)') do |_v|
|
40
|
+
puts "kaitai-struct-visualizer #{Kaitai::Struct::Visualizer::VERSION}"
|
41
|
+
if system('kaitai-struct-compiler', '--version').nil?
|
42
|
+
$stderr.puts "#{prog_name}: unable to find and execute kaitai-struct-compiler in your PATH"
|
43
|
+
exit 1
|
44
|
+
end
|
45
|
+
require 'kaitai/struct/struct'
|
46
|
+
puts "kaitai-struct #{Kaitai::Struct::VERSION} (Kaitai Struct runtime library for Ruby)"
|
47
|
+
exit 0
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
begin
|
52
|
+
parser.parse!
|
53
|
+
rescue OptionParser::InvalidOption => e
|
54
|
+
puts e
|
55
|
+
puts parser
|
56
|
+
exit 1
|
57
|
+
end
|
58
|
+
|
14
59
|
if ARGV.size < 2
|
15
|
-
puts
|
60
|
+
puts parser
|
16
61
|
exit 1
|
17
62
|
end
|
18
63
|
|
19
|
-
|
64
|
+
c = Kaitai::Struct::Visualizer::KSYCompiler.new(options, prog_name)
|
65
|
+
v = Kaitai::Struct::Visualizer::Visualizer.new(c, ARGV[0], ARGV[1..-1], options)
|
20
66
|
v.run
|
data/lib/kaitai/console_ansi.rb
CHANGED
@@ -1,119 +1,124 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'io/console'
|
3
4
|
require 'readline'
|
4
5
|
|
5
6
|
module Kaitai
|
7
|
+
class ConsoleANSI
|
8
|
+
attr_reader :cols, :rows
|
6
9
|
|
7
|
-
|
8
|
-
|
9
|
-
attr_reader :rows
|
10
|
+
def initialize
|
11
|
+
load_term_size
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
-
@cols = `tput cols`.to_i
|
14
|
-
@rows = `tput lines`.to_i
|
13
|
+
@seq_clear = `tput clear`
|
14
|
+
@seq_sgr0 = `tput sgr0`
|
15
15
|
|
16
|
-
|
17
|
-
|
16
|
+
@seq_fgcolor = []
|
17
|
+
@seq_bgcolor = []
|
18
18
|
|
19
|
-
|
20
|
-
@seq_bgcolor = []
|
21
|
-
end
|
19
|
+
@on_resize = nil
|
22
20
|
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
Signal.trap('SIGWINCH', proc {
|
22
|
+
load_term_size
|
23
|
+
@on_resize&.call(true)
|
24
|
+
})
|
25
|
+
end
|
26
26
|
|
27
|
-
|
28
|
-
# Put the cursor up to screen position (x, y). First line is 0,
|
29
|
-
# first column is 0.
|
30
|
-
def goto(x, y)
|
31
|
-
#print `tput cup #{y} #{x}`
|
32
|
-
printf "\e[%d;%dH", y + 1, x + 1
|
33
|
-
end
|
27
|
+
attr_writer :on_resize
|
34
28
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
:gray0 => 232,
|
39
|
-
:gray1 => 233,
|
40
|
-
:gray2 => 234,
|
41
|
-
:gray3 => 235,
|
42
|
-
:gray4 => 236,
|
43
|
-
:gray5 => 237,
|
44
|
-
:gray6 => 238,
|
45
|
-
:gray7 => 239,
|
46
|
-
:gray8 => 240,
|
47
|
-
:gray9 => 241,
|
48
|
-
:gray10 => 242,
|
49
|
-
:gray11 => 243,
|
50
|
-
:gray12 => 244,
|
51
|
-
:gray13 => 245,
|
52
|
-
:gray14 => 246,
|
53
|
-
:gray15 => 247,
|
54
|
-
:gray16 => 248,
|
55
|
-
:gray17 => 249,
|
56
|
-
:gray18 => 250,
|
57
|
-
:gray19 => 251,
|
58
|
-
:gray20 => 252,
|
59
|
-
:gray21 => 253,
|
60
|
-
:gray22 => 254,
|
61
|
-
:gray23 => 255,
|
62
|
-
}
|
63
|
-
|
64
|
-
def fg_color=(col)
|
65
|
-
#print @seq_fgcolor[col] ||= `tput setaf #{col}`
|
66
|
-
code = COLORS[col]
|
67
|
-
raise "Invalid color: #{col}" unless code
|
68
|
-
print "\e[38;5;#{code}m"
|
69
|
-
end
|
29
|
+
def load_term_size
|
30
|
+
@rows, @cols = IO.console.winsize
|
31
|
+
end
|
70
32
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
raise "Invalid color: #{col}" unless code
|
75
|
-
print "\e[48;5;#{code}m"
|
76
|
-
end
|
33
|
+
def clear
|
34
|
+
print @seq_clear
|
35
|
+
end
|
77
36
|
|
78
|
-
|
79
|
-
|
80
|
-
|
37
|
+
# Put the cursor up to screen position (x, y). First line is 0, first column is 0.
|
38
|
+
def goto(x, y)
|
39
|
+
# print `tput cup #{y} #{x}`
|
40
|
+
printf "\e[%d;%dH", y + 1, x + 1
|
41
|
+
end
|
42
|
+
|
43
|
+
COLORS = {
|
44
|
+
black: 0,
|
45
|
+
red: 1,
|
46
|
+
green: 2,
|
47
|
+
yellow: 3,
|
48
|
+
blue: 4,
|
49
|
+
magenta: 5,
|
50
|
+
cyan: 6,
|
51
|
+
white: 7,
|
52
|
+
gray: 8,
|
53
|
+
bright_red: 9,
|
54
|
+
bright_green: 10,
|
55
|
+
bright_yellow: 11,
|
56
|
+
bright_blue: 12,
|
57
|
+
bright_magenta: 13,
|
58
|
+
bright_cyan: 14,
|
59
|
+
bright_white: 15
|
60
|
+
}.freeze
|
61
|
+
|
62
|
+
def fg_color=(col)
|
63
|
+
# print @seq_fgcolor[col] ||= `tput setaf #{col}`
|
64
|
+
code = COLORS[col]
|
65
|
+
raise "Invalid color: #{col}" unless code
|
66
|
+
|
67
|
+
print "\e[38;5;#{code}m"
|
68
|
+
end
|
81
69
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
70
|
+
def bg_color=(col)
|
71
|
+
# print @seq_bgcolor[col] ||= `tput setab #{col}`
|
72
|
+
code = COLORS[col]
|
73
|
+
raise "Invalid color: #{col}" unless code
|
86
74
|
|
87
|
-
|
88
|
-
if input == "\e" then
|
89
|
-
input << $stdin.read_nonblock(3) rescue nil
|
90
|
-
input << $stdin.read_nonblock(2) rescue nil
|
75
|
+
print "\e[48;5;#{code}m"
|
91
76
|
end
|
92
|
-
ensure
|
93
|
-
$stdin.echo = true
|
94
|
-
$stdin.cooked!
|
95
77
|
|
96
|
-
|
97
|
-
|
78
|
+
def reset_colors
|
79
|
+
print @seq_sgr0
|
80
|
+
end
|
98
81
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
82
|
+
# Reads keypresses from the user including 2 and 3 escape character sequences.
|
83
|
+
def read_char
|
84
|
+
$stdin.echo = false
|
85
|
+
$stdin.raw!
|
86
|
+
|
87
|
+
input = $stdin.getc.chr
|
88
|
+
if input == "\e"
|
89
|
+
begin
|
90
|
+
# may return less than 3 bytes because it can only read as many bytes as are
|
91
|
+
# currently available
|
92
|
+
up_to_3bytes = $stdin.read_nonblock(3)
|
93
|
+
input << up_to_3bytes
|
94
|
+
rescue IO::WaitReadable
|
95
|
+
# not an ANSI sequence - the user probably just pressed the Esc key
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
$stdin.echo = true
|
100
|
+
$stdin.cooked!
|
101
|
+
|
102
|
+
input
|
103
|
+
end
|
104
104
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
"\e[C" => :right_arrow,
|
111
|
-
"\e[D" => :left_arrow,
|
112
|
-
"\e[5~" => :pg_up,
|
113
|
-
"\e[6~" => :pg_dn,
|
114
|
-
"\e[H" => :home,
|
115
|
-
"\e[F" => :end,
|
116
|
-
}
|
117
|
-
end
|
105
|
+
def read_char_mapped
|
106
|
+
c = read_char
|
107
|
+
c2 = KEY_MAP[c]
|
108
|
+
c2 || c
|
109
|
+
end
|
118
110
|
|
111
|
+
KEY_MAP = {
|
112
|
+
"\t" => :tab,
|
113
|
+
"\r" => :enter,
|
114
|
+
"\e[A" => :up_arrow,
|
115
|
+
"\e[B" => :down_arrow,
|
116
|
+
"\e[C" => :right_arrow,
|
117
|
+
"\e[D" => :left_arrow,
|
118
|
+
"\e[5~" => :pg_up,
|
119
|
+
"\e[6~" => :pg_dn,
|
120
|
+
"\e[H" => :home,
|
121
|
+
"\e[F" => :end
|
122
|
+
}.freeze
|
123
|
+
end
|
119
124
|
end
|