ver-command_t 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,22 @@
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.
data/README.md ADDED
@@ -0,0 +1,12 @@
1
+ CommandT for VER
2
+ ================
3
+
4
+ Install
5
+ -------
6
+ gem install ver-command_t
7
+ cat >> $HOME/.config/ver/rc.rb
8
+ require 'ver-command_t'
9
+
10
+ Use
11
+ ---
12
+ Hit Control-t.
@@ -0,0 +1,24 @@
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
+ CFLAGS += -std=c99 -Wall -Wextra -Wno-unused-parameter
@@ -0,0 +1,65 @@
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 "match.h"
25
+ #include "matcher.h"
26
+
27
+ VALUE mCommandT = 0; // module CommandT
28
+ VALUE cCommandTMatch = 0; // class CommandT::Match
29
+ VALUE cCommandTMatcher = 0; // class CommandT::Matcher
30
+
31
+ VALUE CommandT_option_from_hash(const char *option, VALUE hash)
32
+ {
33
+ if (NIL_P(hash))
34
+ return Qnil;
35
+ VALUE key = ID2SYM(rb_intern(option));
36
+ if (rb_funcall(hash, rb_intern("has_key?"), 1, key) == Qtrue)
37
+ return rb_hash_aref(hash, key);
38
+ else
39
+ return Qnil;
40
+ }
41
+
42
+ void Init_ext()
43
+ {
44
+ // module CommandT
45
+ mCommandT = rb_define_module("CommandT");
46
+
47
+ // class CommandT::Match
48
+ cCommandTMatch = rb_define_class_under(mCommandT, "Match", rb_cObject);
49
+
50
+ // methods
51
+ rb_define_method(cCommandTMatch, "initialize", CommandTMatch_initialize, -1);
52
+ rb_define_method(cCommandTMatch, "matches?", CommandTMatch_matches, 0);
53
+ rb_define_method(cCommandTMatch, "to_s", CommandTMatch_to_s, 0);
54
+
55
+ // attributes
56
+ rb_define_attr(cCommandTMatch, "score", Qtrue, Qfalse); // reader: true, writer: false
57
+
58
+ // class CommandT::Matcher
59
+ cCommandTMatcher = rb_define_class_under(mCommandT, "Matcher", rb_cObject);
60
+
61
+ // methods
62
+ rb_define_method(cCommandTMatcher, "initialize", CommandTMatcher_initialize, -1);
63
+ rb_define_method(cCommandTMatcher, "sorted_matches_for", CommandTMatcher_sorted_matchers_for, 2);
64
+ rb_define_method(cCommandTMatcher, "matches_for", CommandTMatcher_matches_for, 1);
65
+ }
@@ -0,0 +1,36 @@
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 mCommandT; // module CommandT
27
+ extern VALUE cCommandTMatch; // class CommandT::Match
28
+ extern VALUE cCommandTMatcher; // class CommandT::Matcher
29
+
30
+ // Encapsulates common pattern of checking for an option in an optional
31
+ // options hash. The hash itself may be nil, but an exception will be
32
+ // raised if it is not nil and not a hash.
33
+ VALUE CommandT_option_from_hash(const char *option, VALUE hash);
34
+
35
+ // Debugging macro.
36
+ #define ruby_inspect(obj) rb_funcall(rb_mKernel, rb_intern("p"), 1, obj)
Binary file
@@ -0,0 +1,32 @@
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
+ require 'mkmf'
25
+
26
+ def missing item
27
+ puts "couldn't find #{item} (required)"
28
+ exit 1
29
+ end
30
+
31
+ have_header('ruby.h') or missing('ruby.h')
32
+ create_makefile('ext')
@@ -0,0 +1,189 @@
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 "match.h"
25
+ #include "ext.h"
26
+ #include "ruby_compat.h"
27
+
28
+ // use a struct to make passing params during recursion easier
29
+ typedef struct
30
+ {
31
+ char *str_p; // pointer to string to be searched
32
+ long str_len; // length of same
33
+ char *abbrev_p; // pointer to search string (abbreviation)
34
+ long abbrev_len; // length of same
35
+ double max_score_per_char;
36
+ int dot_file; // boolean: true if str is a dot-file
37
+ int always_show_dot_files; // boolean
38
+ int never_show_dot_files; // boolean
39
+ } matchinfo_t;
40
+
41
+ double recursive_match(matchinfo_t *m, // sharable meta-data
42
+ long str_idx, // where in the path string to start
43
+ long abbrev_idx, // where in the search string to start
44
+ long last_idx, // location of last matched character
45
+ double score) // cumulative score so far
46
+ {
47
+ double seen_score = 0; // remember best score seen via recursion
48
+ int dot_file_match = 0; // true if abbrev matches a dot-file
49
+ int dot_search = 0; // true if searching for a dot
50
+
51
+ for (long i = abbrev_idx; i < m->abbrev_len; i++)
52
+ {
53
+ char c = m->abbrev_p[i];
54
+ if (c == '.')
55
+ dot_search = 1;
56
+ int found = 0;
57
+ for (long j = str_idx; j < m->str_len; j++, str_idx++)
58
+ {
59
+ char d = m->str_p[j];
60
+ if (d == '.')
61
+ {
62
+ if (j == 0 || m->str_p[j - 1] == '/')
63
+ {
64
+ m->dot_file = 1; // this is a dot-file
65
+ if (dot_search) // and we are searching for a dot
66
+ dot_file_match = 1; // so this must be a match
67
+ }
68
+ }
69
+ else if (d >= 'A' && d <= 'Z')
70
+ d += 'a' - 'A'; // add 32 to downcase
71
+ if (c == d)
72
+ {
73
+ found = 1;
74
+ dot_search = 0;
75
+
76
+ // calculate score
77
+ double score_for_char = m->max_score_per_char;
78
+ long distance = j - last_idx;
79
+ if (distance > 1)
80
+ {
81
+ double factor = 1.0;
82
+ char last = m->str_p[j - 1];
83
+ char curr = m->str_p[j]; // case matters, so get again
84
+ if (last == '/')
85
+ factor = 0.9;
86
+ else if (last == '-' ||
87
+ last == '_' ||
88
+ last == ' ' ||
89
+ (last >= '0' && last <= '9'))
90
+ factor = 0.8;
91
+ else if (last >= 'a' && last <= 'z' &&
92
+ curr >= 'A' && curr <= 'Z')
93
+ factor = 0.8;
94
+ else if (last == '.')
95
+ factor = 0.7;
96
+ else
97
+ // if no "special" chars behind char, factor diminishes
98
+ // as distance from last matched char increases
99
+ factor = (1.0 / distance) * 0.75;
100
+ score_for_char *= factor;
101
+ }
102
+
103
+ if (++j < m->str_len)
104
+ {
105
+ // bump cursor one char to the right and
106
+ // use recursion to try and find a better match
107
+ double sub_score = recursive_match(m, j, i, last_idx, score);
108
+ if (sub_score > seen_score)
109
+ seen_score = sub_score;
110
+ }
111
+
112
+ score += score_for_char;
113
+ last_idx = str_idx++;
114
+ break;
115
+ }
116
+ }
117
+ if (!found)
118
+ return 0.0;
119
+ }
120
+ if (m->dot_file)
121
+ {
122
+ if (m->never_show_dot_files ||
123
+ (!dot_file_match && !m->always_show_dot_files))
124
+ return 0.0;
125
+ }
126
+ return (score > seen_score) ? score : seen_score;
127
+ }
128
+
129
+ // Match.new abbrev, string, options = {}
130
+ VALUE CommandTMatch_initialize(int argc, VALUE *argv, VALUE self)
131
+ {
132
+ // process arguments: 2 mandatory, 1 optional
133
+ VALUE str, abbrev, options;
134
+ if (rb_scan_args(argc, argv, "21", &str, &abbrev, &options) == 2)
135
+ options = Qnil;
136
+ str = StringValue(str);
137
+ abbrev = StringValue(abbrev); // already downcased by caller
138
+
139
+ // check optional options hash for overrides
140
+ VALUE always_show_dot_files = CommandT_option_from_hash("always_show_dot_files", options);
141
+ VALUE never_show_dot_files = CommandT_option_from_hash("never_show_dot_files", options);
142
+
143
+ matchinfo_t m;
144
+ m.str_p = RSTRING_PTR(str);
145
+ m.str_len = RSTRING_LEN(str);
146
+ m.abbrev_p = RSTRING_PTR(abbrev);
147
+ m.abbrev_len = RSTRING_LEN(abbrev);
148
+ m.max_score_per_char = (1.0 / m.str_len + 1.0 / m.abbrev_len) / 2;
149
+ m.dot_file = 0;
150
+ m.always_show_dot_files = always_show_dot_files == Qtrue;
151
+ m.never_show_dot_files = never_show_dot_files == Qtrue;
152
+
153
+ // calculate score
154
+ double score = 1.0;
155
+ if (m.abbrev_len == 0) // special case for zero-length search string
156
+ {
157
+ // filter out dot files
158
+ if (!m.always_show_dot_files)
159
+ {
160
+ for (long i = 0; i < m.str_len; i++)
161
+ {
162
+ char c = m.str_p[i];
163
+ if (c == '.' && (i == 0 || m.str_p[i - 1] == '/'))
164
+ {
165
+ score = 0.0;
166
+ break;
167
+ }
168
+ }
169
+ }
170
+ }
171
+ else // normal case
172
+ score = recursive_match(&m, 0, 0, 0, 0.0);
173
+
174
+ // clean-up and final book-keeping
175
+ rb_iv_set(self, "@score", rb_float_new(score));
176
+ rb_iv_set(self, "@str", str);
177
+ return Qnil;
178
+ }
179
+
180
+ VALUE CommandTMatch_matches(VALUE self)
181
+ {
182
+ double score = NUM2DBL(rb_iv_get(self, "@score"));
183
+ return score > 0 ? Qtrue : Qfalse;
184
+ }
185
+
186
+ VALUE CommandTMatch_to_s(VALUE self)
187
+ {
188
+ return rb_iv_get(self, "@str");
189
+ }
@@ -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,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_matchers_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
+ }
@@ -0,0 +1,30 @@
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 CommandTMatcher_initialize(int argc, VALUE *argv, VALUE self);
27
+ extern VALUE CommandTMatcher_sorted_matchers_for(VALUE self, VALUE abbrev, VALUE options);
28
+
29
+ // most likely the function will be subsumed by the sorted_matcher_for function
30
+ extern VALUE CommandTMatcher_matches_for(VALUE self, VALUE abbrev);
@@ -0,0 +1,20 @@
1
+ have_header: checking for ruby.h... -------------------- yes
2
+
3
+ "gcc -o conftest -I/home/tass/.rvm/rubies/ruby-1.9.2-p0/include/ruby-1.9.1/x86_64-linux -I/home/tass/.rvm/rubies/ruby-1.9.2-p0/include/ruby-1.9.1/ruby/backward -I/home/tass/.rvm/rubies/ruby-1.9.2-p0/include/ruby-1.9.1 -I. -O2 -g -Wall -fPIC conftest.c -L. -L/home/tass/.rvm/rubies/ruby-1.9.2-p0/lib -Wl,-R/home/tass/.rvm/rubies/ruby-1.9.2-p0/lib -L. -rdynamic -Wl,-export-dynamic -Wl,-R -Wl,/home/tass/.rvm/rubies/ruby-1.9.2-p0/lib -L/home/tass/.rvm/rubies/ruby-1.9.2-p0/lib -lruby-static -lpthread -lrt -ldl -lcrypt -lm -lc"
4
+ checked program was:
5
+ /* begin */
6
+ 1: #include "ruby.h"
7
+ 2:
8
+ 3: int main() {return 0;}
9
+ /* end */
10
+
11
+ "gcc -E -I/home/tass/.rvm/rubies/ruby-1.9.2-p0/include/ruby-1.9.1/x86_64-linux -I/home/tass/.rvm/rubies/ruby-1.9.2-p0/include/ruby-1.9.1/ruby/backward -I/home/tass/.rvm/rubies/ruby-1.9.2-p0/include/ruby-1.9.1 -I. -O2 -g -Wall -fPIC conftest.c -o conftest.i"
12
+ checked program was:
13
+ /* begin */
14
+ 1: #include "ruby.h"
15
+ 2:
16
+ 3: #include <ruby.h>
17
+ /* end */
18
+
19
+ --------------------
20
+