Support incremental search by last determined word

In the incremental search by C-r, search word is saved when it's determined. In
the next incremental search by C-r, if a user presses C-r again with the empty
search word, the determined previous search word is used to search.
This commit is contained in:
aycabta 2019-12-03 01:17:07 +09:00
Родитель bce38f706e
Коммит a92560132b
3 изменённых файлов: 72 добавлений и 4 удалений

Просмотреть файл

@ -40,6 +40,7 @@ module Reline
attr_accessor :key_stroke attr_accessor :key_stroke
attr_accessor :line_editor attr_accessor :line_editor
attr_accessor :ambiguous_width attr_accessor :ambiguous_width
attr_accessor :last_incremental_search
attr_reader :output attr_reader :output
def initialize def initialize
@ -367,6 +368,8 @@ module Reline
def_single_delegator :line_editor, :rerender, :redisplay def_single_delegator :line_editor, :rerender, :redisplay
def_single_delegators :core, :vi_editing_mode?, :emacs_editing_mode? def_single_delegators :core, :vi_editing_mode?, :emacs_editing_mode?
def_single_delegators :core, :ambiguous_width def_single_delegators :core, :ambiguous_width
def_single_delegators :core, :last_incremental_search
def_single_delegators :core, :last_incremental_search=
def_single_delegators :core, :readmultiline def_single_delegators :core, :readmultiline
def_instance_delegators self, :readmultiline def_instance_delegators self, :readmultiline

Просмотреть файл

@ -1160,6 +1160,9 @@ class Reline::LineEditor
key = Fiber.yield(search_word) key = Fiber.yield(search_word)
search_again = false search_again = false
case key case key
when -1 # determined
Reline.last_incremental_search = search_word
break
when "\C-h".ord, "\C-?".ord when "\C-h".ord, "\C-?".ord
grapheme_clusters = search_word.grapheme_clusters grapheme_clusters = search_word.grapheme_clusters
if grapheme_clusters.size > 0 if grapheme_clusters.size > 0
@ -1176,13 +1179,18 @@ class Reline::LineEditor
end end
end end
hit = nil hit = nil
if @line_backup_in_history&.include?(search_word) if not search_word.empty? and @line_backup_in_history&.include?(search_word)
@history_pointer = nil @history_pointer = nil
hit = @line_backup_in_history hit = @line_backup_in_history
else else
if search_again if search_again
if search_word.empty? and Reline.last_incremental_search
search_word = Reline.last_incremental_search
end
if @history_pointer if @history_pointer
history = Reline::HISTORY[0..(@history_pointer - 1)] history = Reline::HISTORY[0..(@history_pointer - 1)]
else
history = Reline::HISTORY
end end
elsif @history_pointer elsif @history_pointer
history = Reline::HISTORY[0..@history_pointer] history = Reline::HISTORY[0..@history_pointer]
@ -1226,22 +1234,41 @@ class Reline::LineEditor
case k case k
when "\C-j".ord when "\C-j".ord
if @history_pointer if @history_pointer
@line = Reline::HISTORY[@history_pointer] buffer = Reline::HISTORY[@history_pointer]
else else
@line = @line_backup_in_history buffer = @line_backup_in_history
end
if @is_multiline
@buffer_of_lines = buffer.split("\n")
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
@line_index = @buffer_of_lines.size - 1
@line = @buffer_of_lines.last
@rerender_all = true
else
@line = buffer
end end
@searching_prompt = nil @searching_prompt = nil
@waiting_proc = nil @waiting_proc = nil
@cursor_max = calculate_width(@line) @cursor_max = calculate_width(@line)
@cursor = @byte_pointer = 0 @cursor = @byte_pointer = 0
searcher.resume(-1)
when "\C-g".ord when "\C-g".ord
if @is_multiline
@buffer_of_lines = @line_backup_in_history.split("\n")
@buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
@line_index = @buffer_of_lines.size - 1
@line = @buffer_of_lines.last
@rerender_all = true
else
@line = @line_backup_in_history @line = @line_backup_in_history
end
@history_pointer = nil @history_pointer = nil
@searching_prompt = nil @searching_prompt = nil
@waiting_proc = nil @waiting_proc = nil
@line_backup_in_history = nil @line_backup_in_history = nil
@cursor_max = calculate_width(@line) @cursor_max = calculate_width(@line)
@cursor = @byte_pointer = 0 @cursor = @byte_pointer = 0
@rerender_all = true
else else
chr = k.is_a?(String) ? k : k.chr(Encoding::ASCII_8BIT) chr = k.is_a?(String) ? k : k.chr(Encoding::ASCII_8BIT)
if chr.match?(/[[:print:]]/) or k == "\C-h".ord or k == "\C-?".ord or k == "\C-r".ord if chr.match?(/[[:print:]]/) or k == "\C-h".ord or k == "\C-?".ord or k == "\C-r".ord
@ -1267,6 +1294,7 @@ class Reline::LineEditor
@waiting_proc = nil @waiting_proc = nil
@cursor_max = calculate_width(@line) @cursor_max = calculate_width(@line)
@cursor = @byte_pointer = 0 @cursor = @byte_pointer = 0
searcher.resume(-1)
end end
end end
} }

Просмотреть файл

@ -1474,6 +1474,43 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase
assert_cursor_max(0) assert_cursor_max(0)
end end
def test_search_history_by_last_determined
Reline::HISTORY.concat([
'1235', # old
'12aa',
'1234' # new
])
assert_line('')
assert_byte_pointer_size('')
assert_cursor(0)
assert_cursor_max(0)
input_keys("\C-r123")
assert_line('1234')
assert_byte_pointer_size('')
assert_cursor(0)
assert_cursor_max(0) # doesn't determine yet
input_keys("\C-j")
assert_line('1234')
assert_byte_pointer_size('')
assert_cursor(0)
assert_cursor_max(4)
input_keys("\C-k") # delete
assert_line('')
assert_byte_pointer_size('')
assert_cursor(0)
assert_cursor_max(0)
input_keys("\C-r")
assert_line('')
assert_byte_pointer_size('')
assert_cursor(0)
assert_cursor_max(0)
input_keys("\C-r")
assert_line('1235')
assert_byte_pointer_size('')
assert_cursor(0)
assert_cursor_max(0)
end
def test_em_set_mark_and_em_exchange_mark def test_em_set_mark_and_em_exchange_mark
input_keys('aaa bbb ccc ddd') input_keys('aaa bbb ccc ddd')
assert_byte_pointer_size('aaa bbb ccc ddd') assert_byte_pointer_size('aaa bbb ccc ddd')