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
data/lib/fatty/renderer.rb
CHANGED
|
@@ -37,7 +37,7 @@ module Fatty
|
|
|
37
37
|
POPUP_SELECTED_GUTTER = "▶ "
|
|
38
38
|
POPUP_UNSELECTED_GUTTER = " "
|
|
39
39
|
|
|
40
|
-
attr_reader :screen, :palette, :context
|
|
40
|
+
attr_reader :screen, :palette, :context, :theme_version
|
|
41
41
|
|
|
42
42
|
def initialize(screen:, palette:, context:)
|
|
43
43
|
@screen = screen
|
|
@@ -49,12 +49,14 @@ module Fatty
|
|
|
49
49
|
@last_popup_state = nil
|
|
50
50
|
@last_prompt_popup_state = nil
|
|
51
51
|
@last_pager_field_state = nil
|
|
52
|
+
@theme_version = 0
|
|
52
53
|
end
|
|
53
54
|
|
|
54
55
|
attr_writer :screen
|
|
55
56
|
|
|
56
57
|
def apply_theme!(theme)
|
|
57
58
|
Fatty::Themes::Manager.set(theme)
|
|
59
|
+
@theme_version += 1
|
|
58
60
|
theme_spec = Fatty::Themes::Manager.roles(Fatty::Themes::Manager.current) || {}
|
|
59
61
|
@palette = Fatty::Colors::Palette.compile(theme_spec, available_colors: available_colors)
|
|
60
62
|
|
|
@@ -75,6 +77,14 @@ module Fatty
|
|
|
75
77
|
raise NotImplementedError, "#{self.class} must implement #render_input_field"
|
|
76
78
|
end
|
|
77
79
|
|
|
80
|
+
def clear_input_field(...)
|
|
81
|
+
raise NotImplementedError, "#{self.class} must implement #clear_input_field"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def restore_cursor(...)
|
|
85
|
+
raise NotImplementedError, "#{self.class} must implement #restore_cursor"
|
|
86
|
+
end
|
|
87
|
+
|
|
78
88
|
def render_pager_field(...)
|
|
79
89
|
raise NotImplementedError, "#{self.class} must implement #render_pager_field"
|
|
80
90
|
end
|
|
@@ -98,10 +108,23 @@ module Fatty
|
|
|
98
108
|
@last_status_state = nil
|
|
99
109
|
@last_pager_field_state = nil
|
|
100
110
|
@last_popup_state = nil
|
|
111
|
+
@last_prompt_popup_state = nil
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def hide_cursor
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def show_cursor
|
|
101
118
|
end
|
|
102
119
|
|
|
103
120
|
protected
|
|
104
121
|
|
|
122
|
+
# simplecov:disable
|
|
123
|
+
|
|
124
|
+
def alert_role(role)
|
|
125
|
+
:"alert_#{role}"
|
|
126
|
+
end
|
|
127
|
+
|
|
105
128
|
def available_colors
|
|
106
129
|
nil
|
|
107
130
|
end
|
|
@@ -110,74 +133,37 @@ module Fatty
|
|
|
110
133
|
nil
|
|
111
134
|
end
|
|
112
135
|
|
|
113
|
-
def alert_state(
|
|
114
|
-
|
|
115
|
-
alert&.message.dup.freeze,
|
|
116
|
-
alert&.role,
|
|
117
|
-
alert&.details,
|
|
118
|
-
screen.alert_rect.row,
|
|
119
|
-
screen.alert_rect.cols,
|
|
120
|
-
]
|
|
136
|
+
def alert_state(session)
|
|
137
|
+
session.state
|
|
121
138
|
end
|
|
122
139
|
|
|
123
|
-
def status_state(
|
|
124
|
-
|
|
125
|
-
renderable_segments(text, role: role).map { |segment|
|
|
126
|
-
[
|
|
127
|
-
segment[:text].to_s.dup.freeze,
|
|
128
|
-
segment[:role],
|
|
129
|
-
segment[:style],
|
|
130
|
-
].freeze
|
|
131
|
-
}.freeze,
|
|
132
|
-
role,
|
|
133
|
-
screen.status_rect.row,
|
|
134
|
-
screen.status_rect.rows,
|
|
135
|
-
screen.status_rect.cols,
|
|
136
|
-
]
|
|
140
|
+
def status_state(session)
|
|
141
|
+
session.state
|
|
137
142
|
end
|
|
138
143
|
|
|
139
144
|
def popup_state(session)
|
|
140
145
|
[
|
|
141
146
|
popup_border,
|
|
142
|
-
session.
|
|
143
|
-
session.message.to_s.dup.freeze,
|
|
144
|
-
session.displayed.map { |item| item.to_s.dup.freeze }.freeze,
|
|
145
|
-
session.selected,
|
|
146
|
-
session.field.buffer.text.to_s.dup.freeze,
|
|
147
|
-
session.field.buffer.cursor,
|
|
148
|
-
session.field.buffer.virtual_suffix.to_s.dup.freeze,
|
|
149
|
-
session.selected_labels.map { |label| label.to_s.dup.freeze }.sort.freeze,
|
|
150
|
-
session.counts&.dup&.freeze,
|
|
151
|
-
screen.rows,
|
|
152
|
-
screen.cols,
|
|
147
|
+
session.state
|
|
153
148
|
]
|
|
154
149
|
end
|
|
155
150
|
|
|
156
151
|
def prompt_popup_state(session)
|
|
157
152
|
[
|
|
158
153
|
popup_border,
|
|
159
|
-
session.
|
|
160
|
-
session.message.to_s.dup.freeze,
|
|
161
|
-
session.field.prompt_text.to_s.dup.freeze,
|
|
162
|
-
session.field.buffer.text.to_s.dup.freeze,
|
|
163
|
-
session.field.buffer.cursor,
|
|
164
|
-
session.field.buffer.virtual_suffix.to_s.dup.freeze,
|
|
165
|
-
screen.rows,
|
|
166
|
-
screen.cols,
|
|
154
|
+
session.state
|
|
167
155
|
]
|
|
168
156
|
end
|
|
169
157
|
|
|
170
|
-
def output_state(viewport
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
output_cols: screen.output_rect.cols,
|
|
180
|
-
}.freeze
|
|
158
|
+
def output_state(session, viewport: session.viewport)
|
|
159
|
+
session.state(viewport: viewport)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def input_field_state(input_field)
|
|
163
|
+
[
|
|
164
|
+
input_field.state,
|
|
165
|
+
theme_version
|
|
166
|
+
]
|
|
181
167
|
end
|
|
182
168
|
|
|
183
169
|
def pager_field_state(field, row:, role:)
|
|
@@ -201,20 +187,43 @@ module Fatty
|
|
|
201
187
|
}.join
|
|
202
188
|
end
|
|
203
189
|
|
|
204
|
-
def
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
190
|
+
def status_segment_lines(status_session)
|
|
191
|
+
segments = renderable_segments(
|
|
192
|
+
status_session.text,
|
|
193
|
+
role: status_session.role,
|
|
194
|
+
)
|
|
195
|
+
segment_lines(segments, width: screen.status_rect.cols)
|
|
196
|
+
.last(screen.status_rect.rows)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def segment_lines(segments, width:)
|
|
200
|
+
lines = [[]]
|
|
201
|
+
col = 0
|
|
202
|
+
segments.each do |segment|
|
|
203
|
+
text = segment[:text].to_s
|
|
204
|
+
text.each_line do |raw|
|
|
205
|
+
rest = raw.chomp
|
|
206
|
+
until rest.empty?
|
|
207
|
+
remaining = width - col
|
|
208
|
+
if remaining <= 0
|
|
209
|
+
lines << []
|
|
210
|
+
col = 0
|
|
211
|
+
remaining = width
|
|
212
|
+
end
|
|
213
|
+
piece = Fatty::Ansi.truncate_visible(rest, remaining)
|
|
214
|
+
break if piece.empty?
|
|
215
|
+
|
|
216
|
+
lines.last << segment.merge(text: piece)
|
|
217
|
+
col += Fatty::Ansi.visible_length(piece)
|
|
218
|
+
rest = rest[piece.length..].to_s
|
|
219
|
+
end
|
|
220
|
+
if raw.end_with?("\n")
|
|
221
|
+
lines << []
|
|
222
|
+
col = 0
|
|
223
|
+
end
|
|
224
|
+
end
|
|
214
225
|
end
|
|
215
|
-
|
|
216
|
-
lines = [""] if lines.empty?
|
|
217
|
-
lines.last(max_rows)
|
|
226
|
+
lines
|
|
218
227
|
end
|
|
219
228
|
|
|
220
229
|
def wrap_status_line(line, width:)
|
|
@@ -234,18 +243,35 @@ module Fatty
|
|
|
234
243
|
end
|
|
235
244
|
|
|
236
245
|
def renderable_segments(value, role:)
|
|
237
|
-
renderable_parts(value).
|
|
238
|
-
|
|
246
|
+
renderable_parts(value).flat_map do |part|
|
|
247
|
+
part_role =
|
|
248
|
+
if part.is_a?(Hash) && part.key?(:text)
|
|
249
|
+
part[:role] || role
|
|
250
|
+
else
|
|
251
|
+
role
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
text =
|
|
255
|
+
if part.is_a?(Hash) && part.key?(:text)
|
|
256
|
+
part[:text].to_s
|
|
257
|
+
else
|
|
258
|
+
part.to_s
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
if part.is_a?(Hash) && part[:style]
|
|
239
262
|
{
|
|
240
|
-
text:
|
|
241
|
-
role:
|
|
263
|
+
text: text,
|
|
264
|
+
role: part_role,
|
|
242
265
|
style: part[:style],
|
|
243
|
-
}.compact
|
|
244
|
-
else
|
|
245
|
-
{
|
|
246
|
-
text: part.to_s,
|
|
247
|
-
role: role,
|
|
248
266
|
}
|
|
267
|
+
else
|
|
268
|
+
Fatty::Ansi.segment(text).map do |segment_text, style|
|
|
269
|
+
{
|
|
270
|
+
text: segment_text,
|
|
271
|
+
role: part_role,
|
|
272
|
+
style: style,
|
|
273
|
+
}
|
|
274
|
+
end
|
|
249
275
|
end
|
|
250
276
|
end
|
|
251
277
|
end
|
|
@@ -254,19 +280,6 @@ module Fatty
|
|
|
254
280
|
value.is_a?(Array) ? value : [value]
|
|
255
281
|
end
|
|
256
282
|
|
|
257
|
-
def input_field_state(field)
|
|
258
|
-
[
|
|
259
|
-
field.prompt_text.to_s.dup.freeze,
|
|
260
|
-
field.buffer.text.to_s.dup.freeze,
|
|
261
|
-
field.buffer.cursor,
|
|
262
|
-
field.buffer.virtual_suffix.to_s.dup.freeze,
|
|
263
|
-
field.buffer.region_active?,
|
|
264
|
-
field.buffer.region_range,
|
|
265
|
-
screen.input_rect.row,
|
|
266
|
-
screen.input_rect.cols,
|
|
267
|
-
]
|
|
268
|
-
end
|
|
269
|
-
|
|
270
283
|
def popup_counts_text(session)
|
|
271
284
|
counts = session.counts
|
|
272
285
|
|
|
@@ -327,12 +340,12 @@ module Fatty
|
|
|
327
340
|
highlights.each_with_object({}) do |(line_no, ranges), out|
|
|
328
341
|
out[line_no] =
|
|
329
342
|
Array(ranges).map do |r|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
343
|
+
if r.is_a?(Hash)
|
|
344
|
+
[r[:from].to_i, r[:to].to_i, (r[:role] || :primary).to_sym]
|
|
345
|
+
else
|
|
346
|
+
[r[0].to_i, r[1].to_i, (r[2] || :primary).to_sym]
|
|
347
|
+
end
|
|
334
348
|
end
|
|
335
|
-
end
|
|
336
349
|
end
|
|
337
350
|
end
|
|
338
351
|
|
|
@@ -343,9 +356,7 @@ module Fatty
|
|
|
343
356
|
def deep_state(value)
|
|
344
357
|
case value
|
|
345
358
|
when Hash
|
|
346
|
-
value.to_h
|
|
347
|
-
[deep_state(key), deep_state(val)]
|
|
348
|
-
end.freeze
|
|
359
|
+
value.to_h { |key, val| [deep_state(key), deep_state(val)] }.freeze
|
|
349
360
|
when Array
|
|
350
361
|
value.map { |item| deep_state(item) }.freeze
|
|
351
362
|
when String
|
|
@@ -384,7 +395,14 @@ module Fatty
|
|
|
384
395
|
def field_segments(field, base_role:, suggestion_role: :input_suggestion, region_role: :region)
|
|
385
396
|
buf = field.buffer
|
|
386
397
|
text = buf.text.to_s
|
|
387
|
-
segments =
|
|
398
|
+
segments =
|
|
399
|
+
Fatty::Ansi.segment(field.prompt_text.to_s).map do |prompt_text, style|
|
|
400
|
+
{
|
|
401
|
+
text: prompt_text,
|
|
402
|
+
role: base_role,
|
|
403
|
+
style: style,
|
|
404
|
+
}
|
|
405
|
+
end
|
|
388
406
|
|
|
389
407
|
region =
|
|
390
408
|
if buf.respond_to?(:region_range)
|
data/lib/fatty/screen.rb
CHANGED
|
@@ -2,37 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
module Fatty
|
|
4
4
|
# A pinned, non-interactive overlay session responsible for rendering alerts.
|
|
5
|
-
#
|
|
6
|
-
# It is intentionally dumb:
|
|
7
|
-
# - Terminal does not special-case alerts
|
|
8
|
-
# - other sessions emit commands like:
|
|
9
|
-
# [:send, :alert, :show, { level:, message: }]
|
|
10
|
-
# [:send, :alert, :clear, {}]
|
|
11
5
|
class AlertSession < Session
|
|
12
6
|
attr_reader :current
|
|
13
7
|
|
|
14
|
-
def initialize
|
|
15
|
-
super
|
|
8
|
+
def initialize(id: nil)
|
|
9
|
+
super
|
|
16
10
|
@current = nil
|
|
17
11
|
end
|
|
18
12
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
private
|
|
13
|
+
#########################################################################################
|
|
14
|
+
# Session Protocol
|
|
15
|
+
#########################################################################################
|
|
24
16
|
|
|
25
|
-
def
|
|
26
|
-
|
|
27
|
-
case
|
|
17
|
+
def update(command)
|
|
18
|
+
Fatty.debug("AlertSession#update: action: #{command.action} alert: #{command.payload[:alert].inspect}")
|
|
19
|
+
case command.action
|
|
28
20
|
when :show
|
|
29
|
-
show_from_payload(payload)
|
|
21
|
+
show_from_payload(command.payload[:alert] || command.payload)
|
|
30
22
|
when :clear
|
|
31
23
|
@current = nil unless @current&.sticky?
|
|
32
24
|
end
|
|
33
25
|
[]
|
|
34
26
|
end
|
|
35
27
|
|
|
28
|
+
def view
|
|
29
|
+
renderer.render_alert(self)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def state
|
|
33
|
+
[
|
|
34
|
+
current&.text.dup.freeze,
|
|
35
|
+
current&.role,
|
|
36
|
+
current&.details,
|
|
37
|
+
renderer.screen.alert_rect.row,
|
|
38
|
+
renderer.screen.alert_rect.cols,
|
|
39
|
+
renderer.theme_version
|
|
40
|
+
]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
# simplecov:disable
|
|
46
|
+
|
|
47
|
+
def clear
|
|
48
|
+
@current = nil
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def visible?
|
|
52
|
+
!!current
|
|
53
|
+
end
|
|
54
|
+
|
|
36
55
|
def show_from_payload(payload)
|
|
37
56
|
return if payload.nil?
|
|
38
57
|
|
|
@@ -41,12 +60,11 @@ module Fatty
|
|
|
41
60
|
return
|
|
42
61
|
end
|
|
43
62
|
|
|
44
|
-
|
|
45
|
-
|
|
63
|
+
role = (payload[:role] || :info).to_sym
|
|
64
|
+
text = payload[:text].to_s
|
|
46
65
|
details = payload[:details]
|
|
47
66
|
sticky = !!payload[:sticky]
|
|
48
|
-
|
|
49
|
-
@current = Fatty::Alert.new(level: level, message: message, details: details, sticky: sticky)
|
|
67
|
+
@current = Fatty::Alert.new(role: role, text: text, details: details, sticky: sticky)
|
|
50
68
|
end
|
|
51
69
|
end
|
|
52
70
|
end
|
|
@@ -4,7 +4,7 @@ module Fatty
|
|
|
4
4
|
class ISearchSession < Session
|
|
5
5
|
action_on :session
|
|
6
6
|
|
|
7
|
-
attr_reader :field, :direction
|
|
7
|
+
attr_reader :field, :direction, :last_pattern
|
|
8
8
|
|
|
9
9
|
def id = :isearch
|
|
10
10
|
|
|
@@ -12,33 +12,58 @@ module Fatty
|
|
|
12
12
|
DEFAULT_ISEARCH_HISTORY_MAX = 200
|
|
13
13
|
|
|
14
14
|
def initialize(direction: :forward, last_pattern: nil, history: nil)
|
|
15
|
-
super(keymap: Keymaps.emacs
|
|
16
|
-
|
|
15
|
+
super(keymap: Keymaps.emacs)
|
|
17
16
|
@direction = direction.to_sym
|
|
18
17
|
@failed = false
|
|
19
18
|
@last_text = nil
|
|
20
19
|
@last_pattern = last_pattern.to_s
|
|
21
|
-
|
|
22
20
|
@field = Fatty::InputField.new(
|
|
23
21
|
prompt: Prompt.new { isearch_prompt },
|
|
24
22
|
history: history,
|
|
25
23
|
history_kind: :search_string,
|
|
26
|
-
|
|
24
|
+
history_ctx: { kind: :search, regex: false },
|
|
27
25
|
)
|
|
28
26
|
end
|
|
29
27
|
|
|
30
28
|
#########################################################################################
|
|
31
|
-
#
|
|
29
|
+
# Session Protocol
|
|
32
30
|
#########################################################################################
|
|
33
31
|
|
|
34
|
-
def
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
32
|
+
def update(command)
|
|
33
|
+
log_update(command)
|
|
34
|
+
commands =
|
|
35
|
+
case command.action
|
|
36
|
+
when :key
|
|
37
|
+
ev = command.payload.fetch(:event)
|
|
38
|
+
action, args = resolve_action(ev)
|
|
39
|
+
if action
|
|
40
|
+
apply_action(action, args, event: ev)
|
|
41
|
+
else
|
|
42
|
+
[]
|
|
43
|
+
end
|
|
44
|
+
when :terminal_paste
|
|
45
|
+
env = action_env(event: nil)
|
|
46
|
+
@field.act_on(
|
|
47
|
+
:paste,
|
|
48
|
+
command.payload.fetch(:text, ""),
|
|
49
|
+
env: env,
|
|
50
|
+
)
|
|
51
|
+
@field.sync_virtual_suffix!
|
|
52
|
+
maybe_preview!
|
|
53
|
+
when :isearch_set_failed
|
|
54
|
+
@failed = !!command.payload[:failed]
|
|
55
|
+
@field.prompt = isearch_prompt
|
|
56
|
+
[]
|
|
57
|
+
else
|
|
58
|
+
[]
|
|
59
|
+
end
|
|
60
|
+
Array(commands)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def view
|
|
39
64
|
row = screen.output_rect.rows - 1
|
|
40
65
|
|
|
41
|
-
|
|
66
|
+
renderer.show_cursor
|
|
42
67
|
renderer.render_pager_field(@field, row: row, role: :search_input)
|
|
43
68
|
renderer.restore_output_cursor(@field, row: row)
|
|
44
69
|
end
|
|
@@ -69,14 +94,10 @@ module Fatty
|
|
|
69
94
|
|
|
70
95
|
private
|
|
71
96
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
@failed = !!payload[:failed]
|
|
77
|
-
@field.prompt = isearch_prompt
|
|
78
|
-
end
|
|
79
|
-
cmds
|
|
97
|
+
# simplecov:disable
|
|
98
|
+
|
|
99
|
+
def keymap_contexts
|
|
100
|
+
[:isearch, :text, :terminal]
|
|
80
101
|
end
|
|
81
102
|
|
|
82
103
|
def action_env(event:)
|
|
@@ -89,13 +110,14 @@ module Fatty
|
|
|
89
110
|
)
|
|
90
111
|
end
|
|
91
112
|
|
|
92
|
-
def
|
|
113
|
+
def apply_action(action, args, event:)
|
|
93
114
|
env = action_env(event: event)
|
|
94
115
|
|
|
95
116
|
if Fatty::Actions.lookup(action)&.fetch(:on) == :session
|
|
96
117
|
Fatty::Actions.call(action, env, *args)
|
|
97
118
|
else
|
|
98
119
|
@field.act_on(action, *args, env: env)
|
|
120
|
+
@field.sync_virtual_suffix!
|
|
99
121
|
maybe_preview!
|
|
100
122
|
end
|
|
101
123
|
rescue Fatty::ActionError
|
|
@@ -110,30 +132,58 @@ module Fatty
|
|
|
110
132
|
|
|
111
133
|
def accept!
|
|
112
134
|
pattern = @field.accept_line.to_s
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
135
|
+
[
|
|
136
|
+
Command.terminal(
|
|
137
|
+
:send_modal_owner,
|
|
138
|
+
command: Command.session(
|
|
139
|
+
:focused,
|
|
140
|
+
:pager_isearch_commit,
|
|
141
|
+
pattern: pattern,
|
|
142
|
+
direction: @direction,
|
|
143
|
+
),
|
|
144
|
+
),
|
|
145
|
+
Command.terminal(:pop_modal),
|
|
146
|
+
]
|
|
117
147
|
end
|
|
118
148
|
|
|
119
149
|
def cancel!
|
|
120
|
-
[
|
|
150
|
+
[
|
|
151
|
+
Command.terminal(
|
|
152
|
+
:send_modal_owner,
|
|
153
|
+
command: Command.session(:focused, :pager_isearch_cancel),
|
|
154
|
+
),
|
|
155
|
+
Command.terminal(:pop_modal),
|
|
156
|
+
]
|
|
121
157
|
end
|
|
122
158
|
|
|
123
159
|
def step_next!
|
|
124
160
|
@direction = :forward
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
161
|
+
|
|
162
|
+
prefill_last_pattern_if_empty! + [
|
|
163
|
+
Command.terminal(
|
|
164
|
+
:send_modal_owner,
|
|
165
|
+
command: Command.session(
|
|
166
|
+
:focused,
|
|
167
|
+
:pager_isearch_step,
|
|
168
|
+
direction: @direction,
|
|
169
|
+
),
|
|
170
|
+
),
|
|
171
|
+
]
|
|
129
172
|
end
|
|
130
173
|
|
|
131
174
|
def step_prev!
|
|
132
175
|
@direction = :backward
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
176
|
+
|
|
177
|
+
prefill_last_pattern_if_empty! + [
|
|
178
|
+
Command.terminal(
|
|
179
|
+
:send_modal_owner,
|
|
180
|
+
command: Command.session(
|
|
181
|
+
:focused,
|
|
182
|
+
:pager_isearch_step,
|
|
183
|
+
direction: @direction,
|
|
184
|
+
),
|
|
185
|
+
),
|
|
186
|
+
]
|
|
137
187
|
end
|
|
138
188
|
|
|
139
189
|
def prefill_last_pattern_if_empty!
|
|
@@ -161,11 +211,15 @@ module Fatty
|
|
|
161
211
|
|
|
162
212
|
@last_text = text.dup
|
|
163
213
|
[
|
|
164
|
-
|
|
165
|
-
:terminal,
|
|
214
|
+
Command.terminal(
|
|
166
215
|
:send_modal_owner,
|
|
167
|
-
|
|
168
|
-
|
|
216
|
+
command: Command.session(
|
|
217
|
+
:focused,
|
|
218
|
+
:pager_isearch_update,
|
|
219
|
+
pattern: text,
|
|
220
|
+
direction: @direction,
|
|
221
|
+
),
|
|
222
|
+
),
|
|
169
223
|
]
|
|
170
224
|
end
|
|
171
225
|
end
|