[前][次][番号順一覧][スレッド一覧]

ruby-changes:59286

From: aycabta <ko1@a...>
Date: Tue, 17 Dec 2019 13:08:19 +0900 (JST)
Subject: [ruby-changes:59286] a14a0244b4 (master): Support forward-search-history by C-s

https://git.ruby-lang.org/ruby.git/commit/?id=a14a0244b4

From a14a0244b48c422e392547b198af6fb57f7ca568 Mon Sep 17 00:00:00 2001
From: aycabta <aycabta@g...>
Date: Tue, 17 Dec 2019 12:47:09 +0900
Subject: Support forward-search-history by C-s


diff --git a/lib/reline/key_actor/emacs.rb b/lib/reline/key_actor/emacs.rb
index 134f424..ab5c214 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 https://github.com/ruby/ruby/blob/trunk/lib/reline/key_actor/emacs.rb#L39
     #  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 f5b8a01..06e94a9 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 https://github.com/ruby/ruby/blob/trunk/lib/reline/key_actor/vi_insert.rb#L39
     #  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 20d966f..c74db52 100644
--- a/lib/reline/line_editor.rb
+++ b/lib/reline/line_editor.rb
@@ -1181,18 +1181,18 @@ class Reline::LineEditor https://github.com/ruby/ruby/blob/trunk/lib/reline/line_editor.rb#L1181
   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 https://github.com/ruby/ruby/blob/trunk/lib/reline/line_editor.rb#L1206
             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 https://github.com/ruby/ruby/blob/trunk/lib/reline/line_editor.rb#L1225
             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 https://github.com/ruby/ruby/blob/trunk/lib/reline/line_editor.rb#L1279
             @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 https://github.com/ruby/ruby/blob/trunk/lib/reline/line_editor.rb#L1349
         @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 https://github.com/ruby/ruby/blob/trunk/lib/reline/line_editor.rb#L1378
     }
   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 7ffa28e..5e5be0c 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 https://github.com/ruby/ruby/blob/trunk/test/reline/test_key_actor_emacs.rb#L6
     @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 https://github.com/ruby/ruby/blob/trunk/test/reline/test_key_actor_emacs.rb#L1593
     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
-- 
cgit v0.10.2


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]