This file is indexed.

/usr/lib/python2.7/dist-packages/notebook/static/notebook/js/completer.js is in python-notebook 5.2.2-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.

define([
    'jquery',
    'base/js/utils',
    'base/js/keyboard',
    'notebook/js/contexthint',
    'codemirror/lib/codemirror',
], function($, utils, keyboard, CodeMirror) {
    "use strict";

    // easier key mapping
    var keycodes = keyboard.keycodes;

    var prepend_n_prc = function(str, n) {
        for( var i =0 ; i< n ; i++){
            str = '%'+str ;
        }
        return str;
    };

    var _existing_completion = function(item, completion_array){
        for( var i=0; i < completion_array.length; i++) {
            if (completion_array[i].trim().substr(-item.length) == item) {
                return true;
            }
        }
        return false;
    };

    // what is the common start of all completions
    function shared_start(B, drop_prct) {
        if (B.length == 1) {
            return B[0];
        }
        var A = [];
        var common;
        var min_lead_prct = 10;
        for (var i = 0; i < B.length; i++) {
            var str = B[i].str;
            var localmin = 0;
            if(drop_prct === true){
                while ( str.substr(0, 1) == '%') {
                    localmin = localmin+1;
                    str = str.substring(1);
                }
            }
            min_lead_prct = Math.min(min_lead_prct, localmin);
            A.push(str);
        }

        if (A.length > 1) {
            var tem1, tem2, s;
            A = A.slice(0).sort();
            tem1 = A[0];
            s = tem1.length;
            tem2 = A.pop();
            while (s && tem2.indexOf(tem1) == -1) {
                tem1 = tem1.substring(0, --s);
            }
            if (tem1 === "" || tem2.indexOf(tem1) !== 0) {
                return {
                    str:prepend_n_prc('', min_lead_prct),
                    type: "computed",
                    from: B[0].from,
                    to: B[0].to
                    };
            }
            return {
                str: prepend_n_prc(tem1, min_lead_prct),
                type: "computed",
                from: B[0].from,
                to: B[0].to
            };
        }
        return null;
    }


    var Completer = function (cell, events) {
        this.cell = cell;
        this.editor = cell.code_mirror;
        var that = this;
        events.on('kernel_busy.Kernel', function () {
            that.skip_kernel_completion = true;
        });
        events.on('kernel_idle.Kernel', function () {
            that.skip_kernel_completion = false;
        });
    };

    Completer.prototype.startCompletion = function () {
        /**
         * call for a 'first' completion, that will set the editor and do some
         * special behavior like autopicking if only one completion available.
         */
        if (this.editor.somethingSelected()|| this.editor.getSelections().length > 1) return;
        this.done = false;
        // use to get focus back on opera
        this.carry_on_completion(true);
    };


    // easy access for julia to monkeypatch
    //
    Completer.reinvoke_re = /[%0-9a-z._/\\:~-]/i;

    Completer.prototype.reinvoke= function(pre_cursor, block, cursor){
        return Completer.reinvoke_re.test(pre_cursor);
    };

    /**
     *
     * pass true as parameter if this is the first invocation of the completer
     * this will prevent the completer to dissmiss itself if it is not on a
     * word boundary like pressing tab after a space, and make it autopick the
     * only choice if there is only one which prevent from popping the UI.  as
     * well as fast-forwarding the typing if all completion have a common
     * shared start
     **/
    Completer.prototype.carry_on_completion = function (first_invocation) {
        /**
         * Pass true as parameter if you want the completer to autopick when
         * only one completion. This function is automatically reinvoked at
         * each keystroke with first_invocation = false
         */
        var cur = this.editor.getCursor();
        var line = this.editor.getLine(cur.line);
        var pre_cursor = this.editor.getRange({
            line: cur.line,
            ch: cur.ch - 1
        }, cur);

        // we need to check that we are still on a word boundary
        // because while typing the completer is still reinvoking itself
        // so dismiss if we are on a "bad" caracter
        if (!this.reinvoke(pre_cursor) && !first_invocation) {
            this.close();
            return;
        }

        this.autopick = false;
        if (first_invocation) {
            this.autopick = true;
        }

        // We want a single cursor position.
        if (this.editor.somethingSelected()|| this.editor.getSelections().length > 1) {
            return;
        }

        // one kernel completion came back, finish_completing will be called with the results
        // we fork here and directly call finish completing if kernel is busy
        var cursor_pos = this.editor.indexFromPos(cur);
        var text = this.editor.getValue();
        cursor_pos = utils.js_idx_to_char_idx(cursor_pos, text);
        if (this.skip_kernel_completion) {
            this.finish_completing({ content: {
                matches: [],
                cursor_start: cursor_pos,
                cursor_end: cursor_pos,
            }});
        } else {
            this.cell.kernel.complete(text, cursor_pos,
                $.proxy(this.finish_completing, this)
            );
        }
    };

    Completer.prototype.finish_completing = function (msg) {
        /**
         * let's build a function that wrap all that stuff into what is needed
         * for the new completer:
         */
        var content = msg.content;
        var start = content.cursor_start;
        var end = content.cursor_end;
        var matches = content.matches;
        console.log(content);

        var cur = this.editor.getCursor();
        if (end === null) {
            // adapted message spec replies don't have cursor position info,
            // interpret end=null as current position,
            // and negative start relative to that
            end = this.editor.indexFromPos(cur);
            if (start === null) {
                start = end;
            } else if (start < 0) {
                start = end + start;
            }
        } else {
            // handle surrogate pairs
            var text = this.editor.getValue();
            end = utils.char_idx_to_js_idx(end, text);
            start = utils.char_idx_to_js_idx(start, text);
        }

        var results = CodeMirror.contextHint(this.editor);
        var filtered_results = [];
        //remove results from context completion
        //that are already in kernel completion
        var i;
        for (i=0; i < results.length; i++) {
            if (!_existing_completion(results[i].str, matches)) {
                filtered_results.push(results[i]);
            }
        }

        // append the introspection result, in order, at at the beginning of
        // the table and compute the replacement range from current cursor
        // positon and matched_text length.
        var from = this.editor.posFromIndex(start);
        var to = this.editor.posFromIndex(end);
        for (i = matches.length - 1; i >= 0; --i) {
            filtered_results.unshift({
                str: matches[i],
                type: "introspection",
                from: from,
                to: to
            });
        }

        // one the 2 sources results have been merge, deal with it
        this.raw_result = filtered_results;

        // if empty result return
        if (!this.raw_result || !this.raw_result.length) return;

        // When there is only one completion, use it directly.
        if (this.autopick && this.raw_result.length == 1) {
            this.insert(this.raw_result[0]);
            return;
        }

        if (this.raw_result.length == 1) {
            // test if first and only completion totally matches
            // what is typed, in this case dismiss
            var str = this.raw_result[0].str;
            var pre_cursor = this.editor.getRange({
                line: cur.line,
                ch: cur.ch - str.length
            }, cur);
            if (pre_cursor == str) {
                this.close();
                return;
            }
        }

        if (!this.visible) {
            this.complete = $('<div/>').addClass('completions');
            this.complete.attr('id', 'complete');

            // Currently webkit doesn't use the size attr correctly. See:
            // https://code.google.com/p/chromium/issues/detail?id=4579
            this.sel = $('<select/>')
                .attr('tabindex', -1)
                .attr('multiple', 'true');
            this.complete.append(this.sel);
            this.visible = true;
            $('body').append(this.complete);

            //build the container
            var that = this;
            this.sel.click(function () {
                that.pick();
                that.editor.focus();
            });
            this._handle_keydown = function (cm, event) {
                that.keydown(event);
            };
            this.editor.on('keydown', this._handle_keydown);
            this._handle_keypress = function (cm, event) {
                that.keypress(event);
            };
            this.editor.on('keypress', this._handle_keypress);
        }
        this.sel.attr('size', Math.min(10, this.raw_result.length));

        // After everything is on the page, compute the postion.
        // We put it above the code if it is too close to the bottom of the page.
        var pos = this.editor.cursorCoords(
            this.editor.posFromIndex(start)
        );
        var left = pos.left-3;
        var top;
        var cheight = this.complete.height();
        var wheight = $(window).height();
        if (pos.bottom+cheight+5 > wheight) {
            top = pos.top-cheight-4;
        } else {
            top = pos.bottom+1;
        }
        this.complete.css('left', left + 'px');
        this.complete.css('top', top + 'px');

        // Clear and fill the list.
        this.sel.text('');
        this.build_gui_list(this.raw_result);
        return true;
    };

    Completer.prototype.insert = function (completion) {
        this.editor.replaceRange(completion.str, completion.from, completion.to);
    };

    Completer.prototype.build_gui_list = function (completions) {
        for (var i = 0; i < completions.length; ++i) {
            var opt = $('<option/>').text(completions[i].str).addClass(completions[i].type);
            this.sel.append(opt);
        }
        this.sel.children().first().attr('selected', 'true');
        this.sel.scrollTop(0);
    };

    Completer.prototype.close = function () {
        this.done = true;
        $('#complete').remove();
        this.editor.off('keydown', this._handle_keydown);
        this.editor.off('keypress', this._handle_keypress);
        this.visible = false;
    };

    Completer.prototype.pick = function () {
        this.insert(this.raw_result[this.sel[0].selectedIndex]);
        this.close();
    };

    Completer.prototype.keydown = function (event) {
        var code = event.keyCode;

        // Enter
        var options;
        var index;
        if (code == keycodes.enter) {
            event.codemirrorIgnore = true;
            event._ipkmIgnore = true;
            event.preventDefault();
            this.pick();
        // Escape or backspace
        } else if (code == keycodes.esc || code == keycodes.backspace) {
            event.codemirrorIgnore = true;
            event._ipkmIgnore = true;
            event.preventDefault();
            this.close();
        } else if (code == keycodes.tab) {
            //all the fastforwarding operation,
            //Check that shared start is not null which can append with prefixed completion
            // like %pylab , pylab have no shred start, and ff will result in py<tab><tab>
            // to erase py
            var sh = shared_start(this.raw_result, true);
            if (sh.str !== '') {
                this.insert(sh);
            }
            this.close();
            this.carry_on_completion();
        } else if (code == keycodes.up || code == keycodes.down) {
            // need to do that to be able to move the arrow
            // when on the first or last line ofo a code cell
            event.codemirrorIgnore = true;
            event._ipkmIgnore = true;
            event.preventDefault();

            options = this.sel.find('option');
            index = this.sel[0].selectedIndex;
            if (code == keycodes.up) {
                index--;
            }
            if (code == keycodes.down) {
                index++;
            }
            index = Math.min(Math.max(index, 0), options.length-1);
            this.sel[0].selectedIndex = index;
        } else if (code == keycodes.pageup || code == keycodes.pagedown) {
            event._ipkmIgnore = true;

            options = this.sel.find('option');
            index = this.sel[0].selectedIndex;
            if (code == keycodes.pageup) {
                index -= 10; // As 10 is the hard coded size of the drop down menu
            } else {
                index += 10;
            }
            index = Math.min(Math.max(index, 0), options.length-1);
            this.sel[0].selectedIndex = index;
        } else if (code == keycodes.left || code == keycodes.right) {
            this.close();
        }
    };

    Completer.prototype.keypress = function (event) {
        /**
         * FIXME: This is a band-aid.
         * on keypress, trigger insertion of a single character.
         * This simulates the old behavior of completion as you type,
         * before events were disconnected and CodeMirror stopped
         * receiving events while the completer is focused.
         */
        
        var that = this;
        var code = event.keyCode;
        
        // don't handle keypress if it's not a character (arrows on FF)
        // or ENTER/TAB
        if (event.charCode === 0 ||
            code == keycodes.tab ||
            code == keycodes.enter
        ) return;
        
        this.close();
        this.editor.focus();
        setTimeout(function () {
            that.carry_on_completion();
        }, 50);
    };

    return {'Completer': Completer};
});