beniya 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/beniya/application.rb +4 -1
- data/lib/beniya/file_preview.rb +11 -3
- data/lib/beniya/keybind_handler.rb +211 -671
- data/lib/beniya/terminal_ui.rb +54 -25
- data/lib/beniya/version.rb +1 -1
- metadata +2 -2
data/lib/beniya/terminal_ui.rb
CHANGED
@@ -4,14 +4,43 @@ require 'io/console'
|
|
4
4
|
|
5
5
|
module Beniya
|
6
6
|
class TerminalUI
|
7
|
+
# Layout constants
|
8
|
+
HEADER_HEIGHT = 2 # Header占有行数
|
9
|
+
FOOTER_HEIGHT = 1 # Footer占有行数
|
10
|
+
HEADER_FOOTER_MARGIN = 4 # Header + Footer分のマージン
|
11
|
+
|
12
|
+
# Panel layout ratios
|
13
|
+
LEFT_PANEL_RATIO = 0.5 # 左パネルの幅比率
|
14
|
+
RIGHT_PANEL_RATIO = 1.0 - LEFT_PANEL_RATIO
|
15
|
+
|
16
|
+
# Display constants
|
17
|
+
DEFAULT_SCREEN_WIDTH = 80 # デフォルト画面幅
|
18
|
+
DEFAULT_SCREEN_HEIGHT = 24 # デフォルト画面高さ
|
19
|
+
HEADER_PADDING = 2 # ヘッダーのパディング
|
20
|
+
BASE_INFO_RESERVED_WIDTH = 20 # ベースディレクトリ表示の予約幅
|
21
|
+
BASE_INFO_MIN_WIDTH = 10 # ベースディレクトリ表示の最小幅
|
22
|
+
FILTER_TEXT_RESERVED = 15 # フィルタテキスト表示の予約幅
|
23
|
+
|
24
|
+
# File display constants
|
25
|
+
ICON_SIZE_PADDING = 12 # アイコン、選択マーク、サイズ情報分
|
26
|
+
CURSOR_OFFSET = 1 # カーソル位置のオフセット
|
27
|
+
|
28
|
+
# Size display constants (bytes)
|
29
|
+
KILOBYTE = 1024
|
30
|
+
MEGABYTE = KILOBYTE * 1024
|
31
|
+
GIGABYTE = MEGABYTE * 1024
|
32
|
+
|
33
|
+
# Line offsets
|
34
|
+
CONTENT_START_LINE = 3 # コンテンツ開始行(ヘッダー2行スキップ)
|
35
|
+
|
7
36
|
def initialize
|
8
37
|
console = IO.console
|
9
38
|
if console
|
10
39
|
@screen_width, @screen_height = console.winsize.reverse
|
11
40
|
else
|
12
41
|
# fallback values (for test environments etc.)
|
13
|
-
@screen_width =
|
14
|
-
@screen_height =
|
42
|
+
@screen_width = DEFAULT_SCREEN_WIDTH
|
43
|
+
@screen_height = DEFAULT_SCREEN_HEIGHT
|
15
44
|
end
|
16
45
|
@running = false
|
17
46
|
end
|
@@ -83,9 +112,9 @@ module Beniya
|
|
83
112
|
entries = get_display_entries
|
84
113
|
selected_entry = entries[@keybind_handler.current_index]
|
85
114
|
|
86
|
-
# calculate height with header
|
87
|
-
content_height = @screen_height -
|
88
|
-
left_width = @screen_width
|
115
|
+
# calculate height with header and footer margin
|
116
|
+
content_height = @screen_height - HEADER_FOOTER_MARGIN
|
117
|
+
left_width = (@screen_width * LEFT_PANEL_RATIO).to_i
|
89
118
|
right_width = @screen_width - left_width
|
90
119
|
|
91
120
|
# adjust so right panel doesn't overflow into left panel
|
@@ -112,14 +141,14 @@ module Beniya
|
|
112
141
|
end
|
113
142
|
|
114
143
|
# abbreviate if path is too long
|
115
|
-
if header.length > @screen_width -
|
144
|
+
if header.length > @screen_width - HEADER_PADDING
|
116
145
|
if @keybind_handler.filter_active?
|
117
146
|
# prioritize showing filter when active
|
118
147
|
filter_text = " [Filter: #{@keybind_handler.filter_query}]"
|
119
|
-
base_length = @screen_width - filter_text.length -
|
148
|
+
base_length = @screen_width - filter_text.length - FILTER_TEXT_RESERVED
|
120
149
|
header = "📁 beniya - ...#{current_path[-base_length..-1]}#{filter_text}"
|
121
150
|
else
|
122
|
-
header = "📁 beniya - ...#{current_path[-(@screen_width -
|
151
|
+
header = "📁 beniya - ...#{current_path[-(@screen_width - FILTER_TEXT_RESERVED)..-1]}"
|
123
152
|
end
|
124
153
|
end
|
125
154
|
|
@@ -143,15 +172,15 @@ module Beniya
|
|
143
172
|
end
|
144
173
|
|
145
174
|
# 長すぎる場合は省略
|
146
|
-
if base_info.length > @screen_width -
|
175
|
+
if base_info.length > @screen_width - HEADER_PADDING
|
147
176
|
if base_info.include?(" | Selected:")
|
148
177
|
selected_part = base_info.split(" | Selected:").last
|
149
|
-
available_length = @screen_width -
|
178
|
+
available_length = @screen_width - BASE_INFO_RESERVED_WIDTH - " | Selected:#{selected_part}".length
|
150
179
|
else
|
151
|
-
available_length = @screen_width -
|
180
|
+
available_length = @screen_width - BASE_INFO_RESERVED_WIDTH
|
152
181
|
end
|
153
182
|
|
154
|
-
if available_length >
|
183
|
+
if available_length > BASE_INFO_MIN_WIDTH
|
155
184
|
# パスの最後の部分を表示
|
156
185
|
dir_part = base_info.split(": ").last.split(" | ").first
|
157
186
|
short_base_dir = "...#{dir_part[-available_length..-1]}"
|
@@ -170,7 +199,7 @@ module Beniya
|
|
170
199
|
|
171
200
|
(0...height).each do |i|
|
172
201
|
entry_index = start_index + i
|
173
|
-
line_num = i +
|
202
|
+
line_num = i + CONTENT_START_LINE
|
174
203
|
|
175
204
|
print "\e[#{line_num};1H" # set cursor position
|
176
205
|
|
@@ -181,7 +210,7 @@ module Beniya
|
|
181
210
|
draw_entry_line(entry, width, is_selected)
|
182
211
|
else
|
183
212
|
# 左ペイン専用の安全な幅で空行を出力
|
184
|
-
safe_width = [width -
|
213
|
+
safe_width = [width - CURSOR_OFFSET, (@screen_width * LEFT_PANEL_RATIO).to_i - CURSOR_OFFSET].min
|
185
214
|
print ' ' * safe_width
|
186
215
|
end
|
187
216
|
end
|
@@ -192,14 +221,14 @@ module Beniya
|
|
192
221
|
icon, color = get_entry_display_info(entry)
|
193
222
|
|
194
223
|
# 左ペイン専用の安全な幅を計算(右ペインにはみ出さないよう)
|
195
|
-
safe_width = [width -
|
224
|
+
safe_width = [width - CURSOR_OFFSET, (@screen_width * LEFT_PANEL_RATIO).to_i - CURSOR_OFFSET].min
|
196
225
|
|
197
226
|
# 選択マークの追加
|
198
227
|
selection_mark = @keybind_handler.is_selected?(entry[:name]) ? "✓ " : " "
|
199
228
|
|
200
229
|
# ファイル名(必要に応じて切り詰め)
|
201
230
|
name = entry[:name]
|
202
|
-
max_name_length = safe_width -
|
231
|
+
max_name_length = safe_width - ICON_SIZE_PADDING
|
203
232
|
name = name[0...max_name_length - 3] + '...' if max_name_length > 0 && name.length > max_name_length
|
204
233
|
|
205
234
|
# サイズ情報
|
@@ -260,22 +289,22 @@ module Beniya
|
|
260
289
|
def format_size(size)
|
261
290
|
return ' ' if size == 0
|
262
291
|
|
263
|
-
if size <
|
292
|
+
if size < KILOBYTE
|
264
293
|
"#{size}B".rjust(6)
|
265
|
-
elsif size <
|
266
|
-
"#{(size /
|
267
|
-
elsif size <
|
268
|
-
"#{(size /
|
294
|
+
elsif size < MEGABYTE
|
295
|
+
"#{(size / KILOBYTE.to_f).round(1)}K".rjust(6)
|
296
|
+
elsif size < GIGABYTE
|
297
|
+
"#{(size / MEGABYTE.to_f).round(1)}M".rjust(6)
|
269
298
|
else
|
270
|
-
"#{(size /
|
299
|
+
"#{(size / GIGABYTE.to_f).round(1)}G".rjust(6)
|
271
300
|
end
|
272
301
|
end
|
273
302
|
|
274
303
|
def draw_file_preview(selected_entry, width, height, left_offset)
|
275
304
|
(0...height).each do |i|
|
276
|
-
line_num = i +
|
305
|
+
line_num = i + CONTENT_START_LINE
|
277
306
|
# カーソル位置を左パネルの右端に設定
|
278
|
-
cursor_position = left_offset +
|
307
|
+
cursor_position = left_offset + CURSOR_OFFSET
|
279
308
|
|
280
309
|
# 画面の境界を厳密に計算
|
281
310
|
max_chars_from_cursor = @screen_width - cursor_position
|
@@ -450,7 +479,7 @@ module Beniya
|
|
450
479
|
|
451
480
|
def draw_footer
|
452
481
|
# 最下行から1行上に表示してスクロールを避ける
|
453
|
-
footer_line = @screen_height -
|
482
|
+
footer_line = @screen_height - FOOTER_HEIGHT
|
454
483
|
print "\e[#{footer_line};1H"
|
455
484
|
|
456
485
|
if @keybind_handler.filter_active?
|
data/lib/beniya/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: beniya
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- masisz
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-10-19 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: io-console
|