konpeito 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/.ruby-version +1 -0
- data/CHANGELOG.md +75 -0
- data/CONTRIBUTING.md +123 -0
- data/LICENSE +21 -0
- data/README.md +257 -0
- data/Rakefile +11 -0
- data/bin/konpeito +6 -0
- data/konpeito.gemspec +43 -0
- data/lib/konpeito/ast/typed_ast.rb +620 -0
- data/lib/konpeito/ast/visitor.rb +78 -0
- data/lib/konpeito/cache/cache_manager.rb +230 -0
- data/lib/konpeito/cache/dependency_graph.rb +192 -0
- data/lib/konpeito/cache.rb +8 -0
- data/lib/konpeito/cli/base_command.rb +187 -0
- data/lib/konpeito/cli/build_command.rb +220 -0
- data/lib/konpeito/cli/check_command.rb +104 -0
- data/lib/konpeito/cli/config.rb +231 -0
- data/lib/konpeito/cli/deps_command.rb +128 -0
- data/lib/konpeito/cli/doctor_command.rb +340 -0
- data/lib/konpeito/cli/fmt_command.rb +199 -0
- data/lib/konpeito/cli/init_command.rb +312 -0
- data/lib/konpeito/cli/lsp_command.rb +40 -0
- data/lib/konpeito/cli/run_command.rb +150 -0
- data/lib/konpeito/cli/test_command.rb +248 -0
- data/lib/konpeito/cli/watch_command.rb +212 -0
- data/lib/konpeito/cli.rb +301 -0
- data/lib/konpeito/codegen/builtin_methods.rb +229 -0
- data/lib/konpeito/codegen/cruby_backend.rb +1090 -0
- data/lib/konpeito/codegen/debug_info.rb +352 -0
- data/lib/konpeito/codegen/inliner.rb +486 -0
- data/lib/konpeito/codegen/jvm_backend.rb +197 -0
- data/lib/konpeito/codegen/jvm_generator.rb +13412 -0
- data/lib/konpeito/codegen/llvm_generator.rb +13191 -0
- data/lib/konpeito/codegen/loop_optimizer.rb +363 -0
- data/lib/konpeito/codegen/monomorphizer.rb +359 -0
- data/lib/konpeito/codegen/profile_runtime.c +341 -0
- data/lib/konpeito/codegen/profiler.rb +99 -0
- data/lib/konpeito/compiler.rb +592 -0
- data/lib/konpeito/dependency_resolver.rb +296 -0
- data/lib/konpeito/diagnostics/collector.rb +127 -0
- data/lib/konpeito/diagnostics/diagnostic.rb +237 -0
- data/lib/konpeito/diagnostics/renderer.rb +144 -0
- data/lib/konpeito/formatter/formatter.rb +1214 -0
- data/lib/konpeito/hir/builder.rb +7167 -0
- data/lib/konpeito/hir/nodes.rb +2465 -0
- data/lib/konpeito/lsp/document_manager.rb +820 -0
- data/lib/konpeito/lsp/server.rb +183 -0
- data/lib/konpeito/lsp/transport.rb +38 -0
- data/lib/konpeito/parser/prism_adapter.rb +65 -0
- data/lib/konpeito/platform.rb +103 -0
- data/lib/konpeito/profile/report.rb +136 -0
- data/lib/konpeito/rbs_inline/preprocessor.rb +199 -0
- data/lib/konpeito/stdlib/compression/compression.rb +72 -0
- data/lib/konpeito/stdlib/compression/compression.rbs +60 -0
- data/lib/konpeito/stdlib/compression/compression_native.c +415 -0
- data/lib/konpeito/stdlib/compression/extconf.rb +19 -0
- data/lib/konpeito/stdlib/crypto/crypto.rb +85 -0
- data/lib/konpeito/stdlib/crypto/crypto.rbs +74 -0
- data/lib/konpeito/stdlib/crypto/crypto_native.c +312 -0
- data/lib/konpeito/stdlib/crypto/extconf.rb +40 -0
- data/lib/konpeito/stdlib/http/extconf.rb +19 -0
- data/lib/konpeito/stdlib/http/http.rb +125 -0
- data/lib/konpeito/stdlib/http/http.rbs +57 -0
- data/lib/konpeito/stdlib/http/http_native.c +440 -0
- data/lib/konpeito/stdlib/json/extconf.rb +17 -0
- data/lib/konpeito/stdlib/json/json.rb +44 -0
- data/lib/konpeito/stdlib/json/json.rbs +33 -0
- data/lib/konpeito/stdlib/json/json_native.c +286 -0
- data/lib/konpeito/stdlib/ui/extconf.rb +216 -0
- data/lib/konpeito/stdlib/ui/konpeito_ui_native.cpp +1625 -0
- data/lib/konpeito/stdlib/ui/konpeito_ui_native.h +162 -0
- data/lib/konpeito/stdlib/ui/ui.rb +318 -0
- data/lib/konpeito/stdlib/ui/ui.rbs +247 -0
- data/lib/konpeito/type_checker/annotation_parser.rb +67 -0
- data/lib/konpeito/type_checker/hm_inferrer.rb +2565 -0
- data/lib/konpeito/type_checker/inferrer.rb +565 -0
- data/lib/konpeito/type_checker/rbs_loader.rb +1621 -0
- data/lib/konpeito/type_checker/type_resolver.rb +276 -0
- data/lib/konpeito/type_checker/types.rb +1434 -0
- data/lib/konpeito/type_checker/unification.rb +323 -0
- data/lib/konpeito/ui/animation/animated_state.rb +80 -0
- data/lib/konpeito/ui/animation/easing.rb +59 -0
- data/lib/konpeito/ui/animation/value_tween.rb +66 -0
- data/lib/konpeito/ui/app.rb +379 -0
- data/lib/konpeito/ui/box.rb +38 -0
- data/lib/konpeito/ui/castella.rb +70 -0
- data/lib/konpeito/ui/castella_native.rb +76 -0
- data/lib/konpeito/ui/chart/area_chart.rb +305 -0
- data/lib/konpeito/ui/chart/bar_chart.rb +288 -0
- data/lib/konpeito/ui/chart/base_chart.rb +210 -0
- data/lib/konpeito/ui/chart/chart_helpers.rb +79 -0
- data/lib/konpeito/ui/chart/gauge_chart.rb +171 -0
- data/lib/konpeito/ui/chart/heatmap_chart.rb +222 -0
- data/lib/konpeito/ui/chart/line_chart.rb +289 -0
- data/lib/konpeito/ui/chart/pie_chart.rb +219 -0
- data/lib/konpeito/ui/chart/scales.rb +77 -0
- data/lib/konpeito/ui/chart/scatter_chart.rb +303 -0
- data/lib/konpeito/ui/chart/stacked_bar_chart.rb +276 -0
- data/lib/konpeito/ui/column.rb +271 -0
- data/lib/konpeito/ui/core.rb +2199 -0
- data/lib/konpeito/ui/dsl.rb +443 -0
- data/lib/konpeito/ui/frame.rb +171 -0
- data/lib/konpeito/ui/frame_native.rb +494 -0
- data/lib/konpeito/ui/markdown/ast.rb +124 -0
- data/lib/konpeito/ui/markdown/mermaid/layout.rb +387 -0
- data/lib/konpeito/ui/markdown/mermaid/models.rb +232 -0
- data/lib/konpeito/ui/markdown/mermaid/parser.rb +519 -0
- data/lib/konpeito/ui/markdown/mermaid/renderer.rb +336 -0
- data/lib/konpeito/ui/markdown/parser.rb +805 -0
- data/lib/konpeito/ui/markdown/renderer.rb +639 -0
- data/lib/konpeito/ui/markdown/theme.rb +165 -0
- data/lib/konpeito/ui/render_node.rb +260 -0
- data/lib/konpeito/ui/row.rb +207 -0
- data/lib/konpeito/ui/spacer.rb +18 -0
- data/lib/konpeito/ui/style.rb +799 -0
- data/lib/konpeito/ui/theme.rb +563 -0
- data/lib/konpeito/ui/themes/material.rb +35 -0
- data/lib/konpeito/ui/themes/tokyo_night.rb +6 -0
- data/lib/konpeito/ui/widgets/button.rb +103 -0
- data/lib/konpeito/ui/widgets/calendar.rb +1034 -0
- data/lib/konpeito/ui/widgets/checkbox.rb +119 -0
- data/lib/konpeito/ui/widgets/container.rb +91 -0
- data/lib/konpeito/ui/widgets/data_table.rb +667 -0
- data/lib/konpeito/ui/widgets/divider.rb +29 -0
- data/lib/konpeito/ui/widgets/image.rb +105 -0
- data/lib/konpeito/ui/widgets/input.rb +485 -0
- data/lib/konpeito/ui/widgets/markdown.rb +57 -0
- data/lib/konpeito/ui/widgets/modal.rb +163 -0
- data/lib/konpeito/ui/widgets/multiline_input.rb +968 -0
- data/lib/konpeito/ui/widgets/multiline_text.rb +180 -0
- data/lib/konpeito/ui/widgets/net_image.rb +100 -0
- data/lib/konpeito/ui/widgets/progress_bar.rb +70 -0
- data/lib/konpeito/ui/widgets/radio_buttons.rb +93 -0
- data/lib/konpeito/ui/widgets/slider.rb +133 -0
- data/lib/konpeito/ui/widgets/switch.rb +84 -0
- data/lib/konpeito/ui/widgets/tabs.rb +157 -0
- data/lib/konpeito/ui/widgets/text.rb +110 -0
- data/lib/konpeito/ui/widgets/tree.rb +426 -0
- data/lib/konpeito/version.rb +5 -0
- data/lib/konpeito.rb +109 -0
- data/test_native_array.rb +172 -0
- data/test_native_array_class.rb +197 -0
- data/test_native_class.rb +151 -0
- data/tools/konpeito-asm/build.sh +65 -0
- data/tools/konpeito-asm/lib/asm-9.7.1.jar +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KArray.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KCompression.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KConditionVariable.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KCrypto.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KFile.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KHTTP.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KHash.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KJSON$Parser.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KJSON.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KMath.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KRactor.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KRactorPort.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KSizedQueue.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KThread.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KTime.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/RubyDispatch.class +0 -0
- data/tools/konpeito-asm/src/ClassIntrospector.java +312 -0
- data/tools/konpeito-asm/src/KonpeitoAssembler.java +659 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KArray.java +390 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KCompression.java +168 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KConditionVariable.java +48 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KCrypto.java +151 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KFile.java +100 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KHTTP.java +113 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KHash.java +228 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KJSON.java +405 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KMath.java +54 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KRactor.java +244 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KRactorPort.java +53 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KSizedQueue.java +49 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KThread.java +49 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KTime.java +53 -0
- data/tools/konpeito-asm/src/konpeito/runtime/RubyDispatch.java +416 -0
- metadata +267 -0
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Konpeito
|
|
4
|
+
module Commands
|
|
5
|
+
# Doctor command - check development environment
|
|
6
|
+
class DoctorCommand < BaseCommand
|
|
7
|
+
def self.command_name
|
|
8
|
+
"doctor"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.description
|
|
12
|
+
"Check development environment and dependencies"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def run
|
|
16
|
+
parse_options!
|
|
17
|
+
|
|
18
|
+
$stderr.puts "Konpeito v#{Konpeito::VERSION} environment check:"
|
|
19
|
+
$stderr.puts ""
|
|
20
|
+
|
|
21
|
+
checks = []
|
|
22
|
+
checks.concat(core_checks)
|
|
23
|
+
checks.concat(native_checks) if check_native?
|
|
24
|
+
checks.concat(jvm_checks) if check_jvm?
|
|
25
|
+
checks.concat(ui_checks) if check_ui?
|
|
26
|
+
checks.concat(optional_checks)
|
|
27
|
+
|
|
28
|
+
# Display results
|
|
29
|
+
max_name_len = checks.map { |c| c[:name].length }.max || 10
|
|
30
|
+
checks.each do |check|
|
|
31
|
+
display_check(check, max_name_len)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
$stderr.puts ""
|
|
35
|
+
|
|
36
|
+
issues = checks.select { |c| c[:status] == :missing }
|
|
37
|
+
warnings = checks.select { |c| c[:status] == :warning }
|
|
38
|
+
|
|
39
|
+
if issues.empty? && warnings.empty?
|
|
40
|
+
emit("All checks", "passed.")
|
|
41
|
+
else
|
|
42
|
+
emit_warn("Warnings", "#{warnings.size} warning(s)") unless warnings.empty?
|
|
43
|
+
emit_error("Issues", "#{issues.size} issue(s) found.") unless issues.empty?
|
|
44
|
+
exit 1 unless issues.empty?
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
protected
|
|
49
|
+
|
|
50
|
+
def default_options
|
|
51
|
+
{
|
|
52
|
+
verbose: false,
|
|
53
|
+
color: $stderr.tty?,
|
|
54
|
+
target: nil # nil = check both
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def setup_option_parser(opts)
|
|
59
|
+
opts.on("--target TARGET", %i[native jvm ui], "Check only native, jvm, or ui dependencies") do |target|
|
|
60
|
+
options[:target] = target
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
super
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def banner
|
|
67
|
+
"Usage: konpeito doctor [options]"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def check_native?
|
|
73
|
+
options[:target].nil? || options[:target] == :native
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def check_jvm?
|
|
77
|
+
options[:target].nil? || options[:target] == :jvm
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def check_ui?
|
|
81
|
+
options[:target] == :ui
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def core_checks
|
|
85
|
+
checks = []
|
|
86
|
+
|
|
87
|
+
# Ruby version
|
|
88
|
+
checks << {
|
|
89
|
+
name: "Ruby",
|
|
90
|
+
detail: RUBY_VERSION,
|
|
91
|
+
status: ruby_version_ok? ? :ok : :missing,
|
|
92
|
+
hint: "Ruby 4.0+ required. Install with: rbenv install 4.0.1"
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
# Prism
|
|
96
|
+
checks << check_require("Prism", "prism", hint: "Prism is bundled with Ruby 4.0+")
|
|
97
|
+
|
|
98
|
+
# RBS
|
|
99
|
+
checks << check_require("RBS", "rbs", hint: "Install with: gem install rbs")
|
|
100
|
+
|
|
101
|
+
checks
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def native_checks
|
|
105
|
+
checks = []
|
|
106
|
+
|
|
107
|
+
# ruby-llvm (optional — only needed for native target)
|
|
108
|
+
checks << check_require("ruby-llvm", "llvm/core",
|
|
109
|
+
required: false,
|
|
110
|
+
hint: "Optional for JVM-only. Required for --target native. Install: gem install ruby-llvm")
|
|
111
|
+
|
|
112
|
+
# clang
|
|
113
|
+
clang_path = Platform.find_llvm_tool("clang")
|
|
114
|
+
checks << {
|
|
115
|
+
name: "clang",
|
|
116
|
+
detail: clang_path || "not found",
|
|
117
|
+
status: clang_path ? :ok : :missing,
|
|
118
|
+
hint: "Install: #{Platform.llvm_install_hint}"
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
# opt
|
|
122
|
+
opt_path = Platform.find_llvm_tool("opt")
|
|
123
|
+
checks << {
|
|
124
|
+
name: "opt",
|
|
125
|
+
detail: opt_path || "not found",
|
|
126
|
+
status: opt_path ? :ok : :missing,
|
|
127
|
+
hint: "Install: #{Platform.llvm_install_hint}"
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
# libLLVM (for debug info)
|
|
131
|
+
llvm_lib = Platform.find_llvm_lib
|
|
132
|
+
checks << {
|
|
133
|
+
name: "libLLVM",
|
|
134
|
+
detail: llvm_lib || "not found",
|
|
135
|
+
status: llvm_lib ? :ok : :warning,
|
|
136
|
+
hint: "Needed for -g (debug info). #{Platform.llvm_install_hint}"
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
checks
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def jvm_checks
|
|
143
|
+
checks = []
|
|
144
|
+
|
|
145
|
+
# Java
|
|
146
|
+
java_path = find_java_path
|
|
147
|
+
java_version = java_path ? detect_java_version(java_path) : nil
|
|
148
|
+
java_ok = java_version && java_version >= 21
|
|
149
|
+
checks << {
|
|
150
|
+
name: "Java",
|
|
151
|
+
detail: java_path ? "#{java_version || '?'} (#{java_path})" : "not found",
|
|
152
|
+
status: java_ok ? :ok : (java_path ? :warning : :missing),
|
|
153
|
+
hint: "Java 21+ required. Install: #{Platform.java_install_hint}"
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
# ASM tool - check both gem install path and local path
|
|
157
|
+
asm_jar_gem = File.expand_path("../../../tools/konpeito-asm/konpeito-asm.jar", __dir__)
|
|
158
|
+
asm_jar_local = File.join("tools", "konpeito-asm", "konpeito-asm.jar")
|
|
159
|
+
asm_jar = if File.exist?(asm_jar_gem)
|
|
160
|
+
asm_jar_gem
|
|
161
|
+
elsif File.exist?(asm_jar_local)
|
|
162
|
+
asm_jar_local
|
|
163
|
+
end
|
|
164
|
+
asm_exists = !asm_jar.nil?
|
|
165
|
+
checks << {
|
|
166
|
+
name: "ASM tool",
|
|
167
|
+
detail: asm_exists ? asm_jar : "not found (built automatically on first JVM compile)",
|
|
168
|
+
status: asm_exists ? :ok : :warning,
|
|
169
|
+
hint: asm_exists ? nil : "Run: konpeito build --target jvm hello.rb"
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
checks
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def optional_checks
|
|
176
|
+
checks = []
|
|
177
|
+
|
|
178
|
+
# listen gem (for watch)
|
|
179
|
+
checks << check_require("listen", "listen",
|
|
180
|
+
required: false,
|
|
181
|
+
hint: "Optional, for 'konpeito watch'. Install: gem install listen")
|
|
182
|
+
|
|
183
|
+
# Config file
|
|
184
|
+
config_exists = File.exist?("konpeito.toml")
|
|
185
|
+
checks << {
|
|
186
|
+
name: "Config",
|
|
187
|
+
detail: config_exists ? "konpeito.toml" : "not found",
|
|
188
|
+
status: config_exists ? :ok : :warning,
|
|
189
|
+
hint: "Create with: konpeito init"
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
checks
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def ui_checks
|
|
196
|
+
checks = []
|
|
197
|
+
|
|
198
|
+
# SDL3
|
|
199
|
+
sdl3_found = false
|
|
200
|
+
sdl3_detail = "not found"
|
|
201
|
+
sdl3_hint = "See docs for installation"
|
|
202
|
+
case RUBY_PLATFORM
|
|
203
|
+
when /darwin/
|
|
204
|
+
sdl3_prefix = `brew --prefix sdl3 2>/dev/null`.chomp rescue ""
|
|
205
|
+
if !sdl3_prefix.empty? && File.directory?(sdl3_prefix)
|
|
206
|
+
sdl3_found = true
|
|
207
|
+
sdl3_detail = sdl3_prefix
|
|
208
|
+
end
|
|
209
|
+
sdl3_hint = "Install: brew install sdl3"
|
|
210
|
+
when /linux/
|
|
211
|
+
sdl3_pkg = `pkg-config --modversion sdl3 2>/dev/null`.chomp rescue ""
|
|
212
|
+
if !sdl3_pkg.empty?
|
|
213
|
+
sdl3_found = true
|
|
214
|
+
sdl3_detail = "#{sdl3_pkg} (pkg-config)"
|
|
215
|
+
end
|
|
216
|
+
sdl3_hint = "Install: apt install libsdl3-dev"
|
|
217
|
+
when /mingw|mswin/
|
|
218
|
+
sdl3_dir = ENV["SDL3_DIR"]
|
|
219
|
+
if sdl3_dir && File.directory?(sdl3_dir)
|
|
220
|
+
sdl3_found = true
|
|
221
|
+
sdl3_detail = sdl3_dir
|
|
222
|
+
else
|
|
223
|
+
sdl3_pkg = `pkg-config --modversion sdl3 2>NUL`.chomp rescue ""
|
|
224
|
+
if !sdl3_pkg.empty?
|
|
225
|
+
sdl3_found = true
|
|
226
|
+
sdl3_detail = "#{sdl3_pkg} (pkg-config)"
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
sdl3_hint = "Install: pacman -S mingw-w64-ucrt-x86_64-SDL3"
|
|
230
|
+
end
|
|
231
|
+
checks << {
|
|
232
|
+
name: "SDL3",
|
|
233
|
+
detail: sdl3_detail,
|
|
234
|
+
status: sdl3_found ? :ok : :missing,
|
|
235
|
+
hint: sdl3_hint
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
# Skia
|
|
239
|
+
skia_dir = ENV["SKIA_DIR"] || File.expand_path("~/skia-prebuilt")
|
|
240
|
+
skia_found = false
|
|
241
|
+
if File.directory?(File.join(skia_dir, "out"))
|
|
242
|
+
# Search for libskia.a (Unix) or skia.lib (Windows)
|
|
243
|
+
Dir.glob(File.join(skia_dir, "out", "*", "{libskia.a,skia.lib}")).each do |path|
|
|
244
|
+
skia_found = true
|
|
245
|
+
break
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
skia_found ||= File.exist?(File.join(skia_dir, "lib", "libskia.a"))
|
|
249
|
+
skia_found ||= File.exist?(File.join(skia_dir, "lib", "skia.lib"))
|
|
250
|
+
skia_detail = skia_found ? skia_dir : "not found"
|
|
251
|
+
checks << {
|
|
252
|
+
name: "Skia",
|
|
253
|
+
detail: skia_detail,
|
|
254
|
+
status: skia_found ? :ok : :missing,
|
|
255
|
+
hint: "Set SKIA_DIR env var or place at ~/skia-prebuilt. See docs for build instructions."
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
# konpeito_ui extension
|
|
259
|
+
ui_ext_found = false
|
|
260
|
+
ui_ext_detail = "not found"
|
|
261
|
+
begin
|
|
262
|
+
require "konpeito/stdlib/ui/konpeito_ui"
|
|
263
|
+
ui_ext_found = true
|
|
264
|
+
ui_ext_detail = "loaded"
|
|
265
|
+
rescue LoadError
|
|
266
|
+
ui_makefile = File.join(__dir__, "..", "stdlib", "ui", "Makefile")
|
|
267
|
+
if File.exist?(ui_makefile)
|
|
268
|
+
ui_ext_detail = "not compiled (run: cd lib/konpeito/stdlib/ui && make)"
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
checks << {
|
|
272
|
+
name: "konpeito_ui",
|
|
273
|
+
detail: ui_ext_detail,
|
|
274
|
+
status: ui_ext_found ? :ok : :missing,
|
|
275
|
+
hint: "Build: cd lib/konpeito/stdlib/ui && ruby extconf.rb && make"
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
checks
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
def display_check(check, max_name_len)
|
|
282
|
+
name = check[:name].ljust(max_name_len)
|
|
283
|
+
detail = check[:detail] || ""
|
|
284
|
+
|
|
285
|
+
case check[:status]
|
|
286
|
+
when :ok
|
|
287
|
+
status_str = options[:color] ? "\e[32mok\e[0m" : "ok"
|
|
288
|
+
when :warning
|
|
289
|
+
status_str = options[:color] ? "\e[33mWARNING\e[0m" : "WARNING"
|
|
290
|
+
when :missing
|
|
291
|
+
status_str = options[:color] ? "\e[31mMISSING\e[0m" : "MISSING"
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
# Truncate detail to fit in terminal
|
|
295
|
+
detail_max = 50
|
|
296
|
+
detail = detail[0, detail_max] + "..." if detail.length > detail_max + 3
|
|
297
|
+
|
|
298
|
+
$stderr.puts " %-*s %-55s %s" % [max_name_len, name, detail, status_str]
|
|
299
|
+
|
|
300
|
+
# Show hint for non-ok status
|
|
301
|
+
if check[:status] != :ok && check[:hint]
|
|
302
|
+
$stderr.puts " %-*s %s" % [max_name_len, "", check[:hint]]
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def check_require(name, lib, required: true, hint: nil)
|
|
307
|
+
begin
|
|
308
|
+
require lib
|
|
309
|
+
{ name: name, detail: "available", status: :ok, hint: hint }
|
|
310
|
+
rescue LoadError
|
|
311
|
+
{ name: name, detail: "not found", status: required ? :missing : :warning, hint: hint }
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
def ruby_version_ok?
|
|
316
|
+
parts = RUBY_VERSION.split(".").map(&:to_i)
|
|
317
|
+
parts[0] > 4 || (parts[0] == 4 && parts[1] >= 0)
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
def find_java_path
|
|
321
|
+
# Check JAVA_HOME first
|
|
322
|
+
java_home = ENV["JAVA_HOME"] || Platform.default_java_home
|
|
323
|
+
java_path = File.join(java_home, "bin", "java")
|
|
324
|
+
return java_path if File.exist?(java_path)
|
|
325
|
+
|
|
326
|
+
# Fall back to PATH
|
|
327
|
+
Platform.find_executable("java")
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
def detect_java_version(java_path)
|
|
331
|
+
output = `"#{java_path}" -version 2>&1`
|
|
332
|
+
if output =~ /version "(\d+)/
|
|
333
|
+
Regexp.last_match(1).to_i
|
|
334
|
+
end
|
|
335
|
+
rescue
|
|
336
|
+
nil
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
end
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../formatter/formatter"
|
|
4
|
+
|
|
5
|
+
module Konpeito
|
|
6
|
+
module Commands
|
|
7
|
+
# Fmt command - format Ruby source files with built-in Prism-based formatter
|
|
8
|
+
class FmtCommand < BaseCommand
|
|
9
|
+
def self.command_name
|
|
10
|
+
"fmt"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.description
|
|
14
|
+
"Format Ruby source files"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def run
|
|
18
|
+
parse_options!
|
|
19
|
+
|
|
20
|
+
@files = args.empty? ? find_ruby_files : args
|
|
21
|
+
|
|
22
|
+
if @files.empty?
|
|
23
|
+
$stderr.puts "No Ruby files found to format."
|
|
24
|
+
return
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
emit("Formatting", "#{@files.size} file(s)...") unless options[:quiet]
|
|
28
|
+
|
|
29
|
+
changed = 0
|
|
30
|
+
unchanged = 0
|
|
31
|
+
errored = 0
|
|
32
|
+
|
|
33
|
+
@files.each do |file|
|
|
34
|
+
result = format_file(file)
|
|
35
|
+
case result
|
|
36
|
+
when :changed
|
|
37
|
+
changed += 1
|
|
38
|
+
when :unchanged
|
|
39
|
+
unchanged += 1
|
|
40
|
+
when :error
|
|
41
|
+
errored += 1
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
unless options[:quiet]
|
|
46
|
+
parts = []
|
|
47
|
+
parts << "#{changed} changed" if changed > 0
|
|
48
|
+
parts << "#{unchanged} unchanged" if unchanged > 0
|
|
49
|
+
parts << "#{errored} error(s)" if errored > 0
|
|
50
|
+
emit("Finished", parts.join(", "))
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
if options[:check] && changed > 0
|
|
54
|
+
exit 1
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
exit 1 if errored > 0
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
protected
|
|
61
|
+
|
|
62
|
+
def default_options
|
|
63
|
+
{
|
|
64
|
+
verbose: false,
|
|
65
|
+
color: $stderr.tty?,
|
|
66
|
+
check: false,
|
|
67
|
+
diff: false,
|
|
68
|
+
quiet: false,
|
|
69
|
+
exclude: []
|
|
70
|
+
}
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def setup_option_parser(opts)
|
|
74
|
+
opts.on("--check", "Check formatting without modifying files") do
|
|
75
|
+
options[:check] = true
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
opts.on("--diff", "Show what would change (unified diff)") do
|
|
79
|
+
options[:diff] = true
|
|
80
|
+
options[:check] = true # diff implies check
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
opts.on("-q", "--quiet", "Suppress non-error output") do
|
|
84
|
+
options[:quiet] = true
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
opts.on("--exclude PATTERN", "Exclude files matching pattern") do |pattern|
|
|
88
|
+
options[:exclude] << pattern
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
super
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def banner
|
|
95
|
+
<<~BANNER.chomp
|
|
96
|
+
Usage: konpeito fmt [options] [files...]
|
|
97
|
+
|
|
98
|
+
Examples:
|
|
99
|
+
konpeito fmt Format all Ruby files
|
|
100
|
+
konpeito fmt src/main.rb Format specific file
|
|
101
|
+
konpeito fmt --check Check without modifying
|
|
102
|
+
konpeito fmt --diff Show what would change
|
|
103
|
+
BANNER
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
private
|
|
107
|
+
|
|
108
|
+
def find_ruby_files
|
|
109
|
+
default_exclude = ["vendor/", ".bundle/", ".konpeito_cache/", "tools/"]
|
|
110
|
+
all_exclude = default_exclude + options[:exclude]
|
|
111
|
+
|
|
112
|
+
Dir.glob("**/*.rb").reject do |f|
|
|
113
|
+
all_exclude.any? { |pat| f.start_with?(pat) || File.fnmatch?(pat, f) }
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def format_file(file)
|
|
118
|
+
unless File.exist?(file)
|
|
119
|
+
$stderr.puts "Warning: #{file} not found, skipping"
|
|
120
|
+
return :error
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
source = File.read(file)
|
|
124
|
+
formatter = Formatter::Formatter.new(source, filepath: file)
|
|
125
|
+
formatted = formatter.format
|
|
126
|
+
|
|
127
|
+
if source == formatted
|
|
128
|
+
return :unchanged
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
if options[:diff]
|
|
132
|
+
show_diff(file, source, formatted)
|
|
133
|
+
emit("Formatted", file) unless options[:quiet]
|
|
134
|
+
return :changed
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
if options[:check]
|
|
138
|
+
emit_warn("Unformatted", file) unless options[:quiet]
|
|
139
|
+
return :changed
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Write formatted content
|
|
143
|
+
File.write(file, formatted)
|
|
144
|
+
emit("Formatted", file) unless options[:quiet]
|
|
145
|
+
:changed
|
|
146
|
+
rescue => e
|
|
147
|
+
$stderr.puts "Error formatting #{file}: #{e.message}"
|
|
148
|
+
:error
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def show_diff(file, original, formatted)
|
|
152
|
+
orig_lines = original.lines
|
|
153
|
+
fmt_lines = formatted.lines
|
|
154
|
+
|
|
155
|
+
# Simple unified diff
|
|
156
|
+
$stdout.puts "--- #{file}"
|
|
157
|
+
$stdout.puts "+++ #{file} (formatted)"
|
|
158
|
+
|
|
159
|
+
# Find differing regions
|
|
160
|
+
max_len = [orig_lines.size, fmt_lines.size].max
|
|
161
|
+
i = 0
|
|
162
|
+
while i < max_len
|
|
163
|
+
if orig_lines[i] != fmt_lines[i]
|
|
164
|
+
# Find the end of this diff hunk
|
|
165
|
+
hunk_start = i
|
|
166
|
+
while i < max_len && orig_lines[i] != fmt_lines[i]
|
|
167
|
+
i += 1
|
|
168
|
+
end
|
|
169
|
+
hunk_end = i
|
|
170
|
+
|
|
171
|
+
# Context
|
|
172
|
+
ctx_start = [hunk_start - 3, 0].max
|
|
173
|
+
ctx_end = [hunk_end + 3, max_len].min
|
|
174
|
+
|
|
175
|
+
$stdout.puts "@@ -#{ctx_start + 1},#{hunk_end - ctx_start} +#{ctx_start + 1},#{hunk_end - ctx_start} @@"
|
|
176
|
+
|
|
177
|
+
(ctx_start...ctx_end).each do |j|
|
|
178
|
+
if j >= hunk_start && j < hunk_end
|
|
179
|
+
if j < orig_lines.size && orig_lines[j]
|
|
180
|
+
line = orig_lines[j].chomp
|
|
181
|
+
$stdout.puts options[:color] ? "\e[31m-#{line}\e[0m" : "-#{line}"
|
|
182
|
+
end
|
|
183
|
+
if j < fmt_lines.size && fmt_lines[j]
|
|
184
|
+
line = fmt_lines[j].chomp
|
|
185
|
+
$stdout.puts options[:color] ? "\e[32m+#{line}\e[0m" : "+#{line}"
|
|
186
|
+
end
|
|
187
|
+
else
|
|
188
|
+
line = (orig_lines[j] || fmt_lines[j] || "").chomp
|
|
189
|
+
$stdout.puts " #{line}"
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
else
|
|
193
|
+
i += 1
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|