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

ruby-changes:67316

From: aycabta <ko1@a...>
Date: Sun, 29 Aug 2021 20:30:55 +0900 (JST)
Subject: [ruby-changes:67316] 8d4370b066 (master): [ruby/reline] Support for multiple dialog rendering

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

From 8d4370b066fd9ff7e6f6c9ee0c5035ad5c81050e Mon Sep 17 00:00:00 2001
From: aycabta <aycabta@g...>
Date: Fri, 27 Aug 2021 14:58:05 +0900
Subject: [ruby/reline] Support for multiple dialog rendering

https://github.com/ruby/reline/commit/f589fab718
---
 lib/reline.rb             |  18 +++--
 lib/reline/line_editor.rb | 172 +++++++++++++++++++++++++++-------------------
 2 files changed, 115 insertions(+), 75 deletions(-)

diff --git a/lib/reline.rb b/lib/reline.rb
index 8c72d69..81c5f9e 100644
--- a/lib/reline.rb
+++ b/lib/reline.rb
@@ -34,7 +34,7 @@ module Reline https://github.com/ruby/ruby/blob/trunk/lib/reline.rb#L34
       auto_indent_proc
       pre_input_hook
       dig_perfect_match_proc
-      dialog_proc
+      dialog_proc_list
     ).each(&method(:attr_reader))
 
     attr_accessor :config
@@ -48,6 +48,7 @@ module Reline https://github.com/ruby/ruby/blob/trunk/lib/reline.rb#L48
       yield self
       @completion_quote_character = nil
       @bracketed_paste_finished = false
+      @dialog_proc_list = []
     end
 
     def encoding
@@ -131,9 +132,10 @@ module Reline https://github.com/ruby/ruby/blob/trunk/lib/reline.rb#L132
       @dig_perfect_match_proc = p
     end
 
-    def dialog_proc=(p)
+    def add_dialog_proc(name_sym, p)
       raise ArgumentError unless p.respond_to?(:call) or p.nil?
-      @dialog_proc = p
+      raise ArgumentError unless name_sym.instance_of?(Symbol)
+      @dialog_proc_list << [name_sym, p]
     end
 
     def input=(val)
@@ -206,14 +208,15 @@ module Reline https://github.com/ruby/ruby/blob/trunk/lib/reline.rb#L208
       else
         y = 0
       end
-      [Reline::CursorPos.new(x, y), result, pointer]
+      cursor_pos_to_render = Reline::CursorPos.new(x, y)
+      [cursor_pos_to_render, result, pointer]
     }
 
     def readmultiline(prompt = '', add_hist = false, &confirm_multiline_termination)
       unless confirm_multiline_termination
         raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
       end
-      @dialog_proc = DEFAULT_DIALOG_PROC_AUTOCOMPLETE
+      add_dialog_proc(:autocomplete, DEFAULT_DIALOG_PROC_AUTOCOMPLETE)
       inner_readline(prompt, add_hist, true, &confirm_multiline_termination)
 
       whole_buffer = line_editor.whole_buffer.dup
@@ -269,7 +272,10 @@ module Reline https://github.com/ruby/ruby/blob/trunk/lib/reline.rb#L272
       line_editor.auto_indent_proc = auto_indent_proc
       line_editor.dig_perfect_match_proc = dig_perfect_match_proc
       line_editor.pre_input_hook = pre_input_hook
-      line_editor.dialog_proc = dialog_proc
+      @dialog_proc_list.each do |d|
+        name_sym, dialog_proc = d
+        line_editor.add_dialog_proc(name_sym, dialog_proc)
+      end
 
       unless config.test_mode
         config.read
diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb
index 25d6ba4..c888474 100644
--- a/lib/reline/line_editor.rb
+++ b/lib/reline/line_editor.rb
@@ -249,10 +249,7 @@ class Reline::LineEditor https://github.com/ruby/ruby/blob/trunk/lib/reline/line_editor.rb#L249
     @drop_terminate_spaces = false
     @in_pasting = false
     @auto_indent_proc = nil
-    @dialog_column = nil
-    @dialog_vertical_offset = nil
-    @dialog_contents = nil
-    @dialog_lines_backup = nil
+    @dialogs = []
     reset_line
   end
 
@@ -521,75 +518,98 @@ class Reline::LineEditor https://github.com/ruby/ruby/blob/trunk/lib/reline/line_editor.rb#L518
     end
   end
 
-  def dialog_proc=(p)
-    @dialog_proc_scope = DialogProcScope.new(self, p)
-    @dialog_proc = p
+  class Dialog
+    attr_reader :name
+    attr_accessor :column, :vertical_offset, :contents, :lines_backup
+
+    def initialize(name, proc_scope)
+      @name = name
+      @proc_scope = proc_scope
+    end
+
+    def set_cursor_pos(col, row)
+      @proc_scope.set_cursor_pos(col, row)
+    end
+
+    def call
+      @proc_scope.call
+    end
   end
 
-  DIALOG_HEIGHT = 5
+  def add_dialog_proc(name, p)
+    return if @dialogs.any? { |d| d.name == name }
+    @dialogs << Dialog.new(name, DialogProcScope.new(self, p))
+  end
+
+  DIALOG_HEIGHT = 20
   DIALOG_WIDTH = 40
   private def render_dialog(cursor_column)
-    return if @dialog_proc_scope.nil?
+    @dialogs.each do |dialog|
+      render_each_dialog(dialog, cursor_column)
+    end
+  end
+
+  private def render_each_dialog(dialog, cursor_column)
     if @in_pasting
-      @dialog_contents = nil
+      dialog.contents = nil
       return
     end
-    @dialog_proc_scope.set_cursor_pos(cursor_column, @first_line_started_from + @started_from)
-    pos, result, pointer = @dialog_proc_scope.call
-    old_dialog_contents = @dialog_contents
-    old_dialog_column = @dialog_column
-    old_dialog_vertical_offset = @dialog_vertical_offset
+    dialog.set_cursor_pos(cursor_column, @first_line_started_from + @started_from)
+    pos, result, pointer = dialog.call
+    old_dialog_contents = dialog.contents
+    old_dialog_column = dialog.column
+    old_dialog_vertical_offset = dialog.vertical_offset
     if result and not result.empty?
-      @dialog_contents = result
-      @dialog_contents = @dialog_contents[0...DIALOG_HEIGHT] if @dialog_contents.size > DIALOG_HEIGHT
+      dialog.contents = result
+      dialog.contents = dialog.contents[0...DIALOG_HEIGHT] if dialog.contents.size > DIALOG_HEIGHT
     else
-      @dialog_lines_backup = {
+      dialog.lines_backup = {
         lines: modify_lines(whole_lines),
         line_index: @line_index,
         first_line_started_from: @first_line_started_from,
         started_from: @started_from,
         byte_pointer: @byte_pointer
       }
-      clear_dialog
-      @dialog_contents = nil
+      clear_each_dialog(dialog)
+      dialog.contents = nil
       return
     end
     upper_space = @first_line_started_from - @started_from
     lower_space = @highest_in_all - @first_line_started_from - @started_from - 1
-    @dialog_column = pos.x
-    diff = (@dialog_column + DIALOG_WIDTH) - (@screen_size.last - 1)
+    dialog.column = pos.x
+    diff = (dialog.column + DIALOG_WIDTH) - (@screen_size.last - 1)
     if diff > 0
-      @dialog_column -= diff
+      dialog.column -= diff
     end
     if (lower_space + @rest_height) >= DIALOG_HEIGHT
-      @dialog_vertical_offset = pos.y + 1
+      dialog.vertical_offset = pos.y + 1
     elsif upper_space >= DIALOG_HEIGHT
-      @dialog_vertical_offset = pos.y + -(DIALOG_HEIGHT + 1)
+      dialog.vertical_offset = pos.y + -(DIALOG_HEIGHT + 1)
     else
       if (lower_space + @rest_height) < DIALOG_HEIGHT
         scroll_down(DIALOG_HEIGHT)
         move_cursor_up(DIALOG_HEIGHT)
       end
-      @dialog_vertical_offset = pos.y + 1
+      dialog.vertical_offset = pos.y + 1
     end
     Reline::IOGate.hide_cursor
-    reset_dialog(old_dialog_contents, old_dialog_column, old_dialog_vertical_offset)
-    move_cursor_down(@dialog_vertical_offset)
-    Reline::IOGate.move_cursor_column(@dialog_column)
-    @dialog_contents.each_with_index do |item, i|
+    reset_dialog(dialog, old_dialog_contents, old_dialog_column, old_dialog_vertical_offset)
+    move_cursor_down(dialog.vertical_offset)
+    Reline::IOGate.move_cursor_column(dialog.column)
+    dialog.contents.each_with_index do |item, i|
       if i == pointer
         bg_color = '45'
       else
         bg_color = '46'
       end
       @output.write "\e[#{bg_color}m%-#{DIALOG_WIDTH}s\e[49m" % item.slice(0, DIALOG_WIDTH)
-      Reline::IOGate.move_cursor_column(@dialog_column)
-      move_cursor_down(1) if i < (@dialog_contents.size - 1)
+      Reline::IOGate.move_cursor_column(dialog.column)
+      move_cursor_down(1) if i < (dialog.contents.size - 1)
     end
     Reline::IOGate.move_cursor_column(cursor_column)
-    move_cursor_up(@dialog_vertical_offset + @dialog_contents.size - 1)
+    move_cursor_up(dialog.vertical_offset + dialog.contents.size - 1)
     Reline::IOGate.show_cursor
-    @dialog_lines_backup = {
+    dialog.lines_backup = {
       lines: modify_lines(whole_lines),
       line_index: @line_index,
       first_line_started_from: @first_line_started_from,
@@ -598,53 +618,61 @@ class Reline::LineEditor https://github.com/ruby/ruby/blob/trunk/lib/reline/line_editor.rb#L618
     }
   end
 
-  private def reset_dialog(old_dialog_contents, old_dialog_column, old_dialog_vertical_offset)
-    return if @dialog_lines_backup.nil? or old_dialog_contents.nil?
-    prompt, prompt_width, prompt_list = check_multiline_prompt(@dialog_lines_backup[:lines], prompt)
+  private def reset_dialog(dialog, old_dialog_contents, old_dialog_column, old_dialog_vertical_offset)
+    return if dialog.lines_backup.nil? or old_dialog_contents.nil?
+    prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:lines], prompt)
     visual_lines = []
     visual_start = nil
-    @dialog_lines_backup[:lines].each_with_index { |l, i|
+    dialog.lines_backup[:lines].each_with_index { |l, i|
       pr = prompt_list ? prompt_list[i] : prompt
       vl, _ = split_by_width(pr + l, @screen_size.last)
       vl.compact!
-      if i == @dialog_lines_backup[:line_index]
-        visual_start = visual_lines.size + @dialog_lines_backup[:started_from]
+      if i == dialog.lines_backup[:line_index]
+        visual_start = visual_lines.size + dialog.lines_backup[:started_from]
       end
       visual_lines.concat(vl)
     }
-    old_y = @dialog_lines_backup[:first_line_started_from] + @dialog_lines_backup[:started_from]
+    old_y = dialog.lines_backup[:first_line_started_from] + dialog.lines_backup[:started_from]
     y = @first_line_started_from + @started_from
     y_diff = y - old_y
-    if (old_y + old_dialog_vertical_offset) < (y + @dialog_vertical_offset)
+    if (old_y + old_dialog_vertical_offset) < (y + dialog.vertical_offset)
       # rerender top
       move_cursor_down(old_dialog_vertical_offset - y_diff)
       start = visual_start + old_dialog_vertical_offset
-      line_num = @dialog_vertical_offset - old_dialog_ve (... truncated)

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

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