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/input_field.rb
CHANGED
|
@@ -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
|
|
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
|
-
@
|
|
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
|
-
|
|
52
|
-
Fatty::InputBuffer.new(
|
|
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
|
-
|
|
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
|
-
|
|
91
|
-
|
|
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
|
-
|
|
234
|
+
def prompt_text
|
|
235
|
+
prompt.text
|
|
236
|
+
end
|
|
168
237
|
|
|
169
|
-
|
|
170
|
-
|
|
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
|
-
|
|
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
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
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
|
-
|
|
199
|
-
|
|
200
|
-
.
|
|
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
|
-
|
|
206
|
-
result = suggestions.first
|
|
207
|
-
result
|
|
325
|
+
completion_suggestions.first
|
|
208
326
|
end
|
|
209
327
|
|
|
210
328
|
def active_completion_autosuggestion
|
|
211
|
-
|
|
212
|
-
result = nil
|
|
329
|
+
return unless @completion_state
|
|
213
330
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
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
|
|
339
|
+
def completion_replace_range
|
|
224
340
|
text = buffer.text.to_s
|
|
225
|
-
|
|
226
|
-
|
|
341
|
+
cur = buffer.cursor.to_i
|
|
342
|
+
before = text[0...cur].to_s
|
|
227
343
|
|
|
228
|
-
|
|
229
|
-
|
|
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
|
-
|
|
248
|
-
result
|
|
347
|
+
start...cur
|
|
249
348
|
end
|
|
250
349
|
|
|
251
|
-
def
|
|
252
|
-
|
|
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
|
|
259
|
-
return if history.nil?
|
|
354
|
+
def history_autosuggestions
|
|
355
|
+
return [] if history.nil?
|
|
260
356
|
|
|
261
|
-
history.
|
|
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(
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
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}#{
|
|
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
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
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
|
|
data/lib/fatty/key_event.rb
CHANGED
|
@@ -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
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
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
|