glimmer-dsl-libui 0.8.0 → 0.9.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.
@@ -0,0 +1,231 @@
1
+ # Copyright (c) 2007-2023 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ if ARGV.include?('--bundler') && File.exist?(File.expand_path('./Gemfile'))
23
+ require 'bundler'
24
+ Bundler.setup(:default)
25
+ end
26
+ require 'fileutils'
27
+ require 'os'
28
+
29
+ module Glimmer
30
+ # Launcher of glimmer applications and main entry point for the `glimmer` command.
31
+ class Launcher
32
+ # TODO update the verbiage below for Glimmer DSL for LibUI
33
+ TEXT_USAGE = <<~MULTI_LINE_STRING
34
+ Glimmer DSL for LibUI (Prerequisite-Free Ruby Desktop Development Cross-Platform Native GUI Library) - Ruby Gem: glimmer-dsl-libui v#{File.read(File.expand_path('../../../VERSION', __FILE__))}
35
+ Usage: glimmer [--bundler] [--pd] [--quiet] [--debug] [--log-level=VALUE] [[ENV_VAR=VALUE]...] [[-ruby-option]...] (application.rb or task[task_args])
36
+
37
+ Runs Glimmer applications and tasks.
38
+
39
+ When applications are specified, they are run using Ruby,
40
+ automatically preloading the glimmer-dsl-libui Ruby gem.
41
+
42
+ Optionally, extra Glimmer options, Ruby options, and/or environment variables may be passed in.
43
+
44
+ Glimmer options:
45
+ - "--bundler=GROUP" : Activates gems in Bundler default group in Gemfile
46
+ - "--pd=BOOLEAN" : Requires puts_debuggerer to enable pd method
47
+ - "--quiet=BOOLEAN" : Does not announce file path of Glimmer application being launched
48
+ - "--debug" : Displays extra debugging information and enables debug logging
49
+ - "--log-level=VALUE" : Sets Glimmer's Ruby logger level ("ERROR" / "WARN" / "INFO" / "DEBUG"; default is none)
50
+
51
+ Tasks are run via rake. Some tasks take arguments in square brackets (surround with double-quotes if using Zsh).
52
+
53
+ Available tasks are below (if you do not see any, please add `require 'glimmer/rake_task'` to Rakefile and rerun or run rake -T):
54
+
55
+ MULTI_LINE_STRING
56
+
57
+ GLIMMER_LIB_GEM = 'glimmer-dsl-libui'
58
+ GLIMMER_LIB_LOCAL = File.expand_path(File.join('lib', "#{GLIMMER_LIB_GEM}.rb"))
59
+ GLIMMER_OPTIONS = %w[--log-level --quiet --bundler --pd]
60
+ GLIMMER_OPTION_ENV_VAR_MAPPING = {
61
+ '--log-level' => 'GLIMMER_LOGGER_LEVEL' ,
62
+ '--bundler' => 'GLIMMER_BUNDLER_SETUP' ,
63
+ '--pd' => 'PD' ,
64
+ }
65
+ REGEX_RAKE_TASK_WITH_ARGS = /^([^\[]+)\[?([^\]]*)\]?$/
66
+
67
+ class << self
68
+ def is_arm64?
69
+ host_cpu = OS.host_cpu.downcase
70
+ host_cpu.include?('aarch64') || host_cpu.include?('arm')
71
+ end
72
+
73
+ def glimmer_lib
74
+ unless @glimmer_lib
75
+ @glimmer_lib = GLIMMER_LIB_GEM
76
+ if File.exist?(GLIMMER_LIB_LOCAL)
77
+ @glimmer_lib = GLIMMER_LIB_LOCAL
78
+ puts "[DEVELOPMENT MODE] (detected #{@glimmer_lib})"
79
+ end
80
+ end
81
+ @glimmer_lib
82
+ end
83
+
84
+ def dev_mode?
85
+ glimmer_lib == GLIMMER_LIB_LOCAL
86
+ end
87
+
88
+ def glimmer_option_env_vars(glimmer_options)
89
+ GLIMMER_OPTION_ENV_VAR_MAPPING.reduce({}) do |hash, pair|
90
+ glimmer_options[pair.first] ? hash.merge(GLIMMER_OPTION_ENV_VAR_MAPPING[pair.first] => glimmer_options[pair.first]) : hash
91
+ end
92
+ end
93
+
94
+ def load_env_vars(env_vars)
95
+ env_vars.each do |key, value|
96
+ ENV[key] = value
97
+ end
98
+ end
99
+
100
+ def launch(application, ruby_options: [], env_vars: {}, glimmer_options: {})
101
+ ruby_options_string = ruby_options.join(' ') + ' ' if ruby_options.any?
102
+ env_vars = env_vars.merge(glimmer_option_env_vars(glimmer_options))
103
+ env_vars.each do |k,v|
104
+ ENV[k] = v
105
+ end
106
+ the_glimmer_lib = glimmer_lib
107
+ require 'puts_debuggerer' if the_glimmer_lib == GLIMMER_LIB_LOCAL
108
+ is_rake_task = !application.end_with?('.rb')
109
+ rake_tasks = []
110
+ if is_rake_task
111
+ load File.expand_path('./Rakefile') if File.exist?(File.expand_path('./Rakefile')) && caller.join("\n").include?('/bin/glimmer:')
112
+ require_relative 'rake_task'
113
+ rake_tasks = Rake.application.tasks.map(&:to_s).map {|t| t.sub('glimmer:', '')}
114
+
115
+ potential_rake_task_parts = application.match(REGEX_RAKE_TASK_WITH_ARGS)
116
+ application = potential_rake_task_parts[1]
117
+ rake_task_args = potential_rake_task_parts[2].split(',')
118
+ end
119
+ if rake_tasks.include?(application)
120
+ load_env_vars(glimmer_option_env_vars(glimmer_options))
121
+ rake_task = "glimmer:#{application}"
122
+ puts "Running Glimmer rake task: #{rake_task}" if ruby_options_string.to_s.include?('--debug')
123
+ Rake::Task[rake_task].invoke(*rake_task_args)
124
+ else
125
+ puts "Launching Glimmer Application: #{application}" if ruby_options_string.to_s.include?('--debug') || glimmer_options['--quiet'].to_s.downcase != 'true'
126
+ require the_glimmer_lib
127
+ load File.expand_path(application)
128
+ end
129
+ end
130
+ end
131
+
132
+ attr_reader :application_paths
133
+ attr_reader :env_vars
134
+ attr_reader :glimmer_options
135
+ attr_reader :ruby_options
136
+
137
+ def initialize(raw_options)
138
+ raw_options << '--quiet' if !caller.join("\n").include?('/bin/glimmer:') && !raw_options.join.include?('--quiet=')
139
+ raw_options << '--log-level=DEBUG' if raw_options.join.include?('--debug') && !raw_options.join.include?('--log-level=')
140
+ @application_path = extract_application_path(raw_options)
141
+ @env_vars = extract_env_vars(raw_options)
142
+ @glimmer_options = extract_glimmer_options(raw_options)
143
+ @ruby_options = raw_options
144
+ end
145
+
146
+ def launch
147
+ if @application_path.nil?
148
+ display_usage
149
+ else
150
+ launch_application
151
+ end
152
+ end
153
+
154
+ private
155
+
156
+ def launch_application
157
+ self.class.launch(
158
+ @application_path,
159
+ ruby_options: @ruby_options,
160
+ env_vars: @env_vars,
161
+ glimmer_options: @glimmer_options
162
+ )
163
+ end
164
+
165
+ def display_usage
166
+ puts TEXT_USAGE
167
+ display_tasks
168
+ end
169
+
170
+ def display_tasks
171
+ if OS.windows? || Launcher.is_arm64?
172
+ require 'rake'
173
+ Rake::TaskManager.record_task_metadata = true
174
+ require_relative 'rake_task'
175
+ tasks = Rake.application.tasks
176
+ task_lines = tasks.reject do |task|
177
+ task.comment.nil?
178
+ end.map do |task|
179
+ max_task_size = tasks.map(&:name_with_args).map(&:size).max + 1
180
+ task_name = task.name_with_args.sub('glimmer:', '')
181
+ line = "glimmer #{task_name.ljust(max_task_size)} # #{task.comment}"
182
+ end
183
+ puts task_lines.to_a
184
+ else
185
+ require 'rake-tui'
186
+ require 'tty-screen'
187
+ require_relative 'rake_task'
188
+ Rake::TUI.run(branding_header: nil, prompt_question: 'Select a Glimmer task to run:') do |task, tasks|
189
+ max_task_size = tasks.map(&:name_with_args).map(&:size).max + 1
190
+ task_name = task.name_with_args.sub('glimmer:', '')
191
+ line = "glimmer #{task_name.ljust(max_task_size)} # #{task.comment}"
192
+ bound = TTY::Screen.width - 6
193
+ line.size <= bound ? line : "#{line[0..(bound - 3)]}..."
194
+ end
195
+ end
196
+ end
197
+
198
+ # Extract application path (which can also be a rake task, basically a non-arg)
199
+ def extract_application_path(options)
200
+ application_path = options.detect do |option|
201
+ !option.start_with?('-') && !option.include?('=')
202
+ end.tap do
203
+ options.delete(application_path)
204
+ end
205
+ end
206
+
207
+ def extract_env_vars(options)
208
+ options.select do |option|
209
+ !option.start_with?('-') && option.include?('=')
210
+ end.each do |env_var|
211
+ options.delete(env_var)
212
+ end.reduce({}) do |hash, env_var_string|
213
+ match = env_var_string.match(/^([^=]+)=(.+)$/)
214
+ hash.merge(match[1] => match[2])
215
+ end
216
+ end
217
+
218
+ def extract_glimmer_options(options)
219
+ options.select do |option|
220
+ GLIMMER_OPTIONS.reduce(false) do |result, glimmer_option|
221
+ result || option.include?(glimmer_option)
222
+ end
223
+ end.each do |glimmer_option|
224
+ options.delete(glimmer_option)
225
+ end.reduce({}) do |hash, glimmer_option_string|
226
+ match = glimmer_option_string.match(/^([^=]+)=?(.+)?$/)
227
+ hash.merge(match[1] => (match[2] || 'true'))
228
+ end
229
+ end
230
+ end
231
+ end
@@ -0,0 +1,105 @@
1
+ # Copyright (c) 2007-2023 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'facets'
23
+ require 'text-table'
24
+
25
+ module Glimmer
26
+ module RakeTask
27
+ # Lists Glimmer related gems to use in rake_task.rb
28
+ class List
29
+ class << self
30
+ REGEX_GEM_LINE = /^([^\(]+) \(([^\)]+)\)$/
31
+
32
+ def custom_control_gems(query=nil)
33
+ list_gems('glimmer-cw-', query) do |result|
34
+ puts
35
+ puts " Glimmer Custom Control Gems#{" matching [#{query}]" if query} at rubygems.org:"
36
+ puts result
37
+ end
38
+ end
39
+
40
+ def custom_window_gems(query=nil)
41
+ list_gems('glimmer-cs-', query) do |result|
42
+ puts
43
+ puts " Glimmer Custom Window Gems#{" matching [#{query}]" if query} at rubygems.org:"
44
+ puts result
45
+ end
46
+ end
47
+
48
+ def custom_shape_gems(query=nil)
49
+ list_gems('glimmer-cp-', query) do |result|
50
+ puts
51
+ puts " Glimmer Custom Shape Gems#{" matching [#{query}]" if query} at rubygems.org:"
52
+ puts result
53
+ end
54
+ end
55
+
56
+ def dsl_gems(query=nil)
57
+ list_gems('glimmer-dsl-', query) do |result|
58
+ puts
59
+ puts " Glimmer DSL Gems#{" matching [#{query}]" if query} at rubygems.org:"
60
+ puts result
61
+ end
62
+ end
63
+
64
+ def list_gems(gem_prefix, query=nil, &printer)
65
+ lines = `gem search -d #{gem_prefix}`.split("\n")
66
+ gems = lines.slice_before {|l| l.match(REGEX_GEM_LINE) }.to_a
67
+ gems = gems.map do |gem|
68
+ {
69
+ name: gem[0].match(REGEX_GEM_LINE)[1],
70
+ version: gem[0].match(REGEX_GEM_LINE)[2],
71
+ author: gem[1].strip,
72
+ description: gem[4..-1]&.map(&:strip)&.join(' ').to_s
73
+ }
74
+ end.select do |gem|
75
+ query.nil? || "#{gem[:name]} #{gem[:author]} #{gem[:description]}".downcase.include?(query.to_s.downcase)
76
+ end
77
+ printer.call(tablify(gem_prefix, gems))
78
+ end
79
+
80
+ def tablify(gem_prefix, gems)
81
+ array_of_arrays = gems.map do |gem|
82
+ name, namespace = gem[:name].sub(gem_prefix, '').underscore.titlecase.split
83
+ human_name = name
84
+ human_name += " (#{namespace})" unless namespace.nil?
85
+ [
86
+ human_name,
87
+ gem[:name],
88
+ gem[:version],
89
+ gem[:author].sub('Author: ', ''),
90
+ gem[:description],
91
+ ]
92
+ end
93
+ Text::Table.new(
94
+ :head => %w[Name Gem Version Author Description],
95
+ :rows => array_of_arrays,
96
+ :horizontal_padding => 1,
97
+ :vertical_boundary => ' ',
98
+ :horizontal_boundary => ' ',
99
+ :boundary_intersection => ' '
100
+ )
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end