Skip to content

Commit

Permalink
In ed_search_[prev|next]_history, make the cursor come to the end of …
Browse files Browse the repository at this point in the history
…the line when there is no search substr (#714)

* In ed_search_prev_history, make the cursor come to the end of the line when there is no search substr

* In ed_search_next_history, make the cursor come to the end of the line when there is no search substr

* Implemented ActionState to search with empty substr if the previous operation was search with empty string.

* Use a simple 2-element array to represent action_state
  • Loading branch information
QWYNG authored Jun 3, 2024
1 parent 353ec23 commit 95ee80b
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 24 deletions.
24 changes: 20 additions & 4 deletions lib/reline/line_editor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ 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
Expand Down Expand Up @@ -253,6 +254,8 @@ def reset_variables(prompt = '', encoding:)
@input_lines = [[[""], 0, 0]]
@input_lines_position = 0
@undoing = false
@prev_action_state = NullActionState
@next_action_state = NullActionState
reset_line
end

Expand Down Expand Up @@ -1131,6 +1134,9 @@ def input_key(key)
else
normal_char(key)
end

@prev_action_state, @next_action_state = @next_action_state, NullActionState

unless @completion_occurs
@completion_state = CompletionState::NORMAL
@completion_journey_state = nil
Expand Down Expand Up @@ -1761,29 +1767,31 @@ def finish
end

private def ed_search_prev_history(key, arg: 1)
substr = current_line.byteslice(0, @byte_pointer)
substr = prev_action_state_value(:search_history) == :empty ? '' : current_line.byteslice(0, @byte_pointer)
return if @history_pointer == 0
return if @history_pointer.nil? && substr.empty? && !current_line.empty?

history_range = 0...(@history_pointer || Reline::HISTORY.size)
h_pointer, line_index = search_history(substr, history_range.reverse_each)
return unless h_pointer
move_history(h_pointer, line: line_index || :start, cursor: @byte_pointer)
move_history(h_pointer, line: line_index || :start, cursor: substr.empty? ? :end : @byte_pointer)
arg -= 1
set_next_action_state(:search_history, :empty) if substr.empty?
ed_search_prev_history(key, arg: arg) if arg > 0
end
alias_method :history_search_backward, :ed_search_prev_history

private def ed_search_next_history(key, arg: 1)
substr = current_line.byteslice(0, @byte_pointer)
substr = prev_action_state_value(:search_history) == :empty ? '' : current_line.byteslice(0, @byte_pointer)
return if @history_pointer.nil?

history_range = @history_pointer + 1...Reline::HISTORY.size
h_pointer, line_index = search_history(substr, history_range)
return if h_pointer.nil? and not substr.empty?

move_history(h_pointer, line: line_index || :start, cursor: @byte_pointer)
move_history(h_pointer, line: line_index || :start, cursor: substr.empty? ? :end : @byte_pointer)
arg -= 1
set_next_action_state(:search_history, :empty) if substr.empty?
ed_search_next_history(key, arg: arg) if arg > 0
end
alias_method :history_search_forward, :ed_search_next_history
Expand Down Expand Up @@ -2549,4 +2557,12 @@ def finish
target_lines, target_cursor_x, target_cursor_y = @input_lines[@input_lines_position]
set_current_lines(target_lines.dup, target_cursor_x, target_cursor_y)
end

private def prev_action_state_value(type)
@prev_action_state[0] == type ? @prev_action_state[1] : nil
end

private def set_next_action_state(type, value)
@next_action_state = [type, value]
end
end
55 changes: 35 additions & 20 deletions test/reline/test_key_actor_emacs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1242,14 +1242,22 @@ def test_ed_search_prev_history_with_empty
'12345' # new
])
# The ed_search_prev_history doesn't have default binding
@line_editor.__send__(:ed_search_prev_history, "\C-p".ord)
assert_line_around_cursor('', '12345')
@line_editor.__send__(:ed_search_prev_history, "\C-p".ord)
assert_line_around_cursor('', '12aaa')
@line_editor.__send__(:ed_search_prev_history, "\C-p".ord)
assert_line_around_cursor('', '12356')
@line_editor.__send__(:ed_search_prev_history, "\C-p".ord)
assert_line_around_cursor('', '12356')
input_key_by_symbol(:ed_search_prev_history)
assert_line_around_cursor('12345', '')
input_key_by_symbol(:ed_search_prev_history)
assert_line_around_cursor('12aaa', '')
input_key_by_symbol(:ed_search_prev_history)
assert_line_around_cursor('12356', '')
input_key_by_symbol(:ed_search_next_history)
assert_line_around_cursor('12aaa', '')
input_key_by_symbol(:ed_prev_char)
input_key_by_symbol(:ed_next_char)
assert_line_around_cursor('12aaa', '')
input_key_by_symbol(:ed_search_prev_history)
assert_line_around_cursor('12aaa', '')
3.times { input_key_by_symbol(:ed_prev_char) }
input_key_by_symbol(:ed_search_prev_history)
assert_line_around_cursor('12', '356')
end

def test_ed_search_prev_history_without_match
Expand Down Expand Up @@ -1291,18 +1299,25 @@ def test_ed_search_next_history_with_empty
'12345' # new
])
# The ed_search_prev_history and ed_search_next_history doesn't have default binding
@line_editor.__send__(:ed_search_prev_history, "\C-p".ord)
assert_line_around_cursor('', '12345')
@line_editor.__send__(:ed_search_prev_history, "\C-p".ord)
assert_line_around_cursor('', '12aaa')
@line_editor.__send__(:ed_search_prev_history, "\C-p".ord)
assert_line_around_cursor('', '12356')
@line_editor.__send__(:ed_search_next_history, "\C-n".ord)
assert_line_around_cursor('', '12aaa')
@line_editor.__send__(:ed_search_next_history, "\C-n".ord)
assert_line_around_cursor('', '12345')
@line_editor.__send__(:ed_search_next_history, "\C-n".ord)
assert_line_around_cursor('', '')
input_key_by_symbol(:ed_search_prev_history)
assert_line_around_cursor('12345', '')
input_key_by_symbol(:ed_search_prev_history)
assert_line_around_cursor('12aaa', '')
input_key_by_symbol(:ed_search_prev_history)
assert_line_around_cursor('12356', '')
input_key_by_symbol(:ed_search_next_history)
assert_line_around_cursor('12aaa', '')
input_key_by_symbol(:ed_search_next_history)
assert_line_around_cursor('12345', '')
input_key_by_symbol(:ed_search_prev_history)
assert_line_around_cursor('12aaa', '')
input_key_by_symbol(:ed_prev_char)
input_key_by_symbol(:ed_next_char)
input_key_by_symbol(:ed_search_next_history)
assert_line_around_cursor('12aaa', '')
3.times { input_key_by_symbol(:ed_prev_char) }
input_key_by_symbol(:ed_search_next_history)
assert_line_around_cursor('12', '345')
end

def test_incremental_search_history_cancel_by_symbol_key
Expand Down

0 comments on commit 95ee80b

Please sign in to comment.