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/pager.rb
CHANGED
|
@@ -2,16 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
module Fatty
|
|
4
4
|
class Pager
|
|
5
|
-
SCROLL_WHEEL_LINES =
|
|
5
|
+
SCROLL_WHEEL_LINES = 6
|
|
6
6
|
|
|
7
7
|
include Fatty::Actionable
|
|
8
8
|
|
|
9
9
|
action_on :pager
|
|
10
10
|
attr_reader :mode
|
|
11
11
|
|
|
12
|
-
def initialize(output:, viewport
|
|
12
|
+
def initialize(output:, viewport: Viewport.new, mode: :paging, lines: nil)
|
|
13
13
|
@output = output
|
|
14
14
|
@viewport = viewport
|
|
15
|
+
@lines = lines || -> { @output.lines }
|
|
15
16
|
# @mode can be :paging, or :scrolling
|
|
16
17
|
# - paging: the viewport displays one page worth of output at a time,
|
|
17
18
|
# - scrolling: the viewport displays output continuously as it is produced.
|
|
@@ -21,6 +22,8 @@ module Fatty
|
|
|
21
22
|
@last_nav_dir = nil
|
|
22
23
|
# Search state (used by SearchSession, but owned here so paging repeats and
|
|
23
24
|
# highlighting survive after the SearchSession closes).
|
|
25
|
+
@isearch_snapshot = nil
|
|
26
|
+
@search_snapshot = nil
|
|
24
27
|
@search = {
|
|
25
28
|
pattern: nil,
|
|
26
29
|
regex: false,
|
|
@@ -33,10 +36,48 @@ module Fatty
|
|
|
33
36
|
}
|
|
34
37
|
end
|
|
35
38
|
|
|
39
|
+
def quit
|
|
40
|
+
@paused = false
|
|
41
|
+
@mode = :paging
|
|
42
|
+
@anchor = nil
|
|
43
|
+
@autoscroll = false
|
|
44
|
+
end
|
|
45
|
+
|
|
36
46
|
def paused?
|
|
37
47
|
@mode == :paging && @paused
|
|
38
48
|
end
|
|
39
49
|
|
|
50
|
+
def scrolling?
|
|
51
|
+
@mode == :scrolling
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def toggle_paging_mode
|
|
55
|
+
@last_nav_dir = :down
|
|
56
|
+
if @mode == :paging
|
|
57
|
+
set_to_scrolling
|
|
58
|
+
else
|
|
59
|
+
set_to_paging
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def set_to_scrolling
|
|
64
|
+
@mode = :scrolling
|
|
65
|
+
@paused = false
|
|
66
|
+
@autoscroll = true
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def set_to_paging
|
|
70
|
+
@mode = :paging
|
|
71
|
+
@paused = true
|
|
72
|
+
@autoscroll = false
|
|
73
|
+
@anchor = nil
|
|
74
|
+
@viewport.clamp!(lines)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def active?
|
|
78
|
+
paused? || scrolling?
|
|
79
|
+
end
|
|
80
|
+
|
|
40
81
|
def reserve_prompt_row?
|
|
41
82
|
paused?
|
|
42
83
|
end
|
|
@@ -57,23 +98,19 @@ module Fatty
|
|
|
57
98
|
# Called by OutputSession after new text is appended.
|
|
58
99
|
def on_append(ntrim:)
|
|
59
100
|
@viewport.adjust_for_trim(ntrim)
|
|
60
|
-
|
|
61
|
-
total =
|
|
62
|
-
|
|
101
|
+
current_lines = lines
|
|
102
|
+
total = current_lines.size
|
|
63
103
|
case @mode
|
|
64
104
|
when :scrolling
|
|
65
105
|
# In scrolling mode, the viewport is allowed to move continuously.
|
|
66
106
|
# Autoscroll animation (after switching from paging -> scrolling) is
|
|
67
107
|
# driven by #autoscroll_step? in ShellSession#tick, not by incremental
|
|
68
108
|
# scroll deltas during append.
|
|
69
|
-
@viewport.clamp!(
|
|
109
|
+
@viewport.clamp!(current_lines)
|
|
70
110
|
when :paging
|
|
71
111
|
if @anchor
|
|
72
112
|
produced = total - @anchor
|
|
73
|
-
|
|
74
|
-
if produced <= 0
|
|
75
|
-
return
|
|
76
|
-
end
|
|
113
|
+
return if produced <= 0
|
|
77
114
|
|
|
78
115
|
# While producing the first page, keep the viewport pinned to the anchor.
|
|
79
116
|
@viewport.top = @anchor
|
|
@@ -96,7 +133,7 @@ module Fatty
|
|
|
96
133
|
@viewport.page_top
|
|
97
134
|
end
|
|
98
135
|
# Otherwise user is not at bottom; don't force movement.
|
|
99
|
-
@viewport.clamp!(
|
|
136
|
+
@viewport.clamp!(current_lines)
|
|
100
137
|
end
|
|
101
138
|
end
|
|
102
139
|
|
|
@@ -139,7 +176,7 @@ module Fatty
|
|
|
139
176
|
@last_nav_dir = :down
|
|
140
177
|
@anchor = nil
|
|
141
178
|
@autoscroll = false
|
|
142
|
-
@viewport.page_bottom(
|
|
179
|
+
@viewport.page_bottom(lines)
|
|
143
180
|
end
|
|
144
181
|
|
|
145
182
|
desc "One line up"
|
|
@@ -178,12 +215,16 @@ module Fatty
|
|
|
178
215
|
clamp_to_page!
|
|
179
216
|
end
|
|
180
217
|
|
|
181
|
-
desc "Page top"
|
|
182
|
-
action :page_top do
|
|
218
|
+
desc "Page top or go to an output line"
|
|
219
|
+
action :page_top do |count: nil|
|
|
183
220
|
@mode = :paging
|
|
184
221
|
@paused = true
|
|
185
222
|
@last_nav_dir = :up
|
|
186
|
-
|
|
223
|
+
if count
|
|
224
|
+
go_to_line!(count)
|
|
225
|
+
else
|
|
226
|
+
page_top!
|
|
227
|
+
end
|
|
187
228
|
end
|
|
188
229
|
|
|
189
230
|
desc "Page bottom"
|
|
@@ -201,33 +242,19 @@ module Fatty
|
|
|
201
242
|
@anchor = nil
|
|
202
243
|
@last_nav_dir = :down
|
|
203
244
|
@autoscroll = true
|
|
204
|
-
@viewport.clamp!(
|
|
245
|
+
@viewport.clamp!(lines)
|
|
205
246
|
# Make it visibly start immediately, even if no further appends happen.
|
|
206
247
|
autoscroll_step?(max_lines: @viewport.height)
|
|
207
248
|
end
|
|
208
249
|
|
|
209
250
|
desc "Toggle between paging and scrolling"
|
|
210
251
|
action :toggle_paging do
|
|
211
|
-
|
|
212
|
-
if @mode == :paging
|
|
213
|
-
@mode = :scrolling
|
|
214
|
-
@paused = false
|
|
215
|
-
@autoscroll = true # keep if you like the animated “catch up”
|
|
216
|
-
else
|
|
217
|
-
@mode = :paging
|
|
218
|
-
@paused = true
|
|
219
|
-
@autoscroll = false
|
|
220
|
-
@anchor = nil # ensure no command-anchored paging behavior kicks in
|
|
221
|
-
@viewport.clamp!(@output.lines)
|
|
222
|
-
end
|
|
252
|
+
toggle_paging_mode
|
|
223
253
|
end
|
|
224
254
|
|
|
225
255
|
desc "Exit paging and return control to normal input."
|
|
226
256
|
action :quit_paging do
|
|
227
|
-
|
|
228
|
-
@mode = :paging
|
|
229
|
-
@anchor = nil
|
|
230
|
-
@autoscroll = false
|
|
257
|
+
quit
|
|
231
258
|
end
|
|
232
259
|
|
|
233
260
|
def at_top?
|
|
@@ -253,14 +280,14 @@ module Fatty
|
|
|
253
280
|
end
|
|
254
281
|
|
|
255
282
|
def max_page_top
|
|
256
|
-
[
|
|
283
|
+
[lines.size - page_height, 0].max
|
|
257
284
|
end
|
|
258
285
|
|
|
259
286
|
def clamp!
|
|
260
287
|
if paused?
|
|
261
288
|
clamp_to_page!
|
|
262
289
|
else
|
|
263
|
-
@viewport.clamp!(
|
|
290
|
+
@viewport.clamp!(lines)
|
|
264
291
|
end
|
|
265
292
|
end
|
|
266
293
|
|
|
@@ -275,6 +302,17 @@ module Fatty
|
|
|
275
302
|
@autoscroll = false
|
|
276
303
|
end
|
|
277
304
|
|
|
305
|
+
def finish_command!
|
|
306
|
+
@anchor = nil
|
|
307
|
+
if @mode == :scrolling && lines.length > page_height
|
|
308
|
+
set_to_paging
|
|
309
|
+
@viewport.top = max_page_top
|
|
310
|
+
elsif @mode == :paging && lines.length > page_height
|
|
311
|
+
@paused = true
|
|
312
|
+
clamp_to_page!
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
|
|
278
316
|
def reset!(total_lines: 0, mode: :paging)
|
|
279
317
|
@mode = mode
|
|
280
318
|
@paused = false
|
|
@@ -283,7 +321,6 @@ module Fatty
|
|
|
283
321
|
end
|
|
284
322
|
|
|
285
323
|
def autoscroll_step?(max_lines: 200)
|
|
286
|
-
lines = @output.lines
|
|
287
324
|
total = lines.length
|
|
288
325
|
moved = false
|
|
289
326
|
if total > 0
|
|
@@ -310,6 +347,25 @@ module Fatty
|
|
|
310
347
|
!@search[:re].nil?
|
|
311
348
|
end
|
|
312
349
|
|
|
350
|
+
def search_begin!
|
|
351
|
+
ensure_search_snapshot!
|
|
352
|
+
nil
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
def search_cancel!
|
|
356
|
+
if @search_snapshot
|
|
357
|
+
@viewport.top = @search_snapshot[:viewport_top]
|
|
358
|
+
@search = @search_snapshot[:search]
|
|
359
|
+
@search_snapshot = nil
|
|
360
|
+
end
|
|
361
|
+
nil
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
def search_commit!
|
|
365
|
+
@search_snapshot = nil
|
|
366
|
+
nil
|
|
367
|
+
end
|
|
368
|
+
|
|
313
369
|
# Sets the search pattern and moves the viewport to the next match.
|
|
314
370
|
# Returns a result hash:
|
|
315
371
|
# { status: :moved }
|
|
@@ -366,14 +422,13 @@ module Fatty
|
|
|
366
422
|
end
|
|
367
423
|
return { status: :not_found } unless re
|
|
368
424
|
|
|
369
|
-
lines = @output.lines
|
|
370
425
|
total = lines.length
|
|
371
426
|
return { status: :not_found } if total.zero?
|
|
372
427
|
|
|
373
428
|
start = search_start_position(direction: direction, total: total, initial: initial)
|
|
374
429
|
found = find_next_match(lines, re, start, direction: direction, wrap: false)
|
|
375
430
|
|
|
376
|
-
if found
|
|
431
|
+
if valid_search_match?(found)
|
|
377
432
|
apply_search_match(found)
|
|
378
433
|
@search[:pending_wrap] = nil
|
|
379
434
|
return { status: :moved }
|
|
@@ -385,7 +440,7 @@ module Fatty
|
|
|
385
440
|
found = find_next_match(lines, re, wrap_start, direction: direction, wrap: true)
|
|
386
441
|
@search[:pending_wrap] = nil
|
|
387
442
|
|
|
388
|
-
if found
|
|
443
|
+
if valid_search_match?(found)
|
|
389
444
|
apply_search_match(found)
|
|
390
445
|
return { status: :moved, wrapped: true }
|
|
391
446
|
end
|
|
@@ -435,8 +490,8 @@ module Fatty
|
|
|
435
490
|
# the renderer’s slice planner / highlighting behavior.
|
|
436
491
|
def search_visible_highlights(viewport:)
|
|
437
492
|
return unless @search[:re]
|
|
493
|
+
return unless active?
|
|
438
494
|
|
|
439
|
-
lines = @output.lines
|
|
440
495
|
total = lines.length
|
|
441
496
|
return if total.zero?
|
|
442
497
|
|
|
@@ -570,8 +625,10 @@ module Fatty
|
|
|
570
625
|
"#{arrow} #{prefix}#{pat}"
|
|
571
626
|
end
|
|
572
627
|
|
|
628
|
+
# --- ISearch -----------------------------------------------------------
|
|
629
|
+
|
|
573
630
|
def isearch_update!(pattern:, direction:)
|
|
574
|
-
|
|
631
|
+
isearch_begin!
|
|
575
632
|
pattern = pattern.to_s
|
|
576
633
|
|
|
577
634
|
result =
|
|
@@ -598,6 +655,16 @@ module Fatty
|
|
|
598
655
|
{ status: :not_found, message: "Invalid regexp: #{e.message}" }
|
|
599
656
|
end
|
|
600
657
|
|
|
658
|
+
def isearch_begin!
|
|
659
|
+
ensure_isearch_snapshot!
|
|
660
|
+
nil
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
def isearch_commit!
|
|
664
|
+
@isearch_snapshot = nil
|
|
665
|
+
nil
|
|
666
|
+
end
|
|
667
|
+
|
|
601
668
|
def isearch_step!(direction:)
|
|
602
669
|
ensure_isearch_snapshot!
|
|
603
670
|
search_step!(direction: direction, initial: false, update_origin: false)
|
|
@@ -612,19 +679,24 @@ module Fatty
|
|
|
612
679
|
nil
|
|
613
680
|
end
|
|
614
681
|
|
|
615
|
-
def
|
|
616
|
-
|
|
682
|
+
def isearch_accept!(pattern:, direction:)
|
|
683
|
+
isearch_begin!
|
|
684
|
+
|
|
617
685
|
pattern = pattern.to_s
|
|
618
686
|
if pattern.strip.empty?
|
|
619
687
|
isearch_cancel!
|
|
620
688
|
return { status: :not_found }
|
|
621
689
|
end
|
|
690
|
+
|
|
622
691
|
result = isearch_update!(pattern: pattern, direction: direction)
|
|
623
692
|
if result[:status] == :moved
|
|
624
693
|
@search[:original_direction] = direction.to_sym
|
|
625
694
|
@search[:pending_wrap] = nil
|
|
695
|
+
isearch_commit!
|
|
696
|
+
else
|
|
697
|
+
isearch_cancel!
|
|
626
698
|
end
|
|
627
|
-
|
|
699
|
+
|
|
628
700
|
result
|
|
629
701
|
end
|
|
630
702
|
|
|
@@ -637,7 +709,7 @@ module Fatty
|
|
|
637
709
|
end
|
|
638
710
|
|
|
639
711
|
def preserve_after_resize!(was_at_bottom:)
|
|
640
|
-
if @mode == :paging &&
|
|
712
|
+
if @mode == :paging && lines.any? && was_at_bottom
|
|
641
713
|
page_bottom!
|
|
642
714
|
else
|
|
643
715
|
clamp!
|
|
@@ -646,6 +718,35 @@ module Fatty
|
|
|
646
718
|
|
|
647
719
|
private
|
|
648
720
|
|
|
721
|
+
# simplecov:disable
|
|
722
|
+
|
|
723
|
+
def go_to_line!(number)
|
|
724
|
+
target = [number.to_i, 1].max
|
|
725
|
+
current_lines = lines
|
|
726
|
+
index =
|
|
727
|
+
if current_lines.first.respond_to?(:number)
|
|
728
|
+
current_lines.bsearch_index { |line| line.number >= target }
|
|
729
|
+
else
|
|
730
|
+
target - 1
|
|
731
|
+
end
|
|
732
|
+
index ||= current_lines.length - 1
|
|
733
|
+
@viewport.top = [index, 0].max
|
|
734
|
+
clamp_to_page!
|
|
735
|
+
end
|
|
736
|
+
|
|
737
|
+
def lines
|
|
738
|
+
@lines.call
|
|
739
|
+
end
|
|
740
|
+
|
|
741
|
+
def ensure_search_snapshot!
|
|
742
|
+
return if @search_snapshot
|
|
743
|
+
|
|
744
|
+
@search_snapshot = {
|
|
745
|
+
viewport_top: @viewport.top,
|
|
746
|
+
search: @search.dup,
|
|
747
|
+
}
|
|
748
|
+
end
|
|
749
|
+
|
|
649
750
|
def ensure_isearch_snapshot!
|
|
650
751
|
return if @isearch_snapshot
|
|
651
752
|
|
|
@@ -697,7 +798,7 @@ module Fatty
|
|
|
697
798
|
end
|
|
698
799
|
|
|
699
800
|
def search_start_col_for(line_index)
|
|
700
|
-
line =
|
|
801
|
+
line = lines[line_index]
|
|
701
802
|
# Use end-of-line as the backward scan upper bound so the starting line
|
|
702
803
|
# is included. +1 avoids edge weirdness when match ends exactly at len.
|
|
703
804
|
if line
|
|
@@ -785,17 +886,27 @@ module Fatty
|
|
|
785
886
|
end
|
|
786
887
|
|
|
787
888
|
def apply_search_match(match)
|
|
889
|
+
unless valid_search_match?(match)
|
|
890
|
+
raise ArgumentError, "invalid search match: #{match.inspect}"
|
|
891
|
+
end
|
|
892
|
+
|
|
788
893
|
@search[:last] = match
|
|
789
894
|
line = match[:line]
|
|
790
|
-
|
|
895
|
+
|
|
791
896
|
@mode = :paging
|
|
792
897
|
@paused = true
|
|
793
898
|
@last_nav_dir = :down
|
|
794
899
|
|
|
795
|
-
# Position the match line near the middle when possible.
|
|
796
900
|
half = (@viewport.height / 2)
|
|
797
901
|
@viewport.top = [line - half, 0].max
|
|
798
902
|
@search[:last_view_top] = @viewport.top
|
|
799
903
|
end
|
|
904
|
+
|
|
905
|
+
def valid_search_match?(match)
|
|
906
|
+
match.is_a?(Hash) &&
|
|
907
|
+
match[:line].is_a?(Integer) &&
|
|
908
|
+
match[:from].is_a?(Integer) &&
|
|
909
|
+
match[:to].is_a?(Integer)
|
|
910
|
+
end
|
|
800
911
|
end
|
|
801
912
|
end
|