Factor out get_shortdoc_string logic from interactive.js
[conkeror.git] / modules / minibuffer-completion.js
blob82cef54fea61adf92e73096d75bf055162da01a6
1 require("minibuffer.js");
4 function apply_completion_string(str, m) {
5     m._set_selection();
6     m._input_text = str;
9 /**
10  * Completions is either a visit function or an array.
11  */
12 define_keywords("$completions", "$get_string", "$get_description", "$get_value");
13 function all_word_completer()
15     keywords(arguments);
16     var completions = arguments.$completions;
17     var get_string = arguments.$get_string;
18     var get_description = arguments.$get_description;
19     var get_value = arguments.$get_value;
20     var arr;
21     if (typeof(completions) == "function")
22     {
23         arr = [];
24         completions(function (x) { arr.push(x); });
25     } else
26         arr = completions;
27     return function (input, pos, conservative) {
28         if (input.length == 0 && conservative)
29             return undefined;
30         var words = input.toLowerCase().split(" ");
31         var data = arr.filter(function (x) {
32                 var s = get_string(x);
33                 var d = get_description(x);
34                 for (var i = 0; i < words.length; ++i)
35                 {
36                     if (s.toLowerCase().indexOf(words[i]) == -1 && d.toLowerCase().indexOf(words[i]) == -1)
37                         return false;
38                 }
39                 return true;
40             });
41         return {count: data.length,
42                 index_of:  function (x) data.indexOf(x),
43                 get_string: function (i) get_string(data[i]),
44                 get_description : function (i) get_description(data[i]),
45                 apply : function (i, m) apply_completion_string(get_string(data[i]), m),
46                 get_value : function(i) (get_value ? get_value(data[i]) : data[i])
47                };
48     }
51 function get_common_prefix_length(a, b, len) {
52     var lim;
53     if (len != null && len < a.length)
54         lim = len;
55     else
56         lim = a.length;
57     if (b < lim)
58         lim = b;
59     var i;
60     for (i = 0; i < lim && a[i] == b[i]; ++i);
61     return i;
64 function apply_partial_completion(x, prefix_end, suffix_begin, orig_str, m) {
65     if (suffix_begin < orig_str.length)  {
66         if (orig_str[suffix_begin] == " ")
67             suffix_begin++;
68         m._input_text = orig_str.substring(0, prefix_end) + x + " " + orig_str.substring(suffix_begin);
69         let sel = x.length + prefix_end + 1;
70         m._set_selection(sel, sel);
71     } else {
72         m._input_text = orig_str.substring(0, prefix_end) + x;
73         let sel = x.length + prefix_end;
74         m._set_selection(sel, sel);
75     }
78 function prefix_completer()
80     keywords(arguments);
81     var completions = arguments.$completions;
82     var get_string = arguments.$get_string;
83     var get_description = arguments.$get_description;
84     var get_value = arguments.$get_value;
85     var arr;
86     if (typeof(completions) == "function")
87     {
88         arr = [];
89         completions(function (x) { arr.push(x); });
90     } else
91         arr = completions.slice();
92     arr.sort(function (a,b) {
93             a = get_string(a);
94             b = get_string(b);
95             if (a < b)
96                 return -1;
97             if (a > b)
98                 return 1;
99             return 0;
100         });
101     return function (input, pos, conservative) {
102         var common_prefix = null;
103         if (pos == 0 && conservative)
104             return undefined;
105         var input_prefix = input.substring(0,pos);
106         var default_completion = null;
107         var i = 0;
108         var data = arr.filter(function (x) {
109             var s = get_string(x);
110             var retval;
112             if (s == input) {
113                 default_completion = i;
114                 retval = true;
115             } else
116                 retval = (s.length >= pos && s.substring(0,pos) == input_prefix);
117             if (retval)
118                 ++i;
119             return retval;
120         });
121         if (data.length > 0)
122         {
123             let a = get_string(data[0]);
124             let b = get_string(data[data.length - 1]);
125             let i = get_common_prefix_length(a, b);
126             if (i > pos)
127                 common_prefix = a.substring(0,i);
128         }
129         return {count:data.length,
130                 index_of:  function (x) data.indexOf(x),
131                 get_string: function (i) get_string(data[i]),
132                 get_description : function (i) get_description(data[i]),
133                 apply : function (i, m) apply_partial_completion(get_string(data[i]), 0, pos, input, m),
134                 get_value : function(i) get_value(data[i]),
135                 apply_common_prefix: (common_prefix &&
136                                       function (m) apply_partial_completion(common_prefix, 0, pos, input, m)),
137                 default_completion: default_completion
138                };
139     }
142 function javascript_completer(buffer) {
143     var window = buffer.window;
145     return function (input, pos, conservative) {
146         // Derived from Vimperator JavaScript completion
147         if (pos == 0 && conservative)
148             return undefined;
149         var str = input.substr(0, pos);
150         var matches = str.match(/^(.*?)(\s*\.\s*)?(\w*)$/);
151         var filter = matches[3] || "";
152         var start = matches[1].length - 1;
153         var offset = matches[1] ? matches[1].length : 0;
154         offset += matches[2] ? matches[2].length : 0;
156         if (matches[2])
157         {
158             let brackets = 0, parentheses = 0;
159         outer:
160             for (; start >= 0; start--)
161             {
162                 switch (matches[1][start])
163                 {
164                 case ";":
165                 case "{":
166                     break outer;
168                 case "]":
169                     brackets--;
170                     break;
171                 case "[":
172                     brackets++;
173                     break;
174                 case ")":
175                     parentheses--;
176                     break;
177                 case "(":
178                     parentheses++;
179                     break;
180                 }
181                 if (brackets > 0 || parentheses > 0)
182                     break outer;
183             }
184         }
186         var objects = [];
187         var source_obj ;
188         var data = [];
189         var common_prefix_len = null;
190         var common_prefix = null;
192         function add_completion(str, desc) {
193             if (common_prefix != null)
194                 common_prefix_len = get_common_prefix_length(common_prefix, str, common_prefix_len);
195             else
196                 common_prefix = str;
197             data.push([str,desc]);
198         }
199         if (matches[1].substr(start+1))
200         {
201             try {
202                 source_obj = eval(matches[1].substr(start+1));
203             } catch (e) {}
204         }
205         else
206         {
207             source_obj = conkeror;
208             if ("window".substring(0,filter.length) == filter)
209                 add_completion("window", "object");
210             if ("buffer".substring(0,filter.length) == filter)
211                 add_completion("buffer", "object");
212         }
214         if (source_obj != null) {
215             try {
216                 for (let i in source_obj) {
217                     if (i.substring(0,filter.length) != filter)
218                         continue;
219                     let type, description;
220                     try {
221                         type = typeof(source_obj[i]);
222                     } catch (e) { type = "unknown type"; }
223                     if (type == "number" || type == "string" || type == "boolean") {
224                         description = type + ": " + source_obj[i];
225                     } else
226                         description = type;
227                     add_completion(i, description);
228                 }
229             } catch (e) {}
230         }
231         if (common_prefix != null && common_prefix_len > 0)
232             common_prefix = common_prefix.substr(0, common_prefix_len);
233         else if (common_prefix_len != null)
234             common_prefix = null;
235         return {count:data.length,
236                 get_string: function (i) data[i][0],
237                 get_description: function (i) data[i][1],
238                 apply: function (i,m) apply_partial_completion(data[i][0], offset, pos, input, m),
239                 apply_common_prefix: (common_prefix &&
240                                       function (m) apply_partial_completion(common_prefix, offset, pos, input, m))
241                };
242     }