mootool 0.1.0 → 0.2

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.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/.DS_Store +0 -0
  3. data/.github/workflows/ci.yml +37 -0
  4. data/.github/workflows/gem-push.yml +44 -0
  5. data/.overcommit.yml +79 -0
  6. data/.rubocop.yml +144 -0
  7. data/.ruby-version +1 -1
  8. data/.run/All Specs.run.xml +46 -0
  9. data/CODE_OF_CONDUCT.md +2 -1
  10. data/Gemfile +14 -11
  11. data/Gemfile.lock +93 -34
  12. data/README.md +12 -6
  13. data/bin/tapioca +27 -0
  14. data/lib/mootool/command.rb +1 -0
  15. data/lib/mootool/controller_base.rb +4 -1
  16. data/lib/mootool/controllers/dwarf.rb +8 -0
  17. data/lib/mootool/controllers/dyld_linker.rb +8 -0
  18. data/lib/mootool/controllers/dyld_shared_cache.rb +8 -0
  19. data/lib/mootool/controllers/fat_binary.rb +8 -0
  20. data/lib/mootool/controllers/kernel_collection.rb +21 -15
  21. data/lib/mootool/controllers/sections.rb +8 -0
  22. data/lib/mootool/core_extensions.rb +26 -0
  23. data/lib/mootool/models/device_tree.rb +85 -0
  24. data/lib/mootool/models/img4.rb +49 -0
  25. data/lib/mootool/models/ipsw.rb +19 -0
  26. data/lib/mootool/version.rb +1 -1
  27. data/lib/mootool/views/sections.full.erb +2 -2
  28. data/lib/mootool.rb +10 -3
  29. data/mootool.gemspec +17 -14
  30. data/sorbet/rbi/annotations/rainbow.rbi +269 -0
  31. data/sorbet/rbi/gems/ast@2.4.2.rbi +618 -0
  32. data/sorbet/rbi/gems/childprocess@4.1.0.rbi +447 -0
  33. data/sorbet/rbi/gems/coderay@1.1.3.rbi +8 -0
  34. data/sorbet/rbi/gems/diff-lcs@1.5.0.rbi +1219 -0
  35. data/sorbet/rbi/gems/iniparse@1.5.0.rbi +1007 -0
  36. data/sorbet/rbi/gems/json@2.6.2.rbi +1650 -0
  37. data/sorbet/rbi/gems/method_source@1.0.0.rbi +8 -0
  38. data/sorbet/rbi/gems/netrc@0.11.0.rbi +186 -0
  39. data/sorbet/rbi/gems/overcommit@0.59.1.rbi +2747 -0
  40. data/sorbet/rbi/gems/parallel@1.22.1.rbi +353 -0
  41. data/sorbet/rbi/gems/parser@3.1.2.1.rbi +6198 -0
  42. data/sorbet/rbi/gems/plist@3.6.0.rbi +212 -0
  43. data/sorbet/rbi/gems/pry@0.14.1.rbi +8 -0
  44. data/sorbet/rbi/gems/rainbow@3.1.1.rbi +452 -0
  45. data/sorbet/rbi/gems/rake@13.0.6.rbi +3587 -0
  46. data/sorbet/rbi/gems/rbi@0.0.15.rbi +3619 -0
  47. data/sorbet/rbi/gems/regexp_parser@2.5.0.rbi +3927 -0
  48. data/sorbet/rbi/gems/rexml@3.2.5.rbi +5238 -0
  49. data/sorbet/rbi/gems/rspec-core@3.11.0.rbi +12834 -0
  50. data/sorbet/rbi/gems/rspec-expectations@3.11.0.rbi +9151 -0
  51. data/sorbet/rbi/gems/rspec-mocks@3.11.1.rbi +6506 -0
  52. data/sorbet/rbi/gems/rspec-support@3.11.0.rbi +2040 -0
  53. data/sorbet/rbi/gems/rspec@3.11.0.rbi +120 -0
  54. data/sorbet/rbi/gems/rubocop-ast@1.21.0.rbi +7990 -0
  55. data/sorbet/rbi/gems/rubocop-rake@0.6.0.rbi +413 -0
  56. data/sorbet/rbi/gems/rubocop-rspec@2.12.1.rbi +7604 -0
  57. data/sorbet/rbi/gems/rubocop@1.35.0.rbi +62260 -0
  58. data/sorbet/rbi/gems/ruby-macho@3.0.0.rbi +5039 -0
  59. data/sorbet/rbi/gems/ruby-progressbar@1.11.0.rbi +1445 -0
  60. data/sorbet/rbi/gems/rubyzip@2.3.2.rbi +2868 -0
  61. data/sorbet/rbi/gems/spoom@1.1.12.rbi +2829 -0
  62. data/sorbet/rbi/gems/tapioca@0.9.3.rbi +2151 -0
  63. data/sorbet/rbi/gems/thor@1.2.1.rbi +4532 -0
  64. data/sorbet/rbi/gems/unicode-display_width@2.2.0.rbi +60 -0
  65. data/sorbet/rbi/gems/unparser@0.6.5.rbi +8 -0
  66. data/sorbet/rbi/gems/webrick@1.7.0.rbi +3075 -0
  67. data/sorbet/rbi/gems/yard-sorbet@0.6.1.rbi +458 -0
  68. data/sorbet/rbi/gems/yard@0.9.28.rbi +20844 -0
  69. data/sorbet/rbi/sorbet-typed/lib/rainbow/all/rainbow.rbi +72 -24
  70. data/sorbet/rbi/sorbet-typed/lib/rake/all/rake.rbi +1697 -385
  71. data/sorbet/rbi/sorbet-typed/lib/rspec-core/all/rspec-core.rbi +30 -7
  72. data/sorbet/rbi/sorbet-typed/lib/rubocop/>=1.8/rubocop.rbi +3 -1
  73. data/sorbet/rbi/todo.rbi +7 -0
  74. data/sorbet/tapioca/config.yml +13 -0
  75. data/sorbet/tapioca/require.rb +4 -0
  76. metadata +95 -14
@@ -3,7 +3,10 @@
3
3
  CONTROLLERS_PATH = File.join(File.dirname(__FILE__), 'controllers')
4
4
 
5
5
  module MooTool
6
+ # Controller base is the base class for all controllers that respond to command line requests.
6
7
  class ControllerBase
8
+ @controllers = []
9
+
7
10
  def self.load_all
8
11
  Dir.glob(File.join(CONTROLLERS_PATH, '*')).each do |file|
9
12
  require file
@@ -15,8 +18,8 @@ module MooTool
15
18
  end
16
19
 
17
20
  def self.inherited(child)
18
- @@controllers ||= []
19
21
  @@controllers << child
22
+ super
20
23
  end
21
24
 
22
25
  class << self
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MooTools
4
+ module Controllers
5
+ class DWARF < ControllerBase
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MooTool
4
+ module Controllers
5
+ class DyldLinker < ControllerBase
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MooTool
4
+ module Controllers
5
+ class DyldSharedCache < ControllerBase
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MooTool
4
+ module Controllers
5
+ class FatBinary < ControllerBase
6
+ end
7
+ end
8
+ end
@@ -1,24 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MooTool
4
- class KernelCollection < ControllerBase
5
- command 'kc'
6
- description 'Kernel Collections'
4
+ module Controllers
5
+ # Controller for extracting or viewing a KernelCollection (.kc file)
6
+ class KernelCollection < ControllerBase
7
+ command 'kc'
8
+ description 'Kernel Collections'
7
9
 
8
- def extract(command, output_folder)
9
- file = MachO.open command.file
10
- input = File.open(command.file, 'rb')
10
+ def extract(command, output_folder)
11
+ file = MachO.open command.file
12
+ input = File.open(command.file, 'rb')
11
13
 
12
- file.command(:LC_FILESET_ENTRY).each do |entry|
13
- output_path = File.join(output_folder, entry.entry_id.to_s)
14
- puts "Writing to #{output_path}"
15
- output_file = File.open(output_path, 'wb')
16
- matching = file.command(:LC_SEGMENT_64).find { |command| command.fileoff == entry.fileoff }
14
+ file.command(:LC_FILESET_ENTRY).each do |entry|
15
+ output_path = File.join(output_folder, entry.entry_id.to_s)
16
+ puts "Writing to #{output_path}"
17
+ output_file = File.open(output_path, 'wb')
18
+ # rubocop:disable Naming/VariableNumber
19
+ # We do not have control of this name as it is part of ruby-macho
20
+ matching = file.command(:LC_SEGMENT_64).find { |c| c.fileoff == entry.fileoff }
21
+ # rubocop:enable Naming/VariableNumber
17
22
 
18
- input.seek(matching.fileoff)
19
- output_file.write input.read(matching.filesize)
20
- output_file.close
23
+ input.seek(matching.fileoff)
24
+ output_file.write input.read(matching.filesize)
25
+ output_file.close
26
+ end
21
27
  end
22
28
  end
23
29
  end
24
- end
30
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MooTool
4
+ module Controllers
5
+ class Sections < ControllerBase
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ # rubocop:disable Style/Documentation
5
+
6
+ class Integer
7
+ # rubocop:enable Style/Documentation
8
+ extend T::Sig
9
+ # Aligns the integer to the nearest multiple of the alignment.
10
+ # @param alignment [Integer] the alignment
11
+ # @return [Integer] the aligned integer
12
+ sig { params(alignment: T.nilable(Integer)).returns(Integer) }
13
+ def align(alignment = nil)
14
+ alignment ||= Integer.size
15
+
16
+ return self if alignment < 2
17
+
18
+ alignment -= 1
19
+
20
+ if (self & alignment).zero?
21
+ self
22
+ else
23
+ (self | alignment) + 1
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ require 'sorbet-runtime'
5
+
6
+ module MooTool
7
+ module Models
8
+ # DeviceTree is a Apple Device Tree node that has been parsed
9
+ class DeviceTree
10
+ extend T::Sig
11
+
12
+ NODE_FORMAT = 'VV'
13
+ PROP_FORMAT = 'A32V'
14
+
15
+ # Represents a single node in the device tree
16
+ class Node
17
+ extend T::Sig
18
+
19
+ attr_reader :children, :properties
20
+
21
+ sig { params(data: T.any(IO, StringIO)).void }
22
+ def initialize(data)
23
+ vals = T.must(data.read(8)).unpack(NODE_FORMAT)
24
+ property_count = T.cast(vals[0], Integer)
25
+ child_count = T.cast(vals[1], Integer)
26
+
27
+ @properties = T.let({}, T::Hash[String, Property])
28
+ @children = T.let([], T::Array[Node])
29
+
30
+ property_count.times do
31
+ prop = Property.new(data)
32
+ @properties[prop.name] = prop
33
+ end
34
+ child_count.times { @children << Node.new(data) }
35
+ end
36
+ end
37
+
38
+ # Represents a single property and it's value
39
+ class Property
40
+ extend T::Sig
41
+
42
+ attr_accessor :name, :value
43
+
44
+ sig { params(data: T.any(StringIO, IO)).void }
45
+ def initialize(data)
46
+ args = T.must(data.read(36)).unpack(PROP_FORMAT)
47
+
48
+ @name = T.let(T.cast(args[0], String), String)
49
+ @size = T.let(T.cast(args[1], Integer), Integer)
50
+
51
+ if @size & 0x80000000 != 0
52
+ @template = true
53
+ @size &= 0x7fffffff
54
+ end
55
+
56
+ @value = data.read(@size.align(4))
57
+ @value = T.must(@value)[0..@size]
58
+ end
59
+ end
60
+
61
+ attr_reader :root
62
+
63
+ # @param [String] data
64
+ sig { params(data: T.any(IO, String, StringIO, Pathname)).void }
65
+ def initialize(data)
66
+ case data
67
+ when Pathname
68
+ data = T.assert_type!(data, Pathname)
69
+ @data = File.open(data.realpath, 'rb')
70
+ when String
71
+ data = T.assert_type!(data, String)
72
+ @data = StringIO.new(data)
73
+ when IO
74
+ @data = T.cast(data, IO)
75
+ end
76
+ @root = Node.new(@data)
77
+ end
78
+
79
+ sig { params(path: String).returns(DeviceTree) }
80
+ def self.open(path)
81
+ DeviceTree.new(Pathname.new(path))
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openssl'
4
+
5
+ module MooTool
6
+ # Module for Apple's IMG4 encryption and signing format
7
+ module Img4
8
+ # An instance of a IMG4 file
9
+ class File
10
+ attr_reader :payload, :manifest
11
+
12
+ def initialize(path)
13
+ @path = path
14
+ der = ::File.binread(path)
15
+ @data = OpenSSL::ASN1.decode(der)
16
+
17
+ case @data.first.value
18
+ when 'IM4P'
19
+ @type = @data.value[1].value
20
+ @build = @data.value[2].value
21
+ @payload = @data.value[3].value
22
+ when 'IMG4', 'IM4M'
23
+ raise 'Not implemented'
24
+ else
25
+ raise "Unknown IMG4 type #{@data.first.value}"
26
+ end
27
+ end
28
+
29
+ def payload?
30
+ !@payload.nil?
31
+ end
32
+
33
+ def manifest?
34
+ !@manifest.nil?
35
+ end
36
+
37
+ def basename
38
+ basename = ::File.basename(@path)
39
+ extension = ::File.extname(basename)
40
+ "#{basename.chomp(extension)}.#{@type}"
41
+ end
42
+
43
+ def extract_payload
44
+ output_path = ::File.join(::File.dirname(@path), basename)
45
+ ::File.write(output_path, @payload)
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'zip'
4
+ require 'plist'
5
+
6
+ module MooTool
7
+ # Represents a single IPSW package
8
+ class IPSW
9
+ def initialize(file)
10
+ @file = file
11
+ @zip = Zip::File.open(file)
12
+ manifest = @zip.find_entry('BuildManifest.plist')
13
+
14
+ raise 'Invalid IPSW, does not contain BuildManifest.plist' unless manifest
15
+
16
+ @manifest = Plist.parse_xml(manifest.get_input_stream.read)
17
+ end
18
+ end
19
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MooTool
4
- VERSION = '0.1.0'
4
+ VERSION = '0.2'
5
5
  end
@@ -1,5 +1,5 @@
1
1
  <% @load_commands.each_index do |index| %>
2
- Load command <%= index %>
3
- cmd <%= @load_commands[index].cmd %>
2
+ Load command <%= index %>
3
+ cmd <%= @load_commands[index].cmd %>
4
4
  cmdsize <%= @load_commands[index].cmdsize %>
5
5
  <% end %>
data/lib/mootool.rb CHANGED
@@ -1,14 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'mootool/version'
4
-
5
- require 'bundler/setup'
3
+ require_relative 'mootool/version'
6
4
 
7
5
  require 'macho'
6
+ require 'zip'
7
+
8
+ require_relative 'mootool/core_extensions'
8
9
 
10
+ # MooTool
9
11
  module MooTool
10
12
  class Error < StandardError; end
13
+
11
14
  # Your code goes here...
12
15
  autoload :Command, 'mootool/command'
13
16
  autoload :ControllerBase, 'mootool/controller_base'
17
+
18
+ autoload :Img4, 'mootool/models/img4'
19
+ autoload :DeviceTree, 'mootool/models/device_tree'
20
+ autoload :IPSW, 'mootool/models/ipsw'
14
21
  end
data/mootool.gemspec CHANGED
@@ -5,27 +5,27 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
  require 'mootool/version'
6
6
 
7
7
  Gem::Specification.new do |spec|
8
- spec.name = 'mootool'
9
- spec.version = MooTool::VERSION
10
- spec.authors = ['Rick Mark']
11
- spec.email = ['rickmark@outlook.com']
8
+ spec.name = 'mootool'
9
+ spec.version = MooTool::VERSION
10
+ spec.authors = ['Rick Mark']
11
+ spec.email = ['rickmark@outlook.com']
12
12
 
13
- spec.summary = "Mach-O's Other Tool"
14
- spec.description = 'mootool is a swiss army knife for dealing wiith Apple Mach-O files'
15
- spec.homepage = 'https://github.com/hack-different/mootool'
16
- spec.license = 'MIT'
13
+ spec.summary = "Mach-O's Other Tool"
14
+ spec.description = 'mootool is a swiss army knife for dealing with Apple Mach-O files'
15
+ spec.homepage = 'https://github.com/hack-different/mootool'
16
+ spec.license = 'MIT'
17
+
18
+ spec.required_ruby_version = '>= 3.1'
17
19
 
18
20
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
19
21
  # to allow pushing to a single host or delete this section to allow pushing to any host.
20
22
  if spec.respond_to?(:metadata)
21
- spec.metadata['allowed_push_host'] = 'https://rubygems.org'
22
-
23
23
  spec.metadata['homepage_uri'] = spec.homepage
24
24
  spec.metadata['source_code_uri'] = 'https://github.com/hack-different/mootool'
25
25
  spec.metadata['changelog_uri'] = 'https://github.com/hack-different/mootool'
26
26
  else
27
27
  raise 'RubyGems 2.0 or newer is required to protect against ' \
28
- 'public gem pushes.'
28
+ 'public gem pushes.'
29
29
  end
30
30
 
31
31
  # Specify which files should be added to the gem when it is released.
@@ -33,10 +33,13 @@ Gem::Specification.new do |spec|
33
33
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
34
34
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
35
35
  end
36
- spec.bindir = 'exe'
37
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
36
+ spec.bindir = 'exe'
37
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
38
38
  spec.require_paths = ['lib']
39
39
 
40
- spec.add_runtime_dependency 'sorbet-runtime'
40
+ spec.add_runtime_dependency 'plist', '~> 3'
41
41
  spec.add_runtime_dependency 'ruby-macho', '~> 3'
42
+ spec.add_runtime_dependency 'rubyzip', '~> 2'
43
+ spec.add_runtime_dependency 'sorbet-runtime', '~> 0'
44
+ spec.metadata['rubygems_mfa_required'] = 'true'
42
45
  end
@@ -0,0 +1,269 @@
1
+ # typed: strict
2
+
3
+ # DO NOT EDIT MANUALLY
4
+ # This file was pulled from a central RBI files repository.
5
+ # Please run `bin/tapioca annotations` to update it.
6
+
7
+ module Rainbow
8
+ # @shim: https://github.com/sickill/rainbow/blob/master/lib/rainbow.rb#L10-L12
9
+ sig { returns(T::Boolean) }
10
+ attr_accessor :enabled
11
+
12
+ class Color
13
+ sig { returns(Symbol) }
14
+ attr_reader :ground
15
+
16
+ sig { params(ground: Symbol, values: T.any([Integer], [Integer, Integer, Integer])).returns(Color) }
17
+ def self.build(ground, values); end
18
+
19
+ sig { params(hex: String).returns([Integer, Integer, Integer]) }
20
+ def self.parse_hex_color(hex); end
21
+
22
+ class Indexed < Rainbow::Color
23
+ sig { returns(Integer) }
24
+ attr_reader :num
25
+
26
+ sig { params(ground: Symbol, num: Integer).void }
27
+ def initialize(ground, num); end
28
+
29
+ sig { returns(T::Array[Integer]) }
30
+ def codes; end
31
+ end
32
+
33
+ class Named < Rainbow::Color::Indexed
34
+ NAMES = T.let(nil, T::Hash[Symbol, Integer])
35
+
36
+ sig { params(ground: Symbol, name: Symbol).void }
37
+ def initialize(ground, name); end
38
+
39
+ sig { returns(T::Array[Symbol]) }
40
+ def self.color_names; end
41
+
42
+ sig { returns(String) }
43
+ def self.valid_names; end
44
+ end
45
+
46
+ class RGB < Rainbow::Color::Indexed
47
+ sig { returns(Integer) }
48
+ attr_reader :r, :g, :b
49
+
50
+ sig { params(ground: Symbol, values: Integer).void }
51
+ def initialize(ground, *values); end
52
+
53
+ sig { returns(T::Array[Integer]) }
54
+ def codes; end
55
+
56
+ sig { params(value: Numeric).returns(Integer) }
57
+ def self.to_ansi_domain(value); end
58
+ end
59
+
60
+ class X11Named < Rainbow::Color::RGB
61
+ include Rainbow::X11ColorNames
62
+
63
+ sig { returns(T::Array[Symbol]) }
64
+ def self.color_names; end
65
+
66
+ sig { returns(String) }
67
+ def self.valid_names; end
68
+
69
+ sig { params(ground: Symbol, name: Symbol).void }
70
+ def initialize(ground, name); end
71
+ end
72
+ end
73
+
74
+ sig { returns(Wrapper) }
75
+ def self.global; end
76
+
77
+ sig { returns(T::Boolean) }
78
+ def self.enabled; end
79
+
80
+ sig { params(value: T::Boolean).returns(T::Boolean) }
81
+ def self.enabled=(value); end
82
+
83
+ sig { params(string: String).returns(String) }
84
+ def self.uncolor(string); end
85
+
86
+ class NullPresenter < String
87
+ sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(NullPresenter) }
88
+ def color(*values); end
89
+
90
+ sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(NullPresenter) }
91
+ def foreground(*values); end
92
+
93
+ sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(NullPresenter) }
94
+ def fg(*values); end
95
+
96
+ sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(NullPresenter) }
97
+ def background(*values); end
98
+
99
+ sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(NullPresenter) }
100
+ def bg(*values); end
101
+
102
+ sig { returns(NullPresenter) }
103
+ def reset; end
104
+
105
+ sig { returns(NullPresenter) }
106
+ def bright; end
107
+
108
+ sig { returns(NullPresenter) }
109
+ def faint; end
110
+
111
+ sig { returns(NullPresenter) }
112
+ def italic; end
113
+
114
+ sig { returns(NullPresenter) }
115
+ def underline; end
116
+
117
+ sig { returns(NullPresenter) }
118
+ def blink; end
119
+
120
+ sig { returns(NullPresenter) }
121
+ def inverse; end
122
+
123
+ sig { returns(NullPresenter) }
124
+ def hide; end
125
+
126
+ sig { returns(NullPresenter) }
127
+ def cross_out; end
128
+
129
+ sig { returns(NullPresenter) }
130
+ def black; end
131
+
132
+ sig { returns(NullPresenter) }
133
+ def red; end
134
+
135
+ sig { returns(NullPresenter) }
136
+ def green; end
137
+
138
+ sig { returns(NullPresenter) }
139
+ def yellow; end
140
+
141
+ sig { returns(NullPresenter) }
142
+ def blue; end
143
+
144
+ sig { returns(NullPresenter) }
145
+ def magenta; end
146
+
147
+ sig { returns(NullPresenter) }
148
+ def cyan; end
149
+
150
+ sig { returns(NullPresenter) }
151
+ def white; end
152
+
153
+ sig { returns(NullPresenter) }
154
+ def bold; end
155
+
156
+ sig { returns(NullPresenter) }
157
+ def dark; end
158
+
159
+ sig { returns(NullPresenter) }
160
+ def strike; end
161
+ end
162
+
163
+ class Presenter < String
164
+ TERM_EFFECTS = T.let(nil, T::Hash[Symbol, Integer])
165
+
166
+ sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(Presenter) }
167
+ def color(*values); end
168
+
169
+ sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(Presenter) }
170
+ def foreground(*values); end
171
+
172
+ sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(Presenter) }
173
+ def fg(*values); end
174
+
175
+ sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(Presenter) }
176
+ def background(*values); end
177
+
178
+ sig { params(values: T.any([Integer], [Integer, Integer, Integer])).returns(Presenter) }
179
+ def bg(*values); end
180
+
181
+ sig { returns(Presenter) }
182
+ def reset; end
183
+
184
+ sig { returns(Presenter) }
185
+ def bright; end
186
+
187
+ sig { returns(Presenter) }
188
+ def faint; end
189
+
190
+ sig { returns(Presenter) }
191
+ def italic; end
192
+
193
+ sig { returns(Presenter) }
194
+ def underline; end
195
+
196
+ sig { returns(Presenter) }
197
+ def blink; end
198
+
199
+ sig { returns(Presenter) }
200
+ def inverse; end
201
+
202
+ sig { returns(Presenter) }
203
+ def hide; end
204
+
205
+ sig { returns(Presenter) }
206
+ def cross_out; end
207
+
208
+ sig { returns(Presenter) }
209
+ def black; end
210
+
211
+ sig { returns(Presenter) }
212
+ def red; end
213
+
214
+ sig { returns(Presenter) }
215
+ def green; end
216
+
217
+ sig { returns(Presenter) }
218
+ def yellow; end
219
+
220
+ sig { returns(Presenter) }
221
+ def blue; end
222
+
223
+ sig { returns(Presenter) }
224
+ def magenta; end
225
+
226
+ sig { returns(Presenter) }
227
+ def cyan; end
228
+
229
+ sig { returns(Presenter) }
230
+ def white; end
231
+
232
+ sig { returns(Presenter) }
233
+ def bold; end
234
+
235
+ sig { returns(Presenter) }
236
+ def dark; end
237
+
238
+ sig { returns(Presenter) }
239
+ def strike; end
240
+ end
241
+
242
+ class StringUtils
243
+ sig { params(string: String, codes: T::Array[Integer]).returns(String) }
244
+ def self.wrap_with_sgr(string, codes); end
245
+
246
+ sig { params(string: String).returns(String) }
247
+ def self.uncolor(string); end
248
+ end
249
+
250
+ VERSION = T.let(nil, String)
251
+
252
+ class Wrapper
253
+ sig { returns(T::Boolean) }
254
+ attr_accessor :enabled
255
+
256
+ sig { params(enabled: T::Boolean).void }
257
+ def initialize(enabled = true); end
258
+
259
+ sig { params(string: String).returns(T.any(Rainbow::Presenter, Rainbow::NullPresenter)) }
260
+ def wrap(string); end
261
+ end
262
+
263
+ module X11ColorNames
264
+ NAMES = T.let(nil, T::Hash[Symbol, [Integer, Integer, Integer]])
265
+ end
266
+ end
267
+
268
+ sig { params(string: String).returns(Rainbow::Presenter) }
269
+ def Rainbow(string); end