Bug 790016 - Web console remote protocol sends more data than needed for completion; r=msucan

This commit is contained in:
Christos Stathis
2013-08-01 22:31:36 +03:00
parent be4d6d73b5
commit bc3cc4602d
4 changed files with 189 additions and 4 deletions

View File

@@ -144,6 +144,7 @@ MOCHITEST_BROWSER_FILES = \
browser_console_iframe_messages.js \
browser_console_variables_view_while_debugging_and_inspecting.js \
browser_webconsole_bug_686937_autocomplete_JSTerm_helpers.js \
browser_webconsole_cached_autocomplete.js \
head.js \
$(NULL)

View File

@@ -0,0 +1,125 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Tests that the cached autocomplete results are used when the new
// user input is a subset of the existing completion results.
const TEST_URI = "data:text/html;charset=utf8,<p>test cached autocompletion results";
let testDriver;
function test() {
requestLongerTimeout(2);
addTab(TEST_URI);
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
openConsole(null, function(hud) {
testDriver = testCompletion(hud);
testDriver.next();
});
}, true);
}
function testNext() {
executeSoon(function() {
testDriver.next();
});
}
function testCompletion(hud) {
let jsterm = hud.jsterm;
let input = jsterm.inputNode;
let popup = jsterm.autocompletePopup;
// Test if 'doc' gives 'document'
input.value = "doc";
input.setSelectionRange(3, 3);
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
yield undefined;
is(input.value, "doc", "'docu' completion (input.value)");
is(jsterm.completeNode.value, " ument", "'docu' completion (completeNode)");
// Test typing 'window.'.
input.value = "window.";
input.setSelectionRange(7, 7);
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
yield undefined;
ok(popup.getItems().length > 0, "'window.' gave a list of suggestions")
content.wrappedJSObject.docfoobar = true;
// Test typing 'window.doc'.
input.value = "window.doc";
input.setSelectionRange(10, 10);
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
yield undefined;
let newItems = popup.getItems();
ok(newItems.every(function(item) {
return item.label != "docfoobar";
}), "autocomplete cached results do not contain docfoobar. list has not been updated");
// Test that backspace does not cause a request to the server
input.value = "window.do";
input.setSelectionRange(9, 9);
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
yield undefined;
newItems = popup.getItems();
ok(newItems.every(function(item) {
return item.label != "docfoobar";
}), "autocomplete cached results do not contain docfoobar. list has not been updated");
delete content.wrappedJSObject.docfoobar;
// Test if 'window.getC' gives 'getComputedStyle'
input.value = "window."
input.setSelectionRange(7, 7);
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
yield undefined;
input.value = "window.getC";
input.setSelectionRange(11, 11);
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
yield undefined;
newItems = popup.getItems();
ok(!newItems.every(function(item) {
return item.label != "getComputedStyle";
}), "autocomplete results do contain getComputedStyle");
// Test if 'dump(d' gives non-zero results
input.value = "dump(d";
input.setSelectionRange(6, 6);
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
yield undefined;
ok(popup.getItems().length > 0, "'dump(d' gives non-zero results");
// Test that 'dump(window.)' works.
input.value = "dump(window.)";
input.setSelectionRange(12, 12);
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
yield undefined;
content.wrappedJSObject.docfoobar = true;
// Make sure 'dump(window.doc)' does not contain 'docfoobar'.
input.value = "dump(window.doc)";
input.setSelectionRange(15, 15);
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, testNext);
yield undefined;
newItems = popup.getItems();
ok(newItems.every(function(item) {
return item.label != "docfoobar";
}), "autocomplete cached results do not contain docfoobar. list has not been updated");
delete content.wrappedJSObject.docfoobar;
testDriver = null;
executeSoon(finishTest);
yield undefined;
}

View File

@@ -2844,6 +2844,21 @@ JSTerm.prototype = {
*/
lastCompletion: null,
/**
* Array that caches the user input suggestions received from the server.
* @private
* @type array
*/
_autocompleteCache: null,
/**
* The input that caused the last request to the server, whose response is
* cached in the _autocompleteCache array.
* @private
* @type string
*/
_autocompleteQuery: null,
/**
* The Web Console sidebar.
* @see this._createSidebar()
@@ -4125,11 +4140,46 @@ JSTerm.prototype = {
}
let requestId = gSequenceId();
let input = this.inputNode.value;
let cursor = this.inputNode.selectionStart;
let input = this.inputNode.value.substring(0, cursor);
let cache = this._autocompleteCache;
// If the current input starts with the previous input, then we already
// have a list of suggestions and we just need to filter the cached
// suggestions. When the current input ends with a non-alphanumeric
// character we ask the server again for suggestions.
// Check if last character is non-alphanumeric
if (!/[a-zA-Z0-9]$/.test(input)) {
this._autocompleteQuery = null;
this._autocompleteCache = null;
}
if (this._autocompleteQuery && input.startsWith(this._autocompleteQuery)) {
let filterBy = input;
// Find the last non-alphanumeric if exists.
let lastNonAlpha = input.match(/[^a-zA-Z0-9][a-zA-Z0-9]*$/);
// If input contains non-alphanumerics, use the part after the last one
// to filter the cache
if (lastNonAlpha) {
filterBy = input.substring(input.lastIndexOf(lastNonAlpha) + 1);
}
let newList = cache.sort().filter(function(l) {
return l.startsWith(filterBy);
});
this.lastCompletion = {
requestId: null,
completionType: aType,
value: null,
};
let response = { matches: newList, matchProp: filterBy };
this._receiveAutocompleteProperties(null, aCallback, response);
return;
}
// TODO: Bug 787986 - throttle/disable updates, deal with slow/high latency
// network connections.
this.lastCompletion = {
requestId: requestId,
completionType: aType,
@@ -4164,6 +4214,15 @@ JSTerm.prototype = {
return;
}
// Cache whatever came from the server if the last char is alphanumeric or '.'
let cursor = inputNode.selectionStart;
let inputUntilCursor = inputValue.substring(0, cursor);
if (aRequestId != null && /[a-zA-Z0-9.]$/.test(inputUntilCursor)) {
this._autocompleteCache = aMessage.matches;
this._autocompleteQuery = inputUntilCursor;
}
let matches = aMessage.matches;
let lastPart = aMessage.matchProp;
if (!matches.length) {

View File

@@ -614,7 +614,7 @@ const OPEN_CLOSE_BODY = {
"(": ")",
};
const MAX_COMPLETIONS = 256;
const MAX_COMPLETIONS = 1500;
/**
* Analyses a given string to find the last statement that is interesting for