From e86124b04e3d78bb8ec57c6af95c56920e4f03c3 Mon Sep 17 00:00:00 2001
From: tompng <tomoyapenguin@gmail.com>
Date: Mon, 13 Nov 2023 00:33:21 +0900
Subject: [PATCH] Add Reline::Face.force_truecolor to force truecolor without
 COLORTERM env

---
 lib/reline/face.rb       | 18 +++++++++++++++++-
 test/reline/test_face.rb | 33 +++++++++++++++++++++++++++++++++
 2 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/lib/reline/face.rb b/lib/reline/face.rb
index 6ea2f2e0ef..e18ec957e8 100644
--- a/lib/reline/face.rb
+++ b/lib/reline/face.rb
@@ -74,6 +74,13 @@ def define(name, **values)
       @definition[name] = values
     end
 
+    def reconfigure
+      @definition.each_value do |values|
+        values.delete(:escape_sequence)
+        values[:escape_sequence] = format_to_sgr(values.to_a).freeze
+      end
+    end
+
     def [](name)
       @definition.dig(name, :escape_sequence) or raise ArgumentError, "unknown face: #{name}"
     end
@@ -82,7 +89,7 @@ def [](name)
 
     def sgr_rgb(key, value)
       return nil unless rgb_expression?(value)
-      if ENV['COLORTERM'] == 'truecolor'
+      if Reline::Face.truecolor?
         sgr_rgb_truecolor(key, value)
       else
         sgr_rgb_256color(key, value)
@@ -150,6 +157,15 @@ def rgb_expression?(color)
 
   private_constant :SGR_PARAMETERS, :Config
 
+  def self.truecolor?
+    @force_truecolor || %w[truecolor 24bit].include?(ENV['COLORTERM'])
+  end
+
+  def self.force_truecolor
+    @force_truecolor = true
+    @configs&.each_value(&:reconfigure)
+  end
+
   def self.[](name)
     @configs[name]
   end
diff --git a/test/reline/test_face.rb b/test/reline/test_face.rb
index 254652d975..8fa2be8fa4 100644
--- a/test/reline/test_face.rb
+++ b/test/reline/test_face.rb
@@ -160,6 +160,11 @@ def setup
       @config = Reline::Face.const_get(:Config).new(:my_config) { }
     end
 
+    def teardown
+      super
+      Reline::Face.instance_variable_set(:@force_truecolor, nil)
+    end
+
     def test_rgb?
       assert_equal true, @config.send(:rgb_expression?, "#FFFFFF")
     end
@@ -199,6 +204,17 @@ def test_format_to_sgr_with_single_style
       )
     end
 
+    def test_truecolor
+      ENV['COLORTERM'] = 'truecolor'
+      assert_equal true, Reline::Face.truecolor?
+      ENV['COLORTERM'] = '24bit'
+      assert_equal true, Reline::Face.truecolor?
+      ENV['COLORTERM'] = nil
+      assert_equal false, Reline::Face.truecolor?
+      Reline::Face.force_truecolor
+      assert_equal true, Reline::Face.truecolor?
+    end
+
     def test_sgr_rgb_truecolor
       ENV['COLORTERM'] = 'truecolor'
       assert_equal "38;2;255;255;255", @config.send(:sgr_rgb, :foreground, "#ffffff")
@@ -220,5 +236,22 @@ def test_sgr_rgb_256color
       assert_equal '48;5;110', @config.send(:sgr_rgb, :background, '#9ac2ea')
       assert_equal '48;5;153', @config.send(:sgr_rgb, :background, '#9bc3eb')
     end
+
+    def test_force_truecolor_reconfigure
+      ENV['COLORTERM'] = nil
+
+      Reline::Face.config(:my_config) do |face|
+        face.define :default, foreground: '#005f87'
+        face.define :enhanced, background: '#afd7ff'
+      end
+
+      assert_equal "\e[0m\e[38;5;24m", Reline::Face[:my_config][:default]
+      assert_equal "\e[0m\e[48;5;153m", Reline::Face[:my_config][:enhanced]
+
+      Reline::Face.force_truecolor
+
+      assert_equal "\e[0m\e[38;2;0;95;135m", Reline::Face[:my_config][:default]
+      assert_equal "\e[0m\e[48;2;175;215;255m", Reline::Face[:my_config][:enhanced]
+    end
   end
 end