##// END OF EJS Templates
Fixed various typos in docstrings.
Susan Tan -
Show More
@@ -1,353 +1,353
1 // function completer.
1 // function completer.
2 //
2 //
3 // completer should be a class that take an cell instance
3 // completer should be a class that takes an cell instance
4 var IPython = (function (IPython) {
4 var IPython = (function (IPython) {
5 // that will prevent us from misspelling
5 // that will prevent us from misspelling
6 "use strict";
6 "use strict";
7
7
8 // easyier key mapping
8 // easier key mapping
9 var key = IPython.utils.keycodes;
9 var key = IPython.utils.keycodes;
10
10
11 function prepend_n_prc(str, n) {
11 function prepend_n_prc(str, n) {
12 for( var i =0 ; i< n ; i++){
12 for( var i =0 ; i< n ; i++){
13 str = '%'+str ;
13 str = '%'+str ;
14 }
14 }
15 return str;
15 return str;
16 }
16 }
17
17
18 function _existing_completion(item, completion_array){
18 function _existing_completion(item, completion_array){
19 for( var c in completion_array ) {
19 for( var c in completion_array ) {
20 if(completion_array[c].trim().substr(-item.length) == item)
20 if(completion_array[c].trim().substr(-item.length) == item)
21 { return true; }
21 { return true; }
22 }
22 }
23 return false;
23 return false;
24 }
24 }
25
25
26 // what is the common start of all completions
26 // what is the common start of all completions
27 function shared_start(B, drop_prct) {
27 function shared_start(B, drop_prct) {
28 if (B.length == 1) {
28 if (B.length == 1) {
29 return B[0];
29 return B[0];
30 }
30 }
31 var A = new Array();
31 var A = new Array();
32 var common;
32 var common;
33 var min_lead_prct = 10;
33 var min_lead_prct = 10;
34 for (var i = 0; i < B.length; i++) {
34 for (var i = 0; i < B.length; i++) {
35 var str = B[i].str;
35 var str = B[i].str;
36 var localmin = 0;
36 var localmin = 0;
37 if(drop_prct === true){
37 if(drop_prct === true){
38 while ( str.substr(0, 1) == '%') {
38 while ( str.substr(0, 1) == '%') {
39 localmin = localmin+1;
39 localmin = localmin+1;
40 str = str.substring(1);
40 str = str.substring(1);
41 }
41 }
42 }
42 }
43 min_lead_prct = Math.min(min_lead_prct, localmin);
43 min_lead_prct = Math.min(min_lead_prct, localmin);
44 A.push(str);
44 A.push(str);
45 }
45 }
46
46
47 if (A.length > 1) {
47 if (A.length > 1) {
48 var tem1, tem2, s;
48 var tem1, tem2, s;
49 A = A.slice(0).sort();
49 A = A.slice(0).sort();
50 tem1 = A[0];
50 tem1 = A[0];
51 s = tem1.length;
51 s = tem1.length;
52 tem2 = A.pop();
52 tem2 = A.pop();
53 while (s && tem2.indexOf(tem1) == -1) {
53 while (s && tem2.indexOf(tem1) == -1) {
54 tem1 = tem1.substring(0, --s);
54 tem1 = tem1.substring(0, --s);
55 }
55 }
56 if (tem1 === "" || tem2.indexOf(tem1) !== 0) {
56 if (tem1 === "" || tem2.indexOf(tem1) !== 0) {
57 return {
57 return {
58 str:prepend_n_prc('', min_lead_prct),
58 str:prepend_n_prc('', min_lead_prct),
59 type: "computed",
59 type: "computed",
60 from: B[0].from,
60 from: B[0].from,
61 to: B[0].to
61 to: B[0].to
62 };
62 };
63 }
63 }
64 return {
64 return {
65 str: prepend_n_prc(tem1, min_lead_prct),
65 str: prepend_n_prc(tem1, min_lead_prct),
66 type: "computed",
66 type: "computed",
67 from: B[0].from,
67 from: B[0].from,
68 to: B[0].to
68 to: B[0].to
69 };
69 };
70 }
70 }
71 return null;
71 return null;
72 }
72 }
73
73
74
74
75 var Completer = function (cell) {
75 var Completer = function (cell) {
76 this.cell = cell;
76 this.cell = cell;
77 this.editor = cell.code_mirror;
77 this.editor = cell.code_mirror;
78 var that = this;
78 var that = this;
79 $([IPython.events]).on('status_busy.Kernel', function () {
79 $([IPython.events]).on('status_busy.Kernel', function () {
80 that.skip_kernel_completion = true;
80 that.skip_kernel_completion = true;
81 });
81 });
82 $([IPython.events]).on('status_idle.Kernel', function () {
82 $([IPython.events]).on('status_idle.Kernel', function () {
83 that.skip_kernel_completion = false;
83 that.skip_kernel_completion = false;
84 });
84 });
85 };
85 };
86
86
87
87
88 Completer.prototype.startCompletion = function () {
88 Completer.prototype.startCompletion = function () {
89 // call for a 'first' completion, that will set the editor and do some
89 // call for a 'first' completion, that will set the editor and do some
90 // special behaviour like autopicking if only one completion availlable
90 // special behaviour like autopicking if only one completion availlable
91 //
91 //
92 if (this.editor.somethingSelected()) return;
92 if (this.editor.somethingSelected()) return;
93 this.done = false;
93 this.done = false;
94 // use to get focus back on opera
94 // use to get focus back on opera
95 this.carry_on_completion(true);
95 this.carry_on_completion(true);
96 };
96 };
97
97
98
98
99 // easy access for julia to monkeypatch
99 // easy access for julia to monkeypatch
100 //
100 //
101 Completer.reinvoke_re = /[%0-9a-z._/\\:~-]/i;
101 Completer.reinvoke_re = /[%0-9a-z._/\\:~-]/i;
102
102
103 Completer.prototype.reinvoke= function(pre_cursor, block, cursor){
103 Completer.prototype.reinvoke= function(pre_cursor, block, cursor){
104 return Completer.reinvoke_re.test(pre_cursor);
104 return Completer.reinvoke_re.test(pre_cursor);
105 }
105 }
106
106
107 /**
107 /**
108 *
108 *
109 * pass true as parameter if this is the first invocation of the completer
109 * pass true as parameter if this is the first invocation of the completer
110 * this will prevent the completer to dissmiss itself if it is not on a
110 * this will prevent the completer to dissmiss itself if it is not on a
111 * word boundary like pressing tab after a space, and make it autopick the
111 * word boundary like pressing tab after a space, and make it autopick the
112 * only choice if there is only one which prevent from popping the UI. as
112 * only choice if there is only one which prevent from popping the UI. as
113 * well as fast-forwarding the typing if all completion have a common
113 * well as fast-forwarding the typing if all completion have a common
114 * shared start
114 * shared start
115 **/
115 **/
116 Completer.prototype.carry_on_completion = function (first_invocation) {
116 Completer.prototype.carry_on_completion = function (first_invocation) {
117 // Pass true as parameter if you want the commpleter to autopick when
117 // Pass true as parameter if you want the completer to autopick when
118 // only one completion. This function is automatically reinvoked at
118 // only one completion. This function is automatically reinvoked at
119 // each keystroke with first_invocation = false
119 // each keystroke with first_invocation = false
120 var cur = this.editor.getCursor();
120 var cur = this.editor.getCursor();
121 var line = this.editor.getLine(cur.line);
121 var line = this.editor.getLine(cur.line);
122 var pre_cursor = this.editor.getRange({
122 var pre_cursor = this.editor.getRange({
123 line: cur.line,
123 line: cur.line,
124 ch: cur.ch - 1
124 ch: cur.ch - 1
125 }, cur);
125 }, cur);
126
126
127 // we need to check that we are still on a word boundary
127 // we need to check that we are still on a word boundary
128 // because while typing the completer is still reinvoking itself
128 // because while typing the completer is still reinvoking itself
129 // so dismiss if we are on a "bad" caracter
129 // so dismiss if we are on a "bad" caracter
130 if (!this.reinvoke(pre_cursor) && !first_invocation) {
130 if (!this.reinvoke(pre_cursor) && !first_invocation) {
131 this.close();
131 this.close();
132 return;
132 return;
133 }
133 }
134
134
135 this.autopick = false;
135 this.autopick = false;
136 if (first_invocation) {
136 if (first_invocation) {
137 this.autopick = true;
137 this.autopick = true;
138 }
138 }
139
139
140 // We want a single cursor position.
140 // We want a single cursor position.
141 if (this.editor.somethingSelected()) {
141 if (this.editor.somethingSelected()) {
142 return;
142 return;
143 };
143 };
144
144
145 // one kernel completion came back, finish_completing will be called with the results
145 // one kernel completion came back, finish_completing will be called with the results
146 // we fork here and directly call finish completing if kernel is busy
146 // we fork here and directly call finish completing if kernel is busy
147 if (this.skip_kernel_completion == true) {
147 if (this.skip_kernel_completion == true) {
148 this.finish_completing({
148 this.finish_completing({
149 'matches': [],
149 'matches': [],
150 matched_text: ""
150 matched_text: ""
151 })
151 })
152 } else {
152 } else {
153 this.cell.kernel.complete(line, cur.ch, $.proxy(this.finish_completing, this));
153 this.cell.kernel.complete(line, cur.ch, $.proxy(this.finish_completing, this));
154 }
154 }
155 };
155 };
156
156
157 Completer.prototype.finish_completing = function (msg) {
157 Completer.prototype.finish_completing = function (msg) {
158 // let's build a function that wrap all that stuff into what is needed
158 // let's build a function that wrap all that stuff into what is needed
159 // for the new completer:
159 // for the new completer:
160 var content = msg.content;
160 var content = msg.content;
161 var matched_text = content.matched_text;
161 var matched_text = content.matched_text;
162 var matches = content.matches;
162 var matches = content.matches;
163
163
164 var cur = this.editor.getCursor();
164 var cur = this.editor.getCursor();
165 var results = CodeMirror.contextHint(this.editor);
165 var results = CodeMirror.contextHint(this.editor);
166 var filterd_results = Array();
166 var filterd_results = Array();
167 //remove results from context completion
167 //remove results from context completion
168 //that are already in kernel completion
168 //that are already in kernel completion
169 for(var elm in results) {
169 for(var elm in results) {
170 if(_existing_completion(results[elm]['str'], matches) == false)
170 if(_existing_completion(results[elm]['str'], matches) == false)
171 { filterd_results.push(results[elm]); }
171 { filterd_results.push(results[elm]); }
172 }
172 }
173
173
174 // append the introspection result, in order, at at the beginning of
174 // append the introspection result, in order, at at the beginning of
175 // the table and compute the replacement range from current cursor
175 // the table and compute the replacement range from current cursor
176 // positon and matched_text length.
176 // positon and matched_text length.
177 for (var i = matches.length - 1; i >= 0; --i) {
177 for (var i = matches.length - 1; i >= 0; --i) {
178 filterd_results.unshift({
178 filterd_results.unshift({
179 str: matches[i],
179 str: matches[i],
180 type: "introspection",
180 type: "introspection",
181 from: {
181 from: {
182 line: cur.line,
182 line: cur.line,
183 ch: cur.ch - matched_text.length
183 ch: cur.ch - matched_text.length
184 },
184 },
185 to: {
185 to: {
186 line: cur.line,
186 line: cur.line,
187 ch: cur.ch
187 ch: cur.ch
188 }
188 }
189 });
189 });
190 }
190 }
191
191
192 // one the 2 sources results have been merge, deal with it
192 // one the 2 sources results have been merge, deal with it
193 this.raw_result = filterd_results;
193 this.raw_result = filterd_results;
194
194
195 // if empty result return
195 // if empty result return
196 if (!this.raw_result || !this.raw_result.length) return;
196 if (!this.raw_result || !this.raw_result.length) return;
197
197
198 // When there is only one completion, use it directly.
198 // When there is only one completion, use it directly.
199 if (this.autopick == true && this.raw_result.length == 1) {
199 if (this.autopick == true && this.raw_result.length == 1) {
200 this.insert(this.raw_result[0]);
200 this.insert(this.raw_result[0]);
201 return;
201 return;
202 }
202 }
203
203
204 if (this.raw_result.length == 1) {
204 if (this.raw_result.length == 1) {
205 // test if first and only completion totally matches
205 // test if first and only completion totally matches
206 // what is typed, in this case dismiss
206 // what is typed, in this case dismiss
207 var str = this.raw_result[0].str;
207 var str = this.raw_result[0].str;
208 var pre_cursor = this.editor.getRange({
208 var pre_cursor = this.editor.getRange({
209 line: cur.line,
209 line: cur.line,
210 ch: cur.ch - str.length
210 ch: cur.ch - str.length
211 }, cur);
211 }, cur);
212 if (pre_cursor == str) {
212 if (pre_cursor == str) {
213 this.close();
213 this.close();
214 return;
214 return;
215 }
215 }
216 }
216 }
217
217
218 this.complete = $('<div/>').addClass('completions');
218 this.complete = $('<div/>').addClass('completions');
219 this.complete.attr('id', 'complete');
219 this.complete.attr('id', 'complete');
220
220
221 this.sel = $('<select style="width: auto"/>')
221 this.sel = $('<select style="width: auto"/>')
222 .attr('multiple', 'true')
222 .attr('multiple', 'true')
223 .attr('size', Math.min(10, this.raw_result.length));
223 .attr('size', Math.min(10, this.raw_result.length));
224 this.complete.append(this.sel);
224 this.complete.append(this.sel);
225 $('body').append(this.complete);
225 $('body').append(this.complete);
226
226
227 // After everything is on the page, compute the postion.
227 // After everything is on the page, compute the postion.
228 // We put it above the code if it is too close to the bottom of the page.
228 // We put it above the code if it is too close to the bottom of the page.
229 var cur = this.editor.getCursor();
229 var cur = this.editor.getCursor();
230 cur.ch = cur.ch-matched_text.length;
230 cur.ch = cur.ch-matched_text.length;
231 var pos = this.editor.cursorCoords(cur);
231 var pos = this.editor.cursorCoords(cur);
232 var left = pos.left-3;
232 var left = pos.left-3;
233 var top;
233 var top;
234 var cheight = this.complete.height();
234 var cheight = this.complete.height();
235 var wheight = $(window).height();
235 var wheight = $(window).height();
236 if (pos.bottom+cheight+5 > wheight) {
236 if (pos.bottom+cheight+5 > wheight) {
237 top = pos.top-cheight-4;
237 top = pos.top-cheight-4;
238 } else {
238 } else {
239 top = pos.bottom+1;
239 top = pos.bottom+1;
240 }
240 }
241 this.complete.css('left', left + 'px');
241 this.complete.css('left', left + 'px');
242 this.complete.css('top', top + 'px');
242 this.complete.css('top', top + 'px');
243
243
244
244
245 //build the container
245 //build the container
246 var that = this;
246 var that = this;
247 this.sel.dblclick(function () {
247 this.sel.dblclick(function () {
248 that.pick();
248 that.pick();
249 });
249 });
250 this.sel.blur(this.close);
250 this.sel.blur(this.close);
251 this.sel.keydown(function (event) {
251 this.sel.keydown(function (event) {
252 that.keydown(event);
252 that.keydown(event);
253 });
253 });
254
254
255 this.build_gui_list(this.raw_result);
255 this.build_gui_list(this.raw_result);
256
256
257 this.sel.focus();
257 this.sel.focus();
258 // Opera sometimes ignores focusing a freshly created node
258 // Opera sometimes ignores focusing a freshly created node
259 if (window.opera) setTimeout(function () {
259 if (window.opera) setTimeout(function () {
260 if (!this.done) this.sel.focus();
260 if (!this.done) this.sel.focus();
261 }, 100);
261 }, 100);
262 return true;
262 return true;
263 }
263 }
264
264
265 Completer.prototype.insert = function (completion) {
265 Completer.prototype.insert = function (completion) {
266 this.editor.replaceRange(completion.str, completion.from, completion.to);
266 this.editor.replaceRange(completion.str, completion.from, completion.to);
267 }
267 }
268
268
269 Completer.prototype.build_gui_list = function (completions) {
269 Completer.prototype.build_gui_list = function (completions) {
270 for (var i = 0; i < completions.length; ++i) {
270 for (var i = 0; i < completions.length; ++i) {
271 var opt = $('<option/>').text(completions[i].str).addClass(completions[i].type);
271 var opt = $('<option/>').text(completions[i].str).addClass(completions[i].type);
272 this.sel.append(opt);
272 this.sel.append(opt);
273 }
273 }
274 this.sel.children().first().attr('selected', 'true');
274 this.sel.children().first().attr('selected', 'true');
275 this.sel.scrollTop(0);
275 this.sel.scrollTop(0);
276 }
276 }
277
277
278 Completer.prototype.close = function () {
278 Completer.prototype.close = function () {
279 if (this.done) return;
279 if (this.done) return;
280 this.done = true;
280 this.done = true;
281 $('.completions').remove();
281 $('.completions').remove();
282 }
282 }
283
283
284 Completer.prototype.pick = function () {
284 Completer.prototype.pick = function () {
285 this.insert(this.raw_result[this.sel[0].selectedIndex]);
285 this.insert(this.raw_result[this.sel[0].selectedIndex]);
286 this.close();
286 this.close();
287 var that = this;
287 var that = this;
288 setTimeout(function () {
288 setTimeout(function () {
289 that.editor.focus();
289 that.editor.focus();
290 }, 50);
290 }, 50);
291 }
291 }
292
292
293
293
294 Completer.prototype.keydown = function (event) {
294 Completer.prototype.keydown = function (event) {
295 var code = event.keyCode;
295 var code = event.keyCode;
296 var that = this;
296 var that = this;
297 var special_key = false;
297 var special_key = false;
298
298
299 // detect special keys like SHIFT,PGUP,...
299 // detect special keys like SHIFT,PGUP,...
300 for( var _key in key ) {
300 for( var _key in key ) {
301 if (code == key[_key] ) {
301 if (code == key[_key] ) {
302 special_key = true;
302 special_key = true;
303 }
303 }
304 };
304 };
305
305
306 // Enter
306 // Enter
307 if (code == key.ENTER) {
307 if (code == key.ENTER) {
308 CodeMirror.e_stop(event);
308 CodeMirror.e_stop(event);
309 this.pick();
309 this.pick();
310 }
310 }
311 // Escape or backspace
311 // Escape or backspace
312 else if (code == key.ESC) {
312 else if (code == key.ESC) {
313 CodeMirror.e_stop(event);
313 CodeMirror.e_stop(event);
314 this.close();
314 this.close();
315 this.editor.focus();
315 this.editor.focus();
316 } else if (code == key.SPACE || code == key.BACKSPACE) {
316 } else if (code == key.SPACE || code == key.BACKSPACE) {
317 this.close();
317 this.close();
318 this.editor.focus();
318 this.editor.focus();
319 } else if (code == key.TAB) {
319 } else if (code == key.TAB) {
320 //all the fastforwarding operation,
320 //all the fastforwarding operation,
321 //Check that shared start is not null which can append with prefixed completion
321 //Check that shared start is not null which can append with prefixed completion
322 // like %pylab , pylab have no shred start, and ff will result in py<tab><tab>
322 // like %pylab , pylab have no shred start, and ff will result in py<tab><tab>
323 // to erase py
323 // to erase py
324 var sh = shared_start(this.raw_result, true);
324 var sh = shared_start(this.raw_result, true);
325 if (sh) {
325 if (sh) {
326 this.insert(sh);
326 this.insert(sh);
327 }
327 }
328 this.close();
328 this.close();
329 CodeMirror.e_stop(event);
329 CodeMirror.e_stop(event);
330 this.editor.focus();
330 this.editor.focus();
331 //reinvoke self
331 //reinvoke self
332 setTimeout(function () {
332 setTimeout(function () {
333 that.carry_on_completion();
333 that.carry_on_completion();
334 }, 50);
334 }, 50);
335 } else if (code == key.UPARROW || code == key.DOWNARROW) {
335 } else if (code == key.UPARROW || code == key.DOWNARROW) {
336 // need to do that to be able to move the arrow
336 // need to do that to be able to move the arrow
337 // when on the first or last line ofo a code cell
337 // when on the first or last line ofo a code cell
338 event.stopPropagation();
338 event.stopPropagation();
339 } else if (special_key != true) {
339 } else if (special_key != true) {
340 this.close();
340 this.close();
341 this.editor.focus();
341 this.editor.focus();
342 //we give focus to the editor immediately and call sell in 50 ms
342 //we give focus to the editor immediately and call sell in 50 ms
343 setTimeout(function () {
343 setTimeout(function () {
344 that.carry_on_completion();
344 that.carry_on_completion();
345 }, 50);
345 }, 50);
346 }
346 }
347 }
347 }
348
348
349
349
350 IPython.Completer = Completer;
350 IPython.Completer = Completer;
351
351
352 return IPython;
352 return IPython;
353 }(IPython));
353 }(IPython));
General Comments 0
You need to be logged in to leave comments. Login now