aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoraycabta <aycabta@gmail.com>2019-12-17 12:47:09 +0900
committeraycabta <aycabta@gmail.com>2019-12-17 13:07:19 +0900
commita14a0244b48c422e392547b198af6fb57f7ca568 (patch)
tree6e8e4a1101642f250d9939cd0a41009417231e5d
parentc687be4bc01c9ce52ea990945d9304d6fe59fe9b (diff)
downloadruby-a14a0244b48c422e392547b198af6fb57f7ca568.tar.gz
Support forward-search-history by C-s
-rw-r--r--lib/reline/key_actor/emacs.rb2
-rw-r--r--lib/reline/key_actor/vi_insert.rb2
-rw-r--r--lib/reline/line_editor.rb96
-rw-r--r--test/reline/test_key_actor_emacs.rb28
4 files changed, 102 insertions, 26 deletions
diff --git a/lib/reline/key_actor/emacs.rb b/lib/reline/key_actor/emacs.rb
index 134f424a2c..ab5c214600 100644
--- a/lib/reline/key_actor/emacs.rb
+++ b/lib/reline/key_actor/emacs.rb
@@ -39,7 +39,7 @@ class Reline::KeyActor::Emacs < Reline::KeyActor::Base
# 18 ^R
:ed_search_prev_history,
# 19 ^S
- :ed_ignore,
+ :ed_search_next_history,
# 20 ^T
:ed_transpose_chars,
# 21 ^U
diff --git a/lib/reline/key_actor/vi_insert.rb b/lib/reline/key_actor/vi_insert.rb
index f5b8a01982..06e94a9c30 100644
--- a/lib/reline/key_actor/vi_insert.rb
+++ b/lib/reline/key_actor/vi_insert.rb
@@ -39,7 +39,7 @@ class Reline::KeyActor::ViInsert < Reline::KeyActor::Base
# 18 ^R
:ed_search_prev_history,
# 19 ^S
- :ed_ignore,
+ :ed_search_next_history,
# 20 ^T
:ed_insert,
# 21 ^U
diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb
index 20d966f6dc..c74db5286d 100644
--- a/lib/reline/line_editor.rb
+++ b/lib/reline/line_editor.rb
@@ -1181,18 +1181,18 @@ class Reline::LineEditor
end
alias_method :end_of_line, :ed_move_to_end
- private def ed_search_prev_history(key)
- unless @history_pointer
- if @is_multiline
- @line_backup_in_history = whole_buffer
- else
- @line_backup_in_history = @line
- end
- end
- searcher = Fiber.new do
+ private def generate_searcher
+ Fiber.new do |first_key|
+ prev_search_key = first_key
search_word = String.new(encoding: @encoding)
multibyte_buf = String.new(encoding: 'ASCII-8BIT')
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
key = Fiber.yield(search_word)
search_again = false
@@ -1206,8 +1206,9 @@ class Reline::LineEditor
grapheme_clusters.pop
search_word = grapheme_clusters.join
end
- when "\C-r".ord
- search_again = true
+ when "\C-r".ord, "\C-s".ord
+ search_again = true if prev_search_key == key
+ prev_search_key = key
else
multibyte_buf << key
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
search_word = Reline.last_incremental_search
end
- if @history_pointer
- history = Reline::HISTORY[0..(@history_pointer - 1)]
+ if @history_pointer # TODO
+ case prev_search_key
+ when "\C-r".ord
+ history_pointer_base = 0
+ 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
+ history_pointer_base = 0
history = Reline::HISTORY
end
elsif @history_pointer
- history = Reline::HISTORY[0..@history_pointer]
+ case prev_search_key
+ when "\C-r".ord
+ history_pointer_base = 0
+ history = Reline::HISTORY[0..@history_pointer]
+ when "\C-s".ord
+ history_pointer_base = @history_pointer
+ history = Reline::HISTORY[@history_pointer..-1]
+ end
else
+ history_pointer_base = 0
history = Reline::HISTORY
end
- hit_index = history.rindex { |item|
- item.include?(search_word)
- }
+ case prev_search_key
+ when "\C-r".ord
+ hit_index = history.rindex { |item|
+ item.include?(search_word)
+ }
+ when "\C-s".ord
+ hit_index = history.index { |item|
+ item.include?(search_word)
+ }
+ end
if hit_index
- @history_pointer = hit_index
+ @history_pointer = history_pointer_base + hit_index
hit = Reline::HISTORY[@history_pointer]
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 @is_multiline
@buffer_of_lines = hit.split("\n")
@@ -1249,23 +1279,34 @@ class Reline::LineEditor
@line_index = @buffer_of_lines.size - 1
@line = @buffer_of_lines.last
@rerender_all = true
- @searching_prompt = "(reverse-i-search)`%s'" % [search_word]
+ @searching_prompt = "(%s)`%s'" % [prompt_name, search_word]
else
@line = hit
- @searching_prompt = "(reverse-i-search)`%s': %s" % [search_word, hit]
+ @searching_prompt = "(%s)`%s': %s" % [prompt_name, search_word, hit]
end
last_hit = hit
else
if @is_multiline
@rerender_all = true
- @searching_prompt = "(failed reverse-i-search)`%s'" % [search_word]
+ @searching_prompt = "(failed %s)`%s'" % [prompt_name, search_word]
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
- 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)`': "
@waiting_proc = ->(k) {
case k
@@ -1308,7 +1349,7 @@ class Reline::LineEditor
@rerender_all = true
else
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)
else
if @history_pointer
@@ -1337,8 +1378,15 @@ class Reline::LineEditor
}
end
+ private def ed_search_prev_history(key)
+ search_history(key)
+ 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)
if @is_multiline and @line_index > 0
diff --git a/test/reline/test_key_actor_emacs.rb b/test/reline/test_key_actor_emacs.rb
index 7ffa28ec87..5e5be0c15c 100644
--- a/test/reline/test_key_actor_emacs.rb
+++ b/test/reline/test_key_actor_emacs.rb
@@ -6,6 +6,7 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase
@prompt = '> '
@config = Reline::Config.new # Emacs mode is default
Reline::HISTORY.instance_variable_set(:@config, @config)
+ Reline::HISTORY.clear
@encoding = (RELINE_TEST_ENCODING rescue Encoding.default_external)
@line_editor = Reline::LineEditor.new(@config)
@line_editor.reset(@prompt, @encoding)
@@ -1592,6 +1593,33 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase
assert_cursor_max(0)
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
Reline::HISTORY.concat([
'1235', # old