From a486d628ad16788268ea39b37a2b6df91fc7fe69 Mon Sep 17 00:00:00 2001 From: tompng Date: Thu, 20 Nov 2025 00:21:02 +0900 Subject: [PATCH 1/2] em_yank_pop should only work just after em_yank or em_yank_pop --- lib/reline/line_editor.rb | 32 +++++++++++++++++------------ test/reline/test_key_actor_emacs.rb | 6 ++++++ 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb index bfffd17d59..637a9299b4 100644 --- a/lib/reline/line_editor.rb +++ b/lib/reline/line_editor.rb @@ -43,7 +43,6 @@ module CompletionState RenderedScreen = Struct.new(:base_y, :lines, :cursor_y, keyword_init: true) CompletionJourneyState = Struct.new(:line_index, :pre, :target, :post, :list, :pointer) - NullActionState = [nil, nil].freeze class MenuInfo attr_reader :list @@ -253,8 +252,8 @@ def reset_variables(prompt = '') @undo_redo_history = [[[""], 0, 0]] @undo_redo_index = 0 @restoring = false - @prev_action_state = NullActionState - @next_action_state = NullActionState + @prev_action_state = {} + @next_action_state = {} reset_line end @@ -1022,7 +1021,7 @@ def input_key(key) @byte_pointer -= byte_size end - @prev_action_state, @next_action_state = @next_action_state, NullActionState + @prev_action_state, @next_action_state = @next_action_state, {} unless @completion_occurs @completion_state = CompletionState::NORMAL @@ -1779,17 +1778,24 @@ def finish private def em_yank(key) yanked = @kill_ring.yank - insert_text(yanked) if yanked + return unless yanked + + before_cursor = current_line.byteslice(0, @byte_pointer) + after_cursor = current_line.byteslice(@byte_pointer, current_line.bytesize) + set_current_line(before_cursor + yanked + after_cursor, before_cursor.bytesize + yanked.bytesize) + set_next_action_state(:em_yank_line, [before_cursor, after_cursor]) end alias_method :yank, :em_yank private def em_yank_pop(key) - yanked, prev_yank = @kill_ring.yank_pop - if yanked - line, = byteslice!(current_line, @byte_pointer - prev_yank.bytesize, prev_yank.bytesize) - set_current_line(line, @byte_pointer - prev_yank.bytesize) - insert_text(yanked) - end + before_cursor, after_cursor = prev_action_state_value(:em_yank_line) + return unless before_cursor and after_cursor + + yanked, = @kill_ring.yank_pop + return unless yanked + + set_current_line(before_cursor + yanked + after_cursor, before_cursor.bytesize + yanked.bytesize) + set_next_action_state(:em_yank_line, [before_cursor, after_cursor]) end alias_method :yank_pop, :em_yank_pop @@ -2343,11 +2349,11 @@ def finish end private def prev_action_state_value(type) - @prev_action_state[0] == type ? @prev_action_state[1] : nil + @prev_action_state[type] end private def set_next_action_state(type, value) - @next_action_state = [type, value] + @next_action_state[type] = value end private def re_read_init_file(_key) diff --git a/test/reline/test_key_actor_emacs.rb b/test/reline/test_key_actor_emacs.rb index aa608641c3..d524f68e17 100644 --- a/test/reline/test_key_actor_emacs.rb +++ b/test/reline/test_key_actor_emacs.rb @@ -1471,6 +1471,12 @@ def test_em_yank_pop assert_line_around_cursor('def ', '') input_keys("\e\C-y") assert_line_around_cursor('hoge', '') + input_keys("\e\C-y") + assert_line_around_cursor('def ', '') + # Moving arrows aborts yank-pop + input_keys("\C-b\C-f") + input_keys("\e\C-y") + assert_line_around_cursor('def ', '') end def test_em_kill_region_with_kill_ring From 7a11cfc9ee93ce466e7c177a40d606881b86b71f Mon Sep 17 00:00:00 2001 From: tompng Date: Thu, 20 Nov 2025 00:43:58 +0900 Subject: [PATCH 2/2] Correct em_yank_pop key bindings Add M-y and remove M-C-y. M-y and M-Y are both yank_pop but M-C-y has no effect in both Emacs and GNU Readline. --- lib/reline/key_actor/emacs.rb | 4 ++-- test/reline/test_key_actor_emacs.rb | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/reline/key_actor/emacs.rb b/lib/reline/key_actor/emacs.rb index 15c45253e2..cf212d6966 100644 --- a/lib/reline/key_actor/emacs.rb +++ b/lib/reline/key_actor/emacs.rb @@ -307,7 +307,7 @@ module Reline::KeyActor # 152 M-^X nil, # 153 M-^Y - :em_yank_pop, + nil, # 154 M-^Z nil, # 155 M-^[ @@ -499,7 +499,7 @@ module Reline::KeyActor # 248 M-x nil, # 249 M-y - nil, + :em_yank_pop, # 250 M-z nil, # 251 M-{ diff --git a/test/reline/test_key_actor_emacs.rb b/test/reline/test_key_actor_emacs.rb index d524f68e17..da843daddc 100644 --- a/test/reline/test_key_actor_emacs.rb +++ b/test/reline/test_key_actor_emacs.rb @@ -1469,13 +1469,13 @@ def test_em_yank_pop assert_line_around_cursor('', '') input_keys("\C-y") assert_line_around_cursor('def ', '') - input_keys("\e\C-y") + input_keys("\ey") assert_line_around_cursor('hoge', '') - input_keys("\e\C-y") + input_keys("\ey") assert_line_around_cursor('def ', '') # Moving arrows aborts yank-pop input_keys("\C-b\C-f") - input_keys("\e\C-y") + input_keys("\ey") assert_line_around_cursor('def ', '') end