kaitai-struct-visualizer 0.7 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 7b37b3d7fa10586b07b80076fb60a9b5bea5719a
4
- data.tar.gz: 2ff461ac414e9ab3ecf4b0a712ad4e757acc27ff
2
+ SHA256:
3
+ metadata.gz: a4e2b67e9f53f3b692de0e98c7c46c9106c2c88e001ef228e0bd3351f83037d2
4
+ data.tar.gz: 623ee7e33ececcc081b5309746dd8ac9e557e5bc57ae52e3229e71e8ae5a94cf
5
5
  SHA512:
6
- metadata.gz: 2f9f6599576d9d6399cf5ceae258459cb8a26f038a1f95e7a2a1e4560e411b1b59e708026c75c6adb88efbf86cd38fcabeced8e6692868ca6c6495f725b37205
7
- data.tar.gz: d276166a68b97fee40538360bea6717c70a22517972567f2a7886a629eb3b47d5c0bf04bf94ad6c36a5b849616f3e7f26a3aab818ead47fddf1472103d5a79ec
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. <http://fsf.org/>
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 <http://www.gnu.org/licenses/>.
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
- <http://www.gnu.org/licenses/>.
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
- <http://www.gnu.org/philosophy/why-not-lgpl.html>.
674
+ <https://www.gnu.org/licenses/why-not-lgpl.html>.
data/README.md CHANGED
@@ -1,64 +1,125 @@
1
1
  # Kaitai Struct: visualizer
2
2
 
3
- This is a simple visualizer for [Kaitai Struct](https://github.com/kaitai-io/kaitai_struct) project.
3
+ This is a console visualizer for the [Kaitai Struct](https://kaitai.io/) project.
4
+
5
+ ![screenshot](screenshot.png)
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` files) only once and then can be compiled with
11
- this compiler into source files in one of the supported programming
12
- languages. These modules will include a generated code for a parser
13
- that can read described data structure from a file / stream and give
14
- access to it in a nice, easy-to-comprehend API.
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
- Please refer to [documentation in Kaitai Struct project](https://github.com/kaitai-io/kaitai_struct)
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
- ### From Ruby Gems repository
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
- KS visualizer is written in [Ruby](https://www.ruby-lang.org/) and is
24
- available as
25
- [.gem package](https://rubygems.org/gems/kaitai-struct-visualizer). Thus,
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 in repository:
55
+ out the source code from the [kaitai_struct_visualizer](https://github.com/kaitai-io/kaitai_struct_visualizer) GitHub repository:
37
56
 
38
- git clone https://github.com/kaitai-io/kaitai_struct_visualizer
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
- `ksv <binary-file> <ksy-file>...`
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 is copyright (C) 2015-2017 Kaitai Project.
105
+ Kaitai Struct visualizer is copyright (C) 2015-2025 Kaitai Project.
47
106
 
48
107
  This program is free software: you can redistribute it and/or modify
49
108
  it under the terms of the GNU General Public License as published by
50
- the Free Software Foundation, either version 3 of the License, or (at
51
- your option) any later version.
109
+ the Free Software Foundation, either version 3 of the License, or
110
+ (at your option) any later version.
52
111
 
53
- This program is distributed in the hope that it will be useful, but
54
- WITHOUT ANY WARRANTY; without even the implied warranty of
55
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
56
- 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.
57
116
 
58
117
  You should have received a copy of the GNU General Public License
59
- along with this program. If not, see <http://www.gnu.org/licenses/>.
118
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
119
+
120
+ ---
60
121
 
61
- Note that it applies only to compiler itself, not `.ksy` input files
122
+ Note that it applies only to visualizer itself, not `.ksy` input files
62
123
  that one supplies in normal process of compilation, nor to compiler's
63
- output files — that consitutes normal usage process and you obviously
124
+ output files — that constitutes normal usage process and you obviously
64
125
  keep copyright to both.
data/bin/ksdump CHANGED
@@ -1,39 +1,57 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'optparse'
4
5
 
5
6
  # Some additional magic to make it work right after repo checkout,
6
7
  # without installation to proper Ruby library dirs
7
8
 
8
- full_bin_path = File.realpath($PROGRAM_NAME)
9
- dist_path = File.expand_path(File.dirname(full_bin_path) + '/..')
10
-
11
- $LOAD_PATH << "#{dist_path}/lib"
12
- $LOAD_PATH << "#{dist_path}/../runtime/ruby/lib"
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
13
25
 
14
26
  require 'kaitai/struct/visualizer'
27
+ require 'kaitai/struct/visualizer/obj_to_h'
15
28
 
16
29
  # ======================================================================
17
30
 
18
- options = {:format => 'yaml'}
19
- parser = OptionParser.new do |opts|
20
- $prog_name = File.basename($PROGRAM_NAME)
31
+ FORMATS = %w[json xml yaml].freeze
21
32
 
22
- opts.banner = "Usage: #{$prog_name} [options] <file_to_parse.bin> <format.ksy>..."
23
- opts.separator ""
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 ''
24
38
 
25
- opts.on("-I", "--import-path [DIRECTORIES]", ".ksy library search path(s) for imports (see also KSPATH env variable)") do |v|
39
+ opts.on('-I', '--import-path [DIRECTORIES]', '.ksy library search path(s) for imports (see also KSPATH env variable)') do |v|
26
40
  options[:import_path] = v
27
41
  end
28
42
 
29
- FORMATS = ['json', 'xml', 'yaml']
30
- opts.on("-f", "--format FORMAT", FORMATS, "choose dump format - #{FORMATS.join(', ')} (default: #{options[:format]})") do |v|
43
+ opts.on('-f', '--format FORMAT', FORMATS, "choose dump format - #{FORMATS.join(', ')} (default: #{options[:format]})") do |v|
31
44
  options[:format] = v
32
45
  end
33
46
 
34
- opts.on("--version", "show versions of #{$prog_name} and ksc") do |v|
35
- puts "#{$prog_name} #{Kaitai::Struct::Visualizer::VERSION}"
36
- system("ksc", "--version")
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)"
37
55
  exit 0
38
56
  end
39
57
  end
@@ -51,62 +69,14 @@ if ARGV.size < 2
51
69
  exit 1
52
70
  end
53
71
 
54
- c = Kaitai::Struct::Visualizer::KSYCompiler.new(options)
72
+ c = Kaitai::Struct::Visualizer::KSYCompiler.new(options, prog_name)
55
73
  app = Kaitai::Struct::Visualizer::Parser.new(c, ARGV[0], ARGV[1..-1], options)
56
- app.load
74
+ exc = app.load
75
+ raise exc if exc
57
76
 
58
77
  # ======================================================================
59
78
 
60
- def obj_to_h(obj)
61
- if obj == true or obj == false or obj.is_a?(Numeric) or obj.nil?
62
- obj
63
- elsif obj.is_a?(Symbol)
64
- obj.to_s
65
- elsif obj.is_a?(String)
66
- if obj.encoding == Encoding::ASCII_8BIT
67
- r = ''
68
- obj.each_byte { |x| r << sprintf('%02X ', x) }
69
- r.chop!
70
- r
71
- else
72
- obj.encode('UTF-8')
73
- end
74
- elsif obj.is_a?(Array)
75
- obj.map { |x| obj_to_h(x) }
76
- else
77
- root = {}
78
- valid_struct = false
79
-
80
- common_meths = Set.new
81
- obj.class.ancestors.each { |cl|
82
- next if cl == obj.class
83
- valid_struct = true if cl == Kaitai::Struct::Struct
84
- common_meths.merge(cl.instance_methods)
85
- }
86
-
87
- return "OPAQUE (#{obj.class.to_s})" if not valid_struct
88
-
89
- inst_meths = Set.new(obj.public_methods) - common_meths
90
- inst_meths.sort.each { |meth|
91
- k = meth.to_s
92
- next if k =~ /^_/ # or attrs.include?(k)
93
-
94
- el = obj.send(meth)
95
- v = obj_to_h(el)
96
- root[k] = v unless v.nil?
97
- }
98
-
99
- # obj.instance_variables.each { |k|
100
- # k = k.to_s
101
- # next if k =~ /^@_/
102
- # el = obj.instance_eval(k)
103
- # root[k[1..-1]] = obj_to_h(el)
104
- # }
105
- root
106
- end
107
- end
108
-
109
- tree = obj_to_h(app.data)
79
+ tree = Kaitai::Struct::Visualizer.obj_to_h(app.data)
110
80
  r = nil
111
81
 
112
82
  case options[:format]
@@ -123,4 +93,4 @@ when 'yaml'
123
93
  r = r[4..-1] if r[0..3] == "---\n"
124
94
  end
125
95
 
126
- print r
96
+ puts r
data/bin/ksv CHANGED
@@ -1,36 +1,49 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'optparse'
4
5
 
5
6
  # Some additional magic to make it work right after repo checkout,
6
7
  # without installation to proper Ruby library dirs
7
8
 
8
- full_bin_path = File.realpath($PROGRAM_NAME)
9
- dist_path = File.expand_path(File.dirname(full_bin_path) + '/..')
10
-
11
- $LOAD_PATH << "#{dist_path}/lib"
12
- $LOAD_PATH << "#{dist_path}/../runtime/ruby/lib"
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
13
15
 
14
16
  require 'kaitai/struct/visualizer'
15
17
 
16
18
  # ======================================================================
17
19
 
20
+ prog_name = File.basename($PROGRAM_NAME)
18
21
  options = {}
19
22
  parser = OptionParser.new do |opts|
20
- opts.banner = "Usage: #{File.basename($PROGRAM_NAME)} [options] <file_to_parse.bin> <format.ksy>..."
21
- opts.separator ""
23
+ opts.banner = "Usage: #{File.basename($PROGRAM_NAME)} [options] <file_to_parse.bin> <format.ksy>...|<format.rb>"
24
+ opts.separator ''
22
25
 
23
- opts.on("-I", "--import-path [DIRECTORIES]", ".ksy library search path(s) for imports (see also KSPATH env variable)") do |v|
26
+ opts.on('-I', '--import-path [DIRECTORIES]', '.ksy library search path(s) for imports (see also KSPATH env variable)') do |v|
24
27
  options[:import_path] = v
25
28
  end
26
29
 
27
- opts.on("--opaque-types [BOOLEAN]", "opaque types allowed, default: false") do |v|
30
+ opts.on('--opaque-types [BOOLEAN]', 'opaque types allowed, default: false') do |v|
28
31
  options[:opaque_types] = v
29
32
  end
30
33
 
31
- opts.on("--version", "show versions of ksv and ksc") do |v|
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|
32
40
  puts "kaitai-struct-visualizer #{Kaitai::Struct::Visualizer::VERSION}"
33
- system("ksc", "--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)"
34
47
  exit 0
35
48
  end
36
49
  end
@@ -48,6 +61,6 @@ if ARGV.size < 2
48
61
  exit 1
49
62
  end
50
63
 
51
- c = Kaitai::Struct::Visualizer::KSYCompiler.new(options)
64
+ c = Kaitai::Struct::Visualizer::KSYCompiler.new(options, prog_name)
52
65
  v = Kaitai::Struct::Visualizer::Visualizer.new(c, ARGV[0], ARGV[1..-1], options)
53
66
  v.run
@@ -1,132 +1,124 @@
1
- # coding: utf-8
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
- class ConsoleANSI
8
- attr_reader :cols
9
- attr_reader :rows
10
-
11
- def initialize
12
- get_term_size
10
+ def initialize
11
+ load_term_size
13
12
 
14
- @seq_clear = `tput clear`
15
- @seq_sgr0 = `tput sgr0`
13
+ @seq_clear = `tput clear`
14
+ @seq_sgr0 = `tput sgr0`
16
15
 
17
- @seq_fgcolor = []
18
- @seq_bgcolor = []
16
+ @seq_fgcolor = []
17
+ @seq_bgcolor = []
19
18
 
20
- @on_resize = nil
19
+ @on_resize = nil
21
20
 
22
- Signal.trap('SIGWINCH', proc {
23
- get_term_size
24
- @on_resize.call if @on_resize
25
- })
26
- end
21
+ Signal.trap('SIGWINCH', proc {
22
+ load_term_size
23
+ @on_resize&.call(true)
24
+ })
25
+ end
27
26
 
28
- def on_resize=(handler)
29
- @on_resize = handler
30
- end
27
+ attr_writer :on_resize
31
28
 
32
- def get_term_size
33
- @rows, @cols = IO.console.winsize
34
- end
29
+ def load_term_size
30
+ @rows, @cols = IO.console.winsize
31
+ end
35
32
 
36
- def clear
37
- print @seq_clear
38
- end
33
+ def clear
34
+ print @seq_clear
35
+ end
39
36
 
40
- ##
41
- # Put the cursor up to screen position (x, y). First line is 0,
42
- # first column is 0.
43
- def goto(x, y)
44
- #print `tput cup #{y} #{x}`
45
- printf "\e[%d;%dH", y + 1, x + 1
46
- end
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
47
42
 
48
- COLORS = {
49
- :black => 0,
50
- :gray => 7,
51
- :gray0 => 232,
52
- :gray1 => 233,
53
- :gray2 => 234,
54
- :gray3 => 235,
55
- :gray4 => 236,
56
- :gray5 => 237,
57
- :gray6 => 238,
58
- :gray7 => 239,
59
- :gray8 => 240,
60
- :gray9 => 241,
61
- :gray10 => 242,
62
- :gray11 => 243,
63
- :gray12 => 244,
64
- :gray13 => 245,
65
- :gray14 => 246,
66
- :gray15 => 247,
67
- :gray16 => 248,
68
- :gray17 => 249,
69
- :gray18 => 250,
70
- :gray19 => 251,
71
- :gray20 => 252,
72
- :gray21 => 253,
73
- :gray22 => 254,
74
- :gray23 => 255,
75
- }
76
-
77
- def fg_color=(col)
78
- #print @seq_fgcolor[col] ||= `tput setaf #{col}`
79
- code = COLORS[col]
80
- raise "Invalid color: #{col}" unless code
81
- print "\e[38;5;#{code}m"
82
- end
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
83
69
 
84
- def bg_color=(col)
85
- #print @seq_bgcolor[col] ||= `tput setab #{col}`
86
- code = COLORS[col]
87
- raise "Invalid color: #{col}" unless code
88
- print "\e[48;5;#{code}m"
89
- end
70
+ def bg_color=(col)
71
+ # print @seq_bgcolor[col] ||= `tput setab #{col}`
72
+ code = COLORS[col]
73
+ raise "Invalid color: #{col}" unless code
90
74
 
91
- def reset_colors
92
- print @seq_sgr0
93
- end
75
+ print "\e[48;5;#{code}m"
76
+ end
94
77
 
95
- # Reads keypresses from the user including 2 and 3 escape character sequences.
96
- def read_char
97
- $stdin.echo = false
98
- $stdin.raw!
78
+ def reset_colors
79
+ print @seq_sgr0
80
+ end
99
81
 
100
- input = $stdin.getc.chr
101
- if input == "\e" then
102
- input << $stdin.read_nonblock(3) rescue nil
103
- input << $stdin.read_nonblock(2) rescue nil
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
104
103
  end
105
- ensure
106
- $stdin.echo = true
107
- $stdin.cooked!
108
104
 
109
- return input
110
- end
105
+ def read_char_mapped
106
+ c = read_char
107
+ c2 = KEY_MAP[c]
108
+ c2 || c
109
+ end
111
110
 
112
- def read_char_mapped
113
- c = read_char
114
- c2 = KEY_MAP[c]
115
- c2 ? c2 : c
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
116
123
  end
117
-
118
- KEY_MAP = {
119
- "\t" => :tab,
120
- "\r" => :enter,
121
- "\e[A" => :up_arrow,
122
- "\e[B" => :down_arrow,
123
- "\e[C" => :right_arrow,
124
- "\e[D" => :left_arrow,
125
- "\e[5~" => :pg_up,
126
- "\e[6~" => :pg_dn,
127
- "\e[H" => :home,
128
- "\e[F" => :end,
129
- }
130
- end
131
-
132
124
  end