command-t 1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,29 @@
1
+ // Copyright 2010 Wincent Colaiuta. All rights reserved.
2
+ //
3
+ // Redistribution and use in source and binary forms, with or without
4
+ // modification, are permitted provided that the following conditions are met:
5
+ //
6
+ // 1. Redistributions of source code must retain the above copyright notice,
7
+ // this list of conditions and the following disclaimer.
8
+ // 2. Redistributions in binary form must reproduce the above copyright notice,
9
+ // this list of conditions and the following disclaimer in the documentation
10
+ // and/or other materials provided with the distribution.
11
+ //
12
+ // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
13
+ // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14
+ // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15
+ // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
16
+ // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
17
+ // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
18
+ // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
19
+ // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
20
+ // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
21
+ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
22
+ // POSSIBILITY OF SUCH DAMAGE.
23
+
24
+ #include <ruby.h>
25
+
26
+ extern VALUE CommandTMatch_initialize(int argc, VALUE *argv, VALUE self);
27
+ extern VALUE CommandTMatch_matches(VALUE self);
28
+ extern VALUE CommandTMatch_score(VALUE self);
29
+ extern VALUE CommandTMatch_to_s(VALUE self);
@@ -0,0 +1,377 @@
1
+ # Copyright 2010-2011 Wincent Colaiuta. All rights reserved.
2
+ #
3
+ # Redistribution and use in source and binary forms, with or without
4
+ # modification, are permitted provided that the following conditions are met:
5
+ #
6
+ # 1. Redistributions of source code must retain the above copyright notice,
7
+ # this list of conditions and the following disclaimer.
8
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
9
+ # this list of conditions and the following disclaimer in the documentation
10
+ # and/or other materials provided with the distribution.
11
+ #
12
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
13
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
16
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
17
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
18
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
19
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
20
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
21
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
22
+ # POSSIBILITY OF SUCH DAMAGE.
23
+
24
+ require 'ostruct'
25
+ require 'command-t/settings'
26
+
27
+ module CommandT
28
+ class MatchWindow
29
+ @@selection_marker = '> '
30
+ @@marker_length = @@selection_marker.length
31
+ @@unselected_marker = ' ' * @@marker_length
32
+ @@buffer = nil
33
+
34
+ def initialize options = {}
35
+ @prompt = options[:prompt]
36
+ @reverse_list = options[:match_window_reverse]
37
+
38
+ # save existing window dimensions so we can restore them later
39
+ @windows = []
40
+ (0..(::VIM::Window.count - 1)).each do |i|
41
+ window = OpenStruct.new :index => i, :height => ::VIM::Window[i].height
42
+ @windows << window
43
+ end
44
+
45
+ # global settings (must manually save and restore)
46
+ @settings = Settings.new
47
+ ::VIM::set_option 'timeout' # ensure mappings timeout
48
+ ::VIM::set_option 'timeoutlen=0' # respond immediately to mappings
49
+ ::VIM::set_option 'nohlsearch' # don't highlight search strings
50
+ ::VIM::set_option 'noinsertmode' # don't make Insert mode the default
51
+ ::VIM::set_option 'noshowcmd' # don't show command info on last line
52
+ ::VIM::set_option 'report=9999' # don't show "X lines changed" reports
53
+ ::VIM::set_option 'sidescroll=0' # don't sidescroll in jumps
54
+ ::VIM::set_option 'sidescrolloff=0' # don't sidescroll automatically
55
+ ::VIM::set_option 'noequalalways' # don't auto-balance window sizes
56
+
57
+ # show match window
58
+ split_location = options[:match_window_at_top] ? 'topleft' : 'botright'
59
+ if @@buffer # still have buffer from last time
60
+ ::VIM::command "silent! #{split_location} #{@@buffer.number}sbuffer"
61
+ raise "Can't re-open GoToFile buffer" unless $curbuf.number == @@buffer.number
62
+ $curwin.height = 1
63
+ else # creating match window for first time and set it up
64
+ split_command = "silent! #{split_location} 1split GoToFile"
65
+ [
66
+ split_command,
67
+ 'setlocal bufhidden=unload', # unload buf when no longer displayed
68
+ 'setlocal buftype=nofile', # buffer is not related to any file
69
+ 'setlocal nomodifiable', # prevent manual edits
70
+ 'setlocal noswapfile', # don't create a swapfile
71
+ 'setlocal nowrap', # don't soft-wrap
72
+ 'setlocal nonumber', # don't show line numbers
73
+ 'setlocal nolist', # don't use List mode (visible tabs etc)
74
+ 'setlocal foldcolumn=0', # don't show a fold column at side
75
+ 'setlocal foldlevel=99', # don't fold anything
76
+ 'setlocal nocursorline', # don't highlight line cursor is on
77
+ 'setlocal nospell', # spell-checking off
78
+ 'setlocal nobuflisted', # don't show up in the buffer list
79
+ 'setlocal textwidth=0' # don't hard-wrap (break long lines)
80
+ ].each { |command| ::VIM::command command }
81
+
82
+ # sanity check: make sure the buffer really was created
83
+ raise "Can't find GoToFile buffer" unless $curbuf.name.match /GoToFile\z/
84
+ @@buffer = $curbuf
85
+ end
86
+
87
+ # syntax coloring
88
+ if VIM::has_syntax?
89
+ ::VIM::command "syntax match CommandTSelection \"^#{@@selection_marker}.\\+$\""
90
+ ::VIM::command 'syntax match CommandTNoEntries "^-- NO MATCHES --$"'
91
+ ::VIM::command 'syntax match CommandTNoEntries "^-- NO SUCH FILE OR DIRECTORY --$"'
92
+ ::VIM::command 'highlight link CommandTSelection Visual'
93
+ ::VIM::command 'highlight link CommandTNoEntries Error'
94
+ ::VIM::evaluate 'clearmatches()'
95
+
96
+ # hide cursor
97
+ @cursor_highlight = get_cursor_highlight
98
+ hide_cursor
99
+ end
100
+
101
+ # perform cleanup using an autocmd to ensure we don't get caught out
102
+ # by some unexpected means of dismissing or leaving the Command-T window
103
+ # (eg. <C-W q>, <C-W k> etc)
104
+ ::VIM::command 'autocmd! * <buffer>'
105
+ ::VIM::command 'autocmd BufLeave <buffer> ruby $command_t.leave'
106
+ ::VIM::command 'autocmd BufUnload <buffer> ruby $command_t.unload'
107
+
108
+ @has_focus = false
109
+ @selection = nil
110
+ @abbrev = ''
111
+ @window = $curwin
112
+ end
113
+
114
+ def close
115
+ # Workaround for upstream bug in Vim 7.3 on some platforms
116
+ #
117
+ # On some platforms, $curbuf.number always returns 0. One workaround is
118
+ # to build Vim with --disable-largefile, but as this is producing lots of
119
+ # support requests, implement the following fallback to the buffer name
120
+ # instead, at least until upstream gets fixed.
121
+ #
122
+ # For more details, see: https://wincent.com/issues/1617
123
+ if $curbuf.number == 0
124
+ # use bwipeout as bunload fails if passed the name of a hidden buffer
125
+ ::VIM::command 'bwipeout! GoToFile'
126
+ @@buffer = nil
127
+ else
128
+ ::VIM::command "bunload! #{@@buffer.number}"
129
+ end
130
+ end
131
+
132
+ def leave
133
+ close
134
+ unload
135
+ end
136
+
137
+ def unload
138
+ restore_window_dimensions
139
+ @settings.restore
140
+ @prompt.dispose
141
+ show_cursor
142
+ end
143
+
144
+ def add! char
145
+ @abbrev += char
146
+ end
147
+
148
+ def backspace!
149
+ @abbrev.chop!
150
+ end
151
+
152
+ def select_next
153
+ if @selection < @matches.length - 1
154
+ @selection += 1
155
+ print_match(@selection - 1) # redraw old selection (removes marker)
156
+ print_match(@selection) # redraw new selection (adds marker)
157
+ else
158
+ # (possibly) loop or scroll
159
+ end
160
+ end
161
+
162
+ def select_prev
163
+ if @selection > 0
164
+ @selection -= 1
165
+ print_match(@selection + 1) # redraw old selection (removes marker)
166
+ print_match(@selection) # redraw new selection (adds marker)
167
+ else
168
+ # (possibly) loop or scroll
169
+ end
170
+ end
171
+
172
+ def matches= matches
173
+ matches = matches.reverse if @reverse_list
174
+ if matches != @matches
175
+ @matches = matches
176
+ @selection = @reverse_list ? @matches.length - 1 : 0
177
+ print_matches
178
+ end
179
+ end
180
+
181
+ def focus
182
+ unless @has_focus
183
+ @has_focus = true
184
+ if VIM::has_syntax?
185
+ ::VIM::command 'highlight link CommandTSelection Search'
186
+ end
187
+ end
188
+ end
189
+
190
+ def unfocus
191
+ if @has_focus
192
+ @has_focus = false
193
+ if VIM::has_syntax?
194
+ ::VIM::command 'highlight link CommandTSelection Visual'
195
+ end
196
+ end
197
+ end
198
+
199
+ def find char
200
+ # is this a new search or the continuation of a previous one?
201
+ now = Time.now
202
+ if @last_key_time.nil? or @last_key_time < (now - 0.5)
203
+ @find_string = char
204
+ else
205
+ @find_string += char
206
+ end
207
+ @last_key_time = now
208
+
209
+ # see if there's anything up ahead that matches
210
+ @matches.each_with_index do |match, idx|
211
+ if match[0, @find_string.length].casecmp(@find_string) == 0
212
+ old_selection = @selection
213
+ @selection = idx
214
+ print_match(old_selection) # redraw old selection (removes marker)
215
+ print_match(@selection) # redraw new selection (adds marker)
216
+ break
217
+ end
218
+ end
219
+ end
220
+
221
+ # Returns the currently selected item as a String.
222
+ def selection
223
+ @matches[@selection]
224
+ end
225
+
226
+ def print_no_such_file_or_directory
227
+ print_error 'NO SUCH FILE OR DIRECTORY'
228
+ end
229
+
230
+ private
231
+
232
+ def print_error msg
233
+ return unless VIM::Window.select(@window)
234
+ unlock
235
+ clear
236
+ @window.height = 1
237
+ @@buffer[1] = "-- #{msg} --"
238
+ lock
239
+ end
240
+
241
+ def restore_window_dimensions
242
+ # sort from tallest to shortest
243
+ @windows.sort! { |a, b| b.height <=> a.height }
244
+
245
+ # starting with the tallest ensures that there are no constraints
246
+ # preventing windows on the side of vertical splits from regaining
247
+ # their original full size
248
+ @windows.each do |w|
249
+ # beware: window may be nil
250
+ window = ::VIM::Window[w.index]
251
+ window.height = w.height if window
252
+ end
253
+ end
254
+
255
+ def match_text_for_idx idx
256
+ match = truncated_match @matches[idx]
257
+ if idx == @selection
258
+ prefix = @@selection_marker
259
+ suffix = padding_for_selected_match match
260
+ else
261
+ prefix = @@unselected_marker
262
+ suffix = ''
263
+ end
264
+ prefix + match + suffix
265
+ end
266
+
267
+ # Print just the specified match.
268
+ def print_match idx
269
+ return unless VIM::Window.select(@window)
270
+ unlock
271
+ @@buffer[idx + 1] = match_text_for_idx idx
272
+ lock
273
+ end
274
+
275
+ # Print all matches.
276
+ def print_matches
277
+ match_count = @matches.length
278
+ if match_count == 0
279
+ print_error 'NO MATCHES'
280
+ else
281
+ return unless VIM::Window.select(@window)
282
+ unlock
283
+ clear
284
+ actual_lines = 1
285
+ @window_width = @window.width # update cached value
286
+ max_lines = VIM::Screen.lines - 5
287
+ max_lines = 1 if max_lines < 0
288
+ actual_lines = match_count > max_lines ? max_lines : match_count
289
+ @window.height = actual_lines
290
+ (1..actual_lines).each do |line|
291
+ idx = line - 1
292
+ if @@buffer.count >= line
293
+ @@buffer[line] = match_text_for_idx idx
294
+ else
295
+ @@buffer.append line - 1, match_text_for_idx(idx)
296
+ end
297
+ end
298
+ lock
299
+ end
300
+ end
301
+
302
+ # Prepare padding for match text (trailing spaces) so that selection
303
+ # highlighting extends all the way to the right edge of the window.
304
+ def padding_for_selected_match str
305
+ len = str.length
306
+ if len >= @window_width - @@marker_length
307
+ ''
308
+ else
309
+ ' ' * (@window_width - @@marker_length - len)
310
+ end
311
+ end
312
+
313
+ # Convert "really/long/path" into "really...path" based on available
314
+ # window width.
315
+ def truncated_match str
316
+ len = str.length
317
+ available_width = @window_width - @@marker_length
318
+ return str if len <= available_width
319
+ left = (available_width / 2) - 1
320
+ right = (available_width / 2) - 2 + (available_width % 2)
321
+ str[0, left] + '...' + str[-right, right]
322
+ end
323
+
324
+ def clear
325
+ # range = % (whole buffer)
326
+ # action = d (delete)
327
+ # register = _ (black hole register, don't record deleted text)
328
+ ::VIM::command 'silent %d _'
329
+ end
330
+
331
+ def get_cursor_highlight
332
+ # as :highlight returns nothing and only prints,
333
+ # must redirect its output to a variable
334
+ ::VIM::command 'silent redir => g:command_t_cursor_highlight'
335
+
336
+ # force 0 verbosity to ensure origin information isn't printed as well
337
+ ::VIM::command 'silent! 0verbose highlight Cursor'
338
+ ::VIM::command 'silent redir END'
339
+
340
+ # there are 3 possible formats to check for, each needing to be
341
+ # transformed in a certain way in order to reapply the highlight:
342
+ # Cursor xxx guifg=bg guibg=fg -> :hi! Cursor guifg=bg guibg=fg
343
+ # Cursor xxx links to SomethingElse -> :hi! link Cursor SomethingElse
344
+ # Cursor xxx cleared -> :hi! clear Cursor
345
+ highlight = ::VIM::evaluate 'g:command_t_cursor_highlight'
346
+ if highlight =~ /^Cursor\s+xxx\s+links to (\w+)/
347
+ "link Cursor #{$~[1]}"
348
+ elsif highlight =~ /^Cursor\s+xxx\s+cleared/
349
+ 'clear Cursor'
350
+ elsif highlight =~ /Cursor\s+xxx\s+(.+)/
351
+ "Cursor #{$~[1]}"
352
+ else # likely cause E411 Cursor highlight group not found
353
+ nil
354
+ end
355
+ end
356
+
357
+ def hide_cursor
358
+ if @cursor_highlight
359
+ ::VIM::command 'highlight Cursor NONE'
360
+ end
361
+ end
362
+
363
+ def show_cursor
364
+ if @cursor_highlight
365
+ ::VIM::command "highlight #{@cursor_highlight}"
366
+ end
367
+ end
368
+
369
+ def lock
370
+ ::VIM::command 'setlocal nomodifiable'
371
+ end
372
+
373
+ def unlock
374
+ ::VIM::command 'setlocal modifiable'
375
+ end
376
+ end
377
+ end
@@ -0,0 +1,164 @@
1
+ // Copyright 2010 Wincent Colaiuta. All rights reserved.
2
+ //
3
+ // Redistribution and use in source and binary forms, with or without
4
+ // modification, are permitted provided that the following conditions are met:
5
+ //
6
+ // 1. Redistributions of source code must retain the above copyright notice,
7
+ // this list of conditions and the following disclaimer.
8
+ // 2. Redistributions in binary form must reproduce the above copyright notice,
9
+ // this list of conditions and the following disclaimer in the documentation
10
+ // and/or other materials provided with the distribution.
11
+ //
12
+ // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
13
+ // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14
+ // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15
+ // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
16
+ // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
17
+ // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
18
+ // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
19
+ // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
20
+ // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
21
+ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
22
+ // POSSIBILITY OF SUCH DAMAGE.
23
+
24
+ #include <stdlib.h> /* for qsort() */
25
+ #include <string.h> /* for strcmp() */
26
+ #include "matcher.h"
27
+ #include "ext.h"
28
+ #include "ruby_compat.h"
29
+
30
+ // comparison function for use with qsort
31
+ int comp_alpha(const void *a, const void *b)
32
+ {
33
+ VALUE a_val = *(VALUE *)a;
34
+ VALUE b_val = *(VALUE *)b;
35
+ ID to_s = rb_intern("to_s");
36
+
37
+ VALUE a_str = rb_funcall(a_val, to_s, 0);
38
+ VALUE b_str = rb_funcall(b_val, to_s, 0);
39
+ char *a_p = RSTRING_PTR(a_str);
40
+ long a_len = RSTRING_LEN(a_str);
41
+ char *b_p = RSTRING_PTR(b_str);
42
+ long b_len = RSTRING_LEN(b_str);
43
+ int order = 0;
44
+ if (a_len > b_len)
45
+ {
46
+ order = strncmp(a_p, b_p, b_len);
47
+ if (order == 0)
48
+ order = 1; // shorter string (b) wins
49
+ }
50
+ else if (a_len < b_len)
51
+ {
52
+ order = strncmp(a_p, b_p, a_len);
53
+ if (order == 0)
54
+ order = -1; // shorter string (a) wins
55
+ }
56
+ else
57
+ order = strncmp(a_p, b_p, a_len);
58
+ return order;
59
+ }
60
+
61
+ // comparison function for use with qsort
62
+ int comp_score(const void *a, const void *b)
63
+ {
64
+ VALUE a_val = *(VALUE *)a;
65
+ VALUE b_val = *(VALUE *)b;
66
+ ID score = rb_intern("score");
67
+ double a_score = RFLOAT_VALUE(rb_funcall(a_val, score, 0));
68
+ double b_score = RFLOAT_VALUE(rb_funcall(b_val, score, 0));
69
+ if (a_score > b_score)
70
+ return -1; // a scores higher, a should appear sooner
71
+ else if (a_score < b_score)
72
+ return 1; // b scores higher, a should appear later
73
+ else
74
+ return comp_alpha(a, b);
75
+ }
76
+
77
+ VALUE CommandTMatcher_initialize(int argc, VALUE *argv, VALUE self)
78
+ {
79
+ // process arguments: 1 mandatory, 1 optional
80
+ VALUE scanner, options;
81
+ if (rb_scan_args(argc, argv, "11", &scanner, &options) == 1)
82
+ options = Qnil;
83
+ if (NIL_P(scanner))
84
+ rb_raise(rb_eArgError, "nil scanner");
85
+ rb_iv_set(self, "@scanner", scanner);
86
+
87
+ // check optional options hash for overrides
88
+ VALUE always_show_dot_files = CommandT_option_from_hash("always_show_dot_files", options);
89
+ if (always_show_dot_files != Qtrue)
90
+ always_show_dot_files = Qfalse;
91
+ VALUE never_show_dot_files = CommandT_option_from_hash("never_show_dot_files", options);
92
+ if (never_show_dot_files != Qtrue)
93
+ never_show_dot_files = Qfalse;
94
+ rb_iv_set(self, "@always_show_dot_files", always_show_dot_files);
95
+ rb_iv_set(self, "@never_show_dot_files", never_show_dot_files);
96
+ return Qnil;
97
+ }
98
+
99
+ VALUE CommandTMatcher_sorted_matches_for(VALUE self, VALUE abbrev, VALUE options)
100
+ {
101
+ // process optional options hash
102
+ VALUE limit_option = CommandT_option_from_hash("limit", options);
103
+
104
+ // get unsorted matches
105
+ VALUE matches = CommandTMatcher_matches_for(self, abbrev);
106
+
107
+ abbrev = StringValue(abbrev);
108
+ if (RSTRING_LEN(abbrev) == 0 ||
109
+ (RSTRING_LEN(abbrev) == 1 && RSTRING_PTR(abbrev)[0] == '.'))
110
+ // alphabetic order if search string is only "" or "."
111
+ qsort(RARRAY_PTR(matches), RARRAY_LEN(matches), sizeof(VALUE), comp_alpha);
112
+ else
113
+ // for all other non-empty search strings, sort by score
114
+ qsort(RARRAY_PTR(matches), RARRAY_LEN(matches), sizeof(VALUE), comp_score);
115
+
116
+ // apply optional limit option
117
+ long limit = NIL_P(limit_option) ? 0 : NUM2LONG(limit_option);
118
+ if (limit == 0 || RARRAY_LEN(matches) < limit)
119
+ limit = RARRAY_LEN(matches);
120
+
121
+ // will return an array of strings, not an array of Match objects
122
+ for (long i = 0; i < limit; i++)
123
+ {
124
+ VALUE str = rb_funcall(RARRAY_PTR(matches)[i], rb_intern("to_s"), 0);
125
+ RARRAY_PTR(matches)[i] = str;
126
+ }
127
+
128
+ // trim off any items beyond the limit
129
+ if (limit < RARRAY_LEN(matches))
130
+ (void)rb_funcall(matches, rb_intern("slice!"), 2, LONG2NUM(limit),
131
+ LONG2NUM(RARRAY_LEN(matches) - limit));
132
+ return matches;
133
+ }
134
+
135
+ VALUE CommandTMatcher_matches_for(VALUE self, VALUE abbrev)
136
+ {
137
+ if (NIL_P(abbrev))
138
+ rb_raise(rb_eArgError, "nil abbrev");
139
+ VALUE matches = rb_ary_new();
140
+ VALUE scanner = rb_iv_get(self, "@scanner");
141
+ VALUE always_show_dot_files = rb_iv_get(self, "@always_show_dot_files");
142
+ VALUE never_show_dot_files = rb_iv_get(self, "@never_show_dot_files");
143
+ VALUE options = Qnil;
144
+ if (always_show_dot_files == Qtrue)
145
+ {
146
+ options = rb_hash_new();
147
+ rb_hash_aset(options, ID2SYM(rb_intern("always_show_dot_files")), always_show_dot_files);
148
+ }
149
+ else if (never_show_dot_files == Qtrue)
150
+ {
151
+ options = rb_hash_new();
152
+ rb_hash_aset(options, ID2SYM(rb_intern("never_show_dot_files")), never_show_dot_files);
153
+ }
154
+ abbrev = rb_funcall(abbrev, rb_intern("downcase"), 0);
155
+ VALUE paths = rb_funcall(scanner, rb_intern("paths"), 0);
156
+ for (long i = 0, max = RARRAY_LEN(paths); i < max; i++)
157
+ {
158
+ VALUE path = RARRAY_PTR(paths)[i];
159
+ VALUE match = rb_funcall(cCommandTMatch, rb_intern("new"), 3, path, abbrev, options);
160
+ if (rb_funcall(match, rb_intern("matches?"), 0) == Qtrue)
161
+ rb_funcall(matches, rb_intern("push"), 1, match);
162
+ }
163
+ return matches;
164
+ }