Sid Gifari From Gifari Industries - BD Cyber Security Team
Home
/
opt
/
cpanel
/
ea-ruby27
/
root
/
usr
/
local
/
share
/
gems
/
gems
/
irb-1.18.0
/
lib
/
irb
/
✏️
Editing: color.rb
# frozen_string_literal: true require 'reline' require 'prism' require_relative 'ruby-lex' module IRB # :nodoc: module Color CLEAR = 0 BOLD = 1 UNDERLINE = 4 REVERSE = 7 BLACK = 30 RED = 31 GREEN = 32 YELLOW = 33 BLUE = 34 MAGENTA = 35 CYAN = 36 WHITE = 37 # Following pry's colors where possible TOKEN_SEQS = { KEYWORD_NIL: [CYAN, BOLD], KEYWORD_SELF: [CYAN, BOLD], KEYWORD_TRUE: [CYAN, BOLD], KEYWORD_FALSE: [CYAN, BOLD], KEYWORD___FILE__: [CYAN, BOLD], KEYWORD___LINE__: [CYAN, BOLD], KEYWORD___ENCODING__: [CYAN, BOLD], CHARACTER_LITERAL: [BLUE, BOLD], BACK_REFERENCE: [GREEN, BOLD], BACKTICK: [RED, BOLD], COMMENT: [BLUE, BOLD], EMBDOC_BEGIN: [BLUE, BOLD], EMBDOC_LINE: [BLUE, BOLD], EMBDOC_END: [BLUE, BOLD], CONSTANT: [BLUE, BOLD, UNDERLINE], EMBEXPR_BEGIN: [RED], EMBEXPR_END: [RED], EMBVAR: [RED], FLOAT: [MAGENTA, BOLD], GLOBAL_VARIABLE: [GREEN, BOLD], HEREDOC_START: [RED], HEREDOC_END: [RED], FLOAT_IMAGINARY: [BLUE, BOLD], INTEGER_IMAGINARY: [BLUE, BOLD], FLOAT_RATIONAL_IMAGINARY: [BLUE, BOLD], INTEGER_RATIONAL_IMAGINARY: [BLUE, BOLD], INTEGER: [BLUE, BOLD], INTEGER_RATIONAL: [BLUE, BOLD], FLOAT_RATIONAL: [BLUE, BOLD], KEYWORD_END: [GREEN], KEYWORD_CLASS: [GREEN], KEYWORD_MODULE: [GREEN], KEYWORD_IF: [GREEN], KEYWORD_IF_MODIFIER: [GREEN], KEYWORD_UNLESS_MODIFIER: [GREEN], KEYWORD_WHILE_MODIFIER: [GREEN], KEYWORD_UNTIL_MODIFIER: [GREEN], KEYWORD_RESCUE_MODIFIER: [GREEN], KEYWORD_THEN: [GREEN], KEYWORD_UNLESS: [GREEN], KEYWORD_ELSE: [GREEN], KEYWORD_ELSIF: [GREEN], KEYWORD_WHILE: [GREEN], KEYWORD_UNTIL: [GREEN], KEYWORD_CASE: [GREEN], KEYWORD_WHEN: [GREEN], KEYWORD_IN: [GREEN], KEYWORD_DEF: [GREEN], KEYWORD_DO: [GREEN], KEYWORD_DO_BLOCK: [GREEN], KEYWORD_DO_LOOP: [GREEN], KEYWORD_FOR: [GREEN], KEYWORD_BEGIN: [GREEN], KEYWORD_RESCUE: [GREEN], KEYWORD_ENSURE: [GREEN], KEYWORD_ALIAS: [GREEN], KEYWORD_UNDEF: [GREEN], KEYWORD_BEGIN_UPCASE: [GREEN], KEYWORD_END_UPCASE: [GREEN], KEYWORD_YIELD: [GREEN], KEYWORD_REDO: [GREEN], KEYWORD_RETRY: [GREEN], KEYWORD_NEXT: [GREEN], KEYWORD_BREAK: [GREEN], KEYWORD_SUPER: [GREEN], KEYWORD_RETURN: [GREEN], KEYWORD_DEFINED: [GREEN], KEYWORD_NOT: [GREEN], KEYWORD_AND: [GREEN], KEYWORD_OR: [GREEN], LABEL: [MAGENTA], LABEL_END: [RED, BOLD], NUMBERED_REFERENCE: [GREEN, BOLD], PERCENT_UPPER_W: [RED, BOLD], PERCENT_LOWER_W: [RED, BOLD], PERCENT_LOWER_X: [RED, BOLD], REGEXP_BEGIN: [RED, BOLD], REGEXP_END: [RED, BOLD], STRING_BEGIN: [RED, BOLD], STRING_CONTENT: [RED], STRING_END: [RED, BOLD], __END__: [GREEN], # tokens from syntax tree traversal method_name: [CYAN, BOLD], message_name: [CYAN], symbol: [YELLOW], # special colorization error: [RED, REVERSE], }.transform_values do |styles| styles.map { |style| "\e[#{style}m" }.join end CLEAR_SEQ = "\e[#{CLEAR}m" OPERATORS = %i(!= !~ =~ == === <=> > >= < <= & | ^ >> << - + % / * ** -@ +@ ~ ! [] []=) private_constant :TOKEN_SEQS, :CLEAR_SEQ, :OPERATORS class << self def colorable? supported = $stdout.tty? && (/mswin|mingw/.match?(RUBY_PLATFORM) || (ENV.key?('TERM') && ENV['TERM'] != 'dumb')) # because ruby/debug also uses irb's color module selectively, # irb won't be activated in that case. if IRB.respond_to?(:conf) supported && !!IRB.conf.fetch(:USE_COLORIZE, true) else supported end end def inspect_colorable?(obj, seen: {}.compare_by_identity) case obj when String, Symbol, Regexp, Integer, Float, FalseClass, TrueClass, NilClass true when Hash without_circular_ref(obj, seen: seen) do obj.all? { |k, v| inspect_colorable?(k, seen: seen) && inspect_colorable?(v, seen: seen) } end when Array without_circular_ref(obj, seen: seen) do obj.all? { |o| inspect_colorable?(o, seen: seen) } end when Range inspect_colorable?(obj.begin, seen: seen) && inspect_colorable?(obj.end, seen: seen) when Module !obj.name.nil? else false end end def clear(colorable: colorable?) colorable ? CLEAR_SEQ : '' end def colorize(text, seq, colorable: colorable?) return text unless colorable seq = seq.map { |s| "\e[#{const_get(s)}m" }.join('') "#{seq}#{text}#{CLEAR_SEQ}" end # If `complete` is false (code is incomplete), this does not warn compile_error. # This option is needed to avoid warning a user when the compile_error is happening # because the input is not wrong but just incomplete. def colorize_code(code, complete: true, ignore_error: false, colorable: colorable?, local_variables: []) return code unless colorable result = Prism.parse_lex(code, scopes: [local_variables]) # IRB::ColorPrinter skips colorizing syntax invalid fragments return Reline::Unicode.escape_for_print(code) if ignore_error && !result.success? prism_node, prism_tokens = result.value errors = result.errors unless complete errors = filter_incomplete_code_errors(errors, prism_tokens) end visitor = ColorizeVisitor.new prism_node.accept(visitor) error_tokens = errors.map { |e| [e.location.start_line, e.location.start_column, 0, e.location.end_line, e.location.end_column, :error, e.location.slice] } error_tokens.reject! { |t| t.last.match?(/\A\s*\z/) } tokens = prism_tokens.map { |t,| [t.location.start_line, t.location.start_column, 2, t.location.end_line, t.location.end_column, t.type, t.value] } tokens.pop if tokens.last&.[](5) == :EOF colored = +'' line_index = 0 col = 0 lines = code.lines flush = -> next_line_index, next_col { return if next_line_index == line_index && next_col == col (line_index...[next_line_index, lines.size].min).each do |ln| colored << Reline::Unicode.escape_for_print(lines[line_index].byteslice(col..)) line_index = ln + 1 col = 0 end unless col == next_col colored << Reline::Unicode.escape_for_print(lines[next_line_index].byteslice(col..next_col - 1)) end } (visitor.tokens + tokens + error_tokens).sort.each do |start_line, start_column, _priority, end_line, end_column, type, value| next if start_line - 1 < line_index || (start_line - 1 == line_index && start_column < col) flush.call(start_line - 1, start_column) if type == :__END__ color = TOKEN_SEQS[type] end_line = start_line value = '__END__' end_column = start_column + 7 else color = TOKEN_SEQS[type] end if color value.split(/(\n)/).each do |s| colored << (s == "\n" ? s : "#{color}#{Reline::Unicode.escape_for_print(s)}#{CLEAR_SEQ}") end else colored << value end line_index = end_line - 1 col = end_column end flush.call lines.size, 0 colored end class ColorizeVisitor < Prism::Visitor attr_reader :tokens def initialize @tokens = [] end def dispatch(location, type) if location @tokens << [location.start_line, location.start_column, 1, location.end_line, location.end_column, type, location.slice] end end def visit_array_node(node) if node.opening&.match?(/\A%[iI]/) dispatch node.opening_loc, :symbol dispatch node.closing_loc, :symbol end super end def visit_def_node(node) dispatch node.name_loc, :method_name super end def visit_alias_method_node(node) dispatch_alias_method_name node.new_name dispatch_alias_method_name node.old_name super end def visit_call_node(node) if node.call_operator_loc.nil? && OPERATORS.include?(node.name) # Operators should not be colored as method call elsif (node.call_operator_loc.nil? || node.call_operator_loc.slice == "::") && /\A\p{Upper}/.match?(node.name) # Constant-like methods should not be colored as method call else dispatch node.message_loc, :message_name end super end def visit_call_operator_write_node(node) dispatch node.message_loc, :message_name super end alias visit_call_and_write_node visit_call_operator_write_node alias visit_call_or_write_node visit_call_operator_write_node def visit_interpolated_symbol_node(node) dispatch node.opening_loc, :symbol node.parts.each do |part| case part when Prism::StringNode dispatch part.content_loc, :symbol when Prism::EmbeddedStatementsNode dispatch part.opening_loc, :symbol dispatch part.closing_loc, :symbol when Prism::EmbeddedVariableNode dispatch part.operator_loc, :symbol end end dispatch node.closing_loc, :symbol super end def visit_symbol_node(node) if (node.opening_loc.nil? && node.closing == ':') || node.closing&.match?(/\A['"]:\z/) # Colorize { symbol: 1 } and { 'symbol': 1 } as label dispatch node.location, :LABEL else dispatch node.opening_loc, :symbol dispatch node.value_loc, :symbol dispatch node.closing_loc, :symbol end end private def dispatch_alias_method_name(node) if node.type == :symbol_node && node.opening_loc.nil? dispatch node.value_loc, :method_name end end end private FILTERED_ERROR_TYPES = [ :class_name, :module_name, # `class`, `class owner_module` :write_target_unexpected, # `a, b` :parameter_wild_loose_comma, # `def f(a,` :argument_no_forwarding_star, # `[*` :argument_no_forwarding_star_star, # `f(**` :argument_no_forwarding_ampersand, # `f(&` :def_endless, # `def f =` :embdoc_term, # `=begin` ] # Filter out syntax errors that are likely to be caused by incomplete code, to avoid showing misleading error highlights to users. def filter_incomplete_code_errors(errors, tokens) last_non_comment_space_token, = tokens.reverse_each.find do |t,| t.type != :COMMENT && t.type != :EOF && t.type != :IGNORED_NEWLINE && t.type != :NEWLINE end last_offset = last_non_comment_space_token ? last_non_comment_space_token.location.end_offset : 0 errors.reject do |error| error.message.match?(/\Aexpected a|unexpected end-of-input|unterminated/) || (error.location.end_offset == last_offset && FILTERED_ERROR_TYPES.include?(error.type)) end end def without_circular_ref(obj, seen:, &block) return false if seen.key?(obj) seen[obj] = true block.call ensure seen.delete(obj) end end end end
💾 Save
❌ Cancel