2 * (C) Copyright 2007-2008 Jeremy Maitin-Shepard
3 * (C) Copyright 2008 Nelson Elhage
5 * Portions of this file (the JavaScript completer) were derived from Vimperator,
6 * (C) Copyright 2006-2007 Martin Stubenschrott.
8 * Use, modification, and distribution are subject to the terms specified in the
12 require("minibuffer.js");
15 * Completions is either a visit function or an array.
17 define_keywords("$completions", "$get_string", "$get_description", "$get_value");
18 function all_word_completer()
21 var completions = arguments.$completions;
22 var get_string = arguments.$get_string ? arguments.$get_string : function (x) x;
23 var get_description = arguments.$get_description ? arguments.$get_description : function (x) "";
24 var get_value = arguments.$get_value;
26 if (typeof(completions) == "function")
29 completions(function (x) { arr.push(x); });
32 return function (input, pos, conservative) {
33 if (input.length == 0 && conservative)
35 var words = input.toLowerCase().split(" ");
36 var data = arr.filter(function (x) {
37 var s = get_string(x);
38 var d = get_description(x);
39 for (var i = 0; i < words.length; ++i)
41 if (s.toLowerCase().indexOf(words[i]) == -1 && d.toLowerCase().indexOf(words[i]) == -1)
46 return {count: data.length,
47 index_of: function (x) data.indexOf(x),
48 get_string: function (i) get_string(data[i]),
49 get_description : function (i) get_description(data[i]),
50 get_input_state: function (i) [get_string(data[i])],
51 get_value : function(i) (get_value ? get_value(data[i]) : data[i])
56 function get_common_prefix_length(a, b, len) {
58 if (len != null && len < a.length)
65 for (i = 0; i < lim && a[i] == b[i]; ++i);
69 function get_partial_completion_input_state(x, prefix_end, suffix_begin, orig_str) {
70 if (suffix_begin < orig_str.length) {
71 if (orig_str[suffix_begin] == " ")
73 let sel = x.length + prefix_end + 1;
74 return [orig_str.substring(0, prefix_end) + x + " " + orig_str.substring(suffix_begin),
77 let sel = x.length + prefix_end;
78 return [orig_str.substring(0, prefix_end) + x, sel, sel];
82 function prefix_completer()
85 var completions = arguments.$completions;
86 var get_string = arguments.$get_string ? arguments.$get_string : function (x) x;
87 var get_description = arguments.$get_description ? arguments.$get_description : function (x) "";
88 var get_value = arguments.$get_value;
90 if (typeof(completions) == "function")
93 completions(function (x) { arr.push(x); });
95 arr = completions.slice();
96 arr.sort(function (a,b) {
105 return function (input, pos, conservative) {
106 var common_prefix = null;
107 if (pos == 0 && conservative)
109 var input_prefix = input.substring(0,pos);
110 var default_completion = null;
112 var data = arr.filter(function (x) {
113 var s = get_string(x);
117 default_completion = i;
120 retval = (s.length >= pos && s.substring(0,pos) == input_prefix);
127 let a = get_string(data[0]);
128 let b = get_string(data[data.length - 1]);
129 let i = get_common_prefix_length(a, b);
131 common_prefix = a.substring(0,i);
132 if (!default_completion) {
133 for (let j = 0; j < data.length; ++j) {
134 if (get_string(data[j]) == common_prefix) {
135 default_completion = j;
142 return {count:data.length,
143 index_of: function (x) data.indexOf(x),
144 get_string: function (i) get_string(data[i]),
145 get_description : function (i) get_description(data[i]),
146 get_input_state : function (i) get_partial_completion_input_state(get_string(data[i]), 0, pos, input),
147 get_value : function(i) get_value(data[i]),
148 get common_prefix_input_state () {
149 return common_prefix && get_partial_completion_input_state(common_prefix, 0, pos, input);
151 default_completion: default_completion
156 function javascript_completer(buffer) {
157 var window = buffer.window;
159 return function (input, pos, conservative) {
160 // Derived from Vimperator JavaScript completion
161 if (pos == 0 && conservative)
163 var str = input.substr(0, pos);
164 var matches = str.match(/^(.*?)(\s*\.\s*)?(\w*)$/);
165 var filter = matches[3] || "";
166 var start = matches[1].length - 1;
167 var offset = matches[1] ? matches[1].length : 0;
168 offset += matches[2] ? matches[2].length : 0;
172 let brackets = 0, parentheses = 0;
174 for (; start >= 0; start--)
176 switch (matches[1][start])
195 if (brackets > 0 || parentheses > 0)
203 var common_prefix_len = null;
204 var common_prefix = null;
206 function add_completion(str, desc) {
207 if (common_prefix != null)
208 common_prefix_len = get_common_prefix_length(common_prefix, str, common_prefix_len);
211 data.push([str,desc]);
213 if (matches[1].substr(start+1))
216 source_obj = eval(matches[1].substr(start+1));
221 source_obj = conkeror;
222 if ("window".substring(0,filter.length) == filter)
223 add_completion("window", "object");
224 if ("buffer".substring(0,filter.length) == filter)
225 add_completion("buffer", "object");
228 if (source_obj != null) {
230 for (let i in source_obj) {
231 if (i.substring(0,filter.length) != filter)
233 let type, description;
235 type = typeof(source_obj[i]);
236 } catch (e) { type = "unknown type"; }
237 if (type == "number" || type == "string" || type == "boolean") {
238 description = type + ": " + source_obj[i];
241 add_completion(i, description);
245 if (common_prefix != null && common_prefix_len > 0)
246 common_prefix = common_prefix.substr(0, common_prefix_len);
247 else if (common_prefix_len != null)
248 common_prefix = null;
249 return {count:data.length,
250 get_string: function (i) data[i][0],
251 get_description: function (i) data[i][1],
252 get_input_state: function (i) get_partial_completion_input_state(data[i][0], offset, pos, input),
253 get common_prefix_input_state () {
254 return common_prefix && get_partial_completion_input_state(common_prefix, offset, pos, input);
261 function merge_completers(completers) {
262 if(completers.length == 0)
264 return function (input, pos, conservative) {
267 for (let i = 0; i < completers.length; ++i) {
268 let r = yield completers[i](input, pos, conservative);
269 if (r != null && r.count > 0) {
274 function forward(name) {
276 var args = Array.prototype.slice.call(arguments);
277 var i = args.shift();
278 for(var j=0; j < results.length; j++) {
281 if (name in r && r[name] != null) {
283 return r[name].apply(this, args);
291 yield co_return({count: count,
292 get_string: forward('get_string'),
293 get_description: forward('get_description'),
294 get_input_state: forward('get_input_state'),
295 destroy: forward('destroy')
300 function nest_completions(completions, prefix, suffix) {
311 return [prefix + s + suffix, a + prefix.length, b + prefix.length];
314 __proto__: completions,
315 get_input_state: function (i) nest(completions.get_input_state(i)),
316 get common_prefix_input_state () {
317 let x = completions.common_prefix_input_state;