mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Support forward-search-history by C-s
This commit is contained in:
parent
c687be4bc0
commit
a14a0244b4
4 changed files with 103 additions and 27 deletions
|
@ -39,7 +39,7 @@ class Reline::KeyActor::Emacs < Reline::KeyActor::Base
|
||||||
# 18 ^R
|
# 18 ^R
|
||||||
:ed_search_prev_history,
|
:ed_search_prev_history,
|
||||||
# 19 ^S
|
# 19 ^S
|
||||||
:ed_ignore,
|
:ed_search_next_history,
|
||||||
# 20 ^T
|
# 20 ^T
|
||||||
:ed_transpose_chars,
|
:ed_transpose_chars,
|
||||||
# 21 ^U
|
# 21 ^U
|
||||||
|
|
|
@ -39,7 +39,7 @@ class Reline::KeyActor::ViInsert < Reline::KeyActor::Base
|
||||||
# 18 ^R
|
# 18 ^R
|
||||||
:ed_search_prev_history,
|
:ed_search_prev_history,
|
||||||
# 19 ^S
|
# 19 ^S
|
||||||
:ed_ignore,
|
:ed_search_next_history,
|
||||||
# 20 ^T
|
# 20 ^T
|
||||||
:ed_insert,
|
:ed_insert,
|
||||||
# 21 ^U
|
# 21 ^U
|
||||||
|
|
|
@ -1181,18 +1181,18 @@ class Reline::LineEditor
|
||||||
end
|
end
|
||||||
alias_method :end_of_line, :ed_move_to_end
|
alias_method :end_of_line, :ed_move_to_end
|
||||||
|
|
||||||
private def ed_search_prev_history(key)
|
private def generate_searcher
|
||||||
unless @history_pointer
|
Fiber.new do |first_key|
|
||||||
if @is_multiline
|
prev_search_key = first_key
|
||||||
@line_backup_in_history = whole_buffer
|
|
||||||
else
|
|
||||||
@line_backup_in_history = @line
|
|
||||||
end
|
|
||||||
end
|
|
||||||
searcher = Fiber.new do
|
|
||||||
search_word = String.new(encoding: @encoding)
|
search_word = String.new(encoding: @encoding)
|
||||||
multibyte_buf = String.new(encoding: 'ASCII-8BIT')
|
multibyte_buf = String.new(encoding: 'ASCII-8BIT')
|
||||||
last_hit = nil
|
last_hit = nil
|
||||||
|
case first_key
|
||||||
|
when "\C-r".ord
|
||||||
|
prompt_name = 'reverse-i-search'
|
||||||
|
when "\C-s".ord
|
||||||
|
prompt_name = 'i-search'
|
||||||
|
end
|
||||||
loop do
|
loop do
|
||||||
key = Fiber.yield(search_word)
|
key = Fiber.yield(search_word)
|
||||||
search_again = false
|
search_again = false
|
||||||
|
@ -1206,8 +1206,9 @@ class Reline::LineEditor
|
||||||
grapheme_clusters.pop
|
grapheme_clusters.pop
|
||||||
search_word = grapheme_clusters.join
|
search_word = grapheme_clusters.join
|
||||||
end
|
end
|
||||||
when "\C-r".ord
|
when "\C-r".ord, "\C-s".ord
|
||||||
search_again = true
|
search_again = true if prev_search_key == key
|
||||||
|
prev_search_key = key
|
||||||
else
|
else
|
||||||
multibyte_buf << key
|
multibyte_buf << key
|
||||||
if multibyte_buf.dup.force_encoding(@encoding).valid_encoding?
|
if multibyte_buf.dup.force_encoding(@encoding).valid_encoding?
|
||||||
|
@ -1224,24 +1225,53 @@ class Reline::LineEditor
|
||||||
if search_word.empty? and Reline.last_incremental_search
|
if search_word.empty? and Reline.last_incremental_search
|
||||||
search_word = Reline.last_incremental_search
|
search_word = Reline.last_incremental_search
|
||||||
end
|
end
|
||||||
if @history_pointer
|
if @history_pointer # TODO
|
||||||
|
case prev_search_key
|
||||||
|
when "\C-r".ord
|
||||||
|
history_pointer_base = 0
|
||||||
history = Reline::HISTORY[0..(@history_pointer - 1)]
|
history = Reline::HISTORY[0..(@history_pointer - 1)]
|
||||||
|
when "\C-s".ord
|
||||||
|
history_pointer_base = @history_pointer + 1
|
||||||
|
history = Reline::HISTORY[(@history_pointer + 1)..-1]
|
||||||
|
end
|
||||||
else
|
else
|
||||||
|
history_pointer_base = 0
|
||||||
history = Reline::HISTORY
|
history = Reline::HISTORY
|
||||||
end
|
end
|
||||||
elsif @history_pointer
|
elsif @history_pointer
|
||||||
|
case prev_search_key
|
||||||
|
when "\C-r".ord
|
||||||
|
history_pointer_base = 0
|
||||||
history = Reline::HISTORY[0..@history_pointer]
|
history = Reline::HISTORY[0..@history_pointer]
|
||||||
|
when "\C-s".ord
|
||||||
|
history_pointer_base = @history_pointer
|
||||||
|
history = Reline::HISTORY[@history_pointer..-1]
|
||||||
|
end
|
||||||
else
|
else
|
||||||
|
history_pointer_base = 0
|
||||||
history = Reline::HISTORY
|
history = Reline::HISTORY
|
||||||
end
|
end
|
||||||
|
case prev_search_key
|
||||||
|
when "\C-r".ord
|
||||||
hit_index = history.rindex { |item|
|
hit_index = history.rindex { |item|
|
||||||
item.include?(search_word)
|
item.include?(search_word)
|
||||||
}
|
}
|
||||||
|
when "\C-s".ord
|
||||||
|
hit_index = history.index { |item|
|
||||||
|
item.include?(search_word)
|
||||||
|
}
|
||||||
|
end
|
||||||
if hit_index
|
if hit_index
|
||||||
@history_pointer = hit_index
|
@history_pointer = history_pointer_base + hit_index
|
||||||
hit = Reline::HISTORY[@history_pointer]
|
hit = Reline::HISTORY[@history_pointer]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
case prev_search_key
|
||||||
|
when "\C-r".ord
|
||||||
|
prompt_name = 'reverse-i-search'
|
||||||
|
when "\C-s".ord
|
||||||
|
prompt_name = 'i-search'
|
||||||
|
end
|
||||||
if hit
|
if hit
|
||||||
if @is_multiline
|
if @is_multiline
|
||||||
@buffer_of_lines = hit.split("\n")
|
@buffer_of_lines = hit.split("\n")
|
||||||
|
@ -1249,23 +1279,34 @@ class Reline::LineEditor
|
||||||
@line_index = @buffer_of_lines.size - 1
|
@line_index = @buffer_of_lines.size - 1
|
||||||
@line = @buffer_of_lines.last
|
@line = @buffer_of_lines.last
|
||||||
@rerender_all = true
|
@rerender_all = true
|
||||||
@searching_prompt = "(reverse-i-search)`%s'" % [search_word]
|
@searching_prompt = "(%s)`%s'" % [prompt_name, search_word]
|
||||||
else
|
else
|
||||||
@line = hit
|
@line = hit
|
||||||
@searching_prompt = "(reverse-i-search)`%s': %s" % [search_word, hit]
|
@searching_prompt = "(%s)`%s': %s" % [prompt_name, search_word, hit]
|
||||||
end
|
end
|
||||||
last_hit = hit
|
last_hit = hit
|
||||||
else
|
else
|
||||||
if @is_multiline
|
if @is_multiline
|
||||||
@rerender_all = true
|
@rerender_all = true
|
||||||
@searching_prompt = "(failed reverse-i-search)`%s'" % [search_word]
|
@searching_prompt = "(failed %s)`%s'" % [prompt_name, search_word]
|
||||||
else
|
else
|
||||||
@searching_prompt = "(failed reverse-i-search)`%s': %s" % [search_word, last_hit]
|
@searching_prompt = "(failed %s)`%s': %s" % [prompt_name, search_word, last_hit]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
searcher.resume
|
end
|
||||||
|
|
||||||
|
private def search_history(key)
|
||||||
|
unless @history_pointer
|
||||||
|
if @is_multiline
|
||||||
|
@line_backup_in_history = whole_buffer
|
||||||
|
else
|
||||||
|
@line_backup_in_history = @line
|
||||||
|
end
|
||||||
|
end
|
||||||
|
searcher = generate_searcher
|
||||||
|
searcher.resume(key)
|
||||||
@searching_prompt = "(reverse-i-search)`': "
|
@searching_prompt = "(reverse-i-search)`': "
|
||||||
@waiting_proc = ->(k) {
|
@waiting_proc = ->(k) {
|
||||||
case k
|
case k
|
||||||
|
@ -1308,7 +1349,7 @@ class Reline::LineEditor
|
||||||
@rerender_all = true
|
@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 or k == "\C-s".ord
|
||||||
searcher.resume(k)
|
searcher.resume(k)
|
||||||
else
|
else
|
||||||
if @history_pointer
|
if @history_pointer
|
||||||
|
@ -1337,8 +1378,15 @@ class Reline::LineEditor
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
private def ed_search_next_history(key)
|
private def ed_search_prev_history(key)
|
||||||
|
search_history(key)
|
||||||
end
|
end
|
||||||
|
alias_method :reverse_search_history, :ed_search_prev_history
|
||||||
|
|
||||||
|
private def ed_search_next_history(key)
|
||||||
|
search_history(key)
|
||||||
|
end
|
||||||
|
alias_method :forward_search_history, :ed_search_next_history
|
||||||
|
|
||||||
private def ed_prev_history(key, arg: 1)
|
private def ed_prev_history(key, arg: 1)
|
||||||
if @is_multiline and @line_index > 0
|
if @is_multiline and @line_index > 0
|
||||||
|
|
|
@ -6,6 +6,7 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase
|
||||||
@prompt = '> '
|
@prompt = '> '
|
||||||
@config = Reline::Config.new # Emacs mode is default
|
@config = Reline::Config.new # Emacs mode is default
|
||||||
Reline::HISTORY.instance_variable_set(:@config, @config)
|
Reline::HISTORY.instance_variable_set(:@config, @config)
|
||||||
|
Reline::HISTORY.clear
|
||||||
@encoding = (RELINE_TEST_ENCODING rescue Encoding.default_external)
|
@encoding = (RELINE_TEST_ENCODING rescue Encoding.default_external)
|
||||||
@line_editor = Reline::LineEditor.new(@config)
|
@line_editor = Reline::LineEditor.new(@config)
|
||||||
@line_editor.reset(@prompt, @encoding)
|
@line_editor.reset(@prompt, @encoding)
|
||||||
|
@ -1592,6 +1593,33 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase
|
||||||
assert_cursor_max(0)
|
assert_cursor_max(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_search_history_to_front
|
||||||
|
Reline::HISTORY.concat([
|
||||||
|
'1235', # old
|
||||||
|
'12aa',
|
||||||
|
'1234' # new
|
||||||
|
])
|
||||||
|
assert_line('')
|
||||||
|
assert_byte_pointer_size('')
|
||||||
|
assert_cursor(0)
|
||||||
|
assert_cursor_max(0)
|
||||||
|
input_keys("\C-s123")
|
||||||
|
assert_line('1235')
|
||||||
|
assert_byte_pointer_size('')
|
||||||
|
assert_cursor(0)
|
||||||
|
assert_cursor_max(0) # doesn't determine yet
|
||||||
|
input_keys("\C-ha")
|
||||||
|
assert_line('12aa')
|
||||||
|
assert_byte_pointer_size('')
|
||||||
|
assert_cursor(0)
|
||||||
|
assert_cursor_max(0)
|
||||||
|
input_keys("\C-h3")
|
||||||
|
assert_line('1234')
|
||||||
|
assert_byte_pointer_size('')
|
||||||
|
assert_cursor(0)
|
||||||
|
assert_cursor_max(0)
|
||||||
|
end
|
||||||
|
|
||||||
def test_search_history_to_back_in_the_middle_of_histories
|
def test_search_history_to_back_in_the_middle_of_histories
|
||||||
Reline::HISTORY.concat([
|
Reline::HISTORY.concat([
|
||||||
'1235', # old
|
'1235', # old
|
||||||
|
|
Loading…
Reference in a new issue