Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions lib/irb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

require_relative "irb/version"
require_relative "irb/easter-egg"
require_relative "irb/startup_message"
require_relative "irb/debug"
require_relative "irb/pager"

Expand Down Expand Up @@ -50,7 +51,13 @@ def start(ap_path = nil)
irb = Irb.new(nil, @CONF[:SCRIPT])
else
irb = Irb.new

# Only display the banner in the irb executable
if @CONF[:SHOW_BANNER] && ap_path&.end_with?("exe/irb")
StartupMessage.display
end
end

irb.run(@CONF)
end

Expand Down
1 change: 1 addition & 0 deletions lib/irb/init.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ def IRB.init_config(ap_path)
@CONF[:IGNORE_SIGINT] = true
@CONF[:IGNORE_EOF] = false
@CONF[:USE_PAGER] = true
@CONF[:SHOW_BANNER] = true
@CONF[:EXTRA_DOC_DIRS] = []
@CONF[:ECHO] = nil
@CONF[:ECHO_ON_ASSIGNMENT] = nil
Expand Down
4 changes: 4 additions & 0 deletions lib/irb/ruby_logo.aa
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,7 @@ TYPE: UNICODE
⢻⣾⡇ ⠘⣷ ⣼⠃ ⠘⣷⣠⣴⠟⠋ ⠙⢷⣄⢸⣿
⠻⣧⡀ ⠘⣧⣰⡏ ⢀⣠⣤⠶⠛⠉⠛⠛⠛⠛⠛⠛⠻⢶⣶⣶⣶⣶⣶⣤⣤⣽⣿⣿
⠈⠛⠷⢦⣤⣽⣿⣥⣤⣶⣶⡿⠿⠿⠶⠶⠶⠶⠾⠛⠛⠛⠛⠛⠛⠛⠋⠉⠉⠉⠉⠉⠉⠁
TYPE: UNICODE_SMALL
⢀⡴⠊⢉⡟⢟
⣎⣀⣴⡋⡟⣻
⣟⣼⣱⣽⣟⣾
83 changes: 83 additions & 0 deletions lib/irb/startup_message.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# frozen_string_literal: true

require_relative "color"
require_relative "version"

module IRB
module StartupMessage
TIPS = [
'Type "help" for commands, "help <cmd>" for details',
'"show_doc method" to view documentation',
'"ls [object]" to see methods and properties',
'"ls [object] -g pattern" to filter methods and properties',
'"edit method" to open the method\'s source in editor',
'"cd object" to navigate into an object',
'"show_source method" to view source code',
'"copy expr" to copy the output to clipboard',
'"debug" to start integration with the "debug" gem',
'"history -g pattern" to search history',
].freeze

class << self
def display
logo_lines = load_logo
info_lines = build_info_lines

output = if logo_lines
combine_logo_and_info(logo_lines, info_lines)
else
info_lines.join("\n")
end

# Add a blank line to not immediately touch warning messages
puts
puts output
puts
end

private

def load_logo
encoding = STDOUT.external_encoding || Encoding.default_external
return nil unless encoding == Encoding::UTF_8

logo = IRB.send(:easter_egg_logo, :unicode_small)
return nil unless logo

logo.chomp.lines.map(&:chomp)
end

def build_info_lines
version_line = "#{Color.colorize('IRB', [:BOLD])} v#{VERSION} \u2014 Ruby #{RUBY_VERSION}"
tip_line = colorize_tip(TIPS.sample)
dir_line = Color.colorize(short_pwd, [:CYAN])

[version_line, tip_line, dir_line]
end

def colorize_tip(tip)
tip.gsub(/"[^"]*"/) { |match| Color.colorize(match, [:YELLOW]) }
end

def combine_logo_and_info(logo_lines, info_lines)
max_lines = [logo_lines.size, info_lines.size].max
lines = max_lines.times.map do |i|
logo_part = logo_lines[i] || ""
info_part = info_lines[i] || ""
colored_logo = Color.colorize(logo_part, [:RED, :BOLD])
"#{colored_logo} #{info_part}"
end
lines.join("\n")
end

def short_pwd
dir = Dir.pwd
home = ENV['HOME']
if home && (dir == home || dir.start_with?("#{home}/"))
dir = "~#{dir[home.size..]}"
end
dir
end
end
end
end
2 changes: 1 addition & 1 deletion test/irb/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ def run_ruby_file(timeout: TIMEOUT_SEC, via_irb: false, &block)
@envs["XDG_CONFIG_HOME"] ||= tmp_dir
@envs["IRBRC"] = nil unless @envs.key?("IRBRC")

envs_for_spawn = @envs.merge('TERM' => 'dumb', 'TEST_IRB_FORCE_INTERACTIVE' => 'true')
envs_for_spawn = {'TERM' => 'dumb', 'TEST_IRB_FORCE_INTERACTIVE' => 'true'}.merge(@envs)

PTY.spawn(envs_for_spawn, *cmd) do |read, write, pid|
Timeout.timeout(timeout) do
Expand Down
71 changes: 71 additions & 0 deletions test/irb/test_startup_message.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# frozen_string_literal: true

require "irb"

require_relative "helper"

module TestIRB
class StartupMessageTest < TestCase
def test_display_includes_version_info
output, = capture_output { IRB::StartupMessage.display }

assert_match(/IRB/, output)
assert_match(/v#{Regexp.escape(IRB::VERSION)}/, output)
assert_match(/Ruby #{Regexp.escape(RUBY_VERSION)}/, output)
end

def test_display_includes_a_tip
output, = capture_output { IRB::StartupMessage.display }

# Strip ANSI codes for comparison since tips have colorized quoted parts
plain = output.gsub(/\e\[\d+m/, "")
assert(
IRB::StartupMessage::TIPS.any? { |tip| plain.include?(tip) },
"Expected output to include one of the tips"
)
end

def test_display_includes_working_directory
output, = capture_output { IRB::StartupMessage.display }

assert_match(/#{Regexp.escape(File.basename(Dir.pwd))}/, output)
end

def test_short_pwd_replaces_home_with_tilde
Dir.mktmpdir do |tmpdir|
tmpdir = File.realpath(tmpdir)
original_home = ENV['HOME']
original_dir = Dir.pwd
ENV['HOME'] = tmpdir
Dir.chdir(tmpdir)

result = IRB::StartupMessage.send(:short_pwd)
assert_equal "~", result

subdir = File.join(tmpdir, "projects")
Dir.mkdir(subdir)
Dir.chdir(subdir)

result = IRB::StartupMessage.send(:short_pwd)
assert_equal "~/projects", result
ensure
ENV['HOME'] = original_home
Dir.chdir(original_dir)
end
end
end

class StartupMessageIntegrationTest < IntegrationTestCase
def test_banner_does_not_appear_on_binding_irb
write_ruby <<~'RUBY'
binding.irb
RUBY

output = run_ruby_file do
type "exit"
end

assert_not_match(/v#{Regexp.escape(IRB::VERSION)}/, output)
end
end
end
20 changes: 8 additions & 12 deletions test/irb/yamatanooroti/test_rendering.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def setup
@irbrc_backup = ENV['IRBRC']
@irbrc_file = ENV['IRBRC'] = File.join(@tmpdir, 'temporaty_irbrc')
File.unlink(@irbrc_file) if File.exist?(@irbrc_file)
File.write(@irbrc_file, "IRB.conf[:SHOW_BANNER] = false\n")
ENV['HOME'] = File.join(@tmpdir, 'home')
ENV['XDG_CONFIG_HOME'] = File.join(@tmpdir, 'xdg_config_home')
end
Expand Down Expand Up @@ -59,11 +60,9 @@ def test_configuration_file_is_skipped_with_dash_f
write(<<~EOC)
'Hello, World!'
EOC
assert_screen(<<~EOC)
irb(main):001> 'Hello, World!'
=> "Hello, World!"
irb(main):002>
EOC
assert_screen(/irb\(main\):001> 'Hello, World!'\n=> "Hello, World!"\nirb\(main\):002>/)
screen = result.join("\n")
assert_not_include(screen, '.irbrc file should be ignored')
close
end

Expand All @@ -77,13 +76,9 @@ def test_configuration_file_is_skipped_with_dash_f_for_nested_sessions
binding.irb
exit!
EOC
assert_screen(<<~EOC)
irb(main):001> 'Hello, World!'
=> "Hello, World!"
irb(main):002> binding.irb
irb(main):003> exit!
irb(main):001>
EOC
assert_screen(/irb\(main\):001> 'Hello, World!'\n=> "Hello, World!"\nirb\(main\):002> binding\.irb\nirb\(main\):003> exit!\nirb\(main\):001>/)
screen = result.join("\n")
assert_not_include(screen, '.irbrc file should be ignored')
close
end

Expand Down Expand Up @@ -520,6 +515,7 @@ def test_debug_integration_doesnt_hint_debugger_commands_in_nomultiline_mode

def write_irbrc(content)
File.open(@irbrc_file, 'w') do |f|
f.write "IRB.conf[:SHOW_BANNER] = false\n"
f.write content
end
end
Expand Down