Skip to content

Binding to exit command causes TypeError #819

Open

Description

@13k

inputrc:

Control-d: exit
❱ ./bin/console
irb(main):001> ^D
RELINE_SRCDIR/lib/reline/line_editor.rb:975:in 'Kernel#exit': no implicit conversion of String into Integer (TypeError)
	from RELINE_SRCDIR/lib/reline/line_editor.rb:975:in 'Method#call'
	from RELINE_SRCDIR/lib/reline/line_editor.rb:975:in 'Reline::LineEditor#wrap_method_call'
	from RELINE_SRCDIR/lib/reline/line_editor.rb:941:in 'Reline::LineEditor#run_for_operators'
	from RELINE_SRCDIR/lib/reline/line_editor.rb:1001:in 'Reline::LineEditor#process_key'
	from RELINE_SRCDIR/lib/reline/line_editor.rb:1027:in 'Reline::LineEditor#input_key'
	from RELINE_SRCDIR/lib/reline/line_editor.rb:1005:in 'Reline::LineEditor#update'
        <omitted>

I didn't follow the whole call chain, but I'm guessing key.method_symbol == :exit and wrap_method_call simply grabs the method from top-level Kernel and calls it with a string parameter, causing the TypeError exception.

Activity

  1. t-mangoe commented on Dec 6, 2025

    @t-mangoe

    I briefly looked into this issue. As expected, it appears that the Kernel's exit method is being called.
    Because the exit method is inherited, the following respond_to? method returns true. (then, the exit method is executed.)

    return unless respond_to?(method_symbol, true)

    I think only methods defined in the LineEditor class should be called. How about that?

  2. tompng commented on Dec 6, 2025

    @tompng
    Member

    exit is not an existing GNU-Readline functon name. GitHub code search of Readline's config shows that "[key binding here]": exit doesn't seem to be used in real world, so I don't see a use case. Reline just doesn't support exit functionality just like GNU Readline.

    The problem is not only for Kernel's method.

    "\C-d": initialize
    "\C-e": move_history

    Will call LineEditor#initialize or LineEditor#move_history (internal method) with wrong argument.

    Reline maintainer team, including me, thinks there is a maintainability issue in this part

    private def ed_end_of_history(key)
      move_history(Reline::HISTORY.size, line: :end, cursor: :end)
    end
    alias_method :end_of_history, :ed_end_of_history
    • It registers end-of-history as a function. This part is OK (except it just look like normal method aliasing)
    • Unknown weather ed-end-of-history is intended to register as a function, or it's just a meaningful method name that expresses it originates from Editline
    • end-of_history and end_of-history etc are also registered
    • Hard to distinguish valid function from unused method that need to be removed as a refactoring.
    • And problems described in this issue: No error handling, No warning, etc.

    To fix this root cause, we need a large-diff refactoring that introduce explicit function-name register mechanism.

    Workaround pull requests are welcome (If the workaround is simple enough)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions