ratatui_ruby 0.1.0 → 0.3.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 +4 -4
- data/.builds/ruby-3.2.yml +52 -0
- data/.builds/ruby-3.3.yml +52 -0
- data/.builds/ruby-3.4.yml +52 -0
- data/.builds/ruby-4.0.0.yml +53 -0
- data/.pre-commit-config.yaml +9 -2
- data/AGENTS.md +53 -5
- data/CHANGELOG.md +51 -1
- data/README.md +38 -18
- data/REUSE.toml +5 -0
- data/Rakefile +3 -100
- data/{docs → doc}/contributors/index.md +2 -1
- data/doc/custom.css +8 -0
- data/doc/images/examples-calendar_demo.rb.png +0 -0
- data/doc/images/examples-chart_demo.rb.png +0 -0
- data/doc/images/examples-custom_widget.rb.png +0 -0
- data/doc/images/examples-list_styles.rb.png +0 -0
- data/doc/images/examples-popup_demo.rb.gif +0 -0
- data/doc/images/examples-quickstart_lifecycle.rb.png +0 -0
- data/doc/images/examples-scroll_text.rb.png +0 -0
- data/doc/images/examples-stock_ticker.rb.png +0 -0
- data/doc/images/examples-table_select.rb.png +0 -0
- data/{docs → doc}/index.md +1 -1
- data/{docs → doc}/quickstart.md +81 -11
- data/examples/analytics.rb +2 -1
- data/examples/calendar_demo.rb +55 -0
- data/examples/chart_demo.rb +84 -0
- data/examples/custom_widget.rb +43 -0
- data/examples/list_styles.rb +66 -0
- data/examples/login_form.rb +2 -1
- data/examples/popup_demo.rb +105 -0
- data/examples/quickstart_dsl.rb +30 -0
- data/examples/quickstart_lifecycle.rb +40 -0
- data/examples/readme_usage.rb +21 -0
- data/examples/scroll_text.rb +74 -0
- data/examples/stock_ticker.rb +13 -5
- data/examples/system_monitor.rb +2 -1
- data/examples/table_select.rb +70 -0
- data/examples/test_calendar_demo.rb +66 -0
- data/examples/test_list_styles.rb +61 -0
- data/examples/test_popup_demo.rb +62 -0
- data/examples/test_scroll_text.rb +130 -0
- data/examples/test_table_select.rb +37 -0
- data/ext/ratatui_ruby/.cargo/config.toml +5 -0
- data/ext/ratatui_ruby/Cargo.lock +260 -50
- data/ext/ratatui_ruby/Cargo.toml +5 -4
- data/ext/ratatui_ruby/extconf.rb +1 -1
- data/ext/ratatui_ruby/src/buffer.rs +54 -0
- data/ext/ratatui_ruby/src/events.rs +115 -107
- data/ext/ratatui_ruby/src/lib.rs +15 -6
- data/ext/ratatui_ruby/src/rendering.rs +18 -1
- data/ext/ratatui_ruby/src/style.rs +2 -1
- data/ext/ratatui_ruby/src/terminal.rs +27 -24
- data/ext/ratatui_ruby/src/widgets/calendar.rs +82 -0
- data/ext/ratatui_ruby/src/widgets/canvas.rs +1 -2
- data/ext/ratatui_ruby/src/widgets/center.rs +0 -2
- data/ext/ratatui_ruby/src/widgets/chart.rs +260 -0
- data/ext/ratatui_ruby/src/widgets/clear.rs +37 -0
- data/ext/ratatui_ruby/src/widgets/cursor.rs +1 -1
- data/ext/ratatui_ruby/src/widgets/layout.rs +2 -1
- data/ext/ratatui_ruby/src/widgets/list.rs +44 -5
- data/ext/ratatui_ruby/src/widgets/mod.rs +3 -1
- data/ext/ratatui_ruby/src/widgets/overlay.rs +2 -1
- data/ext/ratatui_ruby/src/widgets/paragraph.rs +10 -0
- data/ext/ratatui_ruby/src/widgets/table.rs +25 -6
- data/ext/ratatui_ruby/src/widgets/tabs.rs +2 -1
- data/lib/ratatui_ruby/dsl.rb +64 -0
- data/lib/ratatui_ruby/schema/calendar.rb +26 -0
- data/lib/ratatui_ruby/schema/chart.rb +81 -0
- data/lib/ratatui_ruby/schema/clear.rb +83 -0
- data/lib/ratatui_ruby/schema/list.rb +8 -2
- data/lib/ratatui_ruby/schema/paragraph.rb +7 -4
- data/lib/ratatui_ruby/schema/rect.rb +24 -0
- data/lib/ratatui_ruby/schema/table.rb +8 -2
- data/lib/ratatui_ruby/version.rb +1 -1
- data/lib/ratatui_ruby.rb +24 -2
- data/mise.toml +8 -0
- data/sig/ratatui_ruby/buffer.rbs +11 -0
- data/sig/ratatui_ruby/schema/calendar.rbs +13 -0
- data/sig/ratatui_ruby/schema/{line_chart.rbs → chart.rbs} +20 -1
- data/sig/ratatui_ruby/schema/list.rbs +4 -1
- data/sig/ratatui_ruby/schema/rect.rbs +14 -0
- data/tasks/bump/cargo_lockfile.rb +19 -0
- data/tasks/bump/changelog.rb +37 -0
- data/tasks/bump/comparison_links.rb +41 -0
- data/tasks/bump/header.rb +30 -0
- data/tasks/bump/history.rb +30 -0
- data/tasks/bump/manifest.rb +31 -0
- data/tasks/bump/ruby_gem.rb +35 -0
- data/tasks/bump/sem_ver.rb +34 -0
- data/tasks/bump/unreleased_section.rb +38 -0
- data/tasks/bump.rake +49 -0
- data/tasks/doc.rake +25 -0
- data/tasks/extension.rake +12 -0
- data/tasks/lint.rake +49 -0
- data/tasks/rdoc_config.rb +15 -0
- data/tasks/resources/build.yml.erb +65 -0
- data/tasks/resources/index.html.erb +38 -0
- data/tasks/resources/rubies.yml +7 -0
- data/tasks/sourcehut.rake +38 -0
- data/tasks/test.rake +31 -0
- data/tasks/website/index_page.rb +28 -0
- data/tasks/website/version.rb +117 -0
- data/tasks/website/version_menu.rb +68 -0
- data/tasks/website/versioned_documentation.rb +49 -0
- data/tasks/website/website.rb +53 -0
- data/tasks/website.rake +26 -0
- metadata +119 -28
- data/.build.yml +0 -34
- data/.ruby-version +0 -1
- data/CODE_OF_CONDUCT.md +0 -30
- data/CONTRIBUTING.md +0 -40
- data/docs/images/examples-stock_ticker.rb.png +0 -0
- data/ext/ratatui_ruby/src/widgets/linechart.rs +0 -154
- data/lib/ratatui_ruby/schema/line_chart.rb +0 -41
- /data/{docs → doc}/application_testing.md +0 -0
- /data/{docs → doc}/contributors/design/ruby_frontend.md +0 -0
- /data/{docs → doc}/contributors/design/rust_backend.md +0 -0
- /data/{docs → doc}/contributors/design.md +0 -0
- /data/{docs → doc}/images/examples-analytics.rb.png +0 -0
- /data/{docs → doc}/images/examples-box_demo.rb.png +0 -0
- /data/{docs → doc}/images/examples-dashboard.rb.png +0 -0
- /data/{docs → doc}/images/examples-login_form.rb.png +0 -0
- /data/{docs → doc}/images/examples-map_demo.rb.png +0 -0
- /data/{docs → doc}/images/examples-mouse_events.rb.png +0 -0
- /data/{docs → doc}/images/examples-scrollbar_demo.rb.png +0 -0
- /data/{docs → doc}/images/examples-system_monitor.rb.png +0 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
|
|
6
|
+
# History manages the versioned history of the changelog.
|
|
7
|
+
class History
|
|
8
|
+
# Extracts the history section from the given content, between unreleased and links.
|
|
9
|
+
def self.parse(content, header_length, unreleased_length, links_text)
|
|
10
|
+
start = header_length + unreleased_length
|
|
11
|
+
text = content[start...content.index(links_text)].strip + "\n"
|
|
12
|
+
new(text)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Creates a new History from the given content.
|
|
16
|
+
def initialize(content)
|
|
17
|
+
@content = content.dup
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Adds a new versioned section to the history.
|
|
21
|
+
def add(section)
|
|
22
|
+
@content = "#{section}\n\n#{@content}".strip + "\n"
|
|
23
|
+
nil
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Returns the current state of the history as a string.
|
|
27
|
+
def to_s
|
|
28
|
+
@content
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
|
|
6
|
+
# Manifests hold a copy of the version number and should be changed manually.
|
|
7
|
+
# Use Regexp lookarounds in `pattern` to match the version number.
|
|
8
|
+
class Manifest < Data.define(:path, :pattern, :primary)
|
|
9
|
+
def read
|
|
10
|
+
File.read(path)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def initialize(path:, pattern:, primary: false)
|
|
14
|
+
super
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def version
|
|
18
|
+
content = read
|
|
19
|
+
match = content.match(pattern)
|
|
20
|
+
raise "Version missing in manifest #{path}" unless match
|
|
21
|
+
|
|
22
|
+
SemVer.parse(match[0])
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def write(version)
|
|
26
|
+
return unless File.exist?(path)
|
|
27
|
+
|
|
28
|
+
new_content = read.gsub(pattern, version.to_s)
|
|
29
|
+
File.write(path, new_content)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
|
|
6
|
+
class RubyGem
|
|
7
|
+
def initialize(manifests:, lockfile:, changelog:)
|
|
8
|
+
raise ArgumentError, "Must have exactly one primary manifest" unless manifests.count(&:primary) == 1
|
|
9
|
+
@manifests = manifests
|
|
10
|
+
@lockfile = lockfile
|
|
11
|
+
@changelog = changelog
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def version
|
|
15
|
+
@manifests.find(&:primary).version
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def bump(segment)
|
|
19
|
+
target = version.next(segment)
|
|
20
|
+
|
|
21
|
+
puts "Bumping #{segment}: #{version} -> #{target}"
|
|
22
|
+
@changelog.release(target)
|
|
23
|
+
@manifests.each { |manifest| manifest.write(target) }
|
|
24
|
+
@lockfile.refresh
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def set(version_string)
|
|
28
|
+
target = SemVer.parse(version_string)
|
|
29
|
+
|
|
30
|
+
puts "Setting version: #{version} -> #{target}"
|
|
31
|
+
@changelog.release(target)
|
|
32
|
+
@manifests.each { |manifest| manifest.write(target) }
|
|
33
|
+
@lockfile.refresh
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
|
|
6
|
+
# See https://semver.org/spec/v2.0.0.html
|
|
7
|
+
class SemVer
|
|
8
|
+
SEGMENTS = [:major, :minor, :patch].freeze
|
|
9
|
+
|
|
10
|
+
def self.parse(string)
|
|
11
|
+
require "rubygems"
|
|
12
|
+
segments = Gem::Version.new(string).segments.fill(0, 3).first(3)
|
|
13
|
+
new(segments)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def initialize(segments)
|
|
17
|
+
@segments = segments
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def next(segment)
|
|
21
|
+
index = SEGMENTS.index(segment)
|
|
22
|
+
raise ArgumentError, "Invalid segment: #{segment}" unless index
|
|
23
|
+
|
|
24
|
+
new_segments = @segments.dup
|
|
25
|
+
new_segments[index] += 1
|
|
26
|
+
new_segments.fill(0, (index + 1)..2)
|
|
27
|
+
|
|
28
|
+
SemVer.new(new_segments)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def to_s
|
|
32
|
+
@segments.join(".")
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
|
|
6
|
+
require "date"
|
|
7
|
+
|
|
8
|
+
# UnreleasedSection manages the [Unreleased] section of the changelog.
|
|
9
|
+
class UnreleasedSection
|
|
10
|
+
PATTERN = /^(## \[Unreleased\].*?)(?=## \[\d)/m
|
|
11
|
+
|
|
12
|
+
# Extracts the unreleased section from the given content.
|
|
13
|
+
def self.parse(content)
|
|
14
|
+
match = content.match(PATTERN)
|
|
15
|
+
new(match[1].strip) if match
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Creates a new UnreleasedSection from the given unreleased content.
|
|
19
|
+
def initialize(content)
|
|
20
|
+
@content = content.dup
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Returns the unreleased content as a versioned section.
|
|
24
|
+
def as_version(new_version)
|
|
25
|
+
date = Date.today.iso8601
|
|
26
|
+
@content.sub(/^## \[Unreleased\]/, "## [#{new_version}] - #{date}")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Returns a fresh unreleased section.
|
|
30
|
+
def self.fresh
|
|
31
|
+
new("## [Unreleased]\n\n### Added\n\n### Changed\n\n### Fixed\n\n### Removed")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Returns the current state of the section as a string.
|
|
35
|
+
def to_s
|
|
36
|
+
@content
|
|
37
|
+
end
|
|
38
|
+
end
|
data/tasks/bump.rake
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
|
|
6
|
+
require "rubygems"
|
|
7
|
+
|
|
8
|
+
require_relative "bump/sem_ver"
|
|
9
|
+
require_relative "bump/manifest"
|
|
10
|
+
require_relative "bump/cargo_lockfile"
|
|
11
|
+
require_relative "bump/ruby_gem"
|
|
12
|
+
require_relative "bump/changelog"
|
|
13
|
+
|
|
14
|
+
namespace :bump do
|
|
15
|
+
ratatuiRuby = RubyGem.new(
|
|
16
|
+
manifests: [
|
|
17
|
+
Manifest.new(
|
|
18
|
+
path: "lib/ratatui_ruby/version.rb",
|
|
19
|
+
pattern: /(?<=VERSION = ")[^"]+(?=")/,
|
|
20
|
+
primary: true
|
|
21
|
+
),
|
|
22
|
+
Manifest.new(
|
|
23
|
+
path: "ext/ratatui_ruby/Cargo.toml",
|
|
24
|
+
pattern: /(?<=^version = ")[^"]+(?=")/,
|
|
25
|
+
primary: false
|
|
26
|
+
),
|
|
27
|
+
],
|
|
28
|
+
lockfile: CargoLockfile.new(
|
|
29
|
+
path: "ext/ratatui_ruby/Cargo.lock",
|
|
30
|
+
dir: "ext/ratatui_ruby",
|
|
31
|
+
name: "ratatui_ruby"
|
|
32
|
+
),
|
|
33
|
+
changelog: Changelog.new
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
SemVer::SEGMENTS.each do |segment|
|
|
37
|
+
desc "Bump #{segment} version"
|
|
38
|
+
task segment do
|
|
39
|
+
ratatuiRuby.bump(segment)
|
|
40
|
+
Rake::Task["sourcehut"].invoke
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
desc "Set exact version (e.g. rake bump:exact[0.1.0])"
|
|
45
|
+
task :exact, [:version] do |_, args|
|
|
46
|
+
ratatuiRuby.set(args[:version])
|
|
47
|
+
Rake::Task["sourcehut"].invoke
|
|
48
|
+
end
|
|
49
|
+
end
|
data/tasks/doc.rake
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
|
|
6
|
+
require "rdoc/task"
|
|
7
|
+
|
|
8
|
+
require_relative "rdoc_config"
|
|
9
|
+
|
|
10
|
+
RDoc::Task.new do |rdoc|
|
|
11
|
+
rdoc.rdoc_dir = "tmp/rdoc"
|
|
12
|
+
rdoc.main = RDocConfig::MAIN
|
|
13
|
+
rdoc.rdoc_files.include(RDocConfig::RDOC_FILES)
|
|
14
|
+
rdoc.options << "--template-stylesheets=doc/custom.css"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
task :copy_doc_images do
|
|
18
|
+
if Dir.exist?("doc/images")
|
|
19
|
+
FileUtils.mkdir_p "tmp/rdoc/doc/images"
|
|
20
|
+
FileUtils.cp_r Dir["doc/images/*.png"], "tmp/rdoc/doc/images"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
Rake::Task[:rdoc].enhance [:copy_doc_images]
|
|
25
|
+
Rake::Task[:rerdoc].enhance [:copy_doc_images]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
|
|
6
|
+
require "rake/extensiontask"
|
|
7
|
+
|
|
8
|
+
spec = Gem::Specification.load("ratatui_ruby.gemspec")
|
|
9
|
+
Rake::ExtensionTask.new("ratatui_ruby", spec) do |ext|
|
|
10
|
+
ext.lib_dir = "lib/ratatui_ruby"
|
|
11
|
+
ext.ext_dir = "ext/ratatui_ruby"
|
|
12
|
+
end
|
data/tasks/lint.rake
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
|
|
6
|
+
require "rubocop/rake_task"
|
|
7
|
+
require "rubycritic/rake_task"
|
|
8
|
+
require "inch/rake"
|
|
9
|
+
|
|
10
|
+
RuboCop::RakeTask.new
|
|
11
|
+
|
|
12
|
+
RubyCritic::RakeTask.new do |task|
|
|
13
|
+
task.options = "--no-browser"
|
|
14
|
+
task.paths = FileList.new.include("exe/**/*.rb", "lib/**/*.rb", "sig/**/*.rbs")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
Inch::Rake::Suggest.new("doc:suggest", "exe/**/*.rb", "lib/**/*.rb", "sig/**/*.rbs") do |suggest|
|
|
18
|
+
suggest.args << ""
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
namespace :cargo do
|
|
22
|
+
desc "Run cargo fmt"
|
|
23
|
+
task :fmt do
|
|
24
|
+
sh "cd ext/ratatui_ruby && cargo fmt --all -- --check"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
desc "Run cargo clippy"
|
|
28
|
+
task :clippy do
|
|
29
|
+
sh "cd ext/ratatui_ruby && cargo clippy -- -D warnings"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
namespace :reuse do
|
|
34
|
+
desc "Run the REUSE Tool to confirm REUSE compliance"
|
|
35
|
+
task :lint do
|
|
36
|
+
sh "reuse lint"
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
task(:reuse) { Rake::Task["reuse:lint"].invoke }
|
|
40
|
+
|
|
41
|
+
namespace :lint do
|
|
42
|
+
task docs: %w[rubycritic rdoc:coverage reuse:lint]
|
|
43
|
+
task code: %w[rubocop rubycritic cargo:fmt cargo:clippy cargo:test]
|
|
44
|
+
task licenses: %w[reuse:lint]
|
|
45
|
+
task all: %w[docs code licenses]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
desc "Run all lint tasks"
|
|
49
|
+
task(:lint) { Rake::Task["lint:all"].invoke }
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
|
|
6
|
+
module RDocConfig
|
|
7
|
+
RDOC_FILES = %w[
|
|
8
|
+
**/*.md
|
|
9
|
+
**/*.rdoc
|
|
10
|
+
lib/**/*.rb
|
|
11
|
+
exe/**/*
|
|
12
|
+
].freeze
|
|
13
|
+
|
|
14
|
+
MAIN = "README.md"
|
|
15
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
2
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
|
|
4
|
+
image: alpine/edge
|
|
5
|
+
packages:
|
|
6
|
+
- bash
|
|
7
|
+
- build-base
|
|
8
|
+
- curl
|
|
9
|
+
- openssl-dev
|
|
10
|
+
- yaml-dev
|
|
11
|
+
- zlib-dev
|
|
12
|
+
- readline-dev
|
|
13
|
+
- gdbm-dev
|
|
14
|
+
- ncurses-dev
|
|
15
|
+
- libffi-dev
|
|
16
|
+
- clang-dev
|
|
17
|
+
- git
|
|
18
|
+
artifacts:
|
|
19
|
+
- ratatui_ruby/pkg/<%= gem_filename %>
|
|
20
|
+
sources:
|
|
21
|
+
- https://git.sr.ht/~kerrick/ratatui_ruby
|
|
22
|
+
tasks:
|
|
23
|
+
- setup: |
|
|
24
|
+
curl https://mise.jdx.dev/install.sh | sh
|
|
25
|
+
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.buildenv
|
|
26
|
+
echo 'eval "$($HOME/.local/bin/mise activate bash)"' >> ~/.buildenv
|
|
27
|
+
. ~/.buildenv
|
|
28
|
+
export RUSTFLAGS="-C target-feature=-crt-static"
|
|
29
|
+
export CI="true"
|
|
30
|
+
cd ratatui_ruby
|
|
31
|
+
sed -i 's/ruby = .*/ruby = "<%= ruby_version %>"/' mise.toml
|
|
32
|
+
mise install
|
|
33
|
+
mise x -- pip install reuse
|
|
34
|
+
mise x -- gem install bundler:<%= bundler_version %>
|
|
35
|
+
mise reshim
|
|
36
|
+
mise x -- bundle config set --local frozen 'true'
|
|
37
|
+
mise x -- bundle install
|
|
38
|
+
<% if ruby_version.start_with?("4.0") -%>
|
|
39
|
+
# We allow this to fail so we can see logs without stopping the CI pipeline
|
|
40
|
+
mise x -- bundle exec rake compile || echo "⚠️ Compilation failed (Allowed Failure)"
|
|
41
|
+
<% else -%>
|
|
42
|
+
mise x -- bundle exec rake compile
|
|
43
|
+
<% end -%>
|
|
44
|
+
- test: |
|
|
45
|
+
. ~/.buildenv
|
|
46
|
+
cd ratatui_ruby
|
|
47
|
+
echo "Testing Ruby <%= ruby_version %>"
|
|
48
|
+
<% if ruby_version.start_with?("4.0") -%>
|
|
49
|
+
mise x -- bundle exec rake test || true
|
|
50
|
+
<% else -%>
|
|
51
|
+
mise x -- bundle exec rake test
|
|
52
|
+
<% end -%>
|
|
53
|
+
- lint: |
|
|
54
|
+
. ~/.buildenv
|
|
55
|
+
cd ratatui_ruby
|
|
56
|
+
echo "Linting Ruby <%= ruby_version %>"
|
|
57
|
+
<% if ruby_version.start_with?("4.0") -%>
|
|
58
|
+
mise x -- bundle exec rake lint || true
|
|
59
|
+
<% else -%>
|
|
60
|
+
mise x -- bundle exec rake lint
|
|
61
|
+
<% end -%>
|
|
62
|
+
- package: |
|
|
63
|
+
. ~/.buildenv
|
|
64
|
+
cd ratatui_ruby
|
|
65
|
+
mise x -- bundle exec rake build
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title><%= project_name %> documentation</title>
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<style>
|
|
7
|
+
:root { color-scheme: light dark; }
|
|
8
|
+
body { font-family: system-ui, sans-serif; max-width: 800px; margin: 0 auto; padding: 2rem; line-height: 1.5; color: light-dark(#111, #eee); background: light-dark(#fff, #111); }
|
|
9
|
+
h1 { border-bottom: 2px solid light-dark(#eee, #333); padding-bottom: 0.5rem; }
|
|
10
|
+
ul { list-style: none; padding: 0; }
|
|
11
|
+
li { margin: 0.5rem 0; border: 1px solid light-dark(#ddd, #444); border-radius: 4px; }
|
|
12
|
+
a { display: block; padding: 1rem; text-decoration: none; color: light-dark(#0055aa, #44aaff); font-weight: bold; }
|
|
13
|
+
a:hover { background: light-dark(#f5f5f5, #222); }
|
|
14
|
+
.meta { font-weight: normal; color: light-dark(#666, #aaa); font-size: 0.9em; float: right; }
|
|
15
|
+
</style>
|
|
16
|
+
</head>
|
|
17
|
+
<body>
|
|
18
|
+
<h1><%= project_name %> documentation</h1>
|
|
19
|
+
<ul>
|
|
20
|
+
<% versions.each do |version| %>
|
|
21
|
+
<li>
|
|
22
|
+
<a href='<%= version.slug %>/index.html'>
|
|
23
|
+
<%= version.name %>
|
|
24
|
+
<span class='meta'>
|
|
25
|
+
<% if version.latest? %>
|
|
26
|
+
Latest
|
|
27
|
+
<% elsif version.edge? %>
|
|
28
|
+
Edge
|
|
29
|
+
<% else %>
|
|
30
|
+
Historical
|
|
31
|
+
<% end %>
|
|
32
|
+
</span>
|
|
33
|
+
</a>
|
|
34
|
+
</li>
|
|
35
|
+
<% end %>
|
|
36
|
+
</ul>
|
|
37
|
+
</body>
|
|
38
|
+
</html>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
|
|
6
|
+
desc "Generate SourceHut build manifests from template"
|
|
7
|
+
task :sourcehut do
|
|
8
|
+
require "erb"
|
|
9
|
+
require "yaml"
|
|
10
|
+
|
|
11
|
+
spec = Gem::Specification.load("ratatui_ruby.gemspec")
|
|
12
|
+
|
|
13
|
+
# Read version directly from file to ensure we get the latest version
|
|
14
|
+
# even if it was just bumped in the same Rake execution
|
|
15
|
+
version_content = File.read("lib/ratatui_ruby/version.rb")
|
|
16
|
+
version = version_content.match(/VERSION = "(.+?)"/)[1]
|
|
17
|
+
|
|
18
|
+
gem_filename = "#{spec.name}-#{version}.gem"
|
|
19
|
+
|
|
20
|
+
rubies = YAML.load_file("tasks/resources/rubies.yml")
|
|
21
|
+
|
|
22
|
+
bundler_version = File.read("Gemfile.lock").match(/BUNDLED WITH\n\s+([\d.]+)/)[1]
|
|
23
|
+
|
|
24
|
+
template = File.read("tasks/resources/build.yml.erb")
|
|
25
|
+
erb = ERB.new(template, trim_mode: "-")
|
|
26
|
+
|
|
27
|
+
FileUtils.mkdir_p ".builds"
|
|
28
|
+
|
|
29
|
+
# Remove old generated files to ensure a clean state
|
|
30
|
+
Dir.glob(".builds/*.yml").each { |f| File.delete(f) }
|
|
31
|
+
|
|
32
|
+
rubies.each do |ruby_version|
|
|
33
|
+
filename = ".builds/ruby-#{ruby_version}.yml"
|
|
34
|
+
puts "Generating #{filename}..."
|
|
35
|
+
content = erb.result_with_hash(ruby_version:, gem_filename:, bundler_version:)
|
|
36
|
+
File.write(filename, content)
|
|
37
|
+
end
|
|
38
|
+
end
|
data/tasks/test.rake
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
|
|
6
|
+
require "minitest/test_task"
|
|
7
|
+
|
|
8
|
+
namespace :cargo do
|
|
9
|
+
desc "Run cargo tests"
|
|
10
|
+
task :test do
|
|
11
|
+
sh "cd ext/ratatui_ruby && cargo test"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Clear the default test task created by Minitest::TestTask if it exists
|
|
16
|
+
Rake::Task["test"].clear if Rake::Task.task_defined?("test")
|
|
17
|
+
|
|
18
|
+
desc "Run all tests (Ruby and Rust)"
|
|
19
|
+
task test: %w[test:ruby test:rust]
|
|
20
|
+
|
|
21
|
+
namespace :test do
|
|
22
|
+
desc "Run Rust tests"
|
|
23
|
+
task :rust do
|
|
24
|
+
Rake::Task["cargo:test"].invoke
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Create a specific Minitest task for Ruby tests
|
|
28
|
+
Minitest::TestTask.create(:ruby) do |t|
|
|
29
|
+
t.test_globs = ["test/**/test_*.rb", "examples/**/test_*.rb"]
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
|
|
6
|
+
require "erb"
|
|
7
|
+
|
|
8
|
+
class IndexPage
|
|
9
|
+
def initialize(versions)
|
|
10
|
+
@versions = versions
|
|
11
|
+
|
|
12
|
+
latest_version = @versions.find { |v| v.is_a?(Tagged) }
|
|
13
|
+
latest_version.is_latest = true if latest_version
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def publish_to(path, project_name:)
|
|
17
|
+
puts "Generating index page..."
|
|
18
|
+
|
|
19
|
+
template_path = File.expand_path("../resources/index.html.erb", __dir__)
|
|
20
|
+
template = File.read(template_path)
|
|
21
|
+
|
|
22
|
+
versions = @versions
|
|
23
|
+
# project_name is used in the ERB
|
|
24
|
+
html_content = ERB.new(template).result(binding)
|
|
25
|
+
|
|
26
|
+
File.write(path, html_content)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
|
|
6
|
+
require "rubygems"
|
|
7
|
+
require "fileutils"
|
|
8
|
+
|
|
9
|
+
class Version
|
|
10
|
+
def self.all
|
|
11
|
+
tags = `git tag`.split.grep(/^v\d/)
|
|
12
|
+
sorted_versions = tags.map { |t| Tagged.new(t) }
|
|
13
|
+
.sort_by { |v| v.semver }
|
|
14
|
+
.reverse
|
|
15
|
+
|
|
16
|
+
[Edge.new] + sorted_versions
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def slug
|
|
20
|
+
raise NotImplementedError
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def name
|
|
24
|
+
raise NotImplementedError
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def type
|
|
28
|
+
raise NotImplementedError
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def checkout(globs:, &block)
|
|
32
|
+
raise NotImplementedError
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def latest?
|
|
36
|
+
false
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def edge?
|
|
40
|
+
false
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
class Edge < Version
|
|
45
|
+
def slug
|
|
46
|
+
"main"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def name
|
|
50
|
+
"main"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def type
|
|
54
|
+
:edge
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def edge?
|
|
58
|
+
true
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def checkout(globs:, &block)
|
|
62
|
+
Dir.mktmpdir do |path|
|
|
63
|
+
# Use git ls-files for accurate source list
|
|
64
|
+
files = `git ls-files`.split("\n").select do |f|
|
|
65
|
+
globs.any? { |glob| File.fnmatch(glob, f, File::FNM_PATHNAME) }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
files.each do |file|
|
|
69
|
+
dest = File.join(path, file)
|
|
70
|
+
next unless File.exist?(file) # Skip files that are in the index but deleted in the working tree
|
|
71
|
+
FileUtils.mkdir_p(File.dirname(dest))
|
|
72
|
+
FileUtils.cp(file, dest)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
yield path
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
class Tagged < Version
|
|
81
|
+
attr_reader :tag
|
|
82
|
+
|
|
83
|
+
def initialize(tag)
|
|
84
|
+
@tag = tag
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def slug
|
|
88
|
+
@tag
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def name
|
|
92
|
+
@tag
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def type
|
|
96
|
+
:version
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def semver
|
|
100
|
+
Gem::Version.new(@tag.sub(/^v/, ""))
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
attr_accessor :is_latest
|
|
104
|
+
|
|
105
|
+
def latest?
|
|
106
|
+
@is_latest
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def checkout(globs:, &block)
|
|
110
|
+
Dir.mktmpdir do |path|
|
|
111
|
+
system("git archive #{@tag} | tar -x -C #{path}")
|
|
112
|
+
# We could enforce globs here too, but git archive is usually sufficient.
|
|
113
|
+
FileUtils.rm_rf("#{path}/ext")
|
|
114
|
+
yield path
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|