Skip to content

Commit

Permalink
Switch to StdioInputMethod when TERM is 'dumb' (#907)
Browse files Browse the repository at this point in the history
* Switch to StdioInputMethod when TERM is 'dumb'

This works around Reline's misbehavior on low-capability terminals,
such as when IRB is launched inside Emacs (ruby/reline#616).

It should also resolve #68 and resolve #113 which were filed out of
similar need.

* Add special env for testing

See discussion in #907.

---------

Co-authored-by: tomoya ishida <tomoyapenguin@gmail.com>
  • Loading branch information
dgutov and tompng authored May 1, 2024
1 parent b9b1f35 commit 241e061
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 5 deletions.
7 changes: 5 additions & 2 deletions lib/irb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,9 @@
# ### Input Method
#
# The IRB input method determines how command input is to be read; by default,
# the input method for a session is IRB::RelineInputMethod.
# the input method for a session is IRB::RelineInputMethod. Unless the
# value of the TERM environment variable is 'dumb', in which case the
# most simplistic input method is used.
#
# You can set the input method by:
#
Expand All @@ -329,7 +331,8 @@
# IRB::ReadlineInputMethod.
# * `--nosingleline` or `--multiline` sets the input method to
# IRB::RelineInputMethod.
#
# * `--nosingleline` together with `--nomultiline` sets the
# input to IRB::StdioInputMethod.
#
#
# Method `conf.use_multiline?` and its synonym `conf.use_reline` return:
Expand Down
9 changes: 7 additions & 2 deletions lib/irb/context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def initialize(irb, workspace = nil, input_method = nil)
@io = nil
case use_multiline?
when nil
if STDIN.tty? && IRB.conf[:PROMPT_MODE] != :INF_RUBY && !use_singleline?
if term_interactive? && IRB.conf[:PROMPT_MODE] != :INF_RUBY && !use_singleline?
# Both of multiline mode and singleline mode aren't specified.
@io = RelineInputMethod.new(build_completor)
else
Expand All @@ -99,7 +99,7 @@ def initialize(irb, workspace = nil, input_method = nil)
unless @io
case use_singleline?
when nil
if (defined?(ReadlineInputMethod) && STDIN.tty? &&
if (defined?(ReadlineInputMethod) && term_interactive? &&
IRB.conf[:PROMPT_MODE] != :INF_RUBY)
@io = ReadlineInputMethod.new
else
Expand Down Expand Up @@ -151,6 +151,11 @@ def initialize(irb, workspace = nil, input_method = nil)
@command_aliases = @user_aliases.merge(KEYWORD_ALIASES)
end

private def term_interactive?
return true if ENV['TEST_IRB_FORCE_INTERACTIVE']
STDIN.tty? && ENV['TERM'] != 'dumb'
end

# because all input will eventually be evaluated as Ruby code,
# command names that conflict with Ruby keywords need special workaround
# we can remove them once we implemented a better command system for IRB
Expand Down
4 changes: 3 additions & 1 deletion test/irb/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,9 @@ def run_ruby_file(&block)
@envs["XDG_CONFIG_HOME"] ||= tmp_dir
@envs["IRBRC"] = nil unless @envs.key?("IRBRC")

PTY.spawn(@envs.merge("TERM" => "dumb"), *cmd) do |read, write, pid|
envs_for_spawn = @envs.merge('TERM' => 'dumb', 'TEST_IRB_FORCE_INTERACTIVE' => 'true')

PTY.spawn(envs_for_spawn, *cmd) do |read, write, pid|
Timeout.timeout(TIMEOUT_SEC) do
while line = safe_gets(read)
lines << line
Expand Down

0 comments on commit 241e061

Please sign in to comment.