зеркало из https://github.com/mozilla/gecko-dev.git
Merge fx-team to central, a=merge
--HG-- extra : commitid : 3fYHYStKxoc
This commit is contained in:
Коммит
3a7310f16a
|
@ -13,7 +13,6 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource:///modules/MigrationUtils.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource://gre/modules/LoginHelper.jsm");
|
||||
|
||||
Cu.importGlobalProperties(['FileReader']);
|
||||
|
@ -275,9 +274,9 @@ CtypesVaultHelpers.prototype = {
|
|||
function hostIsIPAddress(aHost) {
|
||||
try {
|
||||
Services.eTLD.getBaseDomainFromHost(aHost);
|
||||
} catch (e if e.result == Cr.NS_ERROR_HOST_IS_IP_ADDRESS) {
|
||||
return true;
|
||||
} catch (e) {}
|
||||
} catch (e) {
|
||||
return e.result == Cr.NS_ERROR_HOST_IS_IP_ADDRESS;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -514,7 +513,7 @@ Cookies.prototype = {
|
|||
migrate(aCallback) {
|
||||
this.ctypesKernelHelpers = new CtypesKernelHelpers();
|
||||
|
||||
let cookiesGenerator = (function genCookie() {
|
||||
let cookiesGenerator = (function* genCookie() {
|
||||
let success = false;
|
||||
let folders = this._migrationType == MSMigrationUtils.MIGRATION_TYPE_EDGE ?
|
||||
this.__cookiesFolders : [this.__cookiesFolder];
|
||||
|
@ -792,12 +791,21 @@ WindowsVaultFormPasswords.prototype = {
|
|||
if (!_isIEOrEdgePassword(item.contents.schemaId.id)) {
|
||||
continue;
|
||||
}
|
||||
let url = item.contents.pResourceElement.contents.itemValue.readString();
|
||||
let realURL;
|
||||
try {
|
||||
realURL = Services.io.newURI(url, null, null);
|
||||
} catch (ex) { /* leave realURL as null */ }
|
||||
if (!realURL || ["http", "https", "ftp"].indexOf(realURL.scheme) == -1) {
|
||||
// Ignore items for non-URLs or URLs that aren't HTTP(S)/FTP
|
||||
continue;
|
||||
}
|
||||
|
||||
// if aOnlyCheckExists is set to true, the purpose of the call is to return true if there is at
|
||||
// least a password which is true in this case because a password was by now already found
|
||||
if (aOnlyCheckExists) {
|
||||
return true;
|
||||
}
|
||||
let url = item.contents.pResourceElement.contents.itemValue.readString();
|
||||
let username = item.contents.pIdentityElement.contents.itemValue.readString();
|
||||
// the current login credential object
|
||||
let credential = new ctypesVaultHelpers._structs.VAULT_ELEMENT.ptr;
|
||||
|
@ -824,7 +832,7 @@ WindowsVaultFormPasswords.prototype = {
|
|||
// create a new login
|
||||
let login = {
|
||||
username, password,
|
||||
hostname: NetUtil.newURI(url).prePath,
|
||||
hostname: realURL.prePath,
|
||||
timeCreated: creation,
|
||||
};
|
||||
LoginHelper.maybeImportLogin(login);
|
||||
|
|
|
@ -76,6 +76,8 @@ this.TabGroupsMigrator = {
|
|||
);
|
||||
}
|
||||
|
||||
// We always write this back to ensure that any spurious tab groups data is
|
||||
// removed:
|
||||
stateAsSupportsString.data = JSON.stringify(state);
|
||||
},
|
||||
|
||||
|
@ -99,15 +101,39 @@ this.TabGroupsMigrator = {
|
|||
}
|
||||
|
||||
let windowGroupData = new Map();
|
||||
let activeGroupID = null;
|
||||
let tabsWithoutGroup = [];
|
||||
for (let tab of win.tabs) {
|
||||
let group;
|
||||
// Get a string group ID:
|
||||
try {
|
||||
group = tab.extData && tab.extData["tabview-tab"] &&
|
||||
(JSON.parse(tab.extData["tabview-tab"]).groupID + "");
|
||||
let tabViewData = tab.extData && tab.extData["tabview-tab"] &&
|
||||
JSON.parse(tab.extData["tabview-tab"]);
|
||||
if (tabViewData && ("groupID" in tabViewData)) {
|
||||
group = tabViewData.groupID + "";
|
||||
}
|
||||
} catch (ex) {
|
||||
// Ignore tabs with no group info
|
||||
continue;
|
||||
// Ignore errors reading group info, treat as active group
|
||||
}
|
||||
if (!group) {
|
||||
// We didn't find group info. If we already have an active group,
|
||||
// pretend this is part of that group:
|
||||
if (activeGroupID) {
|
||||
group = activeGroupID;
|
||||
} else {
|
||||
if (!tabsWithoutGroup) {
|
||||
Cu.reportError("ERROR: the list of tabs without groups was " +
|
||||
"nulled out, but there's no active group ID? " +
|
||||
"This should never happen!");
|
||||
tabsWithoutGroup = [];
|
||||
}
|
||||
// Otherwise, add to the list of tabs with no group and move to
|
||||
// the next tab immediately. We'll add all these tabs at the
|
||||
// beginning of the active group as soon as we find a tab in it,
|
||||
// so as to preserve their order.
|
||||
tabsWithoutGroup.push(tab);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let groupData = windowGroupData.get(group);
|
||||
if (!groupData) {
|
||||
|
@ -119,11 +145,26 @@ this.TabGroupsMigrator = {
|
|||
if (!title) {
|
||||
groupData.anonGroupID = ++globalAnonGroupID;
|
||||
}
|
||||
// If this is the active group, set the active group ID and add
|
||||
// all the already-known tabs (that didn't list a group ID), if any.
|
||||
if (!activeGroupID && !tab.hidden) {
|
||||
activeGroupID = group;
|
||||
groupData.tabs = tabsWithoutGroup;
|
||||
tabsWithoutGroup = null;
|
||||
}
|
||||
windowGroupData.set(group, groupData);
|
||||
}
|
||||
groupData.tabs.push(tab);
|
||||
}
|
||||
|
||||
// If we found tabs but no active group, assume there's just 1 group:
|
||||
if (tabsWithoutGroup && tabsWithoutGroup.length) {
|
||||
windowGroupData.set("active group", {
|
||||
tabs: tabsWithoutGroup,
|
||||
anonGroupID: ++globalAnonGroupID,
|
||||
});
|
||||
}
|
||||
|
||||
allGroupData.set(win, windowGroupData);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,6 +80,91 @@ const TEST_STATES = {
|
|||
}
|
||||
],
|
||||
},
|
||||
TAB_WITHOUT_GROUP: {
|
||||
selectedWindow: 1,
|
||||
windows: [
|
||||
{
|
||||
tabs: [
|
||||
{
|
||||
entries: [{
|
||||
url: "about:robots",
|
||||
title: "Robots 1",
|
||||
}],
|
||||
index: 1,
|
||||
hidden: false,
|
||||
},
|
||||
{
|
||||
entries: [{
|
||||
url: "about:robots",
|
||||
title: "Robots 2",
|
||||
}],
|
||||
index: 1,
|
||||
hidden: false,
|
||||
extData: {
|
||||
"tabview-tab": "{\"groupID\":2}",
|
||||
},
|
||||
},
|
||||
{
|
||||
entries: [{
|
||||
url: "about:robots",
|
||||
title: "Robots 3",
|
||||
}],
|
||||
index: 1,
|
||||
hidden: true,
|
||||
extData: {
|
||||
"tabview-tab": "{\"groupID\":1}",
|
||||
},
|
||||
}
|
||||
],
|
||||
extData: {
|
||||
"tabview-group": "{\"2\":{}, \"1\": {}}",
|
||||
"tabview-groups": "{\"nextID\":20,\"activeGroupId\":2,\"totalNumber\":2}",
|
||||
"tabview-visibility": "false"
|
||||
},
|
||||
}
|
||||
],
|
||||
},
|
||||
ONLY_UNGROUPED_TABS: {
|
||||
selectedWindow: 1,
|
||||
windows: [
|
||||
{
|
||||
tabs: [
|
||||
{
|
||||
entries: [{
|
||||
url: "about:robots",
|
||||
title: "Robots 1",
|
||||
}],
|
||||
index: 1,
|
||||
hidden: false,
|
||||
},
|
||||
{
|
||||
entries: [{
|
||||
url: "about:robots",
|
||||
title: "Robots 2",
|
||||
}],
|
||||
index: 1,
|
||||
hidden: false,
|
||||
extData: {
|
||||
"tabview-tab": "{}",
|
||||
},
|
||||
},
|
||||
{
|
||||
entries: [{
|
||||
url: "about:robots",
|
||||
title: "Robots 3",
|
||||
}],
|
||||
index: 1,
|
||||
hidden: true,
|
||||
extData: {
|
||||
},
|
||||
}
|
||||
],
|
||||
extData: {
|
||||
"tabview-group": "{\"2\":{}}",
|
||||
},
|
||||
}
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
add_task(function* gatherGroupDataTest() {
|
||||
|
@ -89,17 +174,14 @@ add_task(function* gatherGroupDataTest() {
|
|||
Assert.equal(singleWinGroups.size, 2, "2 groups");
|
||||
let group2 = singleWinGroups.get("2");
|
||||
Assert.ok(!!group2, "group 2 should exist");
|
||||
if (group2) {
|
||||
Assert.equal(group2.tabs.length, 2, "2 tabs in group 2");
|
||||
Assert.equal(group2.tabGroupsMigrationTitle, "", "We don't assign titles to untitled groups");
|
||||
Assert.equal(group2.anonGroupID, "1", "We mark an untitled group with an anonymous id");
|
||||
}
|
||||
Assert.equal(group2.tabs.length, 2, "2 tabs in group 2");
|
||||
Assert.equal(group2.tabGroupsMigrationTitle, "", "We don't assign titles to untitled groups");
|
||||
Assert.equal(group2.anonGroupID, "1", "We mark an untitled group with an anonymous id");
|
||||
let group13 = singleWinGroups.get("13");
|
||||
if (group13) {
|
||||
Assert.equal(group13.tabs.length, 1, "1 tabs in group 13");
|
||||
Assert.equal(group13.tabGroupsMigrationTitle, "Foopy", "Group with title has correct title");
|
||||
Assert.ok(!("anonGroupID" in group13), "We don't mark a titled group with an anonymous id");
|
||||
}
|
||||
Assert.ok(!!group13, "group 13 should exist");
|
||||
Assert.equal(group13.tabs.length, 1, "1 tabs in group 13");
|
||||
Assert.equal(group13.tabGroupsMigrationTitle, "Foopy", "Group with title has correct title");
|
||||
Assert.ok(!("anonGroupID" in group13), "We don't mark a titled group with an anonymous id");
|
||||
});
|
||||
|
||||
add_task(function* bookmarkingTest() {
|
||||
|
@ -202,3 +284,27 @@ add_task(function* migrationPageDataTest() {
|
|||
},
|
||||
"Should have added expected tab at the end of the tab list.");
|
||||
});
|
||||
|
||||
add_task(function* correctMissingTabGroupInfo() {
|
||||
let stateClone = JSON.parse(JSON.stringify(TEST_STATES.TAB_WITHOUT_GROUP));
|
||||
let groupInfo = TabGroupsMigrator._gatherGroupData(stateClone);
|
||||
Assert.equal(groupInfo.size, 1, "Should have 1 window");
|
||||
let windowGroups = [...groupInfo][0][1];
|
||||
Assert.equal(windowGroups.size, 2, "Window should have 2 groups");
|
||||
let group2 = windowGroups.get("2");
|
||||
Assert.ok(group2, "Group 2 should exist");
|
||||
Assert.equal(group2.tabs.length, 2, "There should be 2 tabs in group 2");
|
||||
Assert.equal(group2.tabs[0].entries[0].title, "Robots 1", "The first tab of group 2 should be the tab with no group info.");
|
||||
});
|
||||
|
||||
add_task(function* dealWithNoGroupInfo() {
|
||||
let stateClone = JSON.parse(JSON.stringify(TEST_STATES.ONLY_UNGROUPED_TABS));
|
||||
let groupInfo = TabGroupsMigrator._gatherGroupData(stateClone);
|
||||
Assert.equal(groupInfo.size, 1, "Should have 1 window");
|
||||
let windowGroups = [...groupInfo][0][1];
|
||||
Assert.equal(windowGroups.size, 1, "Window should have 1 group");
|
||||
let fallbackActiveGroup = windowGroups.get("active group");
|
||||
Assert.ok(fallbackActiveGroup, "Fallback group should exist");
|
||||
Assert.equal(fallbackActiveGroup.tabs.length, 3, "There should be 3 tabs in the fallback group");
|
||||
});
|
||||
|
||||
|
|
|
@ -41,7 +41,10 @@ exports.TargetComponent = React.createClass({
|
|||
let workerActor = this.props.target.actorID;
|
||||
client.attachWorker(workerActor, (response, workerClient) => {
|
||||
gDevTools.showToolbox(TargetFactory.forWorker(workerClient),
|
||||
"jsdebugger", Toolbox.HostType.WINDOW);
|
||||
"jsdebugger", Toolbox.HostType.WINDOW)
|
||||
.then(toolbox => {
|
||||
toolbox.once("destroy", () => workerClient.detach());
|
||||
});
|
||||
});
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -10,3 +10,4 @@ support-files =
|
|||
|
||||
[browser_addons_install.js]
|
||||
[browser_service_workers.js]
|
||||
[browser_service_workers_timeout.js]
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// Service workers can't be loaded from chrome://,
|
||||
// but http:// is ok with dom.serviceWorkers.testing.enabled turned on.
|
||||
const HTTP_ROOT = CHROME_ROOT.replace("chrome://mochitests/content/",
|
||||
"http://mochi.test:8888/");
|
||||
const SERVICE_WORKER = HTTP_ROOT + "service-workers/empty-sw.js";
|
||||
const TAB_URL = HTTP_ROOT + "service-workers/empty-sw.html";
|
||||
|
||||
const SW_TIMEOUT = 1000;
|
||||
|
||||
function waitForWorkersUpdate(document) {
|
||||
return new Promise(done => {
|
||||
var observer = new MutationObserver(function(mutations) {
|
||||
observer.disconnect();
|
||||
done();
|
||||
});
|
||||
var target = document.getElementById("service-workers");
|
||||
observer.observe(target, { childList: true });
|
||||
});
|
||||
}
|
||||
|
||||
function assertHasWorker(expected, document, type, name) {
|
||||
let names = [...document.querySelectorAll("#" + type + " .target-name")];
|
||||
names = names.map(element => element.textContent);
|
||||
is(names.includes(name), expected, "The " + type + " url appears in the list: " + names);
|
||||
}
|
||||
|
||||
add_task(function *() {
|
||||
yield new Promise(done => {
|
||||
let options = {"set": [
|
||||
// Accept workers from mochitest's http
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
// Reduce the timeout to expose issues when service worker
|
||||
// freezing is broken
|
||||
["dom.serviceWorkers.idle_timeout", SW_TIMEOUT],
|
||||
["dom.serviceWorkers.idle_extended_timeout", SW_TIMEOUT],
|
||||
]};
|
||||
SpecialPowers.pushPrefEnv(options, done);
|
||||
});
|
||||
|
||||
let { tab, document } = yield openAboutDebugging("workers");
|
||||
|
||||
let swTab = yield addTab(TAB_URL);
|
||||
|
||||
yield waitForWorkersUpdate(document);
|
||||
|
||||
assertHasWorker(true, document, "service-workers", SERVICE_WORKER);
|
||||
|
||||
// XXX: race, the WorkerDebugger is ready whereas ServiceWorkerInfo
|
||||
// doesn't has the worker registered yet on its side
|
||||
yield new Promise(done => {
|
||||
require("sdk/timers").setTimeout(done, 250);
|
||||
});
|
||||
|
||||
// Retrieve the DEBUG button for the worker
|
||||
let names = [...document.querySelectorAll("#service-workers .target-name")];
|
||||
let name = names.filter(element => element.textContent === SERVICE_WORKER)[0];
|
||||
ok(name, "Found the service worker in the list");
|
||||
let debugBtn = name.parentNode.parentNode.querySelector("button");
|
||||
ok(debugBtn, "Found its debug button");
|
||||
|
||||
// Click on it and wait for the toolbox to be ready
|
||||
let onToolboxReady = new Promise(done => {
|
||||
gDevTools.once("toolbox-ready", function (e, toolbox) {
|
||||
done(toolbox);
|
||||
});
|
||||
});
|
||||
debugBtn.click();
|
||||
|
||||
let toolbox = yield onToolboxReady;
|
||||
|
||||
// Wait for more than the regular timeout,
|
||||
// so that if the worker freezing doesn't work,
|
||||
// it will be destroyed and removed from the list
|
||||
yield new Promise(done => {
|
||||
setTimeout(done, SW_TIMEOUT * 2);
|
||||
});
|
||||
|
||||
assertHasWorker(true, document, "service-workers", SERVICE_WORKER);
|
||||
|
||||
yield toolbox.destroy();
|
||||
toolbox = null;
|
||||
|
||||
// Now ensure that the worker is correctly destroyed
|
||||
// after we destroy the toolbox.
|
||||
// The list should update once it get destroyed.
|
||||
yield waitForWorkersUpdate(document);
|
||||
|
||||
assertHasWorker(false, document, "service-workers", SERVICE_WORKER);
|
||||
|
||||
// Finally, unregister the service worker itself
|
||||
// Use message manager to work with e10s
|
||||
let frameScript = function () {
|
||||
// Retrieve the `sw` promise created in the html page
|
||||
let { sw } = content.wrappedJSObject;
|
||||
sw.then(function (registration) {
|
||||
registration.unregister().then(function (success) {
|
||||
dump("SW unregistered: " + success + "\n");
|
||||
},
|
||||
function (e) {
|
||||
dump("SW not unregistered; " + e + "\n");
|
||||
});
|
||||
});
|
||||
};
|
||||
swTab.linkedBrowser.messageManager.loadFrameScript("data:,(" + encodeURIComponent(frameScript) + ")()", true);
|
||||
|
||||
yield removeTab(swTab);
|
||||
yield closeAboutDebugging(tab);
|
||||
});
|
|
@ -5,7 +5,7 @@ code, and optionally help with indentation.
|
|||
|
||||
# Upgrade
|
||||
|
||||
Currently used version is 5.7.0. To upgrade, download a new version of
|
||||
Currently used version is 5.9.0. To upgrade, download a new version of
|
||||
CodeMirror from the project's page [1] and replace all JavaScript and
|
||||
CSS files inside the codemirror directory [2].
|
||||
|
||||
|
|
|
@ -21,22 +21,28 @@
|
|||
}
|
||||
|
||||
CodeMirror.commands.toggleComment = function(cm) {
|
||||
var minLine = Infinity, ranges = cm.listSelections(), mode = null;
|
||||
cm.toggleComment();
|
||||
};
|
||||
|
||||
CodeMirror.defineExtension("toggleComment", function(options) {
|
||||
if (!options) options = noOptions;
|
||||
var cm = this;
|
||||
var minLine = Infinity, ranges = this.listSelections(), mode = null;
|
||||
for (var i = ranges.length - 1; i >= 0; i--) {
|
||||
var from = ranges[i].from(), to = ranges[i].to();
|
||||
if (from.line >= minLine) continue;
|
||||
if (to.line >= minLine) to = Pos(minLine, 0);
|
||||
minLine = from.line;
|
||||
if (mode == null) {
|
||||
if (cm.uncomment(from, to)) mode = "un";
|
||||
else { cm.lineComment(from, to); mode = "line"; }
|
||||
if (cm.uncomment(from, to, options)) mode = "un";
|
||||
else { cm.lineComment(from, to, options); mode = "line"; }
|
||||
} else if (mode == "un") {
|
||||
cm.uncomment(from, to);
|
||||
cm.uncomment(from, to, options);
|
||||
} else {
|
||||
cm.lineComment(from, to);
|
||||
cm.lineComment(from, to, options);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("lineComment", function(from, to, options) {
|
||||
if (!options) options = noOptions;
|
||||
|
@ -57,7 +63,14 @@
|
|||
|
||||
self.operation(function() {
|
||||
if (options.indent) {
|
||||
var baseString = firstLine.slice(0, firstNonWS(firstLine));
|
||||
var baseString = null;
|
||||
for (var i = from.line; i < end; ++i) {
|
||||
var line = self.getLine(i);
|
||||
var whitespace = line.slice(0, firstNonWS(line));
|
||||
if (baseString == null || baseString.length > whitespace.length) {
|
||||
baseString = whitespace;
|
||||
}
|
||||
}
|
||||
for (var i = from.line; i < end; ++i) {
|
||||
var line = self.getLine(i), cut = baseString.length;
|
||||
if (!blankLines && !nonWS.test(line)) continue;
|
||||
|
|
0
devtools/client/sourceeditor/codemirror/addon/comment/continuecomment.js
поставляемый
Normal file → Executable file
0
devtools/client/sourceeditor/codemirror/addon/comment/continuecomment.js
поставляемый
Normal file → Executable file
|
@ -25,8 +25,18 @@
|
|||
};
|
||||
|
||||
CodeMirror.defineExtension("showHint", function(options) {
|
||||
// We want a single cursor position.
|
||||
if (this.listSelections().length > 1 || this.somethingSelected()) return;
|
||||
options = parseOptions(this, this.getCursor("start"), options);
|
||||
var selections = this.listSelections()
|
||||
if (selections.length > 1) return;
|
||||
// By default, don't allow completion when something is selected.
|
||||
// A hint function can have a `supportsSelection` property to
|
||||
// indicate that it can handle selections.
|
||||
if (this.somethingSelected()) {
|
||||
if (!options.hint.supportsSelection) return;
|
||||
// Don't try with cross-line selections
|
||||
for (var i = 0; i < selections.length; i++)
|
||||
if (selections[i].head.line != selections[i].anchor.line) return;
|
||||
}
|
||||
|
||||
if (this.state.completionActive) this.state.completionActive.close();
|
||||
var completion = this.state.completionActive = new Completion(this, options);
|
||||
|
@ -38,12 +48,12 @@
|
|||
|
||||
function Completion(cm, options) {
|
||||
this.cm = cm;
|
||||
this.options = this.buildOptions(options);
|
||||
this.options = options;
|
||||
this.widget = null;
|
||||
this.debounce = 0;
|
||||
this.tick = 0;
|
||||
this.startPos = this.cm.getCursor();
|
||||
this.startLen = this.cm.getLine(this.startPos.line).length;
|
||||
this.startPos = this.cm.getCursor("start");
|
||||
this.startLen = this.cm.getLine(this.startPos.line).length - this.cm.getSelection().length;
|
||||
|
||||
var self = this;
|
||||
cm.on("cursorActivity", this.activityFunc = function() { self.cursorActivity(); });
|
||||
|
@ -124,20 +134,21 @@
|
|||
CodeMirror.signal(data, "shown");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
buildOptions: function(options) {
|
||||
var editor = this.cm.options.hintOptions;
|
||||
var out = {};
|
||||
for (var prop in defaultOptions) out[prop] = defaultOptions[prop];
|
||||
if (editor) for (var prop in editor)
|
||||
if (editor[prop] !== undefined) out[prop] = editor[prop];
|
||||
if (options) for (var prop in options)
|
||||
if (options[prop] !== undefined) out[prop] = options[prop];
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
function parseOptions(cm, pos, options) {
|
||||
var editor = cm.options.hintOptions;
|
||||
var out = {};
|
||||
for (var prop in defaultOptions) out[prop] = defaultOptions[prop];
|
||||
if (editor) for (var prop in editor)
|
||||
if (editor[prop] !== undefined) out[prop] = editor[prop];
|
||||
if (options) for (var prop in options)
|
||||
if (options[prop] !== undefined) out[prop] = options[prop];
|
||||
if (out.hint.resolve) out.hint = out.hint.resolve(cm, pos)
|
||||
return out;
|
||||
}
|
||||
|
||||
function getText(completion) {
|
||||
if (typeof completion == "string") return completion;
|
||||
else return completion.text;
|
||||
|
@ -284,6 +295,13 @@
|
|||
setTimeout(function(){cm.focus();}, 20);
|
||||
});
|
||||
|
||||
if (completion.options.completeOnSingleClick)
|
||||
CodeMirror.on(hints, "mousemove", function(e) {
|
||||
var elt = getHintElement(hints, e.target || e.srcElement);
|
||||
if (elt && elt.hintId != null)
|
||||
widget.changeActive(elt.hintId);
|
||||
});
|
||||
|
||||
CodeMirror.signal(data, "select", completions[0], hints.firstChild);
|
||||
return true;
|
||||
}
|
||||
|
@ -336,18 +354,61 @@
|
|||
}
|
||||
};
|
||||
|
||||
CodeMirror.registerHelper("hint", "auto", function(cm, options) {
|
||||
var helpers = cm.getHelpers(cm.getCursor(), "hint"), words;
|
||||
function applicableHelpers(cm, helpers) {
|
||||
if (!cm.somethingSelected()) return helpers
|
||||
var result = []
|
||||
for (var i = 0; i < helpers.length; i++)
|
||||
if (helpers[i].supportsSelection) result.push(helpers[i])
|
||||
return result
|
||||
}
|
||||
|
||||
function resolveAutoHints(cm, pos) {
|
||||
var helpers = cm.getHelpers(pos, "hint"), words
|
||||
if (helpers.length) {
|
||||
for (var i = 0; i < helpers.length; i++) {
|
||||
var cur = helpers[i](cm, options);
|
||||
if (cur && cur.list.length) return cur;
|
||||
var async = false, resolved
|
||||
for (var i = 0; i < helpers.length; i++) if (helpers[i].async) async = true
|
||||
if (async) {
|
||||
resolved = function(cm, callback, options) {
|
||||
var app = applicableHelpers(cm, helpers)
|
||||
function run(i, result) {
|
||||
if (i == app.length) return callback(null)
|
||||
var helper = app[i]
|
||||
if (helper.async) {
|
||||
helper(cm, function(result) {
|
||||
if (result) callback(result)
|
||||
else run(i + 1)
|
||||
}, options)
|
||||
} else {
|
||||
var result = helper(cm, options)
|
||||
if (result) callback(result)
|
||||
else run(i + 1)
|
||||
}
|
||||
}
|
||||
run(0)
|
||||
}
|
||||
resolved.async = true
|
||||
} else {
|
||||
resolved = function(cm, options) {
|
||||
var app = applicableHelpers(cm, helpers)
|
||||
for (var i = 0; i < app.length; i++) {
|
||||
var cur = app[i](cm, options)
|
||||
if (cur && cur.list.length) return cur
|
||||
}
|
||||
}
|
||||
}
|
||||
resolved.supportsSelection = true
|
||||
return resolved
|
||||
} else if (words = cm.getHelper(cm.getCursor(), "hintWords")) {
|
||||
if (words) return CodeMirror.hint.fromList(cm, {words: words});
|
||||
return function(cm) { return CodeMirror.hint.fromList(cm, {words: words}) }
|
||||
} else if (CodeMirror.hint.anyword) {
|
||||
return CodeMirror.hint.anyword(cm, options);
|
||||
return function(cm, options) { return CodeMirror.hint.anyword(cm, options) }
|
||||
} else {
|
||||
return function() {}
|
||||
}
|
||||
}
|
||||
|
||||
CodeMirror.registerHelper("hint", "auto", {
|
||||
resolve: resolveAutoHints
|
||||
});
|
||||
|
||||
CodeMirror.registerHelper("hint", "fromList", function(cm, options) {
|
||||
|
@ -376,7 +437,7 @@
|
|||
alignWithWord: true,
|
||||
closeCharacters: /[\s()\[\]{};:>,]/,
|
||||
closeOnUnfocus: true,
|
||||
completeOnSingleClick: false,
|
||||
completeOnSingleClick: true,
|
||||
container: null,
|
||||
customKeys: null,
|
||||
extraKeys: null
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
query.lastIndex = stream.pos;
|
||||
var match = query.exec(stream.string);
|
||||
if (match && match.index == stream.pos) {
|
||||
stream.pos += match[0].length;
|
||||
stream.pos += match[0].length || 1;
|
||||
return "searching";
|
||||
} else if (match) {
|
||||
stream.pos = match.index;
|
||||
|
|
|
@ -135,6 +135,7 @@
|
|||
},
|
||||
|
||||
destroy: function () {
|
||||
closeArgHints(this)
|
||||
if (this.worker) {
|
||||
this.worker.terminate();
|
||||
this.worker = null;
|
||||
|
|
|
@ -240,7 +240,9 @@
|
|||
});
|
||||
};
|
||||
|
||||
map[ctrl + "/"] = "toggleComment";
|
||||
map[ctrl + "/"] = function(cm) {
|
||||
cm.toggleComment({ indent: true });
|
||||
}
|
||||
|
||||
cmds[map[ctrl + "J"] = "joinLines"] = function(cm) {
|
||||
var ranges = cm.listSelections(), joined = [];
|
||||
|
|
|
@ -3208,7 +3208,7 @@
|
|||
return cur;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Returns the boundaries of the next word. If the cursor in the middle of
|
||||
* the word, then returns the boundaries of the current word, starting at
|
||||
* the cursor. If the cursor is at the start/end of a word, and we are going
|
||||
|
|
|
@ -21,27 +21,29 @@
|
|||
|
||||
// Kludges for bugs and behavior differences that can't be feature
|
||||
// detected are enabled based on userAgent etc sniffing.
|
||||
var userAgent = navigator.userAgent;
|
||||
var platform = navigator.platform;
|
||||
|
||||
var gecko = /gecko\/\d/i.test(navigator.userAgent);
|
||||
var ie_upto10 = /MSIE \d/.test(navigator.userAgent);
|
||||
var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent);
|
||||
var gecko = /gecko\/\d/i.test(userAgent);
|
||||
var ie_upto10 = /MSIE \d/.test(userAgent);
|
||||
var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent);
|
||||
var ie = ie_upto10 || ie_11up;
|
||||
var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]);
|
||||
var webkit = /WebKit\//.test(navigator.userAgent);
|
||||
var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent);
|
||||
var chrome = /Chrome\//.test(navigator.userAgent);
|
||||
var presto = /Opera\//.test(navigator.userAgent);
|
||||
var webkit = /WebKit\//.test(userAgent);
|
||||
var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent);
|
||||
var chrome = /Chrome\//.test(userAgent);
|
||||
var presto = /Opera\//.test(userAgent);
|
||||
var safari = /Apple Computer/.test(navigator.vendor);
|
||||
var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent);
|
||||
var phantom = /PhantomJS/.test(navigator.userAgent);
|
||||
var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent);
|
||||
var phantom = /PhantomJS/.test(userAgent);
|
||||
|
||||
var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
|
||||
var ios = /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent);
|
||||
// This is woefully incomplete. Suggestions for alternative methods welcome.
|
||||
var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent);
|
||||
var mac = ios || /Mac/.test(navigator.platform);
|
||||
var windows = /win/i.test(navigator.platform);
|
||||
var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent);
|
||||
var mac = ios || /Mac/.test(platform);
|
||||
var windows = /win/i.test(platform);
|
||||
|
||||
var presto_version = presto && navigator.userAgent.match(/Version\/(\d*\.\d*)/);
|
||||
var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/);
|
||||
if (presto_version) presto_version = Number(presto_version[1]);
|
||||
if (presto_version && presto_version >= 15) { presto = false; webkit = true; }
|
||||
// Some browsers use the wrong event properties to signal cmd/ctrl on OS X
|
||||
|
@ -408,7 +410,7 @@
|
|||
if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal");
|
||||
});
|
||||
|
||||
this.checkedOverlay = false;
|
||||
this.checkedZeroWidth = false;
|
||||
// Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
|
||||
if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px";
|
||||
}
|
||||
|
@ -443,29 +445,43 @@
|
|||
this.horiz.firstChild.style.width = "0";
|
||||
}
|
||||
|
||||
if (!this.checkedOverlay && measure.clientHeight > 0) {
|
||||
if (sWidth == 0) this.overlayHack();
|
||||
this.checkedOverlay = true;
|
||||
if (!this.checkedZeroWidth && measure.clientHeight > 0) {
|
||||
if (sWidth == 0) this.zeroWidthHack();
|
||||
this.checkedZeroWidth = true;
|
||||
}
|
||||
|
||||
return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0};
|
||||
},
|
||||
setScrollLeft: function(pos) {
|
||||
if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos;
|
||||
if (this.disableHoriz) this.enableZeroWidthBar(this.horiz, this.disableHoriz);
|
||||
},
|
||||
setScrollTop: function(pos) {
|
||||
if (this.vert.scrollTop != pos) this.vert.scrollTop = pos;
|
||||
if (this.disableVert) this.enableZeroWidthBar(this.vert, this.disableVert);
|
||||
},
|
||||
overlayHack: function() {
|
||||
zeroWidthHack: function() {
|
||||
var w = mac && !mac_geMountainLion ? "12px" : "18px";
|
||||
this.horiz.style.minHeight = this.vert.style.minWidth = w;
|
||||
var self = this;
|
||||
var barMouseDown = function(e) {
|
||||
if (e_target(e) != self.vert && e_target(e) != self.horiz)
|
||||
operation(self.cm, onMouseDown)(e);
|
||||
};
|
||||
on(this.vert, "mousedown", barMouseDown);
|
||||
on(this.horiz, "mousedown", barMouseDown);
|
||||
this.horiz.style.height = this.vert.style.width = w;
|
||||
this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none";
|
||||
this.disableHoriz = new Delayed;
|
||||
this.disableVert = new Delayed;
|
||||
},
|
||||
enableZeroWidthBar: function(bar, delay) {
|
||||
bar.style.pointerEvents = "auto";
|
||||
function maybeDisable() {
|
||||
// To find out whether the scrollbar is still visible, we
|
||||
// check whether the element under the pixel in the bottom
|
||||
// left corner of the scrollbar box is the scrollbar box
|
||||
// itself (when the bar is still visible) or its filler child
|
||||
// (when the bar is hidden). If it is still visible, we keep
|
||||
// it enabled, if it's hidden, we disable pointer events.
|
||||
var box = bar.getBoundingClientRect();
|
||||
var elt = document.elementFromPoint(box.left + 1, box.bottom - 1);
|
||||
if (elt != bar) bar.style.pointerEvents = "none";
|
||||
else delay.set(1000, maybeDisable);
|
||||
}
|
||||
delay.set(1000, maybeDisable);
|
||||
},
|
||||
clear: function() {
|
||||
var parent = this.horiz.parentNode;
|
||||
|
@ -3777,7 +3793,7 @@
|
|||
|
||||
// Determines whether an event happened in the gutter, and fires the
|
||||
// handlers for the corresponding event.
|
||||
function gutterEvent(cm, e, type, prevent, signalfn) {
|
||||
function gutterEvent(cm, e, type, prevent) {
|
||||
try { var mX = e.clientX, mY = e.clientY; }
|
||||
catch(e) { return false; }
|
||||
if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false;
|
||||
|
@ -3794,14 +3810,14 @@
|
|||
if (g && g.getBoundingClientRect().right >= mX) {
|
||||
var line = lineAtHeight(cm.doc, mY);
|
||||
var gutter = cm.options.gutters[i];
|
||||
signalfn(cm, type, cm, line, gutter, e);
|
||||
signal(cm, type, cm, line, gutter, e);
|
||||
return e_defaultPrevented(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clickInGutter(cm, e) {
|
||||
return gutterEvent(cm, e, "gutterClick", true, signalLater);
|
||||
return gutterEvent(cm, e, "gutterClick", true);
|
||||
}
|
||||
|
||||
// Kludge to work around strange IE behavior where it'll sometimes
|
||||
|
@ -3822,9 +3838,15 @@
|
|||
if (files && files.length && window.FileReader && window.File) {
|
||||
var n = files.length, text = Array(n), read = 0;
|
||||
var loadFile = function(file, i) {
|
||||
if (cm.options.allowDropFileTypes &&
|
||||
indexOf(cm.options.allowDropFileTypes, file.type) == -1)
|
||||
return;
|
||||
|
||||
var reader = new FileReader;
|
||||
reader.onload = operation(cm, function() {
|
||||
text[i] = reader.result;
|
||||
var content = reader.result;
|
||||
if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) content = "";
|
||||
text[i] = content;
|
||||
if (++read == n) {
|
||||
pos = clipPos(cm.doc, pos);
|
||||
var change = {from: pos, to: pos,
|
||||
|
@ -3966,8 +3988,9 @@
|
|||
|
||||
var display = cm.display, scroll = display.scroller;
|
||||
// Quit if there's nothing to scroll here
|
||||
if (!(dx && scroll.scrollWidth > scroll.clientWidth ||
|
||||
dy && scroll.scrollHeight > scroll.clientHeight)) return;
|
||||
var canScrollX = scroll.scrollWidth > scroll.clientWidth;
|
||||
var canScrollY = scroll.scrollHeight > scroll.clientHeight;
|
||||
if (!(dx && canScrollX || dy && canScrollY)) return;
|
||||
|
||||
// Webkit browsers on OS X abort momentum scrolls when the target
|
||||
// of the scroll event is removed from the scrollable element.
|
||||
|
@ -3991,10 +4014,15 @@
|
|||
// scrolling entirely here. It'll be slightly off from native, but
|
||||
// better than glitching out.
|
||||
if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
|
||||
if (dy)
|
||||
if (dy && canScrollY)
|
||||
setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight)));
|
||||
setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth)));
|
||||
e_preventDefault(e);
|
||||
// Only prevent default scrolling if vertical scrolling is
|
||||
// actually possible. Otherwise, it causes vertical scroll
|
||||
// jitter on OSX trackpads when deltaX is small and deltaY
|
||||
// is large (issue #3579)
|
||||
if (!dy || (dy && canScrollY))
|
||||
e_preventDefault(e);
|
||||
display.wheelStartX = null; // Abort measurement, if in progress
|
||||
return;
|
||||
}
|
||||
|
@ -4222,12 +4250,13 @@
|
|||
// right-click take effect on it.
|
||||
function onContextMenu(cm, e) {
|
||||
if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return;
|
||||
if (signalDOMEvent(cm, e, "contextmenu")) return;
|
||||
cm.display.input.onContextMenu(e);
|
||||
}
|
||||
|
||||
function contextMenuInGutter(cm, e) {
|
||||
if (!hasHandler(cm, "gutterContextMenu")) return false;
|
||||
return gutterEvent(cm, e, "gutterContextMenu", false, signal);
|
||||
return gutterEvent(cm, e, "gutterContextMenu", false);
|
||||
}
|
||||
|
||||
// UPDATING
|
||||
|
@ -5405,6 +5434,7 @@
|
|||
});
|
||||
option("disableInput", false, function(cm, val) {if (!val) cm.display.input.reset();}, true);
|
||||
option("dragDrop", true, dragDropChanged);
|
||||
option("allowDropFileTypes", null);
|
||||
|
||||
option("cursorBlinkRate", 530);
|
||||
option("cursorScrollMargin", 0);
|
||||
|
@ -5709,8 +5739,8 @@
|
|||
var range = cm.listSelections()[i];
|
||||
cm.replaceRange(cm.doc.lineSeparator(), range.anchor, range.head, "+input");
|
||||
cm.indentLine(range.from().line + 1, null, true);
|
||||
ensureCursorVisible(cm);
|
||||
}
|
||||
ensureCursorVisible(cm);
|
||||
});
|
||||
},
|
||||
toggleOverwrite: function(cm) {cm.toggleOverwrite();}
|
||||
|
@ -7059,7 +7089,7 @@
|
|||
spanEndStyle = "";
|
||||
}
|
||||
if (m.className) spanStyle += " " + m.className;
|
||||
if (m.css) css = m.css;
|
||||
if (m.css) css = (css ? css + ";" : "") + m.css;
|
||||
if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
|
||||
if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle;
|
||||
if (m.title && !title) title = m.title;
|
||||
|
@ -7328,6 +7358,7 @@
|
|||
this.id = ++nextDocId;
|
||||
this.modeOption = mode;
|
||||
this.lineSep = lineSep;
|
||||
this.extend = false;
|
||||
|
||||
if (typeof text == "string") text = this.splitLines(text);
|
||||
updateDoc(this, {from: start, to: start, text: text});
|
||||
|
@ -7543,7 +7574,7 @@
|
|||
removeLineWidget: function(widget) { widget.clear(); },
|
||||
|
||||
markText: function(from, to, options) {
|
||||
return markText(this, clipPos(this, from), clipPos(this, to), options, "range");
|
||||
return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range");
|
||||
},
|
||||
setBookmark: function(pos, options) {
|
||||
var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
|
||||
|
@ -8104,24 +8135,30 @@
|
|||
}
|
||||
};
|
||||
|
||||
var noHandlers = []
|
||||
function getHandlers(emitter, type, copy) {
|
||||
var arr = emitter._handlers && emitter._handlers[type]
|
||||
if (copy) return arr && arr.length > 0 ? arr.slice() : noHandlers
|
||||
else return arr || noHandlers
|
||||
}
|
||||
|
||||
var off = CodeMirror.off = function(emitter, type, f) {
|
||||
if (emitter.removeEventListener)
|
||||
emitter.removeEventListener(type, f, false);
|
||||
else if (emitter.detachEvent)
|
||||
emitter.detachEvent("on" + type, f);
|
||||
else {
|
||||
var arr = emitter._handlers && emitter._handlers[type];
|
||||
if (!arr) return;
|
||||
for (var i = 0; i < arr.length; ++i)
|
||||
if (arr[i] == f) { arr.splice(i, 1); break; }
|
||||
var handlers = getHandlers(emitter, type, false)
|
||||
for (var i = 0; i < handlers.length; ++i)
|
||||
if (handlers[i] == f) { handlers.splice(i, 1); break; }
|
||||
}
|
||||
};
|
||||
|
||||
var signal = CodeMirror.signal = function(emitter, type /*, values...*/) {
|
||||
var arr = emitter._handlers && emitter._handlers[type];
|
||||
if (!arr) return;
|
||||
var handlers = getHandlers(emitter, type, true)
|
||||
if (!handlers.length) return;
|
||||
var args = Array.prototype.slice.call(arguments, 2);
|
||||
for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args);
|
||||
for (var i = 0; i < handlers.length; ++i) handlers[i].apply(null, args);
|
||||
};
|
||||
|
||||
var orphanDelayedCallbacks = null;
|
||||
|
@ -8134,8 +8171,8 @@
|
|||
// them to be executed when the last operation ends, or, if no
|
||||
// operation is active, when a timeout fires.
|
||||
function signalLater(emitter, type /*, values...*/) {
|
||||
var arr = emitter._handlers && emitter._handlers[type];
|
||||
if (!arr) return;
|
||||
var arr = getHandlers(emitter, type, false)
|
||||
if (!arr.length) return;
|
||||
var args = Array.prototype.slice.call(arguments, 2), list;
|
||||
if (operationGroup) {
|
||||
list = operationGroup.delayedCallbacks;
|
||||
|
@ -8175,8 +8212,7 @@
|
|||
}
|
||||
|
||||
function hasHandler(emitter, type) {
|
||||
var arr = emitter._handlers && emitter._handlers[type];
|
||||
return arr && arr.length > 0;
|
||||
return getHandlers(emitter, type).length > 0
|
||||
}
|
||||
|
||||
// Add on and off methods to a constructor's prototype, to make
|
||||
|
@ -8830,7 +8866,7 @@
|
|||
|
||||
// THE END
|
||||
|
||||
CodeMirror.version = "5.7.0";
|
||||
CodeMirror.version = "5.9.0";
|
||||
|
||||
return CodeMirror;
|
||||
});
|
||||
|
|
|
@ -25,8 +25,12 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
|
|||
multiLineStrings = parserConfig.multiLineStrings,
|
||||
indentStatements = parserConfig.indentStatements !== false,
|
||||
indentSwitch = parserConfig.indentSwitch !== false,
|
||||
namespaceSeparator = parserConfig.namespaceSeparator;
|
||||
var isOperatorChar = /[+\-*&%=<>!?|\/]/;
|
||||
namespaceSeparator = parserConfig.namespaceSeparator,
|
||||
isPunctuationChar = parserConfig.isPunctuationChar || /[\[\]{}\(\),;\:\.]/,
|
||||
numberStart = parserConfig.numberStart || /[\d\.]/,
|
||||
number = parserConfig.number || /^(?:0x[a-f\d]+|0b[01]+|(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?)(u|ll?|l|f)?/i,
|
||||
isOperatorChar = parserConfig.isOperatorChar || /[+\-*&%=<>!?|\/]/,
|
||||
endStatement = parserConfig.endStatement || /^[;:,]$/;
|
||||
|
||||
var curPunc, isDefKeyword;
|
||||
|
||||
|
@ -40,13 +44,14 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
|
|||
state.tokenize = tokenString(ch);
|
||||
return state.tokenize(stream, state);
|
||||
}
|
||||
if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
|
||||
if (isPunctuationChar.test(ch)) {
|
||||
curPunc = ch;
|
||||
return null;
|
||||
}
|
||||
if (/\d/.test(ch)) {
|
||||
stream.eatWhile(/[\w\.]/);
|
||||
return "number";
|
||||
if (numberStart.test(ch)) {
|
||||
stream.backUp(1)
|
||||
if (stream.match(number)) return "number"
|
||||
stream.next()
|
||||
}
|
||||
if (ch == "/") {
|
||||
if (stream.eat("*")) {
|
||||
|
@ -67,17 +72,17 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
|
|||
stream.eatWhile(/[\w\$_\xa1-\uffff]/);
|
||||
|
||||
var cur = stream.current();
|
||||
if (keywords.propertyIsEnumerable(cur)) {
|
||||
if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
|
||||
if (defKeywords.propertyIsEnumerable(cur)) isDefKeyword = true;
|
||||
if (contains(keywords, cur)) {
|
||||
if (contains(blockKeywords, cur)) curPunc = "newstatement";
|
||||
if (contains(defKeywords, cur)) isDefKeyword = true;
|
||||
return "keyword";
|
||||
}
|
||||
if (types.propertyIsEnumerable(cur)) return "variable-3";
|
||||
if (builtin.propertyIsEnumerable(cur)) {
|
||||
if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
|
||||
if (contains(types, cur)) return "variable-3";
|
||||
if (contains(builtin, cur)) {
|
||||
if (contains(blockKeywords, cur)) curPunc = "newstatement";
|
||||
return "builtin";
|
||||
}
|
||||
if (atoms.propertyIsEnumerable(cur)) return "atom";
|
||||
if (contains(atoms, cur)) return "atom";
|
||||
return "variable";
|
||||
}
|
||||
|
||||
|
@ -168,8 +173,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
|
|||
if (style == "comment" || style == "meta") return style;
|
||||
if (ctx.align == null) ctx.align = true;
|
||||
|
||||
if ((curPunc == ";" || curPunc == ":" || curPunc == ","))
|
||||
while (isStatement(state.context.type)) popContext(state);
|
||||
if (endStatement.test(curPunc)) while (isStatement(state.context.type)) popContext(state);
|
||||
else if (curPunc == "{") pushContext(state, stream.column(), "}");
|
||||
else if (curPunc == "[") pushContext(state, stream.column(), "]");
|
||||
else if (curPunc == "(") pushContext(state, stream.column(), ")");
|
||||
|
@ -212,8 +216,16 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
|
|||
if (state.tokenize != tokenBase && state.tokenize != null) return CodeMirror.Pass;
|
||||
var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
|
||||
if (isStatement(ctx.type) && firstChar == "}") ctx = ctx.prev;
|
||||
if (hooks.indent) {
|
||||
var hook = hooks.indent(state, ctx, textAfter);
|
||||
if (typeof hook == "number") return hook
|
||||
}
|
||||
var closing = firstChar == ctx.type;
|
||||
var switchBlock = ctx.prev && ctx.prev.type == "switchstatement";
|
||||
if (parserConfig.allmanIndentation && /[{(]/.test(firstChar)) {
|
||||
while (ctx.type != "top" && ctx.type != "}") ctx = ctx.prev
|
||||
return ctx.indented
|
||||
}
|
||||
if (isStatement(ctx.type))
|
||||
return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit);
|
||||
if (ctx.align && (!dontAlignCalls || ctx.type != ")"))
|
||||
|
@ -238,9 +250,15 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
|
|||
for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
|
||||
return obj;
|
||||
}
|
||||
function contains(words, word) {
|
||||
if (typeof words === "function") {
|
||||
return words(word);
|
||||
} else {
|
||||
return words.propertyIsEnumerable(word);
|
||||
}
|
||||
}
|
||||
var cKeywords = "auto if break case register continue return default do sizeof " +
|
||||
"static else struct switch extern typedef float union for " +
|
||||
"goto while enum const volatile";
|
||||
"static else struct switch extern typedef union for goto while enum const volatile";
|
||||
var cTypes = "int long char short double float unsigned signed void size_t ptrdiff_t";
|
||||
|
||||
function cppHook(stream, state) {
|
||||
|
@ -413,6 +431,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
|
|||
defKeywords: words("class interface package enum"),
|
||||
typeFirstDefinitions: true,
|
||||
atoms: words("true false null"),
|
||||
endStatement: /^[;:]$/,
|
||||
hooks: {
|
||||
"@": function(stream) {
|
||||
stream.eatWhile(/[\w\$_]/);
|
||||
|
@ -468,7 +487,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
|
|||
keywords: words(
|
||||
|
||||
/* scala */
|
||||
"abstract case catch class def do else extends false final finally for forSome if " +
|
||||
"abstract case catch class def do else extends final finally for forSome if " +
|
||||
"implicit import lazy match new null object override package private protected return " +
|
||||
"sealed super this throw trait try type val var while with yield _ : = => <- <: " +
|
||||
"<% >: # @ " +
|
||||
|
@ -516,6 +535,59 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
|
|||
modeProps: {closeBrackets: {triples: '"'}}
|
||||
});
|
||||
|
||||
function tokenKotlinString(tripleString){
|
||||
return function (stream, state) {
|
||||
var escaped = false, next, end = false;
|
||||
while (!stream.eol()) {
|
||||
if (!tripleString && !escaped && stream.match('"') ) {end = true; break;}
|
||||
if (tripleString && stream.match('"""')) {end = true; break;}
|
||||
next = stream.next();
|
||||
if(!escaped && next == "$" && stream.match('{'))
|
||||
stream.skipTo("}");
|
||||
escaped = !escaped && next == "\\" && !tripleString;
|
||||
}
|
||||
if (end || !tripleString)
|
||||
state.tokenize = null;
|
||||
return "string";
|
||||
}
|
||||
}
|
||||
|
||||
def("text/x-kotlin", {
|
||||
name: "clike",
|
||||
keywords: words(
|
||||
/*keywords*/
|
||||
"package as typealias class interface this super val " +
|
||||
"var fun for is in This throw return " +
|
||||
"break continue object if else while do try when !in !is as? " +
|
||||
|
||||
/*soft keywords*/
|
||||
"file import where by get set abstract enum open inner override private public internal " +
|
||||
"protected catch finally out final vararg reified dynamic companion constructor init " +
|
||||
"sealed field property receiver param sparam lateinit data inline noinline tailrec " +
|
||||
"external annotation crossinline const operator infix"
|
||||
),
|
||||
types: words(
|
||||
/* package java.lang */
|
||||
"Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " +
|
||||
"Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " +
|
||||
"Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " +
|
||||
"StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void"
|
||||
),
|
||||
intendSwitch: false,
|
||||
indentStatements: false,
|
||||
multiLineStrings: true,
|
||||
blockKeywords: words("catch class do else finally for if where try while enum"),
|
||||
defKeywords: words("class val var object package interface fun"),
|
||||
atoms: words("true false null this"),
|
||||
hooks: {
|
||||
'"': function(stream, state) {
|
||||
state.tokenize = tokenKotlinString(stream.match('""'));
|
||||
return state.tokenize(stream, state);
|
||||
}
|
||||
},
|
||||
modeProps: {closeBrackets: {triples: '"'}}
|
||||
});
|
||||
|
||||
def(["x-shader/x-vertex", "x-shader/x-fragment"], {
|
||||
name: "clike",
|
||||
keywords: words("sampler1D sampler2D sampler3D samplerCube " +
|
||||
|
@ -598,7 +670,10 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
|
|||
stream.eatWhile(/[\w\$]/);
|
||||
return "keyword";
|
||||
},
|
||||
"#": cppHook
|
||||
"#": cppHook,
|
||||
indent: function(_state, ctx, textAfter) {
|
||||
if (ctx.type == "statement" && /^@\w/.test(textAfter)) return ctx.indented
|
||||
}
|
||||
},
|
||||
modeProps: {fold: "brace"}
|
||||
});
|
||||
|
@ -616,4 +691,85 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
|
|||
modeProps: {fold: ["brace", "include"]}
|
||||
});
|
||||
|
||||
// Ceylon Strings need to deal with interpolation
|
||||
var stringTokenizer = null;
|
||||
function tokenCeylonString(type) {
|
||||
return function(stream, state) {
|
||||
var escaped = false, next, end = false;
|
||||
while (!stream.eol()) {
|
||||
if (!escaped && stream.match('"') &&
|
||||
(type == "single" || stream.match('""'))) {
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
if (!escaped && stream.match('``')) {
|
||||
stringTokenizer = tokenCeylonString(type);
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
next = stream.next();
|
||||
escaped = type == "single" && !escaped && next == "\\";
|
||||
}
|
||||
if (end)
|
||||
state.tokenize = null;
|
||||
return "string";
|
||||
}
|
||||
}
|
||||
|
||||
def("text/x-ceylon", {
|
||||
name: "clike",
|
||||
keywords: words("abstracts alias assembly assert assign break case catch class continue dynamic else" +
|
||||
" exists extends finally for function given if import in interface is let module new" +
|
||||
" nonempty object of out outer package return satisfies super switch then this throw" +
|
||||
" try value void while"),
|
||||
types: function(word) {
|
||||
// In Ceylon all identifiers that start with an uppercase are types
|
||||
var first = word.charAt(0);
|
||||
return (first === first.toUpperCase() && first !== first.toLowerCase());
|
||||
},
|
||||
blockKeywords: words("case catch class dynamic else finally for function if interface module new object switch try while"),
|
||||
defKeywords: words("class dynamic function interface module object package value"),
|
||||
builtin: words("abstract actual aliased annotation by default deprecated doc final formal late license" +
|
||||
" native optional sealed see serializable shared suppressWarnings tagged throws variable"),
|
||||
isPunctuationChar: /[\[\]{}\(\),;\:\.`]/,
|
||||
isOperatorChar: /[+\-*&%=<>!?|^~:\/]/,
|
||||
numberStart: /[\d#$]/,
|
||||
number: /^(?:#[\da-fA-F_]+|\$[01_]+|[\d_]+[kMGTPmunpf]?|[\d_]+\.[\d_]+(?:[eE][-+]?\d+|[kMGTPmunpf]|)|)/i,
|
||||
multiLineStrings: true,
|
||||
typeFirstDefinitions: true,
|
||||
atoms: words("true false null larger smaller equal empty finished"),
|
||||
indentSwitch: false,
|
||||
styleDefs: false,
|
||||
hooks: {
|
||||
"@": function(stream) {
|
||||
stream.eatWhile(/[\w\$_]/);
|
||||
return "meta";
|
||||
},
|
||||
'"': function(stream, state) {
|
||||
state.tokenize = tokenCeylonString(stream.match('""') ? "triple" : "single");
|
||||
return state.tokenize(stream, state);
|
||||
},
|
||||
'`': function(stream, state) {
|
||||
if (!stringTokenizer || !stream.match('`')) return false;
|
||||
state.tokenize = stringTokenizer;
|
||||
stringTokenizer = null;
|
||||
return state.tokenize(stream, state);
|
||||
},
|
||||
"'": function(stream) {
|
||||
stream.eatWhile(/[\w\$_\xa1-\uffff]/);
|
||||
return "atom";
|
||||
},
|
||||
token: function(_stream, state, style) {
|
||||
if ((style == "variable" || style == "variable-3") &&
|
||||
state.prevToken == ".") {
|
||||
return "variable-2";
|
||||
}
|
||||
}
|
||||
},
|
||||
modeProps: {
|
||||
fold: ["brace", "import"],
|
||||
closeBrackets: {triples: '"'}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -228,7 +228,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
|
|||
if (type == "}" || type == "{") return popAndPass(type, stream, state);
|
||||
if (type == "(") return pushContext(state, stream, "parens");
|
||||
|
||||
if (type == "hash" && !/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(stream.current())) {
|
||||
if (type == "hash" && !/^#([0-9a-fA-f]{3,4}|[0-9a-fA-f]{6}|[0-9a-fA-f]{8})$/.test(stream.current())) {
|
||||
override += " error";
|
||||
} else if (type == "word") {
|
||||
wordAsValue(stream);
|
||||
|
@ -275,6 +275,8 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
|
|||
if (type == "}" || type == ";") return popAndPass(type, stream, state);
|
||||
if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top");
|
||||
|
||||
if (type == "interpolation") return pushContext(state, stream, "interpolation");
|
||||
|
||||
if (type == "word") {
|
||||
var word = stream.current().toLowerCase();
|
||||
if (word == "only" || word == "not" || word == "and" || word == "or")
|
||||
|
|
|
@ -30,14 +30,14 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
|
||||
var jsKeywords = {
|
||||
"if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
|
||||
"return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C, "debugger": C,
|
||||
"return": C, "break": C, "continue": C, "new": kw("new"), "delete": C, "throw": C, "debugger": C,
|
||||
"var": kw("var"), "const": kw("var"), "let": kw("var"),
|
||||
"async": kw("async"), "function": kw("function"), "catch": kw("catch"),
|
||||
"function": kw("function"), "catch": kw("catch"),
|
||||
"for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
|
||||
"in": operator, "typeof": operator, "instanceof": operator,
|
||||
"true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
|
||||
"this": kw("this"), "class": kw("class"), "super": kw("atom"),
|
||||
"await": C, "yield": C, "export": kw("export"), "import": kw("import"), "extends": C
|
||||
"yield": C, "export": kw("export"), "import": kw("import"), "extends": C
|
||||
};
|
||||
|
||||
// Extend the 'normal' keywords with the TypeScript language extensions
|
||||
|
@ -56,7 +56,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
"static": kw("static"),
|
||||
|
||||
// types
|
||||
"string": type, "number": type, "bool": type, "any": type
|
||||
"string": type, "number": type, "boolean": type, "any": type
|
||||
};
|
||||
|
||||
for (var attr in tsKeywords) {
|
||||
|
@ -121,8 +121,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
} else if (stream.eat("/")) {
|
||||
stream.skipToEnd();
|
||||
return ret("comment", "comment");
|
||||
} else if (state.lastType == "operator" || state.lastType == "keyword c" ||
|
||||
state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType)) {
|
||||
} else if (/^(?:operator|sof|keyword c|case|new|[\[{}\(,;:])$/.test(state.lastType)) {
|
||||
readRegexp(stream);
|
||||
stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/);
|
||||
return ret("regexp", "string-2");
|
||||
|
@ -281,8 +280,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
return false;
|
||||
}
|
||||
var state = cx.state;
|
||||
cx.marked = "def";
|
||||
if (state.context) {
|
||||
cx.marked = "def";
|
||||
if (inList(state.localVars)) return;
|
||||
state.localVars = {name: varname, next: state.localVars};
|
||||
} else {
|
||||
|
@ -373,14 +372,14 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
|
||||
var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
|
||||
if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
|
||||
if (type == "async") return cont(expression);
|
||||
if (type == "function") return cont(functiondef, maybeop);
|
||||
if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
|
||||
if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, expect(")"), poplex, maybeop);
|
||||
if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
|
||||
if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
|
||||
if (type == "{") return contCommasep(objprop, "}", null, maybeop);
|
||||
if (type == "quasi") { return pass(quasi, maybeop); }
|
||||
if (type == "quasi") return pass(quasi, maybeop);
|
||||
if (type == "new") return cont(maybeTarget(noComma));
|
||||
return cont();
|
||||
}
|
||||
function maybeexpression(type) {
|
||||
|
@ -431,6 +430,18 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
findFatArrow(cx.stream, cx.state);
|
||||
return pass(type == "{" ? statement : expressionNoComma);
|
||||
}
|
||||
function maybeTarget(noComma) {
|
||||
return function(type) {
|
||||
if (type == ".") return cont(noComma ? targetNoComma : target);
|
||||
else return pass(noComma ? expressionNoComma : expression);
|
||||
};
|
||||
}
|
||||
function target(_, value) {
|
||||
if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorComma); }
|
||||
}
|
||||
function targetNoComma(_, value) {
|
||||
if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorNoComma); }
|
||||
}
|
||||
function maybelabel(type) {
|
||||
if (type == ":") return cont(poplex, statement);
|
||||
return pass(maybeoperatorComma, expect(";"), poplex);
|
||||
|
@ -439,9 +450,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
if (type == "variable") {cx.marked = "property"; return cont();}
|
||||
}
|
||||
function objprop(type, value) {
|
||||
if (type == "async") {
|
||||
return cont(objprop);
|
||||
} else if (type == "variable" || cx.style == "keyword") {
|
||||
if (type == "variable" || cx.style == "keyword") {
|
||||
cx.marked = "property";
|
||||
if (value == "get" || value == "set") return cont(getterSetter);
|
||||
return cont(afterprop);
|
||||
|
@ -452,6 +461,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
return cont(afterprop);
|
||||
} else if (type == "[") {
|
||||
return cont(expression, expect("]"), afterprop);
|
||||
} else if (type == "spread") {
|
||||
return cont(expression);
|
||||
}
|
||||
}
|
||||
function getterSetter(type) {
|
||||
|
@ -501,6 +512,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
}
|
||||
function pattern(type, value) {
|
||||
if (type == "variable") { register(value); return cont(); }
|
||||
if (type == "spread") return cont(pattern);
|
||||
if (type == "[") return contCommasep(pattern, "]");
|
||||
if (type == "{") return contCommasep(proppattern, "}");
|
||||
}
|
||||
|
@ -510,6 +522,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
|||
return cont(maybeAssign);
|
||||
}
|
||||
if (type == "variable") cx.marked = "property";
|
||||
if (type == "spread") return cont(pattern);
|
||||
return cont(expect(":"), pattern, maybeAssign);
|
||||
}
|
||||
function maybeAssign(_type, value) {
|
||||
|
|
|
@ -79,7 +79,7 @@ namespace = "comment_";
|
|||
|
||||
test("indented", "javascript", function(cm) {
|
||||
cm.lineComment(Pos(1, 0), Pos(2), {indent: true});
|
||||
}, simpleProg, "function foo() {\n // return bar;\n // }");
|
||||
}, simpleProg, "function foo() {\n// return bar;\n// }");
|
||||
|
||||
test("singleEmptyLine", "javascript", function(cm) {
|
||||
cm.setCursor(1);
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
var code;
|
||||
for (var c in CodeMirror.keyNames)
|
||||
if (CodeMirror.keyNames[c] == key) { code = c; break; }
|
||||
if (c == null) throw new Error("Unknown key: " + key);
|
||||
if (code == null) throw new Error("Unknown key: " + key);
|
||||
|
||||
return eventCache[keyName] = {
|
||||
type: "keydown", keyCode: code, ctrlKey: ctrl, shiftKey: shift, altKey: alt,
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
|
||||
|
||||
MT("locals",
|
||||
"[keyword function] [variable foo]([def a], [def b]) { [keyword var] [def c] [operator =] [number 10]; [keyword return] [variable-2 a] [operator +] [variable-2 c] [operator +] [variable d]; }");
|
||||
"[keyword function] [def foo]([def a], [def b]) { [keyword var] [def c] [operator =] [number 10]; [keyword return] [variable-2 a] [operator +] [variable-2 c] [operator +] [variable d]; }");
|
||||
|
||||
MT("comma-and-binop",
|
||||
"[keyword function](){ [keyword var] [def x] [operator =] [number 1] [operator +] [number 2], [def y]; }");
|
||||
|
@ -18,7 +18,7 @@
|
|||
"})();");
|
||||
|
||||
MT("class_body",
|
||||
"[keyword class] [variable Foo] {",
|
||||
"[keyword class] [def Foo] {",
|
||||
" [property constructor]() {}",
|
||||
" [property sayName]() {",
|
||||
" [keyword return] [string-2 `foo${][variable foo][string-2 }oo`];",
|
||||
|
@ -26,7 +26,7 @@
|
|||
"}");
|
||||
|
||||
MT("class",
|
||||
"[keyword class] [variable Point] [keyword extends] [variable SuperThing] {",
|
||||
"[keyword class] [def Point] [keyword extends] [variable SuperThing] {",
|
||||
" [property get] [property prop]() { [keyword return] [number 24]; }",
|
||||
" [property constructor]([def x], [def y]) {",
|
||||
" [keyword super]([string 'something']);",
|
||||
|
@ -35,44 +35,44 @@
|
|||
"}");
|
||||
|
||||
MT("import",
|
||||
"[keyword function] [variable foo]() {",
|
||||
"[keyword function] [def foo]() {",
|
||||
" [keyword import] [def $] [keyword from] [string 'jquery'];",
|
||||
" [keyword import] { [def encrypt], [def decrypt] } [keyword from] [string 'crypto'];",
|
||||
"}");
|
||||
|
||||
MT("const",
|
||||
"[keyword function] [variable f]() {",
|
||||
"[keyword function] [def f]() {",
|
||||
" [keyword const] [[ [def a], [def b] ]] [operator =] [[ [number 1], [number 2] ]];",
|
||||
"}");
|
||||
|
||||
MT("for/of",
|
||||
"[keyword for]([keyword let] [variable of] [keyword of] [variable something]) {}");
|
||||
"[keyword for]([keyword let] [def of] [keyword of] [variable something]) {}");
|
||||
|
||||
MT("generator",
|
||||
"[keyword function*] [variable repeat]([def n]) {",
|
||||
"[keyword function*] [def repeat]([def n]) {",
|
||||
" [keyword for]([keyword var] [def i] [operator =] [number 0]; [variable-2 i] [operator <] [variable-2 n]; [operator ++][variable-2 i])",
|
||||
" [keyword yield] [variable-2 i];",
|
||||
"}");
|
||||
|
||||
MT("quotedStringAddition",
|
||||
"[keyword let] [variable f] [operator =] [variable a] [operator +] [string 'fatarrow'] [operator +] [variable c];");
|
||||
"[keyword let] [def f] [operator =] [variable a] [operator +] [string 'fatarrow'] [operator +] [variable c];");
|
||||
|
||||
MT("quotedFatArrow",
|
||||
"[keyword let] [variable f] [operator =] [variable a] [operator +] [string '=>'] [operator +] [variable c];");
|
||||
"[keyword let] [def f] [operator =] [variable a] [operator +] [string '=>'] [operator +] [variable c];");
|
||||
|
||||
MT("fatArrow",
|
||||
"[variable array].[property filter]([def a] [operator =>] [variable-2 a] [operator +] [number 1]);",
|
||||
"[variable a];", // No longer in scope
|
||||
"[keyword let] [variable f] [operator =] ([[ [def a], [def b] ]], [def c]) [operator =>] [variable-2 a] [operator +] [variable-2 c];",
|
||||
"[keyword let] [def f] [operator =] ([[ [def a], [def b] ]], [def c]) [operator =>] [variable-2 a] [operator +] [variable-2 c];",
|
||||
"[variable c];");
|
||||
|
||||
MT("spread",
|
||||
"[keyword function] [variable f]([def a], [meta ...][def b]) {",
|
||||
"[keyword function] [def f]([def a], [meta ...][def b]) {",
|
||||
" [variable something]([variable-2 a], [meta ...][variable-2 b]);",
|
||||
"}");
|
||||
|
||||
MT("comprehension",
|
||||
"[keyword function] [variable f]() {",
|
||||
"[keyword function] [def f]() {",
|
||||
" [[([variable x] [operator +] [number 1]) [keyword for] ([keyword var] [def x] [keyword in] [variable y]) [keyword if] [variable pred]([variable-2 x]) ]];",
|
||||
" ([variable u] [keyword for] ([keyword var] [def u] [keyword of] [variable generateValues]()) [keyword if] ([variable-2 u].[property color] [operator ===] [string 'blue']));",
|
||||
"}");
|
||||
|
@ -84,7 +84,7 @@
|
|||
"[variable x] [operator =] [string-2 `fofdlakj${][variable x] [operator +] [string-2 `foo`] [operator +] [number 1][string-2 }fdsa`] [operator +] [number 2]");
|
||||
|
||||
MT("indent_statement",
|
||||
"[keyword var] [variable x] [operator =] [number 10]",
|
||||
"[keyword var] [def x] [operator =] [number 10]",
|
||||
"[variable x] [operator +=] [variable y] [operator +]",
|
||||
" [atom Infinity]",
|
||||
"[keyword debugger];");
|
||||
|
@ -105,14 +105,14 @@
|
|||
"}");
|
||||
|
||||
MT("indent_for",
|
||||
"[keyword for] ([keyword var] [variable i] [operator =] [number 0];",
|
||||
"[keyword for] ([keyword var] [def i] [operator =] [number 0];",
|
||||
" [variable i] [operator <] [number 100];",
|
||||
" [variable i][operator ++])",
|
||||
" [variable doSomething]([variable i]);",
|
||||
"[keyword debugger];");
|
||||
|
||||
MT("indent_c_style",
|
||||
"[keyword function] [variable foo]()",
|
||||
"[keyword function] [def foo]()",
|
||||
"{",
|
||||
" [keyword debugger];",
|
||||
"}");
|
||||
|
@ -140,24 +140,32 @@
|
|||
"[number 2];");
|
||||
|
||||
MT("multilinestring",
|
||||
"[keyword var] [variable x] [operator =] [string 'foo\\]",
|
||||
"[keyword var] [def x] [operator =] [string 'foo\\]",
|
||||
"[string bar'];");
|
||||
|
||||
MT("scary_regexp",
|
||||
"[string-2 /foo[[/]]bar/];");
|
||||
|
||||
MT("indent_strange_array",
|
||||
"[keyword var] [variable x] [operator =] [[",
|
||||
"[keyword var] [def x] [operator =] [[",
|
||||
" [number 1],,",
|
||||
" [number 2],",
|
||||
"]];",
|
||||
"[number 10];");
|
||||
|
||||
MT("param_default",
|
||||
"[keyword function] [variable foo]([def x] [operator =] [string-2 `foo${][number 10][string-2 }bar`]) {",
|
||||
"[keyword function] [def foo]([def x] [operator =] [string-2 `foo${][number 10][string-2 }bar`]) {",
|
||||
" [keyword return] [variable-2 x];",
|
||||
"}");
|
||||
|
||||
MT("new_target",
|
||||
"[keyword function] [def F]([def target]) {",
|
||||
" [keyword if] ([variable-2 target] [operator &&] [keyword new].[keyword target].[property name]) {",
|
||||
" [keyword return] [keyword new]",
|
||||
" .[keyword target];",
|
||||
" }",
|
||||
"}");
|
||||
|
||||
var jsonld_mode = CodeMirror.getMode(
|
||||
{indentUnit: 2},
|
||||
{name: "javascript", jsonld: true}
|
||||
|
|
|
@ -11,6 +11,12 @@ XPCOMUtils.defineLazyServiceGetter(
|
|||
"nsIWorkerDebuggerManager"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this, "swm",
|
||||
"@mozilla.org/serviceworkers/manager;1",
|
||||
"nsIServiceWorkerManager"
|
||||
);
|
||||
|
||||
function matchWorkerDebugger(dbg, options) {
|
||||
if ("type" in options && dbg.type !== options.type) {
|
||||
return false;
|
||||
|
@ -54,6 +60,14 @@ WorkerActor.prototype = {
|
|||
}
|
||||
|
||||
if (!this._isAttached) {
|
||||
// Automatically disable their internal timeout that shut them down
|
||||
// Should be refactored by having actors specific to service workers
|
||||
if (this._dbg.type == Ci.nsIWorkerDebugger.TYPE_SERVICE) {
|
||||
let worker = this._getServiceWorkerInfo();
|
||||
if (worker) {
|
||||
worker.attachDebugger();
|
||||
}
|
||||
}
|
||||
this._dbg.addListener(this);
|
||||
this._isAttached = true;
|
||||
}
|
||||
|
@ -115,6 +129,11 @@ WorkerActor.prototype = {
|
|||
reportError("ERROR:" + filename + ":" + lineno + ":" + message + "\n");
|
||||
},
|
||||
|
||||
_getServiceWorkerInfo: function () {
|
||||
let info = swm.getRegistrationByPrincipal(this._dbg.principal, this._dbg.url);
|
||||
return info.getWorkerByID(this._dbg.serviceWorkerID);
|
||||
},
|
||||
|
||||
_detach: function () {
|
||||
if (this._threadActor !== null) {
|
||||
this._transport.close();
|
||||
|
@ -122,6 +141,20 @@ WorkerActor.prototype = {
|
|||
this._threadActor = null;
|
||||
}
|
||||
|
||||
// If the worker is already destroyed, nsIWorkerDebugger.type throws
|
||||
// (_dbg.closed appears to be false when it throws)
|
||||
let type;
|
||||
try {
|
||||
type = this._dbg.type;
|
||||
} catch(e) {}
|
||||
|
||||
if (type == Ci.nsIWorkerDebugger.TYPE_SERVICE) {
|
||||
let worker = this._getServiceWorkerInfo();
|
||||
if (worker) {
|
||||
worker.detachDebugger();
|
||||
}
|
||||
}
|
||||
|
||||
this._dbg.removeListener(this);
|
||||
this._isAttached = false;
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ interface nsIServiceWorkerRegistrationInfoListener : nsISupports
|
|||
void onChange();
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(72faba24-0a1b-4284-bad3-d44c044d6d95)]
|
||||
[scriptable, builtinclass, uuid(ddbc1fd4-2f2e-4fca-a395-6e010bbedfe3)]
|
||||
interface nsIServiceWorkerRegistrationInfo : nsISupports
|
||||
{
|
||||
readonly attribute nsIPrincipal principal;
|
||||
|
@ -54,6 +54,12 @@ interface nsIServiceWorkerRegistrationInfo : nsISupports
|
|||
readonly attribute nsIServiceWorkerInfo waitingWorker;
|
||||
readonly attribute nsIServiceWorkerInfo activeWorker;
|
||||
|
||||
// Allows to get the related nsIServiceWorkerInfo for a given
|
||||
// nsIWorkerDebugger. Over time we shouldn't need this anymore,
|
||||
// and instead always control then nsIWorkerDebugger from
|
||||
// nsIServiceWorkerInfo and not the other way around.
|
||||
nsIServiceWorkerInfo getWorkerByID(in unsigned long long aID);
|
||||
|
||||
void addListener(in nsIServiceWorkerRegistrationInfoListener listener);
|
||||
|
||||
void removeListener(in nsIServiceWorkerRegistrationInfoListener listener);
|
||||
|
@ -67,7 +73,7 @@ interface nsIServiceWorkerManagerListener : nsISupports
|
|||
void onUnregister(in nsIServiceWorkerRegistrationInfo aInfo);
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(a03f2b64-7aaf-423a-97b0-e1f733cce0f6)]
|
||||
[scriptable, builtinclass, uuid(12381ddf-9b51-4c0a-9123-9e7754393a5a)]
|
||||
interface nsIServiceWorkerManager : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -100,6 +106,9 @@ interface nsIServiceWorkerManager : nsISupports
|
|||
// Remove ready pending Promise
|
||||
void removeReadyPromise(in nsIDOMWindow aWindow);
|
||||
|
||||
nsIServiceWorkerRegistrationInfo getRegistrationByPrincipal(in nsIPrincipal aPrincipal,
|
||||
in DOMString aScope);
|
||||
|
||||
/**
|
||||
* Call this to request that document `aDoc` be controlled by a ServiceWorker
|
||||
* if a registration exists for it's scope.
|
||||
|
|
|
@ -503,6 +503,20 @@ ServiceWorkerRegistrationInfo::GetActiveWorker(nsIServiceWorkerInfo **aResult)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerRegistrationInfo::GetWorkerByID(uint64_t aID, nsIServiceWorkerInfo **aResult)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aResult);
|
||||
|
||||
RefPtr<ServiceWorkerInfo> info = GetServiceWorkerInfoById(aID);
|
||||
if (NS_WARN_IF(!info)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
info.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerRegistrationInfo::AddListener(
|
||||
nsIServiceWorkerRegistrationInfoListener *aListener)
|
||||
|
@ -4071,6 +4085,30 @@ ServiceWorkerManager::GetRegistration(nsIPrincipal* aPrincipal,
|
|||
return GetRegistration(scopeKey, aScope);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerManager::GetRegistrationByPrincipal(nsIPrincipal* aPrincipal,
|
||||
const nsAString& aScope,
|
||||
nsIServiceWorkerRegistrationInfo** aInfo)
|
||||
{
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
MOZ_ASSERT(aInfo);
|
||||
|
||||
nsCOMPtr<nsIURI> scopeURI;
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), aScope, nullptr, nullptr);
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
RefPtr<ServiceWorkerRegistrationInfo> info =
|
||||
GetServiceWorkerRegistrationInfo(aPrincipal, scopeURI);
|
||||
if (!info) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
info.forget(aInfo);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<ServiceWorkerRegistrationInfo>
|
||||
ServiceWorkerManager::GetRegistration(const nsACString& aScopeKey,
|
||||
const nsACString& aScope) const
|
||||
|
|
|
@ -3710,6 +3710,36 @@ WorkerDebugger::GetWindow(nsIDOMWindow** aResult)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WorkerDebugger::GetPrincipal(nsIPrincipal** aResult)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aResult);
|
||||
|
||||
if (!mWorkerPrivate) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> prin = mWorkerPrivate->GetPrincipal();
|
||||
prin.forget(aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WorkerDebugger::GetServiceWorkerID(uint32_t* aResult)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aResult);
|
||||
|
||||
if (!mWorkerPrivate || !mWorkerPrivate->IsServiceWorker()) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
*aResult = mWorkerPrivate->ServiceWorkerID();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WorkerDebugger::Initialize(const nsAString& aURL, JSContext* aCx)
|
||||
{
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIDOMWindow;
|
||||
interface nsIPrincipal;
|
||||
|
||||
[scriptable, uuid(9cf3b48e-361d-486a-8917-55cf8d00bb41)]
|
||||
interface nsIWorkerDebuggerListener : nsISupports
|
||||
|
@ -13,7 +14,7 @@ interface nsIWorkerDebuggerListener : nsISupports
|
|||
void onMessage(in DOMString message);
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(2b8d801c-973d-425b-a6d5-1a2505dd8b78)]
|
||||
[scriptable, builtinclass, uuid(2fe71e0d-3a39-40a3-b809-8418b72328b4)]
|
||||
interface nsIWorkerDebugger : nsISupports
|
||||
{
|
||||
const unsigned long TYPE_DEDICATED = 0;
|
||||
|
@ -34,6 +35,10 @@ interface nsIWorkerDebugger : nsISupports
|
|||
|
||||
readonly attribute nsIDOMWindow window;
|
||||
|
||||
readonly attribute nsIPrincipal principal;
|
||||
|
||||
readonly attribute unsigned long serviceWorkerID;
|
||||
|
||||
[implicit_jscontext]
|
||||
void initialize(in DOMString url);
|
||||
|
||||
|
|
|
@ -70,7 +70,21 @@
|
|||
info("Attach a debugger to the service worker, and check that the " +
|
||||
"service worker is restarted.");
|
||||
activeWorker.attachDebugger();
|
||||
ok(activeWorker.debugger !== null);
|
||||
let workerDebugger = activeWorker.debugger;
|
||||
ok(workerDebugger !== null);
|
||||
|
||||
// Verify debugger properties
|
||||
ok(workerDebugger.principal instanceof Ci.nsIPrincipal);
|
||||
is(workerDebugger.url, EXAMPLE_URL + "worker.js");
|
||||
|
||||
info("Verify that getRegistrationByPrincipal return the same " +
|
||||
"nsIServiceWorkerRegistrationInfo");
|
||||
let reg = swm.getRegistrationByPrincipal(workerDebugger.principal,
|
||||
workerDebugger.url);
|
||||
is(reg, registration);
|
||||
|
||||
info("Check that getWorkerByID returns the same nsIWorkerDebugger");
|
||||
is(activeWorker, reg.getWorkerByID(workerDebugger.serviceWorkerID));
|
||||
|
||||
info("Detach the debugger from the service worker, and check that " +
|
||||
"the service worker eventually shuts down again.");
|
||||
|
|
Двоичные данные
mobile/android/base/resources/drawable-hdpi/menu_panel_bg.9.png
Двоичные данные
mobile/android/base/resources/drawable-hdpi/menu_panel_bg.9.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 544 B |
Двоичные данные
mobile/android/base/resources/drawable-xhdpi/menu_panel_bg.9.png
Двоичные данные
mobile/android/base/resources/drawable-xhdpi/menu_panel_bg.9.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 661 B |
|
@ -41,7 +41,6 @@
|
|||
<item name="android:actionModeCutDrawable">@drawable/ab_cut</item>
|
||||
<item name="android:actionModePasteDrawable">@drawable/ab_paste</item>
|
||||
<item name="android:listViewStyle">@style/Widget.ListView</item>
|
||||
<item name="android:panelBackground">@drawable/menu_panel_bg</item>
|
||||
<item name="android:spinnerDropDownItemStyle">@style/Widget.DropDownItem.Spinner</item>
|
||||
<item name="android:spinnerItemStyle">@style/Widget.TextView.SpinnerItem</item>
|
||||
<item name="menuItemSwitcherLayoutStyle">@style/Widget.MenuItemSwitcherLayout</item>
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
<item name="android:actionModeSelectAllDrawable">@drawable/ab_select_all</item>
|
||||
<item name="android:actionModeStyle">@style/GeckoActionBar</item>
|
||||
<item name="android:listViewStyle">@style/Widget.ListView</item>
|
||||
<item name="android:panelBackground">@drawable/menu_panel_bg</item>
|
||||
<item name="android:spinnerDropDownItemStyle">@style/Widget.DropDownItem.Spinner</item>
|
||||
<item name="android:spinnerItemStyle">@style/Widget.TextView.SpinnerItem</item>
|
||||
<item name="menuItemSwitcherLayoutStyle">@style/Widget.MenuItemSwitcherLayout</item>
|
||||
|
|
|
@ -42,7 +42,6 @@
|
|||
<style name="GeckoAppBase" parent="Gecko">
|
||||
<item name="android:actionButtonStyle">@style/GeckoActionBar.Button</item>
|
||||
<item name="android:listViewStyle">@style/Widget.ListView</item>
|
||||
<item name="android:panelBackground">@drawable/menu_panel_bg</item>
|
||||
<item name="android:spinnerDropDownItemStyle">@style/Widget.DropDownItem.Spinner</item>
|
||||
<item name="android:spinnerItemStyle">@style/Widget.TextView.SpinnerItem</item>
|
||||
<item name="menuItemSwitcherLayoutStyle">@style/Widget.MenuItemSwitcherLayout</item>
|
||||
|
|
|
@ -12,13 +12,6 @@
|
|||
<style name="GeckoBase" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
|
||||
<!-- Gingerbread "More" menu background color; AppCompat sets this to
|
||||
transparent by default: http://stackoverflow.com/a/31777488.
|
||||
This color is set anecdotally to make all text colors, which change
|
||||
by device, visible. Standard colors are #8D8D8D & #C8C8C8 (disabled)
|
||||
and #000000 has also been seen. -->
|
||||
<item name="android:panelBackground">@color/text_and_tabs_tray_grey</item>
|
||||
</style>
|
||||
|
||||
<style name="GeckoDialogBase" parent="@android:style/Theme.Dialog">
|
||||
|
|
|
@ -14,7 +14,6 @@ Contents:
|
|||
localeswitching
|
||||
uitelemetry
|
||||
adjust
|
||||
gradle
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
@ -22,4 +21,3 @@ Indices and tables
|
|||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
||||
|
|
|
@ -1,155 +0,0 @@
|
|||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 23
|
||||
buildToolsVersion "23.0.1"
|
||||
|
||||
defaultConfig {
|
||||
targetSdkVersion 22
|
||||
minSdkVersion 9
|
||||
applicationId mozconfig.substs.ANDROID_PACKAGE_NAME
|
||||
testApplicationId 'org.mozilla.roboexample.test'
|
||||
testInstrumentationRunner 'org.mozilla.gecko.FennecInstrumentationTestRunner'
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled true
|
||||
proguardFile "${topsrcdir}/mobile/android/config/proguard/proguard.cfg"
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
manifest.srcFile "${topobjdir}/mobile/android/base/AndroidManifest.xml"
|
||||
}
|
||||
|
||||
androidTest {
|
||||
manifest.srcFile "${topobjdir}/build/mobile/robocop/AndroidManifest.xml"
|
||||
java {
|
||||
srcDir "src/robocop"
|
||||
srcDir "src/background"
|
||||
srcDir "src/browser"
|
||||
srcDir "src/javaaddons"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':base')
|
||||
compile project(':omnijar')
|
||||
// Including the Robotium JAR directly can cause issues with dexing.
|
||||
androidTestCompile 'com.jayway.android.robotium:robotium-solo:4.3.1'
|
||||
}
|
||||
|
||||
task syncOmnijarFromDistDir(type: Sync) {
|
||||
into("${project.buildDir}/generated/omnijar")
|
||||
from("${topobjdir}/dist/fennec/assets") {
|
||||
include 'omni.ja'
|
||||
}
|
||||
}
|
||||
|
||||
task checkLibsExistInDistDir<< {
|
||||
if (syncLibsFromDistDir.source.empty) {
|
||||
throw new GradleException("Required JNI libraries not found in ${topobjdir}/dist/fennec/lib. Have you built and packaged?")
|
||||
}
|
||||
}
|
||||
|
||||
task syncLibsFromDistDir(type: Sync, dependsOn: checkLibsExistInDistDir) {
|
||||
into("${project.buildDir}/generated/jniLibs")
|
||||
from("${topobjdir}/dist/fennec/lib")
|
||||
}
|
||||
|
||||
task checkAssetsExistInDistDir<< {
|
||||
if (syncAssetsFromDistDir.source.empty) {
|
||||
throw new GradleException("Required assets not found in ${topobjdir}/dist/fennec/assets. Have you built and packaged?")
|
||||
}
|
||||
}
|
||||
|
||||
task syncAssetsFromDistDir(type: Sync, dependsOn: checkAssetsExistInDistDir) {
|
||||
into("${project.buildDir}/generated/assets")
|
||||
from("${topobjdir}/dist/fennec/assets") {
|
||||
exclude 'omni.ja'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We want to expose the JSM files and chrome content to IDEs; the omnijar
|
||||
* project does this. In addition, the :omnijar:buildOmnijar task builds a new
|
||||
* omni.ja (directly into the object directory).
|
||||
*
|
||||
* The task dependency is: :generateDebugAssets -> :omnijar:buildOmnijar.
|
||||
*
|
||||
* One might expect that we could do this all in the omnijar project, but there
|
||||
* appears to be a bug (which I have not fully isolated) where-by debug-only
|
||||
* assets in a library (.aar file) are ignored in favor of release assets. This
|
||||
* means we would have to insert the omni.ja into the omnijar project's release
|
||||
* assets, which is altogether confusing.
|
||||
*/
|
||||
android.applicationVariants.all { variant ->
|
||||
// We only insert omni.ja and the .so libraries into debug builds.
|
||||
def name = variant.buildType.name
|
||||
if (!name.contains(com.android.builder.core.BuilderConstants.DEBUG)) {
|
||||
return
|
||||
}
|
||||
|
||||
def buildOmnijarTask = project(':omnijar').tasks.getByName('buildOmnijar')
|
||||
syncOmnijarFromDistDir.dependsOn buildOmnijarTask
|
||||
def generateAssetsTask = tasks.findByName("generate${name.capitalize()}Assets")
|
||||
generateAssetsTask.dependsOn syncOmnijarFromDistDir
|
||||
generateAssetsTask.dependsOn syncLibsFromDistDir
|
||||
generateAssetsTask.dependsOn syncAssetsFromDistDir
|
||||
|
||||
android.sourceSets.debug.assets.srcDir syncOmnijarFromDistDir.destinationDir
|
||||
android.sourceSets.debug.assets.srcDir syncAssetsFromDistDir.destinationDir
|
||||
android.sourceSets.debug.jniLibs.srcDir syncLibsFromDistDir.destinationDir
|
||||
}
|
||||
|
||||
apply plugin: 'spoon'
|
||||
|
||||
spoon {
|
||||
// For now, let's be verbose.
|
||||
debug = true
|
||||
// It's not helpful to pass when we don't have a device connected.
|
||||
failIfNoDeviceConnected = true
|
||||
|
||||
def spoonPackageName
|
||||
if (gradle.startParameter.taskNames.contains('runBrowserTests')) {
|
||||
spoonPackageName = 'org.mozilla.tests.browser.junit3'
|
||||
}
|
||||
if (gradle.startParameter.taskNames.contains('runBackgroundTests')) {
|
||||
spoonPackageName = 'org.mozilla.gecko.background'
|
||||
}
|
||||
if (project.hasProperty('spoonPackageName')) {
|
||||
// Command line overrides everything.
|
||||
spoonPackageName = project.spoonPackageName
|
||||
}
|
||||
if (spoonPackageName) {
|
||||
instrumentationArgs = ['-e', "package=${spoonPackageName}".toString()]
|
||||
}
|
||||
}
|
||||
|
||||
// See discussion at https://github.com/stanfy/spoon-gradle-plugin/issues/9.
|
||||
afterEvaluate {
|
||||
tasks["spoon${android.testBuildType.capitalize()}AndroidTest"].outputs.upToDateWhen { false }
|
||||
|
||||
// This is an awkward way to define different sets of instrumentation tests.
|
||||
// The task name itself is fished at runtime and the package name configured
|
||||
// in the spoon configuration.
|
||||
task runBrowserTests {
|
||||
dependsOn tasks["spoonDebugAndroidTest"]
|
||||
}
|
||||
task runBackgroundTests {
|
||||
dependsOn tasks["spoonDebugAndroidTest"]
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.mozilla.gecko">
|
||||
|
||||
</manifest>
|
|
@ -1,132 +0,0 @@
|
|||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion 23
|
||||
buildToolsVersion "23.0.1"
|
||||
|
||||
defaultConfig {
|
||||
targetSdkVersion 22
|
||||
minSdkVersion 9
|
||||
// Used by Robolectric based tests; see TestRunner.
|
||||
buildConfigField 'String', 'BUILD_DIR', "\"${project.buildDir}\""
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFile getDefaultProguardFile('proguard-android.txt')
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
srcDir 'src/services/java'
|
||||
|
||||
exclude 'org/mozilla/gecko/resources/**'
|
||||
|
||||
if (!mozconfig.substs.MOZ_CRASHREPORTER) {
|
||||
exclude 'org/mozilla/gecko/CrashReporter.java'
|
||||
}
|
||||
|
||||
if (!mozconfig.substs.MOZ_NATIVE_DEVICES) {
|
||||
exclude 'org/mozilla/gecko/ChromeCast.java'
|
||||
exclude 'org/mozilla/gecko/GeckoMediaPlayer.java'
|
||||
exclude 'org/mozilla/gecko/MediaPlayerManager.java'
|
||||
}
|
||||
|
||||
if (mozconfig.substs.MOZ_WEBRTC) {
|
||||
srcDir 'src/webrtc_audio_device'
|
||||
srcDir 'src/webrtc_video_capture'
|
||||
srcDir 'src/webrtc_video_render'
|
||||
}
|
||||
|
||||
if (mozconfig.substs.MOZ_INSTALL_TRACKING) {
|
||||
exclude 'org/mozilla/gecko/adjust/StubAdjustHelper.java'
|
||||
} else {
|
||||
exclude 'org/mozilla/gecko/adjust/AdjustHelper.java'
|
||||
}
|
||||
|
||||
srcDir "${project.buildDir}/generated/source/preprocessed_code" // See syncPreprocessedCode.
|
||||
}
|
||||
|
||||
res {
|
||||
srcDir 'src/branding/res'
|
||||
srcDir 'src/services/res'
|
||||
srcDir "${project.buildDir}/generated/source/preprocessed_resources" // See syncPreprocessedResources.
|
||||
if (mozconfig.substs.MOZ_CRASHREPORTER) {
|
||||
srcDir "src/crashreporter/res"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test {
|
||||
java {
|
||||
srcDir "src/background_junit4"
|
||||
}
|
||||
|
||||
resources {
|
||||
srcDir "resources/background_junit4"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
task syncPreprocessedCode(type: Sync, dependsOn: rootProject.generateCodeAndResources) {
|
||||
into("${project.buildDir}/generated/source/preprocessed_code")
|
||||
from("${topobjdir}/mobile/android/base/generated/preprocessed")
|
||||
}
|
||||
|
||||
task syncPreprocessedResources(type: Sync, dependsOn: rootProject.generateCodeAndResources) {
|
||||
into("${project.buildDir}/generated/source/preprocessed_resources")
|
||||
from("${topobjdir}/mobile/android/base/res")
|
||||
}
|
||||
|
||||
android.libraryVariants.all { variant ->
|
||||
variant.preBuild.dependsOn syncPreprocessedCode
|
||||
variant.preBuild.dependsOn syncPreprocessedResources
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'com.android.support:support-v4:23.0.1'
|
||||
compile 'com.android.support:appcompat-v7:23.0.1'
|
||||
compile 'com.android.support:recyclerview-v7:23.0.1'
|
||||
compile 'com.android.support:design:23.0.1'
|
||||
|
||||
if (mozconfig.substs.MOZ_NATIVE_DEVICES) {
|
||||
compile 'com.android.support:mediarouter-v7:23.0.1'
|
||||
compile 'com.google.android.gms:play-services-basement:8.1.0'
|
||||
compile 'com.google.android.gms:play-services-base:8.1.0'
|
||||
compile 'com.google.android.gms:play-services-cast:8.1.0'
|
||||
}
|
||||
|
||||
if (mozconfig.substs.MOZ_ANDROID_GCM) {
|
||||
compile 'com.google.android.gms:play-services-basement:8.1.0'
|
||||
compile 'com.google.android.gms:play-services-base:8.1.0'
|
||||
compile 'com.google.android.gms:play-services-gcm:8.1.0'
|
||||
}
|
||||
|
||||
compile project(':thirdparty')
|
||||
|
||||
testCompile 'junit:junit:4.12'
|
||||
testCompile 'org.robolectric:robolectric:3.0'
|
||||
testCompile 'org.simpleframework:simple-http:4.1.13'
|
||||
}
|
||||
|
||||
apply plugin: 'idea'
|
||||
|
||||
idea {
|
||||
module {
|
||||
excludeDirs += file('org/mozilla/gecko/resources')
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<lint>
|
||||
<!-- Enable relevant checks disabled by default -->
|
||||
<issue id="NegativeMargin" severity="warning" />
|
||||
|
||||
<!-- We have a custom menu and don't conform to the recommended styles. -->
|
||||
<issue id="IconColors" severity="ignore" />
|
||||
</lint>
|
|
@ -1,102 +0,0 @@
|
|||
import java.util.regex.Pattern
|
||||
|
||||
allprojects {
|
||||
// Expose the per-object-directory configuration to all projects.
|
||||
ext {
|
||||
mozconfig = gradle.mozconfig
|
||||
topsrcdir = gradle.mozconfig.topsrcdir
|
||||
topobjdir = gradle.mozconfig.topobjdir
|
||||
}
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
buildDir "${topobjdir}/mobile/android/gradle/build"
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
|
||||
// For spoon-gradle-plugin SNAPSHOT release. This needs to go before
|
||||
// the snapshots repository, otherwise we find a remote 1.0.3-SNAPSHOT
|
||||
// that doesn't include nalexander's local changes.
|
||||
maven {
|
||||
url "file://${gradle.mozconfig.topsrcdir}/mobile/android/gradle/m2repo"
|
||||
}
|
||||
// For spoon SNAPSHOT releases.
|
||||
maven {
|
||||
url 'https://oss.sonatype.org/content/repositories/snapshots'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Unit testing support was added in 1.1.0. IntelliJ 14.1.4 and Android
|
||||
// Studio 1.2.1.1 appear to work fine with plugin version 1.3.0.
|
||||
classpath 'com.android.tools.build:gradle:1.3.0'
|
||||
classpath('com.stanfy.spoon:spoon-gradle-plugin:1.0.3-SNAPSHOT') {
|
||||
// Without these, we get errors linting.
|
||||
exclude module: 'guava'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task generateCodeAndResources(type:Exec) {
|
||||
workingDir "${topobjdir}"
|
||||
|
||||
commandLine mozconfig.substs.GMAKE
|
||||
args '-C'
|
||||
args "${topobjdir}/mobile/android/base"
|
||||
args 'gradle-targets'
|
||||
|
||||
// Only show the output if something went wrong.
|
||||
ignoreExitValue = true
|
||||
standardOutput = new ByteArrayOutputStream()
|
||||
errorOutput = standardOutput
|
||||
doLast {
|
||||
if (execResult.exitValue != 0) {
|
||||
throw new GradleException("Process '${commandLine}' finished with non-zero exit value ${execResult.exitValue}:\n\n${standardOutput.toString()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Skip unit test for all build variants, unless if it was specifically requested by user.
|
||||
// The enabled property for the unit test tasks is reset based on the command line task names just before the task execution.
|
||||
// I bet there is a easier/cleaner way to do this, but this gets the job done for now.
|
||||
Pattern pattern = Pattern.compile('.*test(.+UnitTest)?.*')
|
||||
boolean startTasksIncludeTest = gradle.startParameter.taskNames.any {
|
||||
taskName ->
|
||||
taskName.matches(pattern)
|
||||
}
|
||||
gradle.taskGraph.beforeTask {
|
||||
Task task ->
|
||||
if (task.name.matches(pattern)) {
|
||||
task.enabled = startTasksIncludeTest
|
||||
}
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
subprojects {
|
||||
if (!hasProperty('android')) {
|
||||
return
|
||||
}
|
||||
android.applicationVariants.all {
|
||||
preBuild.dependsOn rootProject.generateCodeAndResources
|
||||
}
|
||||
android.libraryVariants.all {
|
||||
preBuild.dependsOn rootProject.generateCodeAndResources
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'idea'
|
||||
|
||||
idea {
|
||||
project {
|
||||
languageLevel = '1.7'
|
||||
}
|
||||
}
|
||||
|
||||
task wrapper(type: Wrapper) {
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
org.gradle.parallel=true
|
||||
org.gradle.daemon=true
|
|
@ -1,5 +0,0 @@
|
|||
#filter substitution
|
||||
#include gradle.properties
|
||||
|
||||
topsrcdir=@topsrcdir@
|
||||
topobjdir=@topobjdir@
|
Двоичный файл не отображается.
|
@ -1,6 +0,0 @@
|
|||
#Sun Oct 18 17:00:46 PDT 2015
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.7-bin.zip
|
|
@ -1,160 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
esac
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >&-
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >&-
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
|
@ -1,2 +0,0 @@
|
|||
#filter substitution
|
||||
sdk.dir=@ANDROID_SDK_ROOT@
|
|
@ -1,4 +0,0 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.mozilla.gecko.omnijar">
|
||||
|
||||
</manifest>
|
|
@ -1,42 +0,0 @@
|
|||
apply plugin: 'java'
|
||||
|
||||
/**
|
||||
* This task runs when any input file is newer than the omnijar.
|
||||
*/
|
||||
task buildOmnijar(type:Exec) {
|
||||
dependsOn rootProject.generateCodeAndResources
|
||||
|
||||
// Depend on all the Gecko resources.
|
||||
inputs.sourceDir 'src/main/java/locales'
|
||||
inputs.sourceDir 'src/main/java/chrome'
|
||||
inputs.sourceDir 'src/main/java/components'
|
||||
inputs.sourceDir 'src/main/java/modules'
|
||||
inputs.sourceDir 'src/main/java/themes'
|
||||
|
||||
// Produce a single output file.
|
||||
outputs.file "${topobjdir}/dist/fennec/assets/omni.ja"
|
||||
|
||||
workingDir "${topobjdir}"
|
||||
|
||||
commandLine mozconfig.substs.GMAKE
|
||||
args '-C'
|
||||
args "${topobjdir}/mobile/android/base"
|
||||
args 'gradle-omnijar'
|
||||
|
||||
// Only show the output if something went wrong.
|
||||
ignoreExitValue = true
|
||||
standardOutput = new ByteArrayOutputStream()
|
||||
errorOutput = standardOutput
|
||||
doLast {
|
||||
if (execResult.exitValue != 0) {
|
||||
throw new GradleException("Process '${commandLine}' finished with non-zero exit value ${execResult.exitValue}:\n\n${standardOutput.toString()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'idea'
|
||||
|
||||
idea {
|
||||
module {
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
// If our root project is in the object directory, we expect to be given
|
||||
// topsrcdir from our environment via gradle.properties. If we don't get it,
|
||||
// our root project is in the source directory, so we extract topsrcdir relative
|
||||
// to the location of this script.
|
||||
if (!hasProperty('topsrcdir')) {
|
||||
// In the source directory, we're not worried about links crossing directories.
|
||||
binding.variables['topsrcdir'] = new File("../../..").getCanonicalPath()
|
||||
logger.warn("topsrcdir is undefined: assuming source directory Gradle invocation with topsrcdir=${topsrcdir}.")
|
||||
}
|
||||
|
||||
def commandLine = ["${topsrcdir}/mach", "environment", "--format", "json", "--verbose"]
|
||||
def proc = commandLine.execute(null, new File(topsrcdir))
|
||||
def standardOutput = new ByteArrayOutputStream()
|
||||
proc.consumeProcessOutput(standardOutput, standardOutput)
|
||||
proc.waitFor()
|
||||
|
||||
// Only show the output if something went wrong.
|
||||
if (proc.exitValue() != 0) {
|
||||
throw new GradleException("Process '${commandLine}' finished with non-zero exit value ${proc.exitValue()}:\n\n${standardOutput.toString()}")
|
||||
}
|
||||
|
||||
import groovy.json.JsonSlurper
|
||||
def slurper = new JsonSlurper()
|
||||
def json = slurper.parseText(standardOutput.toString())
|
||||
|
||||
include ':app'
|
||||
include ':base'
|
||||
include ':omnijar'
|
||||
include ':thirdparty'
|
||||
|
||||
def gradleRoot = new File("${json.topobjdir}/mobile/android/gradle")
|
||||
project(':app').projectDir = new File(gradleRoot, 'app')
|
||||
project(':base').projectDir = new File(gradleRoot, 'base')
|
||||
project(':omnijar').projectDir = new File(gradleRoot, 'omnijar')
|
||||
project(':thirdparty').projectDir = new File(gradleRoot, 'thirdparty')
|
||||
|
||||
// The Gradle instance is shared between settings.gradle and all the
|
||||
// other build.gradle files (see
|
||||
// http://forums.gradle.org/gradle/topics/define_extension_properties_from_settings_xml).
|
||||
// We use this ext property to pass the per-object-directory mozconfig
|
||||
// between scripts. This lets us execute set-up code before we gradle
|
||||
// tries to configure the project even once, and as a side benefit
|
||||
// saves invoking |mach environment| multiple times.
|
||||
gradle.ext.mozconfig = json
|
|
@ -1,4 +0,0 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.mozilla.gecko.thirdparty">
|
||||
|
||||
</manifest>
|
|
@ -1,34 +0,0 @@
|
|||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion 23
|
||||
buildToolsVersion "23.0.1"
|
||||
|
||||
defaultConfig {
|
||||
targetSdkVersion 22
|
||||
minSdkVersion 9
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
if (!mozconfig.substs.MOZ_INSTALL_TRACKING) {
|
||||
exclude 'com/adjust/**'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'com.android.support:support-v4:23.0.1'
|
||||
}
|
|
@ -37,6 +37,17 @@ and in IntelliJ select File > Import project... and choose
|
|||
'''
|
||||
|
||||
|
||||
# NOTE python/mach/mach/commands/commandinfo.py references this function
|
||||
# by name. If this function is renamed or removed, that file should
|
||||
# be updated accordingly as well.
|
||||
def REMOVED(cls):
|
||||
"""Command no longer exists! Use the Gradle configuration rooted in the top source directory instead.
|
||||
|
||||
See https://developer.mozilla.org/en-US/docs/Simple_Firefox_for_Android_build#Developing_Firefox_for_Android_in_Android_Studio_or_IDEA_IntelliJ.
|
||||
"""
|
||||
return False
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MachCommands(MachCommandBase):
|
||||
@Command('android', category='devenv',
|
||||
|
@ -61,106 +72,15 @@ class MachCommands(MachCommandBase):
|
|||
# Avoid logging the command
|
||||
self.log_manager.terminal_handler.setLevel(logging.CRITICAL)
|
||||
|
||||
code = self.gradle_install(quiet=True)
|
||||
if code:
|
||||
return code
|
||||
|
||||
return self.run_process(['./gradlew'] + args,
|
||||
pass_thru=True, # Allow user to run gradle interactively.
|
||||
ensure_exit_code=False, # Don't throw on non-zero exit code.
|
||||
cwd=mozpath.join(self.topobjdir, 'mobile', 'android', 'gradle'))
|
||||
cwd=mozpath.join(self.topsrcdir))
|
||||
|
||||
@Command('gradle-install', category='devenv',
|
||||
description='Install gradle environment.',
|
||||
conditions=[conditions.is_android])
|
||||
def gradle_install(self, quiet=False):
|
||||
import mozpack.manifests
|
||||
m = mozpack.manifests.InstallManifest()
|
||||
|
||||
def srcdir(dst, src):
|
||||
m.add_symlink(os.path.join(self.topsrcdir, src), dst)
|
||||
|
||||
srcdir('build.gradle', 'mobile/android/gradle/build.gradle')
|
||||
srcdir('settings.gradle', 'mobile/android/gradle/settings.gradle')
|
||||
|
||||
m.add_pattern_copy(os.path.join(self.topsrcdir, 'mobile/android/gradle/gradle/wrapper'), '**', 'gradle/wrapper')
|
||||
m.add_copy(os.path.join(self.topsrcdir, 'mobile/android/gradle/gradlew'), 'gradlew')
|
||||
|
||||
defines = {
|
||||
'topsrcdir': self.topsrcdir,
|
||||
'topobjdir': self.topobjdir,
|
||||
'ANDROID_SDK_ROOT': self.substs['ANDROID_SDK_ROOT'],
|
||||
}
|
||||
m.add_preprocess(os.path.join(self.topsrcdir, 'mobile/android/gradle/gradle.properties.in'),
|
||||
'gradle.properties',
|
||||
defines=defines,
|
||||
deps=os.path.join(self.topobjdir, 'mobile/android/gradle/.deps/gradle.properties.pp'))
|
||||
m.add_preprocess(os.path.join(self.topsrcdir, 'mobile/android/gradle/local.properties.in'),
|
||||
'local.properties',
|
||||
defines=defines,
|
||||
deps=os.path.join(self.topobjdir, 'mobile/android/gradle/.deps/local.properties.pp'))
|
||||
|
||||
srcdir('thirdparty/build.gradle', 'mobile/android/gradle/thirdparty/build.gradle')
|
||||
srcdir('thirdparty/src/main/AndroidManifest.xml', 'mobile/android/gradle/thirdparty/AndroidManifest.xml')
|
||||
srcdir('thirdparty/src/main/java', 'mobile/android/thirdparty')
|
||||
|
||||
srcdir('omnijar/build.gradle', 'mobile/android/gradle/omnijar/build.gradle')
|
||||
srcdir('omnijar/src/main/java/locales', 'mobile/android/locales')
|
||||
srcdir('omnijar/src/main/java/chrome', 'mobile/android/chrome')
|
||||
srcdir('omnijar/src/main/java/components', 'mobile/android/components')
|
||||
srcdir('omnijar/src/main/java/modules', 'mobile/android/modules')
|
||||
srcdir('omnijar/src/main/java/themes', 'mobile/android/themes')
|
||||
|
||||
srcdir('app/build.gradle', 'mobile/android/gradle/app/build.gradle')
|
||||
srcdir('app/src/androidTest/res', 'mobile/android/tests/browser/robocop/res')
|
||||
srcdir('app/src/androidTest/assets', 'mobile/android/tests/browser/robocop/assets')
|
||||
# Test code.
|
||||
srcdir('app/src/robocop', 'mobile/android/tests/browser/robocop/src')
|
||||
srcdir('app/src/background', 'mobile/android/tests/background/junit3/src')
|
||||
srcdir('app/src/browser', 'mobile/android/tests/browser/junit3/src')
|
||||
srcdir('app/src/javaaddons', 'mobile/android/tests/javaaddons/src')
|
||||
|
||||
srcdir('base/build.gradle', 'mobile/android/gradle/base/build.gradle')
|
||||
srcdir('base/lint.xml', 'mobile/android/gradle/base/lint.xml')
|
||||
srcdir('base/src/main/AndroidManifest.xml', 'mobile/android/gradle/base/AndroidManifest.xml')
|
||||
srcdir('base/src/main/java/org/mozilla/gecko', 'mobile/android/base/java/org/mozilla/gecko')
|
||||
srcdir('base/src/main/java/org/mozilla/mozstumbler', 'mobile/android/stumbler/java/org/mozilla/mozstumbler')
|
||||
srcdir('base/src/main/java/org/mozilla/search', 'mobile/android/search/java/org/mozilla/search')
|
||||
srcdir('base/src/main/java/org/mozilla/javaaddons', 'mobile/android/javaaddons/java/org/mozilla/javaaddons')
|
||||
srcdir('base/src/services', 'mobile/android/services/src/main')
|
||||
srcdir('base/src/webrtc_audio_device/java', 'media/webrtc/trunk/webrtc/modules/audio_device/android/java/src')
|
||||
srcdir('base/src/webrtc_video_capture/java', 'media/webrtc/trunk/webrtc/modules/video_capture/android/java/src')
|
||||
srcdir('base/src/webrtc_video_render/java', 'media/webrtc/trunk/webrtc/modules/video_render/android/java/src')
|
||||
srcdir('base/src/main/res', 'mobile/android/base/resources')
|
||||
srcdir('base/src/main/assets', 'mobile/android/app/assets')
|
||||
srcdir('base/src/crashreporter/res', 'mobile/android/base/crashreporter/res')
|
||||
srcdir('base/src/branding/res', os.path.join(self.substs['MOZ_BRANDING_DIRECTORY'], 'res'))
|
||||
# JUnit 4 test code.
|
||||
srcdir('base/src/background_junit4', 'mobile/android/tests/background/junit4/src')
|
||||
srcdir('base/resources/background_junit4', 'mobile/android/tests/background/junit4/resources')
|
||||
|
||||
manifest_path = os.path.join(self.topobjdir, 'mobile', 'android', 'gradle.manifest')
|
||||
with FileAvoidWrite(manifest_path) as f:
|
||||
m.write(fileobj=f)
|
||||
|
||||
self.virtualenv_manager.ensure()
|
||||
code = self.run_process([
|
||||
self.virtualenv_manager.python_path,
|
||||
os.path.join(self.topsrcdir, 'python/mozbuild/mozbuild/action/process_install_manifest.py'),
|
||||
'--no-remove',
|
||||
'--no-remove-all-directory-symlinks',
|
||||
'--no-remove-empty-directories',
|
||||
os.path.join(self.topobjdir, 'mobile', 'android', 'gradle'),
|
||||
manifest_path],
|
||||
pass_thru=True, # Allow user to run gradle interactively.
|
||||
ensure_exit_code=False, # Don't throw on non-zero exit code.
|
||||
cwd=mozpath.join(self.topsrcdir, 'mobile', 'android'))
|
||||
|
||||
if not quiet:
|
||||
if not code:
|
||||
print(SUCCESS.format(topobjdir=self.topobjdir))
|
||||
|
||||
return code
|
||||
conditions=[REMOVED])
|
||||
def gradle_install(self):
|
||||
pass
|
||||
|
||||
|
||||
class ArtifactSubCommand(SubCommand):
|
||||
|
|
|
@ -71,9 +71,6 @@ class MachCommands(MachCommandBase):
|
|||
res = self._mach_context.commands.dispatch('package', self._mach_context)
|
||||
if res != 0:
|
||||
return 1
|
||||
res = self._mach_context.commands.dispatch('gradle-install', self._mach_context)
|
||||
if res != 0:
|
||||
return 1
|
||||
else:
|
||||
# Generate or refresh the IDE backend.
|
||||
python = self.virtualenv_manager.python_path
|
||||
|
|
|
@ -32,10 +32,11 @@ ANDROID_IDE_ADVERTISEMENT = '''
|
|||
=============
|
||||
ADVERTISEMENT
|
||||
|
||||
You are building Firefox for Android. After your build completes, you
|
||||
should run `mach gradle-install` to prepare Gradle and IntelliJ/Android Studio
|
||||
integration. Then import the Gradle project at $OBJDIR/mobile/android/gradle
|
||||
into the IDE of your choice.
|
||||
You are building Firefox for Android. After your build completes, you can open
|
||||
the top source directory in IntelliJ or Android Studio directly and build using
|
||||
Gradle. See the documentation at
|
||||
|
||||
https://developer.mozilla.org/en-US/docs/Simple_Firefox_for_Android_build
|
||||
|
||||
PLEASE BE AWARE THAT GRADLE AND INTELLIJ/ANDROID STUDIO SUPPORT IS EXPERIMENTAL.
|
||||
You should verify any changes using |mach build|.
|
||||
|
|
|
@ -90,7 +90,7 @@ Contains the statistics about the hangs in main and background threads. Note tha
|
|||
To avoid submitting overly large payloads, some limits are applied:
|
||||
|
||||
* Identical, adjacent "(chrome script)" or "(content script)" stack entries are collapsed together. If a stack is reduced, the "(reduced stack)" frame marker is added as the oldest frame.
|
||||
* The depth of the reported stacks is limited to 11 entries. This value represents the 95th percentile of the thread hangs stack depths reported by Telemetry.
|
||||
* The depth of the reported stacks is limited to 11 entries. This value represents the 99.9th percentile of the thread hangs stack depths reported by Telemetry.
|
||||
|
||||
Structure::
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче