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.
Files changed (120) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.org +11 -29
  3. data/README.md +2207 -18
  4. data/README.org +2066 -104
  5. data/exe/fatty +236 -93
  6. data/help/help.md +233 -0
  7. data/lib/fatty/action.rb +3 -7
  8. data/lib/fatty/actionable.rb +2 -0
  9. data/lib/fatty/alert.rb +65 -39
  10. data/lib/fatty/ansi/renderer.rb +26 -6
  11. data/lib/fatty/ansi.rb +1 -0
  12. data/lib/fatty/api/alert.rb +15 -0
  13. data/lib/fatty/api/choose.rb +145 -0
  14. data/lib/fatty/api/environment.rb +12 -0
  15. data/lib/fatty/api/keytest.rb +11 -0
  16. data/lib/fatty/api/menu.rb +104 -0
  17. data/lib/fatty/api/output.rb +55 -0
  18. data/lib/fatty/api/progress.rb +24 -0
  19. data/lib/fatty/api/prompt.rb +77 -0
  20. data/lib/fatty/api/status.rb +55 -0
  21. data/lib/fatty/api.rb +38 -0
  22. data/lib/fatty/callback_environment.rb +74 -0
  23. data/lib/fatty/colors/color.rb +366 -232
  24. data/lib/fatty/colors/pairs.rb +2 -0
  25. data/lib/fatty/command.rb +78 -0
  26. data/lib/fatty/config.rb +227 -39
  27. data/lib/fatty/config_files/config.yml +4 -12
  28. data/lib/fatty/config_files/keydefs.yml +13 -23
  29. data/lib/fatty/config_files/themes/capuchin_monk.yml +140 -0
  30. data/lib/fatty/config_files/themes/catppuccin_latte.yml +140 -0
  31. data/lib/fatty/config_files/themes/catppuccin_mocha.yml +140 -0
  32. data/lib/fatty/config_files/themes/cyberpunk.yml +141 -0
  33. data/lib/fatty/config_files/themes/dracula.yml +140 -0
  34. data/lib/fatty/config_files/themes/everforest_dark.yml +140 -0
  35. data/lib/fatty/config_files/themes/gruvbox_dark.yml +140 -0
  36. data/lib/fatty/config_files/themes/gruvbox_light.yml +140 -0
  37. data/lib/fatty/config_files/themes/mono.yml +119 -47
  38. data/lib/fatty/config_files/themes/monokai.yml +140 -0
  39. data/lib/fatty/config_files/themes/nordic.yml +1 -0
  40. data/lib/fatty/config_files/themes/onedark.yml +140 -0
  41. data/lib/fatty/config_files/themes/solarized_dark.yml +1 -0
  42. data/lib/fatty/config_files/themes/solarized_light.yml +140 -0
  43. data/lib/fatty/config_files/themes/terminal.yml +67 -0
  44. data/lib/fatty/config_files/themes/tokyo_night.yml +140 -0
  45. data/lib/fatty/config_files/themes/wordperfect.yml +80 -9
  46. data/lib/fatty/core_ext/hash.rb +19 -0
  47. data/lib/fatty/core_ext/string.rb +19 -12
  48. data/lib/fatty/core_ext.rb +1 -0
  49. data/lib/fatty/curses/context.rb +86 -84
  50. data/lib/fatty/curses/event_source.rb +128 -40
  51. data/lib/fatty/curses/key_decoder.rb +77 -11
  52. data/lib/fatty/env.rb +21 -20
  53. data/lib/fatty/help.rb +1 -29
  54. data/lib/fatty/history/entry.rb +2 -0
  55. data/lib/fatty/history.rb +17 -14
  56. data/lib/fatty/input_buffer.rb +71 -47
  57. data/lib/fatty/input_field.rb +216 -149
  58. data/lib/fatty/key_event.rb +67 -66
  59. data/lib/fatty/key_map.rb +54 -16
  60. data/lib/fatty/keymaps/emacs.rb +40 -6
  61. data/lib/fatty/log_formats/json.rb +2 -0
  62. data/lib/fatty/log_formats/text.rb +2 -0
  63. data/lib/fatty/logger.rb +7 -2
  64. data/lib/fatty/markdown/ansi_renderer.rb +75 -6
  65. data/lib/fatty/markdown/render.rb +2 -3
  66. data/lib/fatty/mouse_event.rb +142 -2
  67. data/lib/fatty/output_buffer.rb +2 -0
  68. data/lib/fatty/pager.rb +158 -47
  69. data/lib/fatty/progress.rb +417 -0
  70. data/lib/fatty/renderer/curses.rb +340 -184
  71. data/lib/fatty/renderer/truecolor.rb +266 -163
  72. data/lib/fatty/renderer.rb +115 -97
  73. data/lib/fatty/screen.rb +2 -0
  74. data/lib/fatty/session/alert_session.rb +39 -21
  75. data/lib/fatty/session/isearch_session.rb +92 -38
  76. data/lib/fatty/session/keytest_session.rb +105 -85
  77. data/lib/fatty/session/modal_session.rb +38 -1
  78. data/lib/fatty/session/output_session.rb +472 -21
  79. data/lib/fatty/session/popup_session.rb +251 -134
  80. data/lib/fatty/session/prompt_session.rb +68 -26
  81. data/lib/fatty/session/search_session.rb +79 -31
  82. data/lib/fatty/session/shell_session.rb +383 -368
  83. data/lib/fatty/session/status_session.rb +167 -0
  84. data/lib/fatty/session.rb +95 -95
  85. data/lib/fatty/terminal/popup_owner.rb +14 -11
  86. data/lib/fatty/terminal.rb +515 -813
  87. data/lib/fatty/themes/loader.rb +4 -2
  88. data/lib/fatty/themes/manager.rb +4 -0
  89. data/lib/fatty/themes/registry.rb +2 -0
  90. data/lib/fatty/themes/resolver.rb +175 -162
  91. data/lib/fatty/version.rb +1 -1
  92. data/lib/fatty/viewport.rb +8 -1
  93. data/lib/fatty.rb +35 -7
  94. metadata +42 -40
  95. data/.envrc +0 -2
  96. data/.simplecov +0 -23
  97. data/.yardopts +0 -4
  98. data/CHANGELOG.md +0 -34
  99. data/Rakefile +0 -15
  100. data/TODO.org +0 -163
  101. data/examples/markdown/native-markdown.md +0 -370
  102. data/examples/markdown/ox-gfm-markdown.md +0 -373
  103. data/examples/markdown/ox-gfm-markdown.org +0 -376
  104. data/fatty.gemspec +0 -42
  105. data/lib/fatty/accept_env.rb +0 -32
  106. data/lib/fatty/config_files/help.md +0 -120
  107. data/lib/fatty/config_files/help.org +0 -124
  108. data/lib/fatty/config_files/themes/wordperfect_light.yml +0 -77
  109. data/lib/fatty/menu_env.rb +0 -22
  110. data/lib/fatty/session/input_session.rb +0 -99
  111. data/lib/fatty/sessions.rb +0 -14
  112. data/lib/fatty/terminal/progress.rb +0 -374
  113. data/lib/fatty/view/alert_view.rb +0 -14
  114. data/lib/fatty/view/cursor_view.rb +0 -18
  115. data/lib/fatty/view/input_view.rb +0 -9
  116. data/lib/fatty/view/output_view.rb +0 -9
  117. data/lib/fatty/view/status_view.rb +0 -14
  118. data/lib/fatty/view.rb +0 -33
  119. data/lib/fatty/views.rb +0 -9
  120. data/sig/fatty.rbs +0 -4
@@ -20,14 +20,14 @@ module Fatty
20
20
  #
21
21
  # Word-motion and word-deletion semantics are delegated to InputBuffer so
22
22
  # the definition of "word" can be configured in one place (via
23
- # =InputBuffer='s word_chars/word_re).
23
+ # =InputBuffer='s word_char_re).
24
24
  class InputField
25
25
  include Actionable
26
26
 
27
27
  attr_reader :buffer, :prompt, :history
28
28
 
29
29
  def initialize(
30
- prompt:,
30
+ prompt: ">",
31
31
  buffer: nil,
32
32
  completion_proc: nil,
33
33
  history: nil,
@@ -39,17 +39,15 @@ module Fatty
39
39
  @history_kind = history_kind
40
40
  @history_ctx = history_ctx
41
41
  @completion_proc = completion_proc
42
- @completion_cycle_base = nil
43
- @completion_cycle_candidates = []
44
- @completion_cycle_index = nil
42
+ @completion_state = nil
45
43
 
46
44
  @buffer =
47
45
  if buffer
48
46
  buffer
49
47
  else
50
48
  cfg = Fatty::Config.config
51
- word_chars = cfg.dig(:input_buffer, :word_chars) || Fatty::InputBuffer::DEFAULT_WORD_CHARS
52
- Fatty::InputBuffer.new(word_chars: word_chars)
49
+ word_char_re = cfg.dig(:word_char_re) || Fatty::InputBuffer::DEFAULT_WORD_CHAR_RE
50
+ Fatty::InputBuffer.new(word_char_re: word_char_re)
53
51
  end
54
52
  end
55
53
 
@@ -66,52 +64,31 @@ module Fatty
66
64
  buffer.text == ""
67
65
  end
68
66
 
69
- # Visual cursor X position in the window
70
- def cursor_x
71
- before_cursor = buffer.text.to_s[0...buffer.cursor].to_s
72
- prompt_width + Fatty::Ansi.visible_length(before_cursor)
73
- end
74
-
75
- def prompt_text
76
- prompt.text
77
- end
78
-
79
- # The prompt might use coloring, so we use the visible length stripped of
80
- # ANSI controls.
81
- def prompt_width
82
- Fatty::Ansi.visible_length(prompt_text.to_s.lines.last.to_s)
83
- end
84
-
85
- def snapshot_input_state
67
+ def state
86
68
  [
87
69
  prompt_text.to_s.dup.freeze,
88
70
  buffer.text.to_s.dup.freeze,
71
+ buffer.cursor,
89
72
  buffer.virtual_suffix.to_s.dup.freeze,
90
- cursor_x,
91
- (r = buffer.region_range) ? [r.begin, r.end] : nil,
73
+ buffer.region_active?,
74
+ buffer.region_range,
92
75
  ]
93
76
  end
94
77
 
95
- # :category: Setters
96
-
97
- def prompt=(prompt)
98
- @prompt = Prompt.ensure(prompt)
99
- end
100
-
101
78
  # :category: Actions
102
79
 
103
80
  desc "Accept the current line, add to history, and clear the buffer"
104
- action :accept_line do
81
+ action :accept_line do |save_history: true|
105
82
  line = buffer.text.dup
106
- if history
83
+ if save_history && history && !line.empty?
107
84
  history.add(
108
85
  line,
109
86
  kind: resolve_history_kind,
110
87
  ctx: resolve_history_ctx,
111
88
  )
112
- buffer.clear
113
- line
114
89
  end
90
+ buffer.clear
91
+ line
115
92
  end
116
93
 
117
94
  desc "Replace buffer with the previous history entry"
@@ -136,6 +113,101 @@ module Fatty
136
113
  buffer.insert(s)
137
114
  end
138
115
 
116
+ def autosuggestion
117
+ active = active_completion_autosuggestion
118
+ return active if active
119
+
120
+ text = buffer.text.to_s
121
+ return if text.empty?
122
+
123
+ autosuggestion_candidates.first
124
+ end
125
+
126
+ def complete!(direction: 1)
127
+ candidates = tab_completion_candidates
128
+ common_prefix = common_completion_prefix(candidates)
129
+
130
+ if candidates.length == 1
131
+ accept_completion_line(candidates.first)
132
+ elsif direction.positive? &&
133
+ common_prefix &&
134
+ common_prefix.length > buffer.text.length
135
+ accept_completion_line(common_prefix)
136
+ else
137
+ cycle_completion!(direction: direction)
138
+ end
139
+ end
140
+
141
+ def cycle_completion!(direction: 1)
142
+ text = buffer.text.to_s
143
+ candidates = tab_completion_candidates
144
+ result = nil
145
+
146
+ if candidates.empty?
147
+ reset_completion_state!
148
+ elsif same_completion_state?(base: text, candidates: candidates)
149
+ @completion_state[:index] =
150
+ (@completion_state[:index] + direction) % @completion_state[:candidates].length
151
+ result = @completion_state[:candidates][@completion_state[:index]]
152
+ else
153
+ @completion_state = {
154
+ base: text,
155
+ candidates: candidates,
156
+ index: 0,
157
+ }
158
+ result = @completion_state[:candidates].first
159
+ end
160
+
161
+ sync_virtual_suffix!
162
+ result
163
+ end
164
+
165
+ def popup_completion_candidates
166
+ path_prefix = popup_path_completion_prefix
167
+ if path_prefix
168
+ path = rendered_path_candidates(path_prefix)
169
+ return path if path.any?
170
+ end
171
+ autosuggestion_candidates(base: buffer.text.to_s[0...buffer.cursor])
172
+ end
173
+
174
+ def path_completion_candidates
175
+ prefix = path_completion_prefix
176
+ return [] if prefix.nil? || prefix.empty?
177
+
178
+ rendered_path_candidates(prefix)
179
+ end
180
+
181
+ def path_completion_candidates_for(prefix)
182
+ return [] if prefix.nil? || prefix.empty?
183
+
184
+ rendered_path_candidates(prefix)
185
+ end
186
+
187
+ def popup_completion_range
188
+ if popup_path_completion_prefix
189
+ path_completion_range
190
+ else
191
+ 0...buffer.text.length
192
+ end
193
+ end
194
+
195
+ def popup_completion_query
196
+ path_completion_prefix || buffer.completion_prefix
197
+ end
198
+
199
+ def popup_completion_path?
200
+ !!popup_path_completion_prefix
201
+ end
202
+
203
+ def reset_completion_state!
204
+ @completion_state = nil
205
+ end
206
+
207
+ def sync_virtual_suffix!
208
+ buffer.virtual_suffix = autosuggestion_suffix
209
+ end
210
+
139
211
  def act_on(action, *args, env: nil, **kwargs)
140
212
  return unless action
141
213
 
@@ -148,130 +220,147 @@ module Fatty
148
220
  defn = Fatty::Actions.lookup(action)
149
221
  target =
150
222
  case defn[:on]
151
- when :field then self
152
223
  when :buffer then buffer
153
224
  else
154
225
  raise Fatty::ActionError, "Cannot dispatch #{action} without env for target #{defn[:on].inspect}"
155
226
  end
156
227
  target.public_send(defn[:method], *args, **kwargs)
157
228
  end
158
- elsif buffer.respond_to?(action)
159
- buffer.public_send(action, *args, **kwargs)
160
- elsif respond_to?(action)
161
- public_send(action, *args, **kwargs)
162
229
  else
163
230
  raise Fatty::ActionError, "Unknown action: #{action}"
164
231
  end
165
232
  end
166
233
 
167
- # :category: Completion
234
+ def prompt_text
235
+ prompt.text
236
+ end
168
237
 
169
- def autosuggestion
170
- return if buffer.text.empty?
238
+ # Visual cursor X position in the window
239
+ def cursor_x
240
+ before_cursor = buffer.text.to_s[0...buffer.cursor].to_s
241
+ prompt_width + Fatty::Ansi.visible_length(before_cursor)
242
+ end
243
+
244
+ def prompt=(prompt)
245
+ @prompt = Prompt.ensure(prompt)
246
+ end
247
+
248
+ private
249
+
250
+ # simplecov:disable
251
+
252
+ def accept_completion_line(line)
253
+ return unless line
254
+
255
+ buffer.replace(line)
256
+ reset_completion_state!
257
+ buffer.virtual_suffix = ""
258
+ line
259
+ end
171
260
 
172
- active_completion_autosuggestion || default_completion_autosuggestion || history_autosuggestion
261
+ # The prompt might use coloring, so we use the visible length stripped of
262
+ # ANSI controls.
263
+ def prompt_width
264
+ Fatty::Ansi.visible_length(prompt_text.to_s.lines.last.to_s)
173
265
  end
174
266
 
267
+ # :category: Completion
268
+
175
269
  def completion_candidates
176
270
  return [] unless @completion_proc
177
271
 
178
- prefix = buffer.completion_prefix.to_s
179
- return [] if prefix.empty?
180
-
181
272
  Array(@completion_proc.call(buffer))
182
273
  .compact
183
274
  .map(&:to_s)
184
275
  .reject(&:empty?)
185
- .select { |s| s.start_with?(prefix) }
186
- .reject { |s| s == prefix }
187
276
  .uniq
188
277
  end
189
278
 
279
+ def common_completion_prefix(candidates)
280
+ return if candidates.empty?
281
+
282
+ first, last = candidates.minmax
283
+ length = 0
284
+ limit = [first.length, last.length].min
285
+
286
+ length += 1 while length < limit && first[length] == last[length]
287
+ first[0...length]
288
+ end
289
+
190
290
  def completion_suggestions
191
- raw =
192
- if path_completion_candidates.any?
193
- path_completion_candidates
194
- else
195
- completion_candidates
196
- end
291
+ if path_completion_candidates.any?
292
+ path_completion_candidates
293
+ .map { |candidate| build_line_with_completion(candidate, range: path_completion_range) }
294
+ .reject { |line| line == buffer.text.to_s }
295
+ .uniq
296
+ else
297
+ completion_candidates
298
+ .map { |candidate| build_line_with_completion(candidate, range: completion_replace_range) }
299
+ .reject { |line| line == buffer.text.to_s }
300
+ .uniq
301
+ end
302
+ end
197
303
 
198
- raw
199
- .map { |candidate| build_line_with_completion(candidate) }
200
- .reject { |line| line == buffer.text.to_s }
304
+ def autosuggestion_candidates(base: buffer.text.to_s)
305
+ (history_autosuggestions + completion_suggestions)
306
+ .compact
307
+ .map(&:to_s)
308
+ .select { |candidate| candidate.start_with?(base) }
309
+ .reject { |candidate| candidate == buffer.text.to_s }
201
310
  .uniq
202
311
  end
203
312
 
313
+ def tab_completion_candidates
314
+ path = path_completion_candidates
315
+ if path.any?
316
+ path.map { |candidate| build_line_with_completion(candidate, range: path_completion_range) }
317
+ .reject { |line| line == buffer.text.to_s }
318
+ .uniq
319
+ else
320
+ autosuggestion_candidates
321
+ end
322
+ end
323
+
204
324
  def default_completion_autosuggestion
205
- suggestions = completion_suggestions
206
- result = suggestions.first
207
- result
325
+ completion_suggestions.first
208
326
  end
209
327
 
210
328
  def active_completion_autosuggestion
211
- text = buffer.text.to_s
212
- result = nil
329
+ return unless @completion_state
213
330
 
214
- if @completion_cycle_base == text &&
215
- @completion_cycle_index &&
216
- !@completion_cycle_candidates.empty?
217
- result = @completion_cycle_candidates[@completion_cycle_index]
331
+ text = buffer.text.to_s
332
+ if @completion_state[:base] == text &&
333
+ @completion_state[:index] &&
334
+ !@completion_state[:candidates].empty?
335
+ @completion_state[:candidates][@completion_state[:index]]
218
336
  end
219
-
220
- result
221
337
  end
222
338
 
223
- def cycle_completion!
339
+ def completion_replace_range
224
340
  text = buffer.text.to_s
225
- suggestions = completion_suggestions
226
- result = nil
341
+ cur = buffer.cursor.to_i
342
+ before = text[0...cur].to_s
227
343
 
228
- if suggestions.empty?
229
- reset_completion_cycle!
230
- elsif @completion_cycle_base == text &&
231
- @completion_cycle_candidates == suggestions &&
232
- @completion_cycle_index
233
- @completion_cycle_index = (@completion_cycle_index + 1) % @completion_cycle_candidates.length
234
- result = @completion_cycle_candidates[@completion_cycle_index]
235
- else
236
- @completion_cycle_base = text
237
- @completion_cycle_candidates = suggestions
238
- @completion_cycle_index =
239
- if suggestions.length > 1
240
- 1
241
- else
242
- 0
243
- end
244
- result = @completion_cycle_candidates[@completion_cycle_index]
245
- end
344
+ token = before[/\S+\z/].to_s
345
+ start = cur - token.length
246
346
 
247
- sync_virtual_suffix!
248
- result
347
+ start...cur
249
348
  end
250
349
 
251
- def reset_completion_cycle!
252
- @completion_cycle_base = nil
253
- @completion_cycle_candidates = []
254
- @completion_cycle_index = nil
255
- nil
350
+ def completion_prefix
351
+ text[0...cursor].to_s[/\S+\z/].to_s
256
352
  end
257
353
 
258
- def history_autosuggestion
259
- return if history.nil?
354
+ def history_autosuggestions
355
+ return [] if history.nil?
260
356
 
261
- history.suggest_for(
357
+ history.suggestions_for(
262
358
  resolve_history_kind,
263
359
  prefix: buffer.text,
264
360
  ctx: resolve_history_ctx,
265
361
  )
266
362
  end
267
363
 
268
- def path_completion_candidates
269
- prefix = path_completion_prefix
270
- return [] if prefix.nil? || prefix.empty?
271
-
272
- rendered_path_candidates(prefix)
273
- end
274
-
275
364
  def path_like_prefix?(prefix)
276
365
  s = prefix.to_s
277
366
  return false if s.empty?
@@ -403,16 +492,21 @@ module Fatty
403
492
  end
404
493
  end
405
494
 
406
- def build_line_with_completion(completion)
407
- current = buffer.text.to_s
408
- target = path_completion_range || buffer.completion_replace_range
409
- start_i = target.begin
410
- end_i = target.end
411
-
412
- before = current[0...start_i].to_s
413
- after = current[end_i..].to_s
495
+ def build_line_with_completion(candidate, range:)
496
+ text = buffer.text.to_s
497
+ before = text[0...range.begin].to_s
498
+ current = text[range].to_s
499
+ after = text[range.end..].to_s
500
+ candidate = candidate.to_s
501
+
502
+ replacement =
503
+ if !current.empty? && candidate.downcase.start_with?(current.downcase)
504
+ "#{current}#{candidate[current.length..]}"
505
+ else
506
+ candidate
507
+ end
414
508
 
415
- "#{before}#{completion}#{after}"
509
+ "#{before}#{replacement}#{after}"
416
510
  end
417
511
 
418
512
  def autosuggestion_visible?
@@ -437,22 +531,6 @@ module Fatty
437
531
  buffer.accept_virtual_suffix!
438
532
  end
439
533
 
440
- def popup_completion_candidates
441
- path_prefix = popup_path_completion_prefix
442
- if path_prefix
443
- path = rendered_path_candidates(path_prefix)
444
- return path if path.any?
445
- end
446
-
447
- return [] unless @completion_proc
448
-
449
- Array(@completion_proc.call(buffer))
450
- .compact
451
- .map(&:to_s)
452
- .reject(&:empty?)
453
- .uniq
454
- end
455
-
456
534
  def popup_path_completion_prefix
457
535
  prefix = path_completion_prefix
458
536
  return if prefix.nil? || prefix.empty?
@@ -468,24 +546,13 @@ module Fatty
468
546
  end
469
547
  end
470
548
 
471
- def popup_completion_query
472
- popup_path_completion_prefix || path_completion_prefix || buffer.completion_prefix
473
- end
474
-
475
- def popup_completion_range
476
- path_completion_range || buffer.completion_replace_range
549
+ def same_completion_state?(base:, candidates:)
550
+ @completion_state &&
551
+ @completion_state[:base] == base &&
552
+ @completion_state[:candidates] == candidates &&
553
+ @completion_state[:index]
477
554
  end
478
555
 
479
- def popup_completion_query
480
- path_completion_prefix || buffer.completion_prefix
481
- end
482
-
483
- def sync_virtual_suffix!
484
- buffer.virtual_suffix = autosuggestion_suffix
485
- end
486
-
487
- private
488
-
489
556
  def reset_history_cursor_for(action)
490
557
  return if action.to_s.start_with?("history_")
491
558
 
@@ -84,18 +84,10 @@ module Fatty
84
84
  !key.is_a?(Symbol)
85
85
  end
86
86
 
87
- def bindings
88
- Fatty::KeyMap.active.bindings_for(self) || {}
89
- end
90
-
91
87
  def unbound?
92
88
  coded? && bindings.empty?
93
89
  end
94
90
 
95
- def key_name
96
- coded? ? to_s : "(none)"
97
- end
98
-
99
91
  def code
100
92
  case raw
101
93
  when Integer
@@ -109,6 +101,68 @@ module Fatty
109
101
  bytes_from_raw(raw)
110
102
  end
111
103
 
104
+ def color
105
+ if uncoded?
106
+ :error
107
+ elsif unbound?
108
+ :warn
109
+ else
110
+ :good
111
+ end
112
+ end
113
+
114
+ def status_string
115
+ if uncoded?
116
+ "(UNCODED)"
117
+ elsif unbound?
118
+ "(UNBOUND)"
119
+ else
120
+ "(BOUND)"
121
+ end
122
+ end
123
+
124
+ def report
125
+ if uncoded?
126
+ report_for_uncoded
127
+ elsif unbound?
128
+ report_for_unbound
129
+ else
130
+ report_for_bound
131
+ end
132
+ end
133
+
134
+ def suggested_snippet(terminal_name)
135
+ if uncoded?
136
+ suggested_keydef(terminal_name)
137
+ elsif unbound?
138
+ suggested_keybinding
139
+ else
140
+ ''
141
+ end
142
+ end
143
+
144
+ def key_name
145
+ coded? ? to_s : "(none)"
146
+ end
147
+
148
+ def bindings
149
+ Fatty::KeyMap.active.bindings_for(self) || {}
150
+ end
151
+
152
+ def ctrl?
153
+ @ctrl
154
+ end
155
+
156
+ def meta?
157
+ @meta
158
+ end
159
+
160
+ def shift?
161
+ @shift
162
+ end
163
+
164
+ private
165
+
112
166
  def bytes_from_raw(value)
113
167
  case value
114
168
  when Array
@@ -181,48 +235,6 @@ module Fatty
181
235
  name.split("::").last
182
236
  end
183
237
 
184
- def color
185
- if uncoded?
186
- :oops
187
- elsif unbound?
188
- :warn
189
- else
190
- :good
191
- end
192
- end
193
-
194
- def status_string
195
- if uncoded?
196
- "(UNCODED)"
197
- elsif unbound?
198
- "(UNBOUND)"
199
- else
200
- "(BOUND)"
201
- end
202
- end
203
-
204
- def ctrl?
205
- @ctrl
206
- end
207
-
208
- def meta?
209
- @meta
210
- end
211
-
212
- def shift?
213
- @shift
214
- end
215
-
216
- def report
217
- if uncoded?
218
- report_for_uncoded
219
- elsif unbound?
220
- report_for_unbound
221
- else
222
- report_for_bound
223
- end
224
- end
225
-
226
238
  def report_for_uncoded
227
239
  rule = colorize("=" * 55) + "\n"
228
240
  out = +""
@@ -280,16 +292,6 @@ module Fatty
280
292
  end
281
293
  end
282
294
 
283
- def suggested_snippet(terminal_name)
284
- if uncoded?
285
- suggested_keydef(terminal_name)
286
- elsif unbound?
287
- suggested_keybinding
288
- else
289
- ''
290
- end
291
- end
292
-
293
295
  def suggested_keydef(terminal_name)
294
296
  return "" unless code
295
297
 
@@ -301,12 +303,11 @@ module Fatty
301
303
 
302
304
  ............>8 snip here 8<....................
303
305
  #{terminal_name}:
304
- map:
305
- #{code}:
306
- key: key_name
307
- shift: <true/false>
308
- ctrl: <true/false>
309
- meta: <true/false>
306
+ #{code}:
307
+ key: key_name
308
+ shift: <true/false>
309
+ ctrl: <true/false>
310
+ meta: <true/false>
310
311
  ............>8 snip here 8<....................
311
312
  TEXT
312
313
  end