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

Use em_delete in key_delete #504

Merged
merged 3 commits into from
Mar 24, 2023

Conversation

etiennebarrie
Copy link
Contributor

Since #434, the Del key is bound to :key_delete, but :key_delete doesn't behave like readline does in emacs mode. It moves the cursor left if a character was deleted under the cursor, while in readline, it just deletes the character under the cursor.

line type key_delete em_delete
abc| DEL abc| same
ab|c DEL a|b ab|
ab|c DEL DEL |a ab|

:em_delete is almost Del like readline, except it also handles the end-of-file situation. Which is annoying because if you type Del on an empty line, you get EOF instead of no changes.

This fixes it by using :em_delete in emacs mode, but also tweaking the behavior of :em_delete to only handle EOF when the key received is Ctrl-D. I hardcoded this but we could revisit that, see #501.

@ima1zumi ima1zumi added the bug Something isn't working label Mar 21, 2023
@@ -2664,7 +2666,7 @@ def finish
alias_method :kill_whole_line, :em_kill_line

private def em_delete(key)
if (not @is_multiline and @line.empty?) or (@is_multiline and @line.empty? and @buffer_of_lines.size == 1)
if @line.empty? and (not @is_multiline or @buffer_of_lines.size == 1) and key == 4
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could change 4 to "\C-D".ord for more clarity.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, thanks! Also rebased the branch.

ed_delete_next_char(key)
elsif @config.editing_mode_is?(:emacs)
em_delete(key)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a test for this?
I think this part is trying to test key_delete but missing the scenario you reported

def test_ed_delete_next_char
input_keys('abc')
assert_cursor(3)
assert_cursor_max(3)
@line_editor.input_key(Reline::Key.new(:key_delete, :key_delete, false))
assert_cursor(3)
assert_cursor_max(3)
assert_line('abc')
end

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for pointing the tests. I've added a test in the third commit (making this change), that checks that the cursor is preserved. I also renamed this test in the first commit to clarify it's testing key_delete.

@@ -2651,7 +2653,7 @@ def finish
alias_method :kill_whole_line, :em_kill_line

private def em_delete(key)
if (not @is_multiline and @line.empty?) or (@is_multiline and @line.empty? and @buffer_of_lines.size == 1)
if @line.empty? and (not @is_multiline or @buffer_of_lines.size == 1) and key == "\C-D"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"\C-d".ord(lowercase d) is better because lowercase is used in this file.
Could you add a test to check that \C-d with empty line will end the input?
I think we can use assert_line(nil)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for pointing that out, I found a test in test/reline/test_key_actor_vi.rb that was testing the same case: \C-d with an empty line ends the input, so I added it to test/reline/test_key_actor_emacs.rb as well.

Typing Ctrl-D ends editing but typing <Del> does not.

Also renamed a test that is not testing ed_delete_next_char but
key_delete.
By distributivity of AND over OR, we can factor out this condition. This
will make the next commit simpler.
When the editing mode is emacs, use `em_delete` in `key_delete`. We need
to add a condition though to `em_delete`, because it implements both
`delete-char` and `end-of-file`. We only want the `end-of-file` behavior
is the key is really Ctrl-D.

This matches the behavior of the <Del> key with readline, i.e. deleting
the next character if there is one, but not moving the cursor, while not
finishing the editing if there are no characters.
@etiennebarrie
Copy link
Contributor Author

I added some tests. As a separate first commit, tests that were testing the existing behavior that we want to preserve, namely Ctrl-D ends editing with an empty line, but that Del does not. Then there's the small refactor, then for the last commit changing the behavior, I added a test checking the state of the cursor to demonstrate the readline behavior for Del. That test fails when it runs on main.

@tompng tompng merged commit d67cc3d into ruby:master Mar 24, 2023
@tompng
Copy link
Member

tompng commented Mar 24, 2023

Thank you for your contribution 👍 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Development

Successfully merging this pull request may close these issues.

4 participants