Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature.terminal truecolor #1413

Merged
merged 9 commits into from Jan 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/rouge.rb
Expand Up @@ -72,6 +72,7 @@ def lexer_dir(path = '')
load_relative 'rouge/formatters/html_line_table'
load_relative 'rouge/formatters/html_inline'
load_relative 'rouge/formatters/terminal256'
load_relative 'rouge/formatters/terminal_truecolor'
load_relative 'rouge/formatters/tex'
load_relative 'rouge/formatters/null'

Expand Down
19 changes: 18 additions & 1 deletion lib/rouge/cli.rb
Expand Up @@ -4,6 +4,8 @@
# not required by the main lib.
# to use this module, require 'rouge/cli'.

require 'rbconfig'

module Rouge
class FileReader
attr_reader :input
Expand Down Expand Up @@ -200,9 +202,22 @@ def self.doc
yield %[ delimiters. implies --escape]
end

# There is no consistent way to do this, but this is used elsewhere,
# and we provide explicit opt-in and opt-out with $COLORTERM
def self.supports_truecolor?
return true if %w(24bit truecolor).include?(ENV['COLORTERM'])
return false if ENV['COLORTERM'] && ENV['COLORTERM'] =~ /256/

if RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
jneen marked this conversation as resolved.
Show resolved Hide resolved
ENV['ConEmuANSI'] == 'ON' && !ENV['ANSICON']
else
ENV['TERM'] !~ /(^rxvt)|(-color$)/
end
end

def self.parse(argv)
opts = {
:formatter => 'terminal256',
:formatter => supports_truecolor? ? 'terminal-truecolor' : 'terminal256',
:theme => 'thankful_eyes',
:css_class => 'codehilite',
:input_file => '-',
Expand Down Expand Up @@ -299,8 +314,10 @@ def initialize(opts={})

theme = Theme.find(opts[:theme]).new or error! "unknown theme #{opts[:theme]}"

# TODO: document this in --help
@formatter = case opts[:formatter]
when 'terminal256' then Formatters::Terminal256.new(theme)
when 'terminal-truecolor' then Formatters::TerminalTruecolor.new(theme)
when 'html' then Formatters::HTML.new
when 'html-pygments' then Formatters::HTMLPygments.new(Formatters::HTML.new, opts[:css_class])
when 'html-inline' then Formatters::HTMLInline.new(theme)
Expand Down
6 changes: 5 additions & 1 deletion lib/rouge/formatters/terminal256.rb
Expand Up @@ -174,7 +174,11 @@ def escape_sequence(token)
return Unescape.new if escape?(token)
@escape_sequences ||= {}
@escape_sequences[token.qualname] ||=
EscapeSequence.new(get_style(token))
make_escape_sequence(get_style(token))
end

def make_escape_sequence(style)
EscapeSequence.new(style)
end

def get_style(token)
Expand Down
37 changes: 37 additions & 0 deletions lib/rouge/formatters/terminal_truecolor.rb
@@ -0,0 +1,37 @@
# -*- coding: utf-8 -*- #
# frozen_string_literal: true
module Rouge
module Formatters
class TerminalTruecolor < Terminal256
tag 'terminal_truecolor'

class TruecolorEscapeSequence < Terminal256::EscapeSequence
def style_string
@style_string ||= begin
out = String.new('')
out << escape(['48', '2', *get_rgb(style.bg)]) if style.bg
out << escape(['38', '2', *get_rgb(style.fg)]) if style.fg
out << escape(['1']) if style[:bold] || style[:italic]
out
end
end

def get_rgb(color)
color = $1 if color =~ /#(\h+)/

case color.size
when 3 then color.chars.map { |c| c.to_i(16) * 2 }
when 6 then color.scan(/../).map { |cc| cc.to_i(16) }
else
raise "invalid color: #{color.inspect}"
end
end
end

# @override
def make_escape_sequence(style)
TruecolorEscapeSequence.new(style)
end
end
end
end
12 changes: 12 additions & 0 deletions spec/formatters/terminal_truecolor_spec.rb
@@ -0,0 +1,12 @@
# -*- coding: utf-8 -*- #
# frozen_string_literal: true

describe Rouge::Formatters::TerminalTruecolor do
let(:subject) { Rouge::Formatters::TerminalTruecolor.new }

it 'renders a thing' do
result = subject.format([[Token['Text'], 'foo']])

assert { result == "\e[38;2;250;246;228mfoo\e[39m" }
end
end