fatty 0.99.0 → 0.99.3
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/CHANGELOG.org +11 -29
- data/README.md +2207 -18
- data/README.org +2066 -104
- data/exe/fatty +236 -93
- data/help/help.md +233 -0
- data/lib/fatty/action.rb +3 -7
- data/lib/fatty/actionable.rb +2 -0
- data/lib/fatty/alert.rb +65 -39
- data/lib/fatty/ansi/renderer.rb +26 -6
- data/lib/fatty/ansi.rb +1 -0
- data/lib/fatty/api/alert.rb +15 -0
- data/lib/fatty/api/choose.rb +145 -0
- data/lib/fatty/api/environment.rb +12 -0
- data/lib/fatty/api/keytest.rb +11 -0
- data/lib/fatty/api/menu.rb +104 -0
- data/lib/fatty/api/output.rb +55 -0
- data/lib/fatty/api/progress.rb +24 -0
- data/lib/fatty/api/prompt.rb +77 -0
- data/lib/fatty/api/status.rb +55 -0
- data/lib/fatty/api.rb +38 -0
- data/lib/fatty/callback_environment.rb +74 -0
- data/lib/fatty/colors/color.rb +366 -232
- data/lib/fatty/colors/pairs.rb +2 -0
- data/lib/fatty/command.rb +78 -0
- data/lib/fatty/config.rb +227 -39
- data/lib/fatty/config_files/config.yml +4 -12
- data/lib/fatty/config_files/keydefs.yml +13 -23
- data/lib/fatty/config_files/themes/capuchin_monk.yml +140 -0
- data/lib/fatty/config_files/themes/catppuccin_latte.yml +140 -0
- data/lib/fatty/config_files/themes/catppuccin_mocha.yml +140 -0
- data/lib/fatty/config_files/themes/cyberpunk.yml +141 -0
- data/lib/fatty/config_files/themes/dracula.yml +140 -0
- data/lib/fatty/config_files/themes/everforest_dark.yml +140 -0
- data/lib/fatty/config_files/themes/gruvbox_dark.yml +140 -0
- data/lib/fatty/config_files/themes/gruvbox_light.yml +140 -0
- data/lib/fatty/config_files/themes/mono.yml +119 -47
- data/lib/fatty/config_files/themes/monokai.yml +140 -0
- data/lib/fatty/config_files/themes/nordic.yml +1 -0
- data/lib/fatty/config_files/themes/onedark.yml +140 -0
- data/lib/fatty/config_files/themes/solarized_dark.yml +1 -0
- data/lib/fatty/config_files/themes/solarized_light.yml +140 -0
- data/lib/fatty/config_files/themes/terminal.yml +67 -0
- data/lib/fatty/config_files/themes/tokyo_night.yml +140 -0
- data/lib/fatty/config_files/themes/wordperfect.yml +80 -9
- data/lib/fatty/core_ext/hash.rb +19 -0
- data/lib/fatty/core_ext/string.rb +19 -12
- data/lib/fatty/core_ext.rb +1 -0
- data/lib/fatty/curses/context.rb +86 -84
- data/lib/fatty/curses/event_source.rb +128 -40
- data/lib/fatty/curses/key_decoder.rb +77 -11
- data/lib/fatty/env.rb +21 -20
- data/lib/fatty/help.rb +1 -29
- data/lib/fatty/history/entry.rb +2 -0
- data/lib/fatty/history.rb +17 -14
- data/lib/fatty/input_buffer.rb +71 -47
- data/lib/fatty/input_field.rb +216 -149
- data/lib/fatty/key_event.rb +67 -66
- data/lib/fatty/key_map.rb +54 -16
- data/lib/fatty/keymaps/emacs.rb +40 -6
- data/lib/fatty/log_formats/json.rb +2 -0
- data/lib/fatty/log_formats/text.rb +2 -0
- data/lib/fatty/logger.rb +7 -2
- data/lib/fatty/markdown/ansi_renderer.rb +75 -6
- data/lib/fatty/markdown/render.rb +2 -3
- data/lib/fatty/mouse_event.rb +142 -2
- data/lib/fatty/output_buffer.rb +2 -0
- data/lib/fatty/pager.rb +158 -47
- data/lib/fatty/progress.rb +417 -0
- data/lib/fatty/renderer/curses.rb +340 -184
- data/lib/fatty/renderer/truecolor.rb +266 -163
- data/lib/fatty/renderer.rb +115 -97
- data/lib/fatty/screen.rb +2 -0
- data/lib/fatty/session/alert_session.rb +39 -21
- data/lib/fatty/session/isearch_session.rb +92 -38
- data/lib/fatty/session/keytest_session.rb +105 -85
- data/lib/fatty/session/modal_session.rb +38 -1
- data/lib/fatty/session/output_session.rb +472 -21
- data/lib/fatty/session/popup_session.rb +251 -134
- data/lib/fatty/session/prompt_session.rb +68 -26
- data/lib/fatty/session/search_session.rb +79 -31
- data/lib/fatty/session/shell_session.rb +383 -368
- data/lib/fatty/session/status_session.rb +167 -0
- data/lib/fatty/session.rb +95 -95
- data/lib/fatty/terminal/popup_owner.rb +14 -11
- data/lib/fatty/terminal.rb +515 -813
- data/lib/fatty/themes/loader.rb +4 -2
- data/lib/fatty/themes/manager.rb +4 -0
- data/lib/fatty/themes/registry.rb +2 -0
- data/lib/fatty/themes/resolver.rb +175 -162
- data/lib/fatty/version.rb +1 -1
- data/lib/fatty/viewport.rb +8 -1
- data/lib/fatty.rb +35 -7
- metadata +42 -40
- data/.envrc +0 -2
- data/.simplecov +0 -23
- data/.yardopts +0 -4
- data/CHANGELOG.md +0 -34
- data/Rakefile +0 -15
- data/TODO.org +0 -163
- data/examples/markdown/native-markdown.md +0 -370
- data/examples/markdown/ox-gfm-markdown.md +0 -373
- data/examples/markdown/ox-gfm-markdown.org +0 -376
- data/fatty.gemspec +0 -42
- data/lib/fatty/accept_env.rb +0 -32
- data/lib/fatty/config_files/help.md +0 -120
- data/lib/fatty/config_files/help.org +0 -124
- data/lib/fatty/config_files/themes/wordperfect_light.yml +0 -77
- data/lib/fatty/menu_env.rb +0 -22
- data/lib/fatty/session/input_session.rb +0 -99
- data/lib/fatty/sessions.rb +0 -14
- data/lib/fatty/terminal/progress.rb +0 -374
- data/lib/fatty/view/alert_view.rb +0 -14
- data/lib/fatty/view/cursor_view.rb +0 -18
- data/lib/fatty/view/input_view.rb +0 -9
- data/lib/fatty/view/output_view.rb +0 -9
- data/lib/fatty/view/status_view.rb +0 -14
- data/lib/fatty/view.rb +0 -33
- data/lib/fatty/views.rb +0 -9
- data/sig/fatty.rbs +0 -4
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
name: wordperfect_light
|
|
2
|
-
inherit: wordperfect
|
|
3
|
-
|
|
4
|
-
output:
|
|
5
|
-
fg: white
|
|
6
|
-
bg: lightblue
|
|
7
|
-
|
|
8
|
-
# input:
|
|
9
|
-
# fg: white
|
|
10
|
-
# bg: navy
|
|
11
|
-
# attrs: [bold]
|
|
12
|
-
|
|
13
|
-
# input_suggestion:
|
|
14
|
-
# fg: lightgray
|
|
15
|
-
# bg: navy
|
|
16
|
-
|
|
17
|
-
# cursor:
|
|
18
|
-
# fg: white
|
|
19
|
-
# bg: red
|
|
20
|
-
|
|
21
|
-
# region:
|
|
22
|
-
# fg: navy
|
|
23
|
-
# bg: yellow
|
|
24
|
-
|
|
25
|
-
# good:
|
|
26
|
-
# fg: green
|
|
27
|
-
# bg: navy
|
|
28
|
-
|
|
29
|
-
# info:
|
|
30
|
-
# fg: black
|
|
31
|
-
# bg: navy
|
|
32
|
-
|
|
33
|
-
# warn:
|
|
34
|
-
# fg: black
|
|
35
|
-
# bg: magenta
|
|
36
|
-
|
|
37
|
-
# error:
|
|
38
|
-
# fg: white
|
|
39
|
-
# bg: red
|
|
40
|
-
|
|
41
|
-
# pager_status:
|
|
42
|
-
# fg: black
|
|
43
|
-
# bg: lightgreen
|
|
44
|
-
|
|
45
|
-
# search_input:
|
|
46
|
-
# fg: black
|
|
47
|
-
# bg: cyan
|
|
48
|
-
|
|
49
|
-
# match_current:
|
|
50
|
-
# fg: black
|
|
51
|
-
# bg: red
|
|
52
|
-
|
|
53
|
-
# match_other:
|
|
54
|
-
# fg: grey
|
|
55
|
-
# bg: pink
|
|
56
|
-
|
|
57
|
-
# popup:
|
|
58
|
-
# fg: white
|
|
59
|
-
# bg: navy
|
|
60
|
-
|
|
61
|
-
# popup_input:
|
|
62
|
-
# fg: white
|
|
63
|
-
# bg: navy
|
|
64
|
-
|
|
65
|
-
# popup_counts:
|
|
66
|
-
# fg: navy
|
|
67
|
-
# bg: red
|
|
68
|
-
|
|
69
|
-
# popup_selection:
|
|
70
|
-
# fg: navy
|
|
71
|
-
# bg: yellow
|
|
72
|
-
|
|
73
|
-
# popup_frame:
|
|
74
|
-
# fg: navy
|
|
75
|
-
# bg: yellow
|
|
76
|
-
# border: single
|
|
77
|
-
# corners: rounded
|
data/lib/fatty/menu_env.rb
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Fatty
|
|
4
|
-
class MenuEnv
|
|
5
|
-
attr_reader :terminal, :session, :label, :payload
|
|
6
|
-
|
|
7
|
-
def initialize(terminal:, session:, label: '', payload: nil)
|
|
8
|
-
@terminal = terminal
|
|
9
|
-
@session = session
|
|
10
|
-
@label = label
|
|
11
|
-
@payload = payload
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def output(text)
|
|
15
|
-
session.output.append(text.to_s)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def status(text)
|
|
19
|
-
terminal.set_status(text.to_s)
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Fatty
|
|
4
|
-
class InputSession < Session
|
|
5
|
-
attr_reader :field
|
|
6
|
-
|
|
7
|
-
# @param on_accept: ->(line, session, terminal) { ... }
|
|
8
|
-
def initialize(field:, keymap:, views: [], on_accept: nil)
|
|
9
|
-
super(keymap: keymap, views: views)
|
|
10
|
-
@field = field
|
|
11
|
-
@on_accept = on_accept
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
#########################################################################################
|
|
15
|
-
# Framework and Session Hooks
|
|
16
|
-
#########################################################################################
|
|
17
|
-
|
|
18
|
-
def keymap_contexts
|
|
19
|
-
if paging_mode?
|
|
20
|
-
[:paging, :text, :terminal]
|
|
21
|
-
else
|
|
22
|
-
[:text, :terminal]
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
############################################################################################
|
|
27
|
-
# Actions
|
|
28
|
-
############################################################################################
|
|
29
|
-
|
|
30
|
-
action_on :session
|
|
31
|
-
|
|
32
|
-
action :input_accept do
|
|
33
|
-
line = @field.accept_line
|
|
34
|
-
|
|
35
|
-
if @on_accept
|
|
36
|
-
Array(@on_accept.call(line, self, terminal))
|
|
37
|
-
else
|
|
38
|
-
Array(emit([:accept_line, line]))
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
action :input_cycle_theme do
|
|
43
|
-
[[:terminal, :cycle_theme]]
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
private
|
|
47
|
-
|
|
48
|
-
# Unbound keys land here.
|
|
49
|
-
def update_key(ev)
|
|
50
|
-
[]
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def update_cmd(name, payload)
|
|
54
|
-
case name
|
|
55
|
-
when :paste
|
|
56
|
-
text = payload.fetch(:text, "").to_s
|
|
57
|
-
env = action_env(event: nil)
|
|
58
|
-
field.act_on(:paste, text, env: env)
|
|
59
|
-
end
|
|
60
|
-
[]
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
# Bound keys land here because Session#update resolves via keymap first.
|
|
64
|
-
def handle_action(action, args, event:)
|
|
65
|
-
which =
|
|
66
|
-
if event&.respond_to?(:key)
|
|
67
|
-
event.key.inspect
|
|
68
|
-
elsif event&.respond_to?(:mouse)
|
|
69
|
-
event.mouse.inspect
|
|
70
|
-
end
|
|
71
|
-
Fatty.debug("InputSession#handle_action: #{which}", tag: :session)
|
|
72
|
-
env = action_env(event: event)
|
|
73
|
-
|
|
74
|
-
with_virtual_suffix_sync do
|
|
75
|
-
Fatty::Actions.call(action, env, *args)
|
|
76
|
-
end
|
|
77
|
-
[]
|
|
78
|
-
rescue ActionError => e
|
|
79
|
-
Fatty.error("InputSession#handle_action: ActionError #{e.message}", tag: :session)
|
|
80
|
-
[]
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def action_env(event:)
|
|
84
|
-
ActionEnvironment.new(
|
|
85
|
-
session: self,
|
|
86
|
-
terminal: terminal,
|
|
87
|
-
event: event,
|
|
88
|
-
field: @field,
|
|
89
|
-
)
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def with_virtual_suffix_sync
|
|
93
|
-
@field.sync_virtual_suffix!
|
|
94
|
-
result = yield
|
|
95
|
-
@field.sync_virtual_suffix!
|
|
96
|
-
result
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
end
|
data/lib/fatty/sessions.rb
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "session"
|
|
4
|
-
|
|
5
|
-
require_relative "session/alert_session"
|
|
6
|
-
require_relative "session/modal_session"
|
|
7
|
-
require_relative "session/popup_session"
|
|
8
|
-
require_relative "session/search_session"
|
|
9
|
-
require_relative "session/isearch_session"
|
|
10
|
-
require_relative "session/input_session"
|
|
11
|
-
require_relative "session/output_session"
|
|
12
|
-
require_relative "session/shell_session"
|
|
13
|
-
require_relative 'session/prompt_session'
|
|
14
|
-
require_relative 'session/keytest_session'
|
|
@@ -1,374 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Fatty
|
|
4
|
-
class Terminal
|
|
5
|
-
class Progress
|
|
6
|
-
PARTIAL_BLOCKS = ["", "▏", "▎", "▍", "▌", "▋", "▊", "▉"].freeze
|
|
7
|
-
FULL_BLOCK = "█"
|
|
8
|
-
EMPTY_BAR = "."
|
|
9
|
-
|
|
10
|
-
SHADE_EMPTY = "░"
|
|
11
|
-
SHADE_HALF = "▒"
|
|
12
|
-
SHADE_FULL = "▓"
|
|
13
|
-
|
|
14
|
-
BRAILLE_STEPS = ["⠀", "⣀", "⣄", "⣆", "⣇", "⣧", "⣷", "⣿"].freeze
|
|
15
|
-
|
|
16
|
-
attr_reader :terminal, :label, :total, :style, :role, :width
|
|
17
|
-
|
|
18
|
-
# The width parameter's purpose varies by style:
|
|
19
|
-
#
|
|
20
|
-
# :trail width = max visible width of the trail portion
|
|
21
|
-
# :bar width = max bar width
|
|
22
|
-
# :unicode_bar width = max bar width
|
|
23
|
-
# :braille_bar width = max bar width
|
|
24
|
-
# :spinner width ignored, unless later used for suffix/trail
|
|
25
|
-
# :count width ignored
|
|
26
|
-
# :percent width ignored
|
|
27
|
-
def initialize(terminal:, label:, total: nil, style: :percent, role: :info, width: 40)
|
|
28
|
-
@terminal = terminal
|
|
29
|
-
@label = label.to_s
|
|
30
|
-
@total = total&.to_i
|
|
31
|
-
@style = style.to_sym
|
|
32
|
-
@role = role
|
|
33
|
-
@width = width.to_i
|
|
34
|
-
@trail = []
|
|
35
|
-
@current = 0
|
|
36
|
-
@spinner_index = 0
|
|
37
|
-
|
|
38
|
-
validate_total_requirement!
|
|
39
|
-
|
|
40
|
-
refresh
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def update(current: nil, total: @total, label: @label, indicator: nil, render: false)
|
|
44
|
-
@current = current.to_i unless current.nil?
|
|
45
|
-
@total = total&.to_i
|
|
46
|
-
@label = label.to_s
|
|
47
|
-
|
|
48
|
-
if style == :spinner
|
|
49
|
-
advance_spinner
|
|
50
|
-
else
|
|
51
|
-
append_indicator(indicator)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
refresh
|
|
55
|
-
terminal.render_now if render
|
|
56
|
-
self
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def finish(message = nil, clear: false, role: @role, render: false, transient: true)
|
|
60
|
-
if clear
|
|
61
|
-
terminal.clear_status
|
|
62
|
-
else
|
|
63
|
-
text =
|
|
64
|
-
if message && !message.empty?
|
|
65
|
-
render_text(suffix: message)
|
|
66
|
-
else
|
|
67
|
-
render_text
|
|
68
|
-
end
|
|
69
|
-
terminal.set_status(text, role: role, transient: transient)
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
terminal.render_now if render
|
|
73
|
-
self
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def clear
|
|
77
|
-
terminal.clear_status
|
|
78
|
-
self
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
private
|
|
82
|
-
|
|
83
|
-
attr_reader :current
|
|
84
|
-
|
|
85
|
-
def append_indicator(indicator)
|
|
86
|
-
return if indicator.nil?
|
|
87
|
-
|
|
88
|
-
item =
|
|
89
|
-
if indicator.is_a?(Hash) && indicator.key?(:text)
|
|
90
|
-
indicator
|
|
91
|
-
else
|
|
92
|
-
indicator.to_s
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
return if renderable_indicator_text(item).empty?
|
|
96
|
-
|
|
97
|
-
@trail << item
|
|
98
|
-
trim_trail if @width && @width > 0
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def renderable_indicator_text(item)
|
|
102
|
-
if item.is_a?(Hash) && item.key?(:text)
|
|
103
|
-
item[:text].to_s
|
|
104
|
-
else
|
|
105
|
-
item.to_s
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
def refresh
|
|
110
|
-
terminal.set_status(render_text, role: role)
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
def render_text(suffix: nil)
|
|
114
|
-
case style
|
|
115
|
-
when :count
|
|
116
|
-
base = total ? "#{label} [#{current}/#{total}]" : "#{label} [#{current}]"
|
|
117
|
-
suffix_text(base, suffix)
|
|
118
|
-
when :simple_percent
|
|
119
|
-
base = total && total > 0 ? "#{label} #{percent}%" : label.to_s
|
|
120
|
-
suffix_text(base, suffix)
|
|
121
|
-
when :trail
|
|
122
|
-
render_trail_text(suffix: suffix)
|
|
123
|
-
when :bar
|
|
124
|
-
render_bar_text(suffix: suffix, mode: :solid)
|
|
125
|
-
when :unicode_bar
|
|
126
|
-
render_bar_text(suffix: suffix, mode: :unicode)
|
|
127
|
-
when :braille_bar
|
|
128
|
-
render_bar_text(suffix: suffix, mode: :braille)
|
|
129
|
-
when :spinner
|
|
130
|
-
render_spinner_text(suffix: suffix)
|
|
131
|
-
else
|
|
132
|
-
base = total && total > 0 ? "#{label} [#{current}/#{total}] #{percent}%" : "#{label} [#{current}]"
|
|
133
|
-
suffix_text(base, suffix)
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def percent
|
|
138
|
-
((current.to_f / total.to_f) * 100).round
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
def suffix_text(base, suffix)
|
|
142
|
-
extra = suffix.to_s
|
|
143
|
-
return base if extra.empty?
|
|
144
|
-
|
|
145
|
-
"#{base} #{extra}"
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
def render_trail_text(suffix: nil)
|
|
149
|
-
base =
|
|
150
|
-
if total && total > 0
|
|
151
|
-
"#{label} [#{current}/#{total}] #{percent}%"
|
|
152
|
-
else
|
|
153
|
-
"#{label} [#{current}]"
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
trailer = suffix.to_s.empty? ? "" : " #{suffix}"
|
|
157
|
-
return "#{base}#{trailer}" if @trail.empty?
|
|
158
|
-
|
|
159
|
-
limit = trail_limit(base, trailer)
|
|
160
|
-
trail = limited_trail(limit)
|
|
161
|
-
[base, " ", *trail, trailer]
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
def trail_limit(prefix, suffix = "")
|
|
165
|
-
cols =
|
|
166
|
-
if terminal.screen
|
|
167
|
-
terminal.screen.cols.to_i
|
|
168
|
-
else
|
|
169
|
-
80
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
available = cols - visible_length(prefix) - visible_length(suffix) - 4
|
|
173
|
-
available = 0 if available < 0
|
|
174
|
-
available
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
def limited_trail(limit)
|
|
178
|
-
used = 0
|
|
179
|
-
selected = []
|
|
180
|
-
|
|
181
|
-
@trail.reverse_each do |item|
|
|
182
|
-
width = visible_length(item)
|
|
183
|
-
break if used + width > limit
|
|
184
|
-
|
|
185
|
-
selected.unshift(item)
|
|
186
|
-
used += width
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
selected
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
def trim_trail
|
|
193
|
-
used = 0
|
|
194
|
-
selected = []
|
|
195
|
-
|
|
196
|
-
@trail.reverse_each do |item|
|
|
197
|
-
width = visible_length(item)
|
|
198
|
-
break if used + width > @width
|
|
199
|
-
|
|
200
|
-
selected.unshift(item)
|
|
201
|
-
used += width
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
@trail = selected
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
def visible_length(value)
|
|
208
|
-
if value.is_a?(Hash) && value.key?(:text)
|
|
209
|
-
Fatty::Ansi.visible_length(value[:text].to_s)
|
|
210
|
-
else
|
|
211
|
-
Fatty::Ansi.visible_length(value.to_s)
|
|
212
|
-
end
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
def render_bar_text(suffix: nil, mode: :solid)
|
|
216
|
-
base = label.to_s
|
|
217
|
-
info = progress_info_text
|
|
218
|
-
extra = suffix.to_s
|
|
219
|
-
trailer = extra.empty? ? "" : " #{extra}"
|
|
220
|
-
|
|
221
|
-
bar_width = bar_width_for(base, info, trailer)
|
|
222
|
-
bar =
|
|
223
|
-
case mode
|
|
224
|
-
when :unicode
|
|
225
|
-
unicode_bar(bar_width)
|
|
226
|
-
when :braille
|
|
227
|
-
braille_bar(bar_width)
|
|
228
|
-
else
|
|
229
|
-
solid_bar(bar_width)
|
|
230
|
-
end
|
|
231
|
-
|
|
232
|
-
pieces = [base]
|
|
233
|
-
pieces << "[#{bar}]" unless bar.empty?
|
|
234
|
-
pieces << info unless info.empty?
|
|
235
|
-
|
|
236
|
-
text = pieces.join(" ")
|
|
237
|
-
text = "#{text}#{trailer}" unless trailer.empty?
|
|
238
|
-
text
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
def render_spinner_text(suffix: nil)
|
|
242
|
-
frame = spinner_frames[@spinner_index % spinner_frames.length]
|
|
243
|
-
base =
|
|
244
|
-
if total && total > 0
|
|
245
|
-
"#{label} #{frame} #{percent}%"
|
|
246
|
-
else
|
|
247
|
-
"#{label} #{frame}"
|
|
248
|
-
end
|
|
249
|
-
|
|
250
|
-
suffix_text(base, suffix)
|
|
251
|
-
end
|
|
252
|
-
|
|
253
|
-
def progress_info_text
|
|
254
|
-
if total && total > 0
|
|
255
|
-
"#{percent}% [#{current}/#{total}]"
|
|
256
|
-
else
|
|
257
|
-
"[#{current}]"
|
|
258
|
-
end
|
|
259
|
-
end
|
|
260
|
-
|
|
261
|
-
def bar_width_for(base, info, trailer)
|
|
262
|
-
cols =
|
|
263
|
-
if terminal.screen
|
|
264
|
-
terminal.screen.cols.to_i
|
|
265
|
-
else
|
|
266
|
-
80
|
|
267
|
-
end
|
|
268
|
-
|
|
269
|
-
reserved = visible_length(base)
|
|
270
|
-
reserved += 1 + visible_length(info) unless info.empty?
|
|
271
|
-
reserved += visible_length(trailer) unless trailer.empty?
|
|
272
|
-
|
|
273
|
-
# Space for:
|
|
274
|
-
# " ["
|
|
275
|
-
# "]"
|
|
276
|
-
# around the bar
|
|
277
|
-
available = cols - reserved - 4
|
|
278
|
-
available = 0 if available < 0
|
|
279
|
-
[available, @width].min
|
|
280
|
-
end
|
|
281
|
-
|
|
282
|
-
def solid_bar(width)
|
|
283
|
-
return "" if width <= 0
|
|
284
|
-
|
|
285
|
-
ratio = progress_ratio
|
|
286
|
-
filled = (ratio * width).round
|
|
287
|
-
filled = 0 if filled < 0
|
|
288
|
-
filled = width if filled > width
|
|
289
|
-
|
|
290
|
-
empty = width - filled
|
|
291
|
-
(FULL_BLOCK * filled) + (EMPTY_BAR * empty)
|
|
292
|
-
end
|
|
293
|
-
|
|
294
|
-
def unicode_bar(width)
|
|
295
|
-
return "" if width <= 0
|
|
296
|
-
|
|
297
|
-
raw = progress_ratio * width
|
|
298
|
-
full = raw.floor
|
|
299
|
-
|
|
300
|
-
# Show a transition block whenever the bar is in progress but not complete,
|
|
301
|
-
# provided there is space for it.
|
|
302
|
-
half =
|
|
303
|
-
if progress_ratio.positive? && progress_ratio < 1.0 && full < width
|
|
304
|
-
1
|
|
305
|
-
else
|
|
306
|
-
0
|
|
307
|
-
end
|
|
308
|
-
|
|
309
|
-
bar = +""
|
|
310
|
-
bar << (SHADE_FULL * full)
|
|
311
|
-
bar << SHADE_HALF if half == 1
|
|
312
|
-
|
|
313
|
-
remaining = width - Fatty::Ansi.visible_length(bar)
|
|
314
|
-
remaining = 0 if remaining < 0
|
|
315
|
-
bar << (SHADE_EMPTY * remaining)
|
|
316
|
-
bar
|
|
317
|
-
end
|
|
318
|
-
|
|
319
|
-
def braille_bar(width)
|
|
320
|
-
return "" if width <= 0
|
|
321
|
-
|
|
322
|
-
raw = progress_ratio * width
|
|
323
|
-
full = raw.floor
|
|
324
|
-
remainder = raw - full
|
|
325
|
-
|
|
326
|
-
partial_idx = (remainder * (BRAILLE_STEPS.length - 1)).round
|
|
327
|
-
partial_idx = 0 if partial_idx < 0
|
|
328
|
-
partial_idx = BRAILLE_STEPS.length - 1 if partial_idx >= BRAILLE_STEPS.length
|
|
329
|
-
|
|
330
|
-
bar = +""
|
|
331
|
-
bar << (BRAILLE_STEPS[-1] * full)
|
|
332
|
-
|
|
333
|
-
if progress_ratio.positive? && progress_ratio < 1.0 && full < width
|
|
334
|
-
partial =
|
|
335
|
-
if partial_idx.zero?
|
|
336
|
-
BRAILLE_STEPS[1]
|
|
337
|
-
else
|
|
338
|
-
BRAILLE_STEPS[partial_idx]
|
|
339
|
-
end
|
|
340
|
-
bar << partial
|
|
341
|
-
end
|
|
342
|
-
|
|
343
|
-
remaining = width - Fatty::Ansi.visible_length(bar)
|
|
344
|
-
remaining = 0 if remaining < 0
|
|
345
|
-
bar << (BRAILLE_STEPS[0] * remaining)
|
|
346
|
-
bar
|
|
347
|
-
end
|
|
348
|
-
|
|
349
|
-
def progress_ratio
|
|
350
|
-
return 0.0 unless total && total > 0
|
|
351
|
-
|
|
352
|
-
ratio = current.to_f / total.to_f
|
|
353
|
-
ratio = 0.0 if ratio < 0.0
|
|
354
|
-
ratio = 1.0 if ratio > 1.0
|
|
355
|
-
ratio
|
|
356
|
-
end
|
|
357
|
-
|
|
358
|
-
def validate_total_requirement!
|
|
359
|
-
return if style == :spinner
|
|
360
|
-
return if total && total > 0
|
|
361
|
-
|
|
362
|
-
raise ArgumentError, "progress style #{style.inspect} requires total:"
|
|
363
|
-
end
|
|
364
|
-
|
|
365
|
-
def advance_spinner
|
|
366
|
-
@spinner_index = (@spinner_index + 1) % spinner_frames.length
|
|
367
|
-
end
|
|
368
|
-
|
|
369
|
-
def spinner_frames
|
|
370
|
-
BRAILLE_STEPS[1..]
|
|
371
|
-
end
|
|
372
|
-
end
|
|
373
|
-
end
|
|
374
|
-
end
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Fatty
|
|
4
|
-
class AlertView < Fatty::View
|
|
5
|
-
def initialize(id: "alert", z: 1_000, log: false)
|
|
6
|
-
super(id: id, z: z, log: log)
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def draw(screen:, renderer:, terminal:, session:)
|
|
10
|
-
# session is AlertSession; it owns `current`
|
|
11
|
-
renderer.render_alert(session.current)
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Fatty
|
|
4
|
-
class CursorView < Fatty::View
|
|
5
|
-
def draw(screen:, renderer:, terminal:, session:)
|
|
6
|
-
# When paging is active, the output pane owns the screen and the shell
|
|
7
|
-
# input cursor should be turned off. This also prevents the underlying
|
|
8
|
-
# ShellSession from overriding the cursor while a modal (e.g. SearchSession)
|
|
9
|
-
# is displayed over the pager/status line.
|
|
10
|
-
if session.respond_to?(:pager_active?) && session.pager_active?
|
|
11
|
-
::Curses.curs_set(0)
|
|
12
|
-
else
|
|
13
|
-
::Curses.curs_set(1)
|
|
14
|
-
renderer.restore_cursor(session.field)
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Fatty
|
|
4
|
-
class StatusView < View
|
|
5
|
-
def render(screen:, renderer:, terminal:)
|
|
6
|
-
return unless terminal.status_text
|
|
7
|
-
|
|
8
|
-
renderer.render_status(
|
|
9
|
-
terminal.status_text,
|
|
10
|
-
role: terminal.status_role || :info,
|
|
11
|
-
)
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
data/lib/fatty/view.rb
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Fatty
|
|
4
|
-
class View
|
|
5
|
-
attr_reader :id, :z
|
|
6
|
-
|
|
7
|
-
def initialize(id: nil, z: 0, log: false)
|
|
8
|
-
@id = (id || self.class.name.split("::").last).to_s
|
|
9
|
-
@z = Integer(z)
|
|
10
|
-
@log = !!log
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
# Render wrapper: logs once, then delegates to #draw.
|
|
14
|
-
# Subclasses implement #draw.
|
|
15
|
-
def render(screen:, renderer:, terminal:, session:)
|
|
16
|
-
if @log
|
|
17
|
-
Fatty.debug(
|
|
18
|
-
"View#render",
|
|
19
|
-
tag: :render,
|
|
20
|
-
view: id,
|
|
21
|
-
z: z,
|
|
22
|
-
session: session.respond_to?(:id) ? session.id : session.class.name,
|
|
23
|
-
)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
draw(screen:, renderer:, terminal:, session:)
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def draw(screen:, renderer:, terminal:, session:)
|
|
30
|
-
raise NotImplementedError, "#{self.class} must implement #draw"
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
end
|
data/lib/fatty/views.rb
DELETED
data/sig/fatty.rbs
DELETED