command-t-standalone 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in command-t-standalone.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Howard Yeh
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ # Command::T::Standalone
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'command-t-standalone'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install command-t-standalone
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
@@ -0,0 +1,20 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ def bail_on_failure
4
+ exitstatus = $?.exitstatus
5
+ if exitstatus != 0
6
+ err "last command failed with exit status #{exitstatus}"
7
+ exit 1
8
+ end
9
+ end
10
+
11
+ # desc 'Compile extension'
12
+ # task :make do
13
+ # Dir.chdir 'lib/command-t' do
14
+ # ruby 'extconf.rb'
15
+ # system 'make clean'
16
+ # bail_on_failure
17
+ # system 'make'
18
+ # bail_on_failure
19
+ # end
20
+ # end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'command-t-standalone/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "command-t-standalone"
8
+ gem.version = CommandT::VERSION
9
+ gem.authors = ["Howard Yeh"]
10
+ gem.email = ["howard@metacircus.com"]
11
+ gem.description = %q{CommandT finder as standalone gem}
12
+ gem.summary = %q{ditto}
13
+ gem.homepage = "http://github.com/hayeah"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ # gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ # gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+
19
+ gem.extensions = "lib/command-t-standalone/extconf.rb"
20
+
21
+ gem.require_paths = ["lib"]
22
+ end
@@ -0,0 +1,5 @@
1
+ require "command-t-standalone/version"
2
+ require "command-t-standalone/finder/file_finder"
3
+
4
+ module CommandT
5
+ end
@@ -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_matches_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)
@@ -0,0 +1,34 @@
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
+ RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC']
32
+
33
+ have_header('ruby.h') or missing('ruby.h')
34
+ create_makefile('ext')
@@ -0,0 +1,54 @@
1
+ # Copyright 2010-2012 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 'command-t-standalone/ext'
25
+
26
+ module CommandT
27
+ # Encapsulates a Scanner instance (which builds up a list of available files
28
+ # in a directory) and a Matcher instance (which selects from that list based
29
+ # on a search string).
30
+ #
31
+ # Specialized subclasses use different kinds of scanners adapted for
32
+ # different kinds of search (files, buffers).
33
+ class Finder
34
+ # include VIM::PathUtilities
35
+
36
+ def initialize path = Dir.pwd, options = {}
37
+ raise RuntimeError, 'Subclass responsibility'
38
+ end
39
+
40
+ # Options:
41
+ # :limit (integer): limit the number of returned matches
42
+ def sorted_matches_for str, options = {}
43
+ @matcher.sorted_matches_for str, options
44
+ end
45
+
46
+ # def open_selection command, selection, options = {}
47
+ # ::VIM::command "silent #{command} #{selection}"
48
+ # end
49
+
50
+ def path= path
51
+ @scanner.path = path
52
+ end
53
+ end # class Finder
54
+ end # CommandT
@@ -0,0 +1,39 @@
1
+ # Copyright 2010-2012 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 'command-t-standalone/ext' # CommandT::Matcher
25
+ require 'command-t-standalone/finder'
26
+ require 'command-t-standalone/scanner/file_scanner'
27
+
28
+ module CommandT
29
+ class FileFinder < Finder
30
+ def initialize path = Dir.pwd, options = {}
31
+ @scanner = FileScanner.new path, options
32
+ @matcher = Matcher.new @scanner, options
33
+ end
34
+
35
+ def flush
36
+ @scanner.flush
37
+ end
38
+ end # class FileFinder
39
+ end # CommandT
@@ -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
+ }