summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortomoya ishida <tomoyapenguin@gmail.com>2024-04-02 01:25:17 +0900
committergit <svn-admin@ruby-lang.org>2024-04-01 16:25:26 +0000
commit508bddc86516ed798365594b70d57e9ec5713e8b (patch)
tree1d418f71411cdd2987a62885769956f225b3828f
parente2a1d0b53dddc29b03a535286763fde51d4e089d (diff)
[ruby/reline] Align completion menu items
(https://github.com/ruby/reline/pull/613) https://github.com/ruby/reline/commit/a622704f62
-rw-r--r--lib/reline/line_editor.rb30
-rw-r--r--test/reline/test_line_editor.rb25
2 files changed, 51 insertions, 4 deletions
diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb
index d202ba02d2..d30ab3f367 100644
--- a/lib/reline/line_editor.rb
+++ b/lib/reline/line_editor.rb
@@ -49,7 +49,29 @@ class Reline::LineEditor
RenderedScreen = Struct.new(:base_y, :lines, :cursor_y, keyword_init: true)
CompletionJourneyData = Struct.new(:preposing, :postposing, :list, :pointer)
- MenuInfo = Struct.new(:target, :list)
+
+ class MenuInfo
+ attr_reader :list
+
+ def initialize(list)
+ @list = list
+ end
+
+ def lines(screen_width)
+ return [] if @list.empty?
+
+ list = @list.sort
+ sizes = list.map { |item| Reline::Unicode.calculate_width(item) }
+ item_width = sizes.max + 2
+ num_cols = [screen_width / item_width, 1].max
+ num_rows = list.size.fdiv(num_cols).ceil
+ list_with_padding = list.zip(sizes).map { |item, size| item + ' ' * (item_width - size) }
+ aligned = (list_with_padding + [nil] * (num_rows * num_cols - list_with_padding.size)).each_slice(num_rows).to_a.transpose
+ aligned.map do |row|
+ row.join.rstrip
+ end
+ end
+ end
MINIMUM_SCROLLBAR_HEIGHT = 1
@@ -458,7 +480,7 @@ class Reline::LineEditor
[[0, Reline::Unicode.calculate_width(l, true), l]]
end
if @menu_info
- @menu_info.list.sort!.each do |item|
+ @menu_info.lines(screen_width).each do |item|
new_lines << [[0, Reline::Unicode.calculate_width(item), item]]
end
@menu_info = nil # TODO: do not change state here
@@ -779,8 +801,8 @@ class Reline::LineEditor
@config.editing_mode
end
- private def menu(target, list)
- @menu_info = MenuInfo.new(target, list)
+ private def menu(_target, list)
+ @menu_info = MenuInfo.new(list)
end
private def complete_internal_proc(list, is_menu)
diff --git a/test/reline/test_line_editor.rb b/test/reline/test_line_editor.rb
index 0963d2c8fe..bf688ac3c6 100644
--- a/test/reline/test_line_editor.rb
+++ b/test/reline/test_line_editor.rb
@@ -127,4 +127,29 @@ class Reline::LineEditor
end
end
end
+
+ def test_menu_info_format
+ list = %w[aa b c d e f g hhh i j k]
+ col3 = [
+ 'aa e i',
+ 'b f j',
+ 'c g k',
+ 'd hhh'
+ ]
+ col2 = [
+ 'aa g',
+ 'b hhh',
+ 'c i',
+ 'd j',
+ 'e k',
+ 'f'
+ ]
+ assert_equal(col3, Reline::LineEditor::MenuInfo.new(list).lines(19))
+ assert_equal(col3, Reline::LineEditor::MenuInfo.new(list).lines(15))
+ assert_equal(col2, Reline::LineEditor::MenuInfo.new(list).lines(14))
+ assert_equal(col2, Reline::LineEditor::MenuInfo.new(list).lines(10))
+ assert_equal(list, Reline::LineEditor::MenuInfo.new(list).lines(9))
+ assert_equal(list, Reline::LineEditor::MenuInfo.new(list).lines(0))
+ assert_equal([], Reline::LineEditor::MenuInfo.new([]).lines(10))
+ end
end