command-t 1.2

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.
@@ -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
+ }