1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

Bug 481126 - Tern-QML Directory Imports

Added functionality to tern-qml that allows it to recognize directory
imports of the form:  import "<directory>" [as <Qualifier>].  Content
assist and find definitions also work for these new imports.  Moreover,
fixed the QML Scoping to be easier to handle in the future by defining
new Scope Objects specifically for QML.  Finally, used JS Hint and
Beautify to have a more uniform coding style between all the files of
acorn-qml and tern-qml.

Also fixed up the HTML Demo to allow editing of multiple files to show
the new imports.

Change-Id: I2cdd18b1b8765400f6b24145f0677127a221fe10
Signed-off-by: Matthew Bastien <mbastien@blackberry.com>
This commit is contained in:
Matthew Bastien 2015-12-03 15:24:36 -05:00 committed by Gerrit Code Review @ Eclipse.org
parent 3ec33023c3
commit dd3815bb91
20 changed files with 2562 additions and 868 deletions

View file

@ -8,18 +8,14 @@
* Contributors:
* QNX Software Systems - Initial API and implementation
*******************************************************************************/
// This will only be visible globally if we are in a browser environment
var acornQML;
(function (mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
return module.exports = mod(require("./inject.js"), require("acorn"));
return mod(require("./inject.js"), require("acorn"));
if (typeof define == "function" && define.amd) // AMD
return define(["./inject.js", "acorn/dist/acorn"], mod);
acornQML = mod(injectQML, acorn); // Plain browser env
})(function (injectQML, acorn) {
mod(acornQMLInjector, acorn); // Plain browser env
})(function (acornQMLInjector, acorn) {
'use strict';
return injectQML(acorn);
})
acornQMLInjector.inject(acorn);
});

View file

@ -8,20 +8,16 @@
* Contributors:
* QNX Software Systems - Initial API and implementation
*******************************************************************************/
// This will only be visible globally if we are in a browser environment
var injectQML;
(function (mod) {
(function (root, mod) {
if (typeof exports === "object" && typeof module === "object") // CommonJS
return module.exports = mod();
return mod(exports);
if (typeof define === "function" && define.amd) // AMD
return define([], mod);
injectQML = mod(); // Plain browser env
})(function () {
return define(["exports"], mod);
mod(root.acornQMLInjector || (root.acornQMLInjector = {})); // Plain browser env
})(this, function (exports) {
'use strict';
return function (acorn) {
exports.inject = function (acorn) {
// Acorn token types
var tt = acorn.tokTypes;
@ -88,7 +84,7 @@ var injectQML;
* the type import or pragma
*/
pp.qml_parseHeaderStatements = function () {
var node = this.startNode()
var node = this.startNode();
node.statements = [];
var loop = true;
@ -103,7 +99,7 @@ var injectQML;
}
return this.finishNode(node, "QMLHeaderStatements");
}
};
/*
* Parses a QML Pragma statement of the form:
@ -115,7 +111,7 @@ var injectQML;
node.id = this.parseIdent(false);
this.semicolon();
return this.finishNode(node, "QMLPragmaStatement");
}
};
/*
* Parses a QML Import statement of the form:
@ -180,7 +176,7 @@ var injectQML;
node.raw = this.input.slice(this.start, this.end);
node.value = this.value;
var matches;
if (matches = /(\d+)\.(\d+)/.exec(node.raw)) {
if ((matches = /(\d+)\.(\d+)/.exec(node.raw))) {
node.major = parseInt(matches[1]);
node.minor = parseInt(matches[2]);
this.next();
@ -189,7 +185,7 @@ var injectQML;
}
return this.finishNode(node, "QMLVersionLiteral");
}
};
/*
* Parses a QML Qualifier of the form:
@ -200,7 +196,7 @@ var injectQML;
this.expectContextual(qtt._as);
node.id = this.qml_parseIdent(false);
return this.finishNode(node, "QMLQualifier");
}
};
/*
* Parses a QML Object Literal of the form:
@ -217,7 +213,7 @@ var injectQML;
}
node.body = this.qml_parseMemberBlock();
return this.finishNode(node, "QMLObjectLiteral");
}
};
/*
* Parses a QML Member Block of the form:
@ -231,7 +227,7 @@ var injectQML;
node.members.push(this.qml_parseMember());
}
return this.finishNode(node, "QMLMemberBlock");
}
};
/*
* Parses a QML Member which can be one of the following:
@ -250,7 +246,7 @@ var injectQML;
return this.qml_parseFunctionMember();
}
return this.qml_parseObjectLiteralOrPropertyBinding();
}
};
/*
* Parses a JavaScript function as a member of a QML Object Literal
@ -259,7 +255,7 @@ var injectQML;
var node = this.startNode();
this.expect(tt._function);
return this.parseFunction(node, true);
}
};
/*
* Parses a QML Object Literal or Property Binding depending on the tokens found.
@ -278,7 +274,7 @@ var injectQML;
return this.qml_parsePropertyBinding(node);
}
this.unexpected();
}
};
/*
* Parses a QML Property of the form:
@ -294,7 +290,7 @@ var injectQML;
this.expect(tt.colon);
node.binding = this.qml_parseBinding();
return this.finishNode(node, "QMLPropertyBinding");
}
};
/*
* Parses a QML Signal Definition of the form:
@ -325,7 +321,7 @@ var injectQML;
this.qml_parseSignalParams(node);
this.semicolon();
return this.finishNode(node, "QMLSignalDefinition");
}
};
/*
* Parses QML Signal Parameters of the form:
@ -344,7 +340,7 @@ var injectQML;
this.expect(tt.parenR);
}
}
}
};
/*
* Parses a QML Property Declaration (or Alias) of the form:
@ -354,10 +350,10 @@ var injectQML;
var node = this.startNode();
// Parse 'default' or 'readonly'
node["default"] = false;
node["readonly"] = false;
node.default = false;
node.readonly = false;
if (this.eat(tt._default)) {
node["default"] = true;
node.default = true;
} else if (this.isContextual(qtt._readonly)) {
// Parse as a qualified id in case this is not a property declaration
var readonly = this.qml_parseQualifiedId(true);
@ -367,7 +363,7 @@ var injectQML;
node.id = readonly;
return this.qml_parseObjectLiteralOrPropertyBinding(node);
}
node["readonly"] = true;
node.readonly = true;
} else {
// Readonly keyword is a qualified ID. This is not a property declaration.
node.id = readonly;
@ -377,22 +373,22 @@ var injectQML;
// Parse as a qualified id in case this is not a property declaration
var property = this.qml_parseQualifiedId(true);
if (property.parts.length === 1 || node["default"] || node["readonly"]) {
if (property.parts.length === 1 || node.default || node.readonly) {
if (property.name !== qtt._property) {
this.unexpected();
}
if (this.type === tt.colon || this.type === tt.braceL) {
// This is a property binding or object literal.
node["default"] = undefined;
node["readonly"] = undefined;
node.default = undefined;
node.readonly = undefined;
node.id = property;
return this.qml_parseObjectLiteralOrPropertyBinding(node);
}
} else {
// Property keyword is a qualified ID. This is not a property declaration.
node["default"] = undefined;
node["readonly"] = undefined;
node.default = undefined;
node.readonly = undefined;
node.id = property;
return this.qml_parseObjectLiteralOrPropertyBinding(node);
}
@ -407,7 +403,7 @@ var injectQML;
}
return this.finishNode(node, "QMLPropertyDeclaration");
}
};
/*
* Parses one of the following possibilities for a QML Property assignment:
@ -422,7 +418,7 @@ var injectQML;
// test: QMLObject.QualifiedId { }
return this.qml_parseScriptBinding();
}
};
/*
* Parses one of the following Script Bindings:
@ -440,7 +436,7 @@ var injectQML;
this.semicolon();
}
return this.finishNode(node, "QMLScriptBinding");
}
};
/*
* Parses a QML Statement Block of the form:
@ -454,7 +450,7 @@ var injectQML;
node.statements.push(this.parseStatement(true, false));
}
return this.finishNode(node, "QMLStatementBlock");
}
};
/*
* Parses a QML Type which can be either a Qualified ID or a primitive type keyword.
@ -468,7 +464,7 @@ var injectQML;
return this.qml_parseQualifiedId(false);
}
this.unexpected();
}
};
/*
* Parses a Qualified ID of the form:
@ -494,7 +490,7 @@ var injectQML;
}
return this.finishNode(node, "QMLQualifiedID");
}
};
/*
* Parses an Identifier in a QML Context. That is, this method uses 'isQMLContextual'
@ -511,7 +507,7 @@ var injectQML;
}
}
return this.parseIdent(liberal);
}
};
/*
* Returns whether or not a given token type and name can be a QML Identifier.
@ -520,13 +516,13 @@ var injectQML;
pp.qml_isIdent = function (type, name) {
if (type === tt.name) {
var key;
if (key = keywords[name]) {
return key.isQMLContextual
if ((key = keywords[name])) {
return key.isQMLContextual;
}
return true;
}
return false;
}
};
/*
* Returns whether or not the current token is a QML primitive type and consumes
@ -538,7 +534,7 @@ var injectQML;
return true;
}
return false;
}
};
/*
* Returns whether or not the current token is a QML primitive type.
@ -550,12 +546,12 @@ var injectQML;
if (type === tt.name) {
var key;
if (key = keywords[name]) {
if ((key = keywords[name])) {
return key.isPrimitive;
}
}
return false;
}
};
acorn.plugins.qml = function (instance) {
@ -589,8 +585,8 @@ var injectQML;
return this.finishNode(node, "QMLProgram");
};
});
}
};
return acorn;
};
})
});

View file

@ -8,18 +8,14 @@
* Contributors:
* QNX Software Systems - Initial API and implementation
*******************************************************************************/
// This will only be visible globally if we are in a browser environment
var acornQMLLoose;
(function (mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
return module.exports = mod(require("./inject.js"), require("acorn"), require("acorn/dist/acorn_loose"));
return mod(require("./inject.js"), require("acorn"), require("acorn/dist/acorn_loose"));
if (typeof define == "function" && define.amd) // AMD
return define(["./inject.js", "acorn", "acorn/dist/acorn_loose"], mod);
acornQMLLoose = mod(injectQMLLoose, acorn, acorn); // Plain browser env
})(function (injectQMLLoose, acorn, acorn_loose) {
mod(acornQMLLooseInjector, acorn, acorn); // Plain browser env
})(function (acornQMLLooseInjector, acorn, acorn_loose) {
"use strict";
return injectQMLLoose(acorn);
})
acornQMLLooseInjector.inject(acorn);
});

View file

@ -12,16 +12,16 @@
// This will only be visible globally if we are in a browser environment
var injectQMLLoose;
(function (mod) {
(function (root, mod) {
if (typeof exports === "object" && typeof module === "object") // CommonJS
return module.exports = mod();
return mod(module.exports);
if (typeof define === "function" && define.amd) // AMD
return define([], mod);
injectQMLLoose = mod(); // Plain browser env
})(function () {
return define(["exports"], mod);
mod(root.acornQMLLooseInjector || (root.acornQMLLooseInjector = {})); // Plain browser env
})(this, function (exports) {
"use strict";
return function (acorn) {
exports.inject = function (acorn) {
// Acorn token types
var tt = acorn.tokTypes;
@ -38,7 +38,7 @@ var injectQMLLoose;
* the type import or pragma
*/
lp.qml_parseHeaderStatements = function () {
var node = this.startNode()
var node = this.startNode();
node.statements = [];
var loop = true;
@ -53,7 +53,7 @@ var injectQMLLoose;
}
return this.finishNode(node, "QMLHeaderStatements");
}
};
/*
* Parses a QML Pragma statement of the form:
@ -65,7 +65,7 @@ var injectQMLLoose;
node.id = this.parseIdent(false);
this.semicolon();
return this.finishNode(node, "QMLPragmaStatement");
}
};
/*
* Parses a QML Import statement of the form:
@ -122,7 +122,7 @@ var injectQMLLoose;
node.value = this.tok.value;
var matches;
if (this.tok.type === tt.num) {
if (matches = /(\d+)\.(\d+)/.exec(node.raw)) {
if ((matches = /(\d+)\.(\d+)/.exec(node.raw))) {
node.major = parseInt(matches[1]);
node.minor = parseInt(matches[2]);
this.next();
@ -139,7 +139,7 @@ var injectQMLLoose;
}
return this.finishNode(node, "QMLVersionLiteral");
}
};
/*
* Parses a QML Qualifier of the form:
@ -150,7 +150,7 @@ var injectQMLLoose;
this.expectContextual(qtt._as);
node.id = this.qml_parseIdent(false);
return this.finishNode(node, "QMLQualifier");
}
};
/*
* Parses a QML Object Literal of the form:
@ -163,7 +163,7 @@ var injectQMLLoose;
node.id = this.qml_parseQualifiedId(false);
node.body = this.qml_parseMemberBlock();
return this.finishNode(node, "QMLObjectLiteral");
}
};
/*
* Parses a QML Member Block of the form:
@ -184,7 +184,7 @@ var injectQMLLoose;
this.popCx();
this.eat(tt.braceR);
return this.finishNode(node, "QMLMemberBlock");
}
};
/*
* Parses a QML Member which can be one of the following:
@ -222,7 +222,7 @@ var injectQMLLoose;
}
// ignore the current token if it didn't pass the previous tests
this.next();
}
};
/*
* Parses a JavaScript function as a member of a QML Object Literal
@ -231,7 +231,7 @@ var injectQMLLoose;
var node = this.startNode();
this.expect(tt._function);
return this.qml_parseFunction(node, true);
}
};
/*
* QML version of 'parseFunction' needed to have proper error tolerant parsing
@ -250,7 +250,7 @@ var injectQMLLoose;
node.body = this.parseBlock();
} else {
if (this.options.locations) {
node.body = this.startNodeAt([ this.last.end, this.last.loc.end ])
node.body = this.startNodeAt([ this.last.end, this.last.loc.end ]);
} else {
node.body = this.startNodeAt(this.last.end);
}
@ -258,7 +258,7 @@ var injectQMLLoose;
this.finishNode(node.body, "BlockStatement");
}
return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression");
}
};
/*
* Parses a QML Object Literal or Property Binding depending on the tokens found.
@ -282,7 +282,7 @@ var injectQMLLoose;
return this.qml_parsePropertyBinding();
}
return null;
}
};
/*
* Parses a QML Property of the form:
@ -295,7 +295,7 @@ var injectQMLLoose;
this.expect(tt.colon);
node.binding = this.qml_parseBinding(start);
return this.finishNode(node, "QMLPropertyBinding");
}
};
/*
* Parses a QML Signal Definition of the form:
@ -315,13 +315,13 @@ var injectQMLLoose;
this.qml_parseSignalParams(node);
this.semicolon();
return this.finishNode(node, "QMLSignalDefinition");
}
};
/*
* Checks if the given node is a dummy identifier
*/
function isDummy(node) {
return node.name === "✖"
return node.name === "✖";
}
/*
@ -329,8 +329,8 @@ var injectQMLLoose;
* [(<Type> <Identifier> [',' <Type> <Identifier>]* )]?
*/
lp.qml_parseSignalParams = function (node) {
this.pushCx()
var indent = this.curIndent, line = this.curLineStart
this.pushCx();
var indent = this.curIndent, line = this.curLineStart;
node.params = [];
if (this.eat(tt.parenL)) {
while (!this.closes(tt.parenR, indent + 1, line)) {
@ -352,15 +352,15 @@ var injectQMLLoose;
}
this.eat(tt.comma);
}
this.popCx()
this.popCx();
if (!this.eat(tt.parenR)) {
// If there is no closing brace, make the node span to the start
// of the next token (this is useful for Tern)
this.last.end = this.tok.start
if (this.options.locations) this.last.loc.end = this.tok.loc.start
this.last.end = this.tok.start;
if (this.options.locations) this.last.loc.end = this.tok.loc.start;
}
}
}
};
/*
* Parses a QML Property Declaration (or Alias) of the form:
@ -368,25 +368,26 @@ var injectQMLLoose;
*/
lp.qml_parsePropertyDeclaration = function () {
var node = this.startNode();
var objOrBind = null;
// Parse 'default' or 'readonly'
node["default"] = false;
node["readonly"] = false;
node.default = false;
node.readonly = false;
if (this.eat(tt._default)) {
node["default"] = true;
node.default = true;
} else if (this.isContextual(qtt._readonly)) {
var objOrBind = this.qml_parseObjectLiteralOrPropertyBinding();
objOrBind = this.qml_parseObjectLiteralOrPropertyBinding();
if (objOrBind) {
objOrBind["default"] = undefined;
objOrBind["readonly"] = undefined;
objOrBind.default = undefined;
objOrBind.readonly = undefined;
return objOrBind;
}
this.expectContextual(qtt._readonly);
node["readonly"] = true;
node.readonly = true;
}
if (!node["default"] && !node["readonly"]) {
var objOrBind = this.qml_parseObjectLiteralOrPropertyBinding();
if (!node.default && !node.readonly) {
objOrBind = this.qml_parseObjectLiteralOrPropertyBinding();
if (objOrBind) {
return objOrBind;
}
@ -408,7 +409,7 @@ var injectQMLLoose;
}
return this.finishNode(node, "QMLPropertyDeclaration");
}
};
/*
* Parses one of the following possibilities for a QML Property assignment:
@ -437,7 +438,7 @@ var injectQMLLoose;
} else {
return this.qml_parseScriptBinding(start);
}
}
};
/*
* Parses one of the following Script Bindings:
@ -458,7 +459,7 @@ var injectQMLLoose;
}
// If this node consumed valid syntax, reset its start position
if (!node.script.type === "Identifier" || node.script.name !== "✖") {
if (node.script.type !== "Identifier" || node.script.name !== "✖") {
if (node.loc) {
node.loc.start = node.script.loc.start;
}
@ -470,7 +471,7 @@ var injectQMLLoose;
}
return this.finishNode(node, "QMLScriptBinding");
}
};
/*
* Parses a QML Statement Block of the form:
@ -489,7 +490,7 @@ var injectQMLLoose;
this.popCx();
this.eat(tt.braceR);
return this.finishNode(node, "QMLStatementBlock");
}
};
/*
* Parses a QML Type which can be either a Qualified ID or a primitive type keyword.
@ -501,7 +502,7 @@ var injectQMLLoose;
} else {
return this.qml_parseQualifiedId(false);
}
}
};
/*
* Parses a Qualified ID of the form:
@ -527,7 +528,7 @@ var injectQMLLoose;
}
return this.finishNode(node, "QMLQualifiedID");
}
};
/*
* Parses an Identifier in a QML Context. That is, this method uses 'isQMLContextual'
@ -544,7 +545,7 @@ var injectQMLLoose;
}
}
return this.parseIdent();
}
};
/*
* Checks the next token to see if it matches the given contextual keyword. If the
@ -552,14 +553,14 @@ var injectQMLLoose;
* and jumps ahead if it was found there. Returns whether or not the keyword was found.
*/
lp.expectContextual = function(name) {
if (this.eatContextual(name)) return true
if (this.eatContextual(name)) return true;
for (var i = 1; i <= 2; i++) {
if (this.lookAhead(i).type == tt.name && this.lookAhead(i).value === name) {
for (var j = 0; j < i; j++) this.next()
return true
for (var j = 0; j < i; j++) this.next();
return true;
}
}
}
};
// Functions left un-changed from the main parser
lp.qml_isIdent = pp.qml_isIdent;
@ -592,8 +593,8 @@ var injectQMLLoose;
return this.finishNode(node, "QMLProgram");
};
});
}
};
return acorn;
};
})
});

View file

@ -8,7 +8,7 @@
* Contributors:
* QNX Software Systems - Initial API and implementation
*******************************************************************************/
"use-strict";
"use strict";
var tests = [];
@ -31,10 +31,10 @@ exports.runTests = function(config, callback) {
try {
var testOpts = test.options || {locations: true};
var expected = {};
if (expected.onComment = testOpts.onComment) {
testOpts.onComment = []
if ((expected.onComment = testOpts.onComment)) {
testOpts.onComment = [];
}
if (expected.onToken = testOpts.onToken) {
if ((expected.onToken = testOpts.onToken)) {
testOpts.onToken = [];
}
testOpts.plugins = { qml: true };
@ -87,6 +87,7 @@ function addPath(str, pt) {
}
var misMatch = exports.misMatch = function(exp, act) {
var mis = null;
if (!exp || !act || (typeof exp != "object") || (typeof act != "object")) {
if (exp !== act) return ppJSON(exp) + " !== " + ppJSON(act);
} else if (exp instanceof RegExp || act instanceof RegExp) {
@ -96,12 +97,12 @@ var misMatch = exports.misMatch = function(exp, act) {
if (!act.slice) return ppJSON(exp) + " != " + ppJSON(act);
if (act.length != exp.length) return "array length mismatch " + exp.length + " != " + act.length;
for (var i = 0; i < act.length; ++i) {
var mis = misMatch(exp[i], act[i]);
mis = misMatch(exp[i], act[i]);
if (mis) return addPath(mis, i);
}
} else {
for (var prop in exp) {
var mis = misMatch(exp[prop], act[prop]);
mis = misMatch(exp[prop], act[prop]);
if (mis) return addPath(mis, prop);
}
}

View file

@ -8,11 +8,18 @@
* Contributors:
* QNX Software Systems - Initial API and implementation
*******************************************************************************/
"use-strict";
"use strict";
// Get the driver and test code
var driver = require("./driver.js");
require("./tests-qml.js");
// Get and inject the QML plugin into Acorn
var acorn = require("acorn");
require("acorn/dist/acorn_loose");
require("..");
require("../loose");
function group(name) {
if (typeof console === "object" && console.group) {
console.group(name);
@ -32,7 +39,7 @@ function log(title, message) {
var stats, modes = {
Normal: {
config: {
parse: require("..").parse,
parse: acorn.parse,
normal: true,
filter: function (test) {
var opts = test.options || {};
@ -42,7 +49,7 @@ var stats, modes = {
},
Loose: {
config: {
parse: require("../loose").parse_dammit,
parse: acorn.parse_dammit,
loose: true,
filter: function (test) {
var opts = test.options || {};
@ -63,9 +70,9 @@ for (var name in modes) {
group(name);
var mode = modes[name];
stats = mode.stats = {testsRun: 0, failed: 0};
var t0 = +new Date;
var t0 = +new Date();
driver.runTests(mode.config, report);
mode.stats.duration = +new Date - t0;
mode.stats.duration = +new Date() - t0;
groupEnd();
}

View file

@ -8,11 +8,12 @@
* Contributors:
* QNX Software Systems - Initial API and implementation
*******************************************************************************/
"use-strict";
"use strict";
var test = require("./driver.js").test;
var testFail = require("./driver.js").testFail;
var tokTypes = require("../").tokTypes;
var driver = require("./driver.js");
var test = driver.test;
var testFail = driver.testFail;
var tokTypes = driver.tokTypes;
testFail('', "QML only supports ECMA Script Language Specification 5 or older",
{ locations: true, ecmaVersion: 6, allowReserved: false });
@ -3241,7 +3242,7 @@ function program(headerStatements, rootObject) {
statements: headerStatements || []
},
rootObject: rootObject || null
}
};
}
/*

View file

@ -10,7 +10,7 @@
*******************************************************************************/
(function (mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
return module.exports = mod(require("acorn/dist/walk"));
return mod(require("acorn/dist/walk"));
if (typeof define == "function" && define.amd) // AMD
return define(["acorn/dist/walk"], mod);
mod(acorn.walk); // Plain browser env
@ -18,53 +18,59 @@
"use strict";
function skipThrough(node, st, c) {
c(node, st)
c(node, st);
}
function ignore(node, st, c) {}
var base = walk.base;
base["QMLProgram"] = function (node, st, c) {
c(node.headerStatements, st);
if (node.rootObject) {
c(node.rootObject, st, "QMLRootObject");
function extendWalk(walker, funcs) {
for (var prop in funcs) {
walker[prop] = funcs[prop];
}
};
base["QMLHeaderStatements"] = function (node, st, c) {
for (var i = 0; i < node.statements.length; i++) {
c(node.statements[i], st, "QMLHeaderStatement");
}
};
base["QMLHeaderStatement"] = skipThrough;
base["QMLImportStatement"] = ignore;
base["QMLPragmaStatement"] = ignore;
base["QMLRootObject"] = skipThrough;
base["QMLObjectLiteral"] = function (node, st, c) {
c(node.body, st);
};
base["QMLMemberBlock"] = function (node, st, c) {
for (var i = 0; i < node.members.length; i++) {
c(node.members[i], st, "QMLMember");
}
};
base["QMLMember"] = skipThrough;
base["QMLPropertyDeclaration"] = function (node, st, c) {
if (node.binding) {
c(node.binding, st);
}
};
base["QMLSignalDefinition"] = ignore;
base["QMLPropertyBinding"] = function (node, st, c) {
c(node.binding, st);
};
base["QMLScriptBinding"] = function (node, st, c) {
c(node.script, st);
}
base["QMLQualifiedID"] = ignore;
base["QMLStatementBlock"] = function (node, st, c) {
for (var i = 0; i < node.statements.length; i++) {
c(node.statements[i], st, "Statement");
extendWalk(walk.base, {
QMLProgram: function (node, st, c) {
c(node.headerStatements, st);
if (node.rootObject) {
c(node.rootObject, st, "QMLRootObject");
}
},
QMLHeaderStatements: function (node, st, c) {
for (var i = 0; i < node.statements.length; i++) {
c(node.statements[i], st, "QMLHeaderStatement");
}
},
QMLHeaderStatement: skipThrough,
QMLImportStatement: ignore,
QMLPragmaStatement: ignore,
QMLRootObject: skipThrough,
QMLObjectLiteral: function (node, st, c) {
c(node.body, st);
},
QMLMemberBlock: function (node, st, c) {
for (var i = 0; i < node.members.length; i++) {
c(node.members[i], st, "QMLMember");
}
},
QMLMember: skipThrough,
QMLPropertyDeclaration: function (node, st, c) {
if (node.binding) {
c(node.binding, st);
}
},
QMLSignalDefinition: ignore,
QMLPropertyBinding: function (node, st, c) {
c(node.binding, st);
},
QMLScriptBinding: function (node, st, c) {
c(node.script, st);
},
QMLQualifiedID: ignore,
QMLStatementBlock: function (node, st, c) {
for (var i = 0; i < node.statements.length; i++) {
c(node.statements[i], st, "Statement");
}
}
};
return walk;
})
});
});

View file

@ -1,5 +1,4 @@
(function() {
var def = {
var ecma5 = {
"!name": "ecma5",
"!define": {"Error.prototype": "Error.prototype"},
"Infinity": {
@ -964,6 +963,4 @@ var def = {
"!url": "https://developer.mozilla.org/en-US/docs/JSON",
"!doc": "JSON (JavaScript Object Notation) is a data-interchange format. It closely resembles a subset of JavaScript syntax, although it is not a strict subset. (See JSON in the JavaScript Reference for full details.) It is useful when writing any kind of JavaScript-based application, including websites and browser extensions. For example, you might store user information in JSON format in a cookie, or you might store extension preferences in JSON in a string-valued browser preference."
}
}
CodeMirror.tern.addDef(def);
})();
}

View file

@ -0,0 +1,91 @@
.CodeMirror {
border: 1px solid silver;
height: 400px;
line-height: 1.3;
font-size: 13pt;
font-family: "Ubuntu Mono", monospace;
z-index: 2;
}
.CodeMirror pre {
padding: 0 9px;
}
.CodeMirror-linenumber {
font-size: 80%;
padding-top: 2px;
}
ul.tabs {
list-style: none;
margin: 0 0 -1px 0;
padding: 0 0 0 37px;
font-family: "Ubuntu Mono", monospace;
overflow: hidden;
}
ul.tabs li {
font-size: 11pt;
color: #777;
cursor: pointer;
margin: 0 2px 0 0;
padding: 2px 10px 5px;
border: 1px solid silver;
border-bottom-width: 0px;
background: #f3f3f3;
display: inline-block;
z-index: 1;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
position: relative;
}
ul.tabs li:hover {
color: #444;
}
ul.tabs li.selected {
background: white;
color: #222;
z-index: 3;
cursor: default;
}
ul.tabs li:before,
ul.tabs li:after {
position: absolute;
bottom: 0;
width: 6px;
height: 6px;
content: " ";
border: 1px solid silver;
}
ul.tabs li:before {
left: -7px;
border-bottom-right-radius: 6px;
border-width: 0 1px 1px 0;
box-shadow: 2px 2px 0 #f3f3f3;
}
ul.tabs li:after {
right: -7px;
border-bottom-left-radius: 6px;
border-width: 0 0 1px 1px;
box-shadow: -2px 2px 0 #f3f3f3;
}
ul.tabs li.selected:before {
box-shadow: 2px 2px 0 white;
}
ul.tabs li.selected:after {
box-shadow: -2px 2px 0 white;
}
#menus {
position: absolute;
right: 0;
top: 0;
}
#menus select {
font-family: "Ubuntu Mono", monospace;
font-size: 11pt;
width: 8em;
}
.CodeMirror div.CodeMirror-cursor {
border-left: 2px solid #444;
}
.CodeMirror-hint { font-size: 12pt; }

View file

@ -0,0 +1,232 @@
var project;
function Project(name, place, config, docs) {
this.name = name;
this.docs = Object.create(null);
this.tabs = place.appendChild(document.createElement("ul"));
this.tabs.className = "tabs";
var self = this;
CodeMirror.on(this.tabs, "click", function (e) {
var target = e.target || e.srcElement;
if (target.nodeName.toLowerCase() != "li") return;
var doc = self.findDoc(target.textContent);
if (doc) self.selectDoc(doc);
});
var myConf = {
switchToDoc: function (name) {
self.selectDoc(self.findDoc(name));
},
useWorker: false
};
for (var prop in config) myConf[prop] = config[prop];
var server = this.server = new CodeMirror.TernServer(myConf);
var firstDoc;
for (name in docs) {
var data = this.registerDoc(name, new CodeMirror.Doc(docs[name], "javascript"));
if (!firstDoc) firstDoc = data;
}
this.curDoc = firstDoc;
this.setSelectedTab(firstDoc);
var keyMap = {
"Ctrl-I": function (cm) {
server.showType(cm);
},
"Ctrl-O": function (cm) {
server.showDocs(cm);
},
"Ctrl-Space": function (cm) {
server.complete(cm);
},
"Ctrl-J": function (cm) {
server.jumpToDef(cm);
},
"Ctrl-,": function (cm) {
server.jumpBack(cm);
},
"Ctrl-Q": function (cm) {
server.rename(cm);
}
};
this.editor = new CodeMirror(place, {
mode: 'text/javascript',
theme: "eclipse",
styleActiveLine: true,
lineNumbers: true,
lineWrapping: true,
autoCloseBrackets: true,
matchBrackets: true,
indentWithTabs: true,
indentUnit: 4,
tabSize: 4,
extraKeys: keyMap,
value: firstDoc.doc
});
this.editor.on("cursorActivity", function (cm) {
server.updateArgHints(cm);
});
}
Project.prototype = {
findDoc: function (name) {
return this.docs[name];
},
registerDoc: function (name, doc) {
this.server.addDoc(name, doc);
var data = this.docs[name] = {
name: name,
doc: doc,
tab: this.tabs.appendChild(document.createElement("li"))
};
data.tab.textContent = name;
return data;
},
unregisterDoc: function (doc) {
this.server.delDoc(doc.name);
delete this.docs[doc.name];
this.tabs.removeChild(doc.tab);
if (this.curDoc == doc)
for (var n in this.docs) return this.selectDoc(this.docs[n]);
},
setSelectedTab: function (doc) {
for (var n = this.tabs.firstChild; n; n = n.nextSibling)
n.className = n.textContent == doc.name ? "selected" : "";
},
selectDoc: function (doc) {
if (doc == this.curDoc) return;
this.server.hideDoc(this.curDoc);
this.setSelectedTab(doc);
this.curDoc = doc;
this.editor.swapDoc(doc.doc);
}
};
// Initialization
CodeMirror.on(window, "load", function () {
var cmds = document.getElementById("commands");
CodeMirror.on(cmds, "change", function () {
if (!project || cmds.selectedIndex === 0) return;
var found = commands[cmds.value];
cmds.selectedIndex = 0;
project.editor.focus();
if (found) found();
});
var projects = document.getElementById("projects");
var projectNames = [];
var projectTags = document.querySelectorAll("project");
for (var i = 0; i < projectTags.length; i++) {
var opt = projects.appendChild(document.createElement("option"));
projectNames.push(opt.textContent = projectTags[i].id);
}
CodeMirror.on(projects, "change", function () {
initProject(projects.value, function () {
projects.selectedIndex = 0;
project.editor.focus();
});
});
function updateFromHash() {
var name = location.hash.slice(1);
if (projectNames.indexOf(name) > -1 &&
(!project || project.name != name)) {
initProject(name);
return true;
}
}
CodeMirror.on(window, "hashchange", updateFromHash);
updateFromHash() || initProject("simple");
});
function loadFiles(project, c) {
var found = {};
function inner(node) {
while (node && node.nodeName != "PRE") node = node.nextSibling;
if (!node) return c(found);
if (node.hasAttribute("file")) {
load(node.getAttribute("file"), function (data) {
found[node.id] = data;
inner(node.nextSibling);
});
} else {
found[node.id] = node.textContent;
inner(node.nextSibling);
}
}
inner(project.firstChild);
}
function words(str) {
return str ? str.split(" ") : [];
}
function initProject(name, c) {
var node = document.getElementById(name);
var plugins = {};
words(node.getAttribute("data-plugins")).forEach(function (name) {
plugins[name] = true;
});
if (plugins.requirejs) plugins.requirejs = {
override: {
"jquery": "=$"
}
};
loadFiles(node, function (files) {
var place = document.getElementById("place");
place.textContent = "";
if (project) project.server.destroy();
project = new Project(name, place, {
defs: [ecma5],
plugins: plugins
}, files);
location.hash = "#" + name;
c && c();
});
}
var commands = {
complete: function () {
project.server.complete(project.editor);
},
jumptodef: function () {
project.server.jumpToDef(project.editor);
},
finddocs: function () {
project.server.showDocs(project.editor);
},
findtype: function () {
project.server.showType(project.editor);
},
rename: function () {
project.server.rename(project.editor);
},
addfile: function () {
var name = prompt("Name of the new buffer", "");
if (name == null) return;
if (!name) name = "test";
var i = 0;
while (project.findDoc(name + (i || ""))) ++i;
project.selectDoc(project.registerDoc(name + (i || ""), new CodeMirror.Doc("", "javascript")));
},
delfile: function () {
var hasDoc = false;
for (var _ in project.docs) {
hasDoc = true;
break;
}
if (hasDoc) project.unregisterDoc(project.curDoc);
}
};

View file

@ -0,0 +1,142 @@
@font-face {
font-family: 'Signika';
font-style: normal;
font-weight: 700;
src: local('Signika-Bold'), url(http://themes.googleusercontent.com/static/fonts/signika/v3/7M5kxD4eGxuhgFaIk95pBRsxEYwM7FgeyaSgU71cLG0.woff) format('woff');
}
@font-face {
font-family: 'Ubuntu Mono';
font-style: normal;
font-weight: 500;
src: local('Ubuntu Mono'), local('UbuntuMono-Regular'), url('http://themes.googleusercontent.com/static/fonts/ubuntumono/v3/ViZhet7Ak-LRXZMXzuAfkYbN6UDyHWBl620a-IRfuBk.woff') format('woff');
}
body {
font-family: "Helvetica Neue", "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, sans-serif;
color: #222;
font-size: 11pt;
max-width: 700px;
margin: 0 0 0 60px;
padding: 60px 0 4em;
}
#top {
position: fixed;
top: 0;
background: white;
padding-top: 15px;
left: 20px; right: 20px;
z-index: 5;
}
#head {
border-radius: 5px;
background: #1c5b64;
box-shadow: 0px 3px 3px rgba(0, 0, 0, .5);
position: relative;
font-family: "Signika", sans-serif;
font-weight: 700;
}
#head > a {
border-right: 1px solid #276c81;
display: inline-block;
height: 25px;
padding: 5px 20px;
color: white;
text-decoration: none;
line-height: 25px;
font-size: 17px;
}
#head > a.title {
font-size: 20px;
line-height: 24px;
padding-left: 80px;
background: url(logo.png);
background-position: 40px center;
background-size: auto 80%;
background-repeat: no-repeat;
border-bottom-left-radius: 5px;
border-top-left-radius: 5px;
}
#head > a:hover {
background-color: #276c81 !important;
}
.title span {
font-size: 13px;
}
code, pre { font-family: "Ubuntu Mono", monospace; }
code { color: #124f55; font-size: 110%; }
pre {
border-left: 3px solid #def;
padding: 2px 0 2px 10px;
}
h1, h2, h3, h4 {
font-family: "Signika", sans-serif;
font-weight: 700;
color: #124f55;
}
h1 { font-size: 20pt; }
h2 { font-size: 17pt; }
h3 { font-size: 13pt; }
h4 { font-size: 11pt; }
a, a:visited, a code { color: #df4c11; text-decoration: none; }
a:hover { text-decoration: underline; }
ul, ol {
margin: 0;
padding: 0;
}
li {
margin-left: 1.5em;
padding: 0;
}
li p { margin: 0; }
dd p:first-child { margin-top: 1px; }
dd { margin-left: 20px; }
dt { text-indent: -1em; padding-left: 1em; }
a[id] {
position: relative;
display: inline-block;
vertical-align: top;
top: -60px;
}
.release-note {
margin-left: 1em;
}
/* CodeMirror default theme for highlighting */
.cm-s-default .cm-keyword {color: #708;}
.cm-s-default .cm-atom {color: #219;}
.cm-s-default .cm-number {color: #164;}
.cm-s-default .cm-def {color: #00f;}
.cm-s-default .cm-variable {color: black;}
.cm-s-default .cm-variable-2 {color: #05a;}
.cm-s-default .cm-variable-3 {color: #085;}
.cm-s-default .cm-property {color: black;}
.cm-s-default .cm-operator {color: black;}
.cm-s-default .cm-comment {color: #a50;}
.cm-s-default .cm-string {color: #a11;}
.cm-s-default .cm-string-2 {color: #f50;}
.cm-s-default .cm-meta {color: #555;}
.cm-s-default .cm-error {color: #f00;}
.cm-s-default .cm-qualifier {color: #555;}
.cm-s-default .cm-builtin {color: #30a;}
.cm-s-default .cm-bracket {color: #997;}
.cm-s-default .cm-tag {color: #170;}
.cm-s-default .cm-attribute {color: #00c;}
.cm-s-default .cm-header {color: blue;}
.cm-s-default .cm-quote {color: #090;}
.cm-s-default .cm-hr {color: #999;}
.cm-s-default .cm-link {color: #00c;}

View file

@ -1,102 +1,254 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>QML Tern Demo</title>
<!-- CodeMirror -->
<link rel="stylesheet" href="../node_modules/codemirror/lib/codemirror.css">
<script src="../node_modules/codemirror/lib/codemirror.js"></script>
<link rel="stylesheet" href="../node_modules/codemirror/theme/eclipse.css">
<script src="../node_modules/codemirror/addon/hint/show-hint.js"></script>
<script src="../node_modules/codemirror/addon/edit/closetag.js"></script>
<script src="../node_modules/codemirror/addon/edit/closebrackets.js"></script>
<script src="../node_modules/codemirror/addon/edit/matchbrackets.js"></script>
<script src="../node_modules/codemirror/addon/selection/active-line.js"></script>
<script src="../node_modules/codemirror/mode/javascript/javascript.js"></script>
<head>
<meta charset="utf-8">
<title>Tern QML Demo</title>
<!-- Acorn -->
<script src="../node_modules/acorn/dist/acorn.js"></script>
<script src="../node_modules/acorn/dist/acorn_loose.js"></script>
<script src="../node_modules/acorn/dist/walk.js"></script>
<script src="../node_modules/acorn-qml/inject.js"></script>
<script src="../node_modules/acorn-qml/index.js"></script>
<script src="../node_modules/acorn-qml/loose/inject.js"></script>
<script src="../node_modules/acorn-qml/loose/index.js"></script>
<script src="../node_modules/acorn-qml/walk/index.js"></script>
<!-- CodeMirror Stylesheets -->
<link rel=stylesheet href="../node_modules/codemirror/lib/codemirror.css">
<link rel="stylesheet" href="../node_modules/codemirror/theme/eclipse.css">
<link rel="stylesheet" href="../node_modules/codemirror/addon/dialog/dialog.css">
<!-- Tern JS -->
<script src="../node_modules/tern/lib/signal.js"></script>
<script src="../node_modules/tern/lib/tern.js"></script>
<script src="../node_modules/tern/lib/def.js"></script>
<script src="../node_modules/tern/lib/comment.js"></script>
<script src="../node_modules/tern/lib/infer.js"></script>
<script src="../qml.js"></script>
<!-- CodeMirror-JavaScript Stylesheets -->
<link rel="stylesheet" href="../node_modules/codemirror-javascript/addon/hint/tern/tern-extension.css">
<!-- Official CodeMirror Tern addon -->
<script src="../node_modules/codemirror/addon/tern/tern.js"></script>
<!-- CodeMirror-Extension Stylesheets -->
<link rel="stylesheet" href="../node_modules/codemirror-extension/addon/hover/text-hover.css">
<link rel="stylesheet" href="../node_modules/codemirror-extension/addon/hint/templates-hint.css">
<link rel="stylesheet" href="../node_modules/codemirror-extension/addon/hint/show-hint-eclipse.css">
<link rel="stylesheet" href="../node_modules/codemirror-extension/addon/hint/show-context-info.css">
<!-- Extension of CodeMirror Tern addon -->
<link rel="stylesheet" href="../node_modules/codemirror-javascript/addon/hint/tern/tern-extension.css">
<script src="../node_modules/codemirror-javascript/addon/hint/tern/tern-extension.js"></script>
<script src="defs/ecma5.json.js"></script>
<!-- Demo Specific Stylesheets -->
<link rel=stylesheet href="./docs.css">
<link rel=stylesheet href="./demo.css">
</head>
<!-- CodeMirror Extension -->
<link rel="stylesheet" href="../node_modules/codemirror-extension/addon/hint/show-hint-eclipse.css">
<script src="../node_modules/codemirror-extension/addon/hint/show-context-info.js"></script>
<link rel="stylesheet" href="../node_modules/codemirror-extension/addon/hint/show-context-info.css">
<body>
<h1>Demo with QML Tern plugin </h1>
<title>QML Tern Demo</title>
<link rel="stylesheet" href="../node_modules/codemirror-extension/addon/hint/templates-hint.css">
<script src="../node_modules/codemirror-extension/addon/hint/templates-hint.js"></script>
<!-- CodeMirror -->
<script src="../node_modules/codemirror/lib/codemirror.js"></script>
<script src="../node_modules/codemirror/addon/hint/show-hint.js"></script>
<script src="../node_modules/codemirror/addon/edit/closetag.js"></script>
<script src="../node_modules/codemirror/addon/edit/closebrackets.js"></script>
<script src="../node_modules/codemirror/addon/edit/matchbrackets.js"></script>
<script src="../node_modules/codemirror/addon/selection/active-line.js"></script>
<script src="../node_modules/codemirror/mode/javascript/javascript.js"></script>
<!-- CodeMirror Javascript -->
<script src="../node_modules/codemirror-javascript/addon/hint/javascript/javascript-templates.js"></script>
<!-- Acorn -->
<script src="../node_modules/acorn/dist/acorn.js"></script>
<script src="../node_modules/acorn/dist/acorn_loose.js"></script>
<script src="../node_modules/acorn/dist/walk.js"></script>
<script src="../node_modules/acorn-qml/inject.js"></script>
<script src="../node_modules/acorn-qml/index.js"></script>
<script src="../node_modules/acorn-qml/loose/inject.js"></script>
<script src="../node_modules/acorn-qml/loose/index.js"></script>
<script src="../node_modules/acorn-qml/walk/index.js"></script>
<!-- Tern Hover -->
<link rel="stylesheet" href="../node_modules/codemirror-extension/addon/hover/text-hover.css">
<script src="../node_modules/codemirror-extension/addon/hover/text-hover.js"></script>
<script src="../node_modules/codemirror-javascript/addon/hint/tern/tern-hover.js"></script>
</head>
<body>
<h1>Demo with QML Tern plugin </h1>
<div style="border: solid 1px #AAAAAA;">
<form><textarea id="code" name="code">import QtQuick 2.3&#10;Window {&#10;&#09;prop: {&#10;&#09;&#09;Qt.quit();&#10;&#09;}&#10;}&#10;</textarea></form>
<!-- Tern JS -->
<script src="../node_modules/tern/lib/signal.js"></script>
<script src="../node_modules/tern/lib/tern.js"></script>
<script src="../node_modules/tern/lib/def.js"></script>
<script src="../node_modules/tern/lib/comment.js"></script>
<script src="../node_modules/tern/lib/infer.js"></script>
<script src="../qml.js"></script>
<!-- Official CodeMirror Tern addon -->
<script src="../node_modules/codemirror/addon/tern/tern.js"></script>
<!-- ECMA 5th Edition Definitions File -->
<script src="defs/ecma5.json.js"></script>
<!-- CodeMirror Extension -->
<script src="../node_modules/codemirror-extension/addon/hint/show-context-info.js"></script>
<script src="../node_modules/codemirror-extension/addon/hint/templates-hint.js"></script>
<!-- CodeMirror Javascript -->
<script src="../node_modules/codemirror-javascript/addon/hint/javascript/javascript-templates.js"></script>
<!-- Tern Hover -->
<script src="../node_modules/codemirror-extension/addon/hover/text-hover.js"></script>
<script src="../node_modules/codemirror-javascript/addon/hint/tern/tern-hover.js"></script>
<!-- Extra script to control project logic -->
<script src="./demo.js"></script>
<div style="position: relative" id="demospace">
<div id="menus">
<select id="commands">
<option>commands...</option>
<option value="complete">Autocomplete (Ctrl-Space)</option>
<option value="jumptodef">Jump to definition (ctrl-J)</option>
<option value="finddocs">Describe (Ctrl-O)</option>
<option value="findtype">Find type of (Ctrl-I)</option>
<option value="rename">Rename variable (Ctrl-Q)</option>
<option value="addfile">Add a new file</option>
<option value="delfile">Remove this file</option>
</select>
</div>
<script type="text/javascript">
function passAndHint(cm) {
setTimeout(function() {cm.execCommand("autocomplete");}, 100);
return CodeMirror.Pass;
}
<form id="place">
<ul class="tabs">
<li class="selected">test</li>
</ul>
<div class="CodeMirror cm-s-default">
<div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 5px; left: 40px;">
<textarea autocorrect="off" autocapitalize="off" spellcheck="false" style="position: absolute; padding: 0px; width: 1000px; height: 1em; outline: none;" tabindex="0"></textarea>
</div>
<div class="CodeMirror-vscrollbar" cm-not-content="true" style="display: block; bottom: 0px;">
<div style="min-width: 1px; height: 580px;"></div>
</div>
<div class="CodeMirror-hscrollbar" cm-not-content="true">
<div style="height: 100%; min-height: 1px; width: 0px;"></div>
</div>
<div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div>
<div class="CodeMirror-gutter-filler" cm-not-content="true"></div>
<div class="CodeMirror-scroll" tabindex="-1">
<div class="CodeMirror-sizer" style="margin-left: 30px; margin-bottom: -21px; border-right-width: 9px; min-height: 580px; min-width: 531.891px; padding-right: 21px; padding-bottom: 0px;">
<div style="position: relative; top: 0px;">
<div class="CodeMirror-lines">
<div style="position: relative; outline: none;">
<div class="CodeMirror-measure"><span><span></span>x</span>
</div>
<div class="CodeMirror-measure"></div>
<div style="position: relative; z-index: 1;"></div>
<div class="CodeMirror-cursors">
<div class="CodeMirror-cursor" style="left: 9px; top: 0px; height: 22px;">&nbsp;</div>
</div>
<div class="CodeMirror-code">
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">1</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-comment">// Use ctrl-space to complete something</span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">2</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-variable">co</span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">3</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-variable">document</span>.<span class="cm-property">body</span>.<span class="cm-property">a</span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">4</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span cm-text=""></span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">5</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-comment">// Put the cursor in or after an expression, press ctrl-i to</span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">6</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-comment">// find its type</span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">7</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span cm-text=""></span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">8</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-keyword">var</span> <span class="cm-def">foo</span> <span class="cm-operator">=</span> [<span class="cm-string">"array"</span>, <span class="cm-string">"of"</span>, <span class="cm-string">"strings"</span>]</span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">9</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-keyword">var</span> <span class="cm-def">bar</span> <span class="cm-operator">=</span> <span class="cm-variable">foo</span>.<span class="cm-property">slice</span>(<span class="cm-number">0</span>, <span class="cm-number">2</span>).<span class="cm-property">join</span>(<span class="cm-string">""</span>).<span class="cm-property">split</span>(<span class="cm-string">"a"</span>)[<span class="cm-number">0</span>]</span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">10</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span cm-text=""></span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">11</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-comment">// Works for locally defined types too.</span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">12</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span cm-text=""></span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">13</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-keyword">function</span> <span class="cm-def">CTor</span>() { <span class="cm-keyword">this</span>.<span class="cm-property">size</span> <span class="cm-operator">=</span> <span class="cm-number">10</span> }</span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">14</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-variable">CTor</span>.<span class="cm-property">prototype</span>.<span class="cm-property">hallo</span> <span class="cm-operator">=</span> <span class="cm-string">"hallo"</span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">15</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span cm-text=""></span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">16</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-keyword">var</span> <span class="cm-def">baz</span> <span class="cm-operator">=</span> <span class="cm-keyword">new</span> <span class="cm-variable">CTor</span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">17</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-variable">baz</span>.</span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">18</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span cm-text=""></span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">19</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-comment">// You can press ctrl-q when the cursor is on a variable</span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">20</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-comment">// name to rename it. Try it with CTor...</span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">21</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span cm-text=""></span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">22</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-comment">// When the cursor is in an argument list, the arguments</span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">23</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-comment">// are shown below the editor.</span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">24</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span cm-text=""></span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">25</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;">[<span class="cm-number">1</span>].<span class="cm-property">reduce</span>( )</span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">26</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span cm-text=""></span></span></pre></div>
</div>
</div>
</div>
</div>
</div>
<div style="position: absolute; height: 9px; width: 1px; top: 580px;"></div>
<div class="CodeMirror-gutters" style="height: 589px;">
<div class="CodeMirror-gutter CodeMirror-linenumbers" style="width: 29px;"></div>
</div>
</div>
</div>
</form>
</div>
function myHint(cm) {
return CodeMirror.showHint(cm, CodeMirror.ternHint, {async: true});
}
<div style="display: none" id="projects">
<project id="simple" data-plugins="qml">
<pre id="main.qml">MyButton {
}
</pre>
<pre id="MyButton.qml">Button {
property int width;
property int height;
property var parent;
}
</pre>
</project>
</div>
</body>
CodeMirror.commands.autocomplete = function(cm) {
CodeMirror.showHint(cm, myHint);
}
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
mode: 'text/javascript',
theme : "eclipse",
styleActiveLine: true,
lineNumbers: true,
lineWrapping: true,
autoCloseBrackets: true,
matchBrackets: true,
indentWithTabs: true,
indentUnit: 4,
extraKeys: {
"'.'": passAndHint,
"Ctrl-Space": "autocomplete",
"Ctrl-I": function(cm) { CodeMirror.tern.showType(cm); },
"Ctrl-J": function(cm) { CodeMirror.tern.jumpToDef(cm); },
"Alt-,": function(cm) { CodeMirror.tern.jumpBack(cm); },
"Ctrl-Q": function(cm) { CodeMirror.tern.rename(cm); }
},
gutters: ["CodeMirror-linenumbers"],
ternWith: { plugins: { "qml" : true } }
});
</script>
</body>
</html>
</html>

File diff suppressed because it is too large Load diff

View file

@ -24,8 +24,8 @@ var groupName;
function TestCase(group, code, run) {
this.code = code;
this.group = group;
this.runTest = run || function (server, callback) {
callback("fail", code, "runTest function was not provided.");
this.runTest = run || function (server, callback, code) {
callback("fail", this.code, "runTest function was not provided.");
};
}
@ -37,19 +37,19 @@ exports.isolate = function (code) {
i--;
}
}
}
};
exports.groupStart = function (group) {
groupName = group;
}
};
exports.groupEnd = function () {
groupName = undefined;
}
};
exports.test = function (code, runTest) {
testCases.push(new TestCase(groupName || "Default", code, runTest));
}
};
exports.testCompletion = function (code, expected, beforeTest) {
testCases.push(new TestCase(groupName || "Default", code, function (server, callback) {
@ -70,7 +70,7 @@ exports.testCompletion = function (code, expected, beforeTest) {
}
});
}, beforeTest));
}
};
exports.testDefinition = function (code, expected, beforeTest) {
testCases.push(new TestCase(groupName || "Default", code, function (server, callback) {
@ -91,21 +91,21 @@ exports.testDefinition = function (code, expected, beforeTest) {
}
});
}, beforeTest));
}
};
exports.runTests = function (config, callback) {
for (var i = 0; i < testCases.length; ++i) {
var test = testCases[i];
if (test.group === config.group) {
var server = createServer();
test.runTest(server, callback);
test.runTest(server, callback, test.code);
}
}
};
function createServer(defs) {
var plugins = {};
plugins["qml"] = {};
plugins.qml = true;
var server = new tern.Server({
ecmaVersion: 5,
plugins : plugins,
@ -114,12 +114,12 @@ function createServer(defs) {
return server;
}
function assertCompletion(server, code, expected, pos, callback) {
server.addFile("test1.qml", code);
var assertCompletion = exports.assertCompletion = function (server, code, expected, pos, callback) {
server.addFile("main.qml", code);
server.request({
query : {
type: "completions",
file: "test1.qml",
file: "main.qml",
end: pos,
types: true,
docs: false,
@ -139,12 +139,12 @@ function assertCompletion(server, code, expected, pos, callback) {
});
};
function assertDefinition(server, code, expected, pos, callback) {
server.addFile("test1.qml", code);
var assertDefinition = exports.assertDefinition = function (server, code, expected, pos, callback) {
server.addFile("main.qml", code);
server.request({
query : {
type: "definition",
file: "test1.qml",
file: "main.qml",
end: pos,
types: true,
docs: false,
@ -175,6 +175,7 @@ function addPath(str, pt) {
}
var misMatch = exports.misMatch = function (exp, act) {
var mis = null;
if (!exp || !act || (typeof exp != "object") || (typeof act != "object")) {
if (exp !== act) return ppJSON(exp) + " !== " + ppJSON(act);
} else if (exp instanceof RegExp || act instanceof RegExp) {
@ -184,12 +185,12 @@ var misMatch = exports.misMatch = function (exp, act) {
if (!act.slice) return ppJSON(exp) + " != " + ppJSON(act);
if (act.length != exp.length) return "array length mismatch " + exp.length + " != " + act.length;
for (var i = 0; i < act.length; ++i) {
var mis = misMatch(exp[i], act[i]);
mis = misMatch(exp[i], act[i]);
if (mis) return addPath(mis, i);
}
} else {
for (var prop in exp) {
var mis = misMatch(exp[prop], act[prop]);
mis = misMatch(exp[prop], act[prop]);
if (mis) return addPath(mis, prop);
}
}

View file

@ -8,6 +8,8 @@
* Contributors:
* QNX Software Systems - Initial API and implementation
*******************************************************************************/
"use strict";
module.exports = {
"!name": "ecma5",
"!define": {
@ -975,4 +977,4 @@ module.exports = {
"!url": "https://developer.mozilla.org/en-US/docs/JSON",
"!doc": "JSON (JavaScript Object Notation) is a data-interchange format. It closely resembles a subset of JavaScript syntax, although it is not a strict subset. (See JSON in the JavaScript Reference for full details.) It is useful when writing any kind of JavaScript-based application, including websites and browser extensions. For example, you might store user information in JSON format in a cookie, or you might store extension preferences in JSON in a string-valued browser preference."
}
}
};

View file

@ -8,7 +8,7 @@
* Contributors:
* QNX Software Systems - Initial API and implementation
*******************************************************************************/
"use-strict";
"use strict";
var driver = require("./driver.js");
@ -20,7 +20,7 @@ function group(name) {
function groupEnd() {
if (typeof console === "object" && console.groupEnd) {
console.groupEnd(name);
console.groupEnd();
}
}
@ -29,8 +29,9 @@ function log(title, message) {
}
var stats, tests = [];
tests.push(require("./test-completions.js"));
tests.push(require("./test-scoping.js"));
tests.push(require("./test-finddef.js"));
tests.push(require("./test-completions.js"));
function report(state, code, message) {
if (state != "ok") {++stats.failed; log(code, message);}
@ -45,9 +46,9 @@ for (var i = 0; i < tests.length; i++) {
stats = test.stats = {testsRun: 0, failed: 0};
var config = test.config || {};
config.group = test.group;
var t0 = +new Date;
var t0 = +new Date();
driver.runTests(config, report);
test.stats.duration = +new Date - t0;
test.stats.duration = +new Date() - t0;
groupEnd();
}

View file

@ -8,58 +8,259 @@
* Contributors:
* QNX Software Systems - Initial API and implementation
*******************************************************************************/
"use-strict";
"use strict";
var driver = require("./driver.js");
var test = driver.test;
var testCompletion = driver.testCompletion;
var assertCompletion = driver.assertCompletion;
var groupStart = driver.groupStart;
var groupEnd = driver.groupEnd;
var group = exports.group = "Code Completion"
var group = exports.group = "Code Completion";
groupStart(group);
// Import Completions
//testCompletion("import QtQu|", {
// start: { line: 0, ch: 7 },
// end: { line: 0, ch: 11 },
// isProperty: false,
// isObjectKey: false,
// completions: [{ name: "QtQuick", type: "", origin: "QML" }]
//});
//
//testCompletion("import QtQuick 2.|", {
// start: { line: 0, ch: 17 },
// end: { line: 0, ch: 17 },
// isProperty: false,
// isObjectKey: false,
// completions: [
// { name: "0", type: "number", origin: "QML" },
// { name: "1", type: "number", origin: "QML" },
// { name: "2", type: "number", origin: "QML" },
// { name: "3", type: "number", origin: "QML" },
// { name: "4", type: "number", origin: "QML" },
// { name: "5", type: "number", origin: "QML" }
// ]
//});
//
//testCompletion('import "other.qml" as Other\n|', {
// start: { line: 1, ch: 0 },
// end: { line: 1, ch: 0 },
// isProperty: false,
// isObjectKey: false,
// completions: [{ name: "Other", type: "?", origin: "test1.qml" }]
//})
//
//testCompletion('My|', {
// start: { line: 0, ch: 2 },
// end: { line: 0, ch: 2 },
// isProperty: false,
// isObjectKey: false,
// completions: [{ name: "MyObject", type: "Button", origin: "MyObject.qml" }]
//}, function (server) {
// server.addFile("MyObject.qml", "Button {\n\tproperty int width\n}");
//});
// Local Directory Completions
testCompletion('My|', {
start: { line: 0, ch: 0 },
end: { line: 0, ch: 2 },
isProperty: false,
isObjectKey: false,
completions: [{ name: "MyObject", type: "MyObject", origin: "MyObject.qml" }]
}, function (server) {
server.addFile("MyObject.qml", "Button {}");
});
testCompletion('import "./subdir/"\nSameDirTest {\n\t|\n}', {
start: { line: 2, ch: 1 },
end: { line: 2, ch: 1 },
isProperty: false,
isObjectKey: false,
completions: [
{ name: "obj", type: "?", origin: "subdir/Button.qml" },
{ name: "Button", type: "Button", origin: "subdir/Button.qml" },
{ name: "SameDirTest", type: "SameDirTest", origin: "subdir/SameDirTest.qml" }
]
}, function (server) {
server.addFile("subdir/SameDirTest.qml", "Button {}");
server.addFile("subdir/Button.qml", "QtObject {property var obj}");
});
testCompletion('MyObject {\n\t|\n}', {
start: { line: 1, ch: 1 },
end: { line: 1, ch: 1 },
isProperty: false,
isObjectKey: false,
completions: [
{ name: "width", type: "number", origin: "MyObject.qml" },
{ name: "MyObject", type: "MyObject", origin: "MyObject.qml" }
]
}, function (server) {
server.addFile("MyObject.qml", "Button {\n\tproperty int width\n}");
});
testCompletion('MyObject {\n\tid: obj\n\ts: obj.|\n}', {
start: { line: 2, ch: 8 },
end: { line: 2, ch: 8 },
isProperty: true,
isObjectKey: false,
completions: [{ name: "width", type: "number", origin: "MyObject.qml" }]
}, function (server) {
server.addFile("MyObject.qml", "Button {\n\tproperty int width\n}");
});
testCompletion('Button {\n\t|\n}', {
start: { line: 1, ch: 1 },
end: { line: 1, ch: 1 },
isProperty: false,
isObjectKey: false,
completions: [
{ name: "onClicked", type: "Signal Handler", origin: "Button.qml" },
{ name: "Button", type: "Button", origin: "Button.qml" }
]
}, function (server) {
server.addFile("Button.qml", "QtObject {\n\signal clicked(int mouseX, int mouseY)\n}");
});
testCompletion('CButton {\n\t|\n}', {
start: { line: 1, ch: 1 },
end: { line: 1, ch: 1 },
isProperty: false,
isObjectKey: false,
completions: [
{ name: "height", type: "number", origin: "Button.qml" },
{ name: "numClicks", type: "number", origin: "CButton.qml" },
{ name: "text", type: "string", origin: "Button.qml" },
{ name: "width", type: "number", origin: "Button.qml" },
{ name: "Button", type: "Button", origin: "Button.qml" },
{ name: "CButton", type: "CButton", origin: "CButton.qml" }
]
}, function (server) {
server.addFile("CButton.qml", "Button {\n\tproperty int numClicks\n}");
server.addFile("Button.qml", "QtObject {\n\tproperty string text\n\tproperty int width\n\tproperty int height\n}");
});
testCompletion('CButton {\n\tid:btn\n\ts: btn.|\n}', {
start: { line: 2, ch: 8 },
end: { line: 2, ch: 8 },
isProperty: true,
isObjectKey: false,
completions: [
{ name: "height", type: "number", origin: "Button.qml" },
{ name: "numClicks", type: "number", origin: "CButton.qml" },
{ name: "text", type: "string", origin: "Button.qml" },
{ name: "width", type: "number", origin: "Button.qml" }
]
}, function (server) {
server.addFile("CButton.qml", "Button {\n\tproperty int numClicks\n}");
server.addFile("Button.qml", "QtObject {\n\tproperty string text\n\tproperty int width\n\tproperty int height\n}");
});
// Directory Import Completions
testCompletion('NotVisible {\n\t|\n}', {
start: { line: 1, ch: 1 },
end: { line: 1, ch: 1 },
isProperty: false,
isObjectKey: false,
completions: []
}, function (server) {
server.addFile("subdir/NotVisible.qml", "QtObject {\n\signal clicked(int mouseX, int mouseY)\n}");
});
testCompletion('import "./subdir/"\nButton {\n\t|\n}', {
start: { line: 2, ch: 1 },
end: { line: 2, ch: 1 },
isProperty: false,
isObjectKey: false,
completions: [
{ name: "onClicked", type: "Signal Handler", origin: "subdir/Button.qml" },
{ name: "Button", type: "Button", origin: "subdir/Button.qml" }
]
}, function (server) {
server.addFile("subdir/Button.qml", "QtObject {\n\signal clicked(int mouseX, int mouseY)\n}");
});
testCompletion('import "./subdir/" as Controls\nControls.Button {\n\t|\n}', {
start: { line: 2, ch: 1 },
end: { line: 2, ch: 1 },
isProperty: false,
isObjectKey: false,
completions: [
{ name: "onClicked", type: "Signal Handler", origin: "subdir/Button.qml" },
{ name: "Controls", type: "Controls", origin: "main.qml" }
]
}, function (server) {
server.addFile("subdir/Button.qml", "QtObject {\n\signal clicked(int mouseX, int mouseY)\n}");
});
testCompletion('import "./subdir/" as Controls\nControls.|', {
start: { line: 1, ch: 9 },
end: { line: 1, ch: 9 },
isProperty: false,
isObjectKey: false,
completions: [
{ name: "Button", type: "Button", origin: "subdir/Button.qml" }
]
}, function (server) {
server.addFile("subdir/Button.qml", "QtObject {\n\signal clicked(int mouseX, int mouseY)\n}");
});
testCompletion('import "./subdir/" as Controls\nControls.|.', {
start: { line: 1, ch: 9 },
end: { line: 1, ch: 9 },
isProperty: false,
isObjectKey: false,
completions: [
{ name: "Button", type: "Button", origin: "subdir/Button.qml" }
]
}, function (server) {
server.addFile("subdir/Button.qml", "QtObject {\n\signal clicked(int mouseX, int mouseY)\n}");
});
testCompletion('import "./subdir/" as Controls\nControls..|', {
start: { line: 1, ch: 10 },
end: { line: 1, ch: 10 },
isProperty: false,
isObjectKey: false,
completions: []
}, function (server) {
server.addFile("subdir/Button.qml", "QtObject {\n\signal clicked(int mouseX, int mouseY)\n}");
});
test("{Add File After Import}", function (server, callback, name) {
var failed;
assertCompletion(server, "", {
start: { line: 0, ch: 0 },
end: { line: 0, ch: 0 },
isProperty: false,
isObjectKey: false,
completions: []
}, 0, function (mis) {
failed = mis;
});
if (failed) {
return callback("fail", name, "- failed on initial file " + failed);
}
server.addFile("MyObject.qml", "QtObject {\n\tproperty var test\n}");
assertCompletion(server, "M", {
start: { line: 0, ch: 0 },
end: { line: 0, ch: 1 },
isProperty: false,
isObjectKey: false,
completions: [{ name: "MyObject", type: "MyObject", origin: "MyObject.qml" }]
}, 1, function (mis) {
failed = mis;
});
if (failed) {
return callback("fail", name, "- failed after adding file " + failed);
}
return callback("ok", name);
});
// Cyclic Dependency Completions
testCompletion('Cyclic {\n\t|\n}', {
start: { line: 1, ch: 1 },
end: { line: 1, ch: 1 },
isProperty: false,
isObjectKey: false,
completions: [
{ name: "test", type: "?", origin: "Cyclic.qml" },
{ name: "Cyclic", type: "Cyclic", origin: "Cyclic.qml" }
]
}, function (server) {
server.addFile("Cyclic.qml", "Cyclic {\n\property var test\n}");
});
testCompletion('Cyclic2 {\n\t|\n}', {
start: { line: 1, ch: 1 },
end: { line: 1, ch: 1 },
isProperty: false,
isObjectKey: false,
completions: [
{ name: "test1", type: "?", origin: "Cyclic2.qml" },
{ name: "test2", type: "?", origin: "OtherCyclic.qml" },
{ name: "Cyclic2", type: "Cyclic2", origin: "Cyclic2.qml" },
{ name: "OtherCyclic", type: "OtherCyclic", origin: "OtherCyclic.qml" }
]
}, function (server) {
server.addFile("Cyclic2.qml", "OtherCyclic {\n\property var test1\n}");
server.addFile("OtherCyclic.qml", "Cyclic2 {\n\property var test2\n}");
});
testCompletion('OtherCyclic {\n\t|\n}', {
start: { line: 1, ch: 1 },
end: { line: 1, ch: 1 },
isProperty: false,
isObjectKey: false,
completions: [
{ name: "test2", type: "?", origin: "OtherCyclic.qml" },
{ name: "Cyclic", type: "Cyclic", origin: "Cyclic.qml" },
{ name: "OtherCyclic", type: "OtherCyclic", origin: "OtherCyclic.qml" }
]
}, function (server) {
server.addFile("Cyclic.qml", "OtherCyclic {\n\property var test1\n}");
server.addFile("OtherCyclic.qml", "Cyclic {\n\property var test2\n}");
});
// QML Object Property Completions
testCompletion("Window {\n\tproperty int height\n\the|\n}", {
@ -67,7 +268,7 @@ testCompletion("Window {\n\tproperty int height\n\the|\n}", {
end: { line: 2, ch: 3 },
isProperty: false,
isObjectKey: false,
completions: [{ name: "height", type: "number", origin: "test1.qml" }]
completions: [{ name: "height", type: "number", origin: "main.qml" }]
});
testCompletion("Window {\n\tproperty int height\n\tproperty int width\n\tproperty string text\n\t|\n}", {
@ -76,9 +277,9 @@ testCompletion("Window {\n\tproperty int height\n\tproperty int width\n\tpropert
isProperty: false,
isObjectKey: false,
completions: [
{ name: "height", type: "number", origin: "test1.qml" },
{ name: "text", type: "string", origin: "test1.qml" },
{ name: "width", type: "number", origin: "test1.qml" }
{ name: "height", type: "number", origin: "main.qml" },
{ name: "text", type: "string", origin: "main.qml" },
{ name: "width", type: "number", origin: "main.qml" }
]
});
@ -96,8 +297,8 @@ testCompletion("Window {\n\tproperty var prop\n\tfunction test() {\n\t\t|\n\t}\n
isProperty: false,
isObjectKey: false,
completions: [
{ name: "prop", type: "?", origin: "test1.qml" },
{ name: "test", type: "fn()", origin: "test1.qml" }
{ name: "prop", type: "?", origin: "main.qml" },
{ name: "test", type: "fn()", origin: "main.qml" }
]
}, function (server) { server.jsDefs = []; });
@ -115,7 +316,7 @@ testCompletion("Window {\n\tButton {\n\t\tid: btn\n\t\tproperty int height\n\t}\
end: { line: 5, ch: 11 },
isProperty: true,
isObjectKey: false,
completions: [{ name: "height", type: "number", origin: "test1.qml" }]
completions: [{ name: "height", type: "number", origin: "main.qml" }]
}, function (server) { server.jsDefs = []; });
testCompletion("Window {\n\tproperty var btn\n\tButton {\n\t\tid: btn\n\t\tproperty int height\n\t}\n\ttest: btn.|\n}", {
@ -123,7 +324,7 @@ testCompletion("Window {\n\tproperty var btn\n\tButton {\n\t\tid: btn\n\t\tprope
end: { line: 6, ch: 11 },
isProperty: true,
isObjectKey: false,
completions: [{ name: "height", type: "number", origin: "test1.qml" }]
completions: [{ name: "height", type: "number", origin: "main.qml" }]
}, function (server) { server.jsDefs = []; });
testCompletion("Window {\n\tButton {\n\t\tproperty var id\n\t\tid: btn\n\t}\n\ts: bt|\n}", {
@ -131,7 +332,7 @@ testCompletion("Window {\n\tButton {\n\t\tproperty var id\n\t\tid: btn\n\t}\n\ts
end: { line: 5, ch: 6 },
isProperty: false,
isObjectKey: false,
completions: [{ name: "btn", type: "Button", origin: "test1.qml" }]
completions: [{ name: "btn", type: "Button", origin: "main.qml" }]
}, function (server) { server.jsDefs = []; });
testCompletion("Window {\n\tButton {\n\t\tproperty var id\n\t\tid: btn\n\t\ts: i|\n\t}\n}", {
@ -139,7 +340,7 @@ testCompletion("Window {\n\tButton {\n\t\tproperty var id\n\t\tid: btn\n\t\ts: i
end: { line: 4, ch: 6 },
isProperty: false,
isObjectKey: false,
completions: [{ name: "id", type: "?", origin: "test1.qml" }]
completions: [{ name: "id", type: "?", origin: "main.qml" }]
}, function (server) { server.jsDefs = []; });
testCompletion("Window {\n\tButton {\n\t\tproperty var id: 34\n\t\tid: btn\n\t\ts: i|\n\t}\n}", {
@ -147,7 +348,7 @@ testCompletion("Window {\n\tButton {\n\t\tproperty var id: 34\n\t\tid: btn\n\t\t
end: { line: 4, ch: 6 },
isProperty: false,
isObjectKey: false,
completions: [{ name: "id", type: "number", origin: "test1.qml" }]
completions: [{ name: "id", type: "number", origin: "main.qml" }]
}, function (server) { server.jsDefs = []; });
testCompletion("Window {\n\tButton {\n\t\tproperty string id\n\t\tid: btn\n\t\ts: i|\n\t}\n}", {
@ -155,7 +356,7 @@ testCompletion("Window {\n\tButton {\n\t\tproperty string id\n\t\tid: btn\n\t\ts
end: { line: 4, ch: 6 },
isProperty: false,
isObjectKey: false,
completions: [{ name: "id", type: "string", origin: "test1.qml" }]
completions: [{ name: "id", type: "string", origin: "main.qml" }]
}, function (server) { server.jsDefs = []; });
testCompletion("Window {\n\tButton {\n\t\tproperty var id\n\t\ts: i|\n\t}\n}", {
@ -163,7 +364,7 @@ testCompletion("Window {\n\tButton {\n\t\tproperty var id\n\t\ts: i|\n\t}\n}", {
end: { line: 3, ch: 6 },
isProperty: false,
isObjectKey: false,
completions: [{ name: "id", type: "?", origin: "test1.qml" }]
completions: [{ name: "id", type: "?", origin: "main.qml" }]
}, function (server) { server.jsDefs = []; });
testCompletion("Window {\n\tButton {\n\t\tproperty var id: 34\n\t\ts: i|\n\t}\n}", {
@ -171,7 +372,7 @@ testCompletion("Window {\n\tButton {\n\t\tproperty var id: 34\n\t\ts: i|\n\t}\n}
end: { line: 3, ch: 6 },
isProperty: false,
isObjectKey: false,
completions: [{ name: "id", type: "number", origin: "test1.qml" }]
completions: [{ name: "id", type: "number", origin: "main.qml" }]
}, function (server) { server.jsDefs = []; });
testCompletion("Window {\n\tButton {\n\t\tproperty string id\n\t\ts: i|\n\t}\n}", {
@ -179,7 +380,7 @@ testCompletion("Window {\n\tButton {\n\t\tproperty string id\n\t\ts: i|\n\t}\n}"
end: { line: 3, ch: 6 },
isProperty: false,
isObjectKey: false,
completions: [{ name: "id", type: "string", origin: "test1.qml" }]
completions: [{ name: "id", type: "string", origin: "main.qml" }]
}, function (server) { server.jsDefs = []; });
testCompletion("Window {\n\tid: wind\n\tfunction test() {\n\t\t|\n\t}\n}", {
@ -188,8 +389,8 @@ testCompletion("Window {\n\tid: wind\n\tfunction test() {\n\t\t|\n\t}\n}", {
isProperty: false,
isObjectKey: false,
completions: [
{ name: "test", type: "fn()", origin: "test1.qml" },
{ name: "wind", type: "Window", origin: "test1.qml" }
{ name: "test", type: "fn()", origin: "main.qml" },
{ name: "wind", type: "Window", origin: "main.qml" }
]
}, function (server) { server.jsDefs = []; });
@ -209,7 +410,7 @@ testCompletion("Window {\n\tproperty var test: |\n}", {
{ name: "isNaN", type: "fn(value: number) -> bool", origin: "ecma5" },
{ name: "parseFloat", type: "fn(string: string) -> number", origin: "ecma5" },
{ name: "parseInt", type: "fn(string: string, radix?: number) -> number", origin: "ecma5" },
{ name: "test", type: "?", origin: "test1.qml" },
{ name: "test", type: "?", origin: "main.qml" },
{ name: "undefined", type: "?", origin: "ecma5" },
{ name: "Array", type: "fn(size: number)", origin: "ecma5" },
{ name: "Boolean", type: "fn(value: ?) -> bool", origin: "ecma5" },
@ -324,7 +525,7 @@ testCompletion("Window {\n\tfunction test() {\n\t\t|\n\t}\n}", {
{ name: "isNaN", type: "fn(value: number) -> bool", origin: "ecma5" },
{ name: "parseFloat", type: "fn(string: string) -> number", origin: "ecma5" },
{ name: "parseInt", type: "fn(string: string, radix?: number) -> number", origin: "ecma5" },
{ name: "test", type: "fn()", origin: "test1.qml" },
{ name: "test", type: "fn()", origin: "main.qml" },
{ name: "undefined", type: "?", origin: "ecma5" },
{ name: "Array", type: "fn(size: number)", origin: "ecma5" },
{ name: "Boolean", type: "fn(value: ?) -> bool", origin: "ecma5" },
@ -355,7 +556,7 @@ testCompletion("Window {\n\tsignal clicked(int mouseX, int mouseY)\n\t|\n}", {
isProperty: false,
isObjectKey: false,
completions: [
{ name: "onClicked", type: "Signal Handler", origin: "test1.qml" }
{ name: "onClicked", type: "Signal Handler", origin: "main.qml" }
]
});
@ -373,8 +574,8 @@ testCompletion("Window {\n\tsignal clicked(int mouseX, int mouseY)\n\ts: |\n}",
isProperty: false,
isObjectKey: false,
completions: [
{ name: "clicked", type: "fn(mouseX: number, mouseY: number)", origin: "test1.qml" },
{ name: "onClicked", type: "Signal Handler", origin: "test1.qml" }
{ name: "clicked", type: "fn(mouseX: number, mouseY: number)", origin: "main.qml" },
{ name: "onClicked", type: "Signal Handler", origin: "main.qml" }
]
}, function (server) { server.jsDefs = []; });
@ -384,8 +585,8 @@ testCompletion("Window {\n\tsignal error(string msg, boolean flag)\n\ts: |\n}",
isProperty: false,
isObjectKey: false,
completions: [
{ name: "error", type: "fn(msg: string, flag: bool)", origin: "test1.qml" },
{ name: "onError", type: "Signal Handler", origin: "test1.qml" }
{ name: "error", type: "fn(msg: string, flag: bool)", origin: "main.qml" },
{ name: "onError", type: "Signal Handler", origin: "main.qml" }
]
}, function (server) { server.jsDefs = []; });
@ -395,8 +596,8 @@ testCompletion("Window {\n\tid: wind\n\tsignal error(string msg, boolean flag)\n
isProperty: true,
isObjectKey: false,
completions: [
{ name: "error", type: "fn(msg: string, flag: bool)", origin: "test1.qml" },
{ name: "onError", type: "Signal Handler", origin: "test1.qml" }
{ name: "error", type: "fn(msg: string, flag: bool)", origin: "main.qml" },
{ name: "onError", type: "Signal Handler", origin: "main.qml" }
]
}, function (server) { server.jsDefs = []; });
@ -406,10 +607,10 @@ testCompletion("Window {\n\tsignal error(string msg, boolean flag)\n\tonError: |
isProperty: false,
isObjectKey: false,
completions: [
{ name: "error", type: "fn(msg: string, flag: bool)", origin: "test1.qml" },
{ name: "flag", type: "bool", origin: "test1.qml" },
{ name: "msg", type: "string", origin: "test1.qml" },
{ name: "onError", type: "Signal Handler", origin: "test1.qml" }
{ name: "error", type: "fn(msg: string, flag: bool)", origin: "main.qml" },
{ name: "flag", type: "bool", origin: "main.qml" },
{ name: "msg", type: "string", origin: "main.qml" },
{ name: "onError", type: "Signal Handler", origin: "main.qml" }
]
}, function (server) { server.jsDefs = []; });
@ -419,10 +620,10 @@ testCompletion("Window {\n\tsignal error(string msg, boolean flag)\n\tonError: {
isProperty: false,
isObjectKey: false,
completions: [
{ name: "error", type: "fn(msg: string, flag: bool)", origin: "test1.qml" },
{ name: "flag", type: "bool", origin: "test1.qml" },
{ name: "msg", type: "string", origin: "test1.qml" },
{ name: "onError", type: "Signal Handler", origin: "test1.qml" }
{ name: "error", type: "fn(msg: string, flag: bool)", origin: "main.qml" },
{ name: "flag", type: "bool", origin: "main.qml" },
{ name: "msg", type: "string", origin: "main.qml" },
{ name: "onError", type: "Signal Handler", origin: "main.qml" }
]
}, function (server) { server.jsDefs = []; });
@ -432,10 +633,10 @@ testCompletion("Window {\n\tproperty int msg\n\tsignal error(string msg, boolean
isProperty: false,
isObjectKey: false,
completions: [
{ name: "error", type: "fn(msg: string, flag: bool)", origin: "test1.qml" },
{ name: "flag", type: "bool", origin: "test1.qml" },
{ name: "msg", type: "string", origin: "test1.qml" },
{ name: "onError", type: "Signal Handler", origin: "test1.qml" }
{ name: "error", type: "fn(msg: string, flag: bool)", origin: "main.qml" },
{ name: "flag", type: "bool", origin: "main.qml" },
{ name: "msg", type: "string", origin: "main.qml" },
{ name: "onError", type: "Signal Handler", origin: "main.qml" }
]
}, function (server) { server.jsDefs = []; });
@ -454,10 +655,10 @@ testCompletion("Window {\n\tfunction test(a, b, c) {\n\t\t|\n\t}\n}", {
isProperty: false,
isObjectKey: false,
completions: [
{ name: "a", type: "?", origin: "test1.qml" },
{ name: "b", type: "?", origin: "test1.qml" },
{ name: "c", type: "?", origin: "test1.qml" },
{ name: "test", type: "fn(a: ?, b: ?, c: ?)", origin: "test1.qml" }
{ name: "a", type: "?", origin: "main.qml" },
{ name: "b", type: "?", origin: "main.qml" },
{ name: "c", type: "?", origin: "main.qml" },
{ name: "test", type: "fn(a: ?, b: ?, c: ?)", origin: "main.qml" }
]
}, function (server) { server.jsDefs = []; });
@ -467,8 +668,8 @@ testCompletion("Window {\n\tfunction test(a) {\n\t\ta = 3\n\t\t|\n\t}\n}", {
isProperty: false,
isObjectKey: false,
completions: [
{ name: "a", type: "number", origin: "test1.qml" },
{ name: "test", type: "fn(a: number)", origin: "test1.qml" }
{ name: "a", type: "number", origin: "main.qml" },
{ name: "test", type: "fn(a: number)", origin: "main.qml" }
]
}, function (server) { server.jsDefs = []; });
@ -478,8 +679,8 @@ testCompletion('Window {\n\tfunction test(a) {\n\t\ttest("something")\n\t\t|\n\t
isProperty: false,
isObjectKey: false,
completions: [
{ name: "a", type: "string", origin: "test1.qml" },
{ name: "test", type: "fn(a: string)", origin: "test1.qml" }
{ name: "a", type: "string", origin: "main.qml" },
{ name: "test", type: "fn(a: string)", origin: "main.qml" }
]
}, function (server) { server.jsDefs = []; });
@ -489,8 +690,8 @@ testCompletion('Window {\n\tfunction test(a) {\n\t\t|\n\t\treturn 7\n\t}\n}', {
isProperty: false,
isObjectKey: false,
completions: [
{ name: "a", type: "?", origin: "test1.qml" },
{ name: "test", type: "fn(a: ?) -> number", origin: "test1.qml" }
{ name: "a", type: "?", origin: "main.qml" },
{ name: "test", type: "fn(a: ?) -> number", origin: "main.qml" }
]
}, function (server) { server.jsDefs = []; });
@ -502,8 +703,8 @@ testCompletion('Window {\n\tfunction test(a) {\n\t\t|\n\t\treturn 7\n\t}\n}', {
// isProperty: false,
// isObjectKey: false,
// completions: [
// { name: "a", type: "?", origin: "test1.qml" },
// { name: "test", type: "fn()", origin: "test1.qml" }
// { name: "a", type: "?", origin: "main.qml" },
// { name: "test", type: "fn()", origin: "main.qml" }
// ]
//}, function (server) { server.jsDefs = []; });

View file

@ -8,79 +8,163 @@
* Contributors:
* QNX Software Systems - Initial API and implementation
*******************************************************************************/
"use-strict";
"use strict";
var driver = require("./driver.js");
var test = driver.test;
var testDefinition = driver.testDefinition;
var assertDefinition = driver.assertDefintion;
var groupStart = driver.groupStart;
var groupEnd = driver.groupEnd;
var group = exports.group = "Find Definition";
groupStart(group);
// Directory Imports
// TODO: Getting this test to pass breaks some of the type inferencing which is more important
//testDefinition('My|Object {}', {
// origin: "MyObject.qml",
// start: { line: 0, ch: 0 },
// end: { line: 0, ch: 6 },
// file: "MyObject.qml",
// contextOffset: 0
//}, function (server) {
// server.addFile("MyObject.qml", "Button {}");
//});
testDefinition("MyObject {\n\tte|stProp: ident\n}", {
origin: "MyObject.qml",
start: { line: 1, ch: 14 },
end: { line: 1, ch: 22 },
file: "MyObject.qml",
contextOffset: 23
}, function (server) {
server.addFile("MyObject.qml", "Button {\n\tproperty var testProp\n}");
});
testDefinition("MyObject {\n\ts: te|stSig()\n}", {
origin: "MyObject.qml",
start: { line: 1, ch: 8 },
end: { line: 1, ch: 15 },
file: "MyObject.qml",
contextOffset: 17
}, function (server) {
server.addFile("MyObject.qml", "Button {\n\tsignal testSig()\n}");
});
testDefinition("MyObject {\n\tonTe|stSig: ident\n}", {
origin: "MyObject.qml",
start: { line: 1, ch: 8 },
end: { line: 1, ch: 15 },
file: "MyObject.qml",
contextOffset: 17
}, function (server) {
server.addFile("MyObject.qml", "Button {\n\tsignal testSig()\n}");
});
testDefinition("MyObject {\n\tonTestSig: ar|g0\n}", {
origin: "MyObject.qml",
start: { line: 1, ch: 20 },
end: { line: 1, ch: 24 },
file: "MyObject.qml",
contextOffset: 29
}, function (server) {
server.addFile("MyObject.qml", "Button {\n\tsignal testSig(int arg0)\n}");
});
testDefinition("MyObject {\n\ts: te|stFn()\n}", {
origin: "MyObject.qml",
start: { line: 1, ch: 10 },
end: { line: 1, ch: 16 },
file: "MyObject.qml",
contextOffset: 19
}, function (server) {
server.addFile("MyObject.qml", "Button {\n\tfunction testFn() {}\n}");
});
testDefinition("MyObject {\n\ts: btn|Id\n}", {
origin: undefined,
start: undefined,
end: undefined,
file: undefined,
contextOffset: undefined
}, function (server) {
server.addFile("MyObject.qml", "Button {\n\tid: btnId\n}");
});
testDefinition("MyObject {\n\tot|her: ident\n}", {
origin: undefined,
start: undefined,
end: undefined,
file: undefined,
contextOffset: undefined
}, function (server) {
server.addFile("MyObject.qml", "Button {\n\tSecondButton {\n\t\tjproperty var other\n\t}\n}");
});
// ID Property
testDefinition("QtObject {\n\tid: obj\n\tproperty var prop: {\n\t\tob|j\n\t}\n}", {
origin: "test1.qml",
origin: "main.qml",
start: { line: 1, ch: 5 },
end: { line: 1, ch: 8 },
file: "test1.qml",
file: "main.qml",
contextOffset: 16
});
testDefinition("Window {\n\tButton {\n\t\tid: btn\n\t\tproperty int height\n\t}\n\ttest: bt|n\n}", {
origin: "test1.qml",
origin: "main.qml",
start: { line: 2, ch: 6 },
end: { line: 2, ch: 9 },
file: "test1.qml",
file: "main.qml",
contextOffset: 25
});
testDefinition("Window {\n\tproperty var btn\n\tButton {\n\t\tid: btn\n\t\tproperty int height\n\t}\n\ttest: bt|n\n}", {
origin: "test1.qml",
origin: "main.qml",
start: { line: 3, ch: 6 },
end: { line: 3, ch: 9 },
file: "test1.qml",
file: "main.qml",
contextOffset: 43
});
testDefinition("Window {\n\tproperty var btn\n\tButton {\n\t\tid: bt|n\n\t\tproperty int height\n\t}\n}", {
origin: "test1.qml",
origin: "main.qml",
start: { line: 3, ch: 6 },
end: { line: 3, ch: 9 },
file: "test1.qml",
file: "main.qml",
contextOffset: 43
});
// Property Declarations
testDefinition("QtObject {\n\tproperty var prop\n\tpr|op: 3\n}", {
origin: "test1.qml",
origin: "main.qml",
start: { line: 1, ch: 14 },
end: { line: 1, ch: 18 },
file: "test1.qml",
file: "main.qml",
contextOffset: 25
});
testDefinition("Window {\n\tproperty var btn\n\tButton {\n\t\tprop: b|tn\n\t}\n}", {
origin: "test1.qml",
origin: "main.qml",
start: { line: 1, ch: 14 },
end: { line: 1, ch: 17 },
file: "test1.qml",
file: "main.qml",
contextOffset: 23
});
testDefinition("Window {\n\tproperty var btn\n\tButton {\n\t\tButton {\n\t\t\tprop: b|tn\n\t\t}\n\t}\n}", {
origin: "test1.qml",
origin: "main.qml",
start: { line: 1, ch: 14 },
end: { line: 1, ch: 17 },
file: "test1.qml",
file: "main.qml",
contextOffset: 23
});
testDefinition("Window {\n\tButton {\n\t\tproperty var btn\n\t\tbt|n: 3\n\t}\n}", {
origin: "test1.qml",
origin: "main.qml",
start: { line: 2, ch: 15 },
end: { line: 2, ch: 18 },
file: "test1.qml",
file: "main.qml",
contextOffset: 34
});
@ -94,115 +178,115 @@ testDefinition("Window {\n\tButton {\n\t\tproperty var btn\n\t\tButton {\n\t\t\t
// Signals and Signal Handlers
testDefinition("Window {\n\tsignal clic|ked(int mouseX, int mouseY)\n}", {
origin: "test1.qml",
origin: "main.qml",
start: { line: 1, ch: 8 },
end: { line: 1, ch: 15 },
file: "test1.qml",
file: "main.qml",
contextOffset: 17
});
testDefinition("Window {\n\tsignal clicked(int mouseX, int mouseY)\n\tonCli|cked: 3\n}", {
origin: "test1.qml",
origin: "main.qml",
start: { line: 1, ch: 8 },
end: { line: 1, ch: 15 },
file: "test1.qml",
file: "main.qml",
contextOffset: 17
});
testDefinition("Window {\n\tsignal clicked(int mouseX, int mouseY)\n\tonClicked: mou|seX\n}", {
origin: "test1.qml",
origin: "main.qml",
start: { line: 1, ch: 20 },
end: { line: 1, ch: 26 },
file: "test1.qml",
file: "main.qml",
contextOffset: 29
});
testDefinition("Window {\n\tsignal clicked(int mouseX, int mouseY)\n\tonClicked: cli|cked(3,4)\n}", {
origin: "test1.qml",
origin: "main.qml",
start: { line: 1, ch: 8 },
end: { line: 1, ch: 15 },
file: "test1.qml",
file: "main.qml",
contextOffset: 17
});
testDefinition("Window {\n\tsignal clicked(int mouseX, int mouseY)\n\tonClicked: onCli|cked\n}", {
origin: "test1.qml",
origin: "main.qml",
start: { line: 1, ch: 8 },
end: { line: 1, ch: 15 },
file: "test1.qml",
file: "main.qml",
contextOffset: 17
});
testDefinition("Window {\n\tsignal clicked(int mouseX, int mouseY)\n\tid: wind\n\tonClicked: wind.onCli|cked\n}", {
origin: "test1.qml",
origin: "main.qml",
start: { line: 1, ch: 8 },
end: { line: 1, ch: 15 },
file: "test1.qml",
file: "main.qml",
contextOffset: 17
});
testDefinition("Window {\n\tsignal clicked(int mouseX, int mouseY)\n\tid: wind\n\tonClicked: wind.cli|cked(3,4)\n}", {
origin: "test1.qml",
origin: "main.qml",
start: { line: 1, ch: 8 },
end: { line: 1, ch: 15 },
file: "test1.qml",
file: "main.qml",
contextOffset: 17
});
testDefinition("Window {\n\tproperty int msg\n\tsignal error(string msg, boolean flag)\n\tonError: {\n\t\tms|g\n\t}\n}", {
origin: "test1.qml",
origin: "main.qml",
start: { line: 2, ch: 21 },
end: { line: 2, ch: 24 },
file: "test1.qml",
file: "main.qml",
contextOffset: 48
}, function (server) { server.jsDefs = []; });
// Function Declarations
testDefinition("Window {\n\tfunction te|st(a) {}\n}", {
origin: "test1.qml",
origin: "main.qml",
start: { line: 1, ch: 10 },
end: { line: 1, ch: 14 },
file: "test1.qml",
file: "main.qml",
contextOffset: 19
});
testDefinition("Window {\n\tfunction test(a) {\n\t\ta|\n\t}\n}", {
origin: "test1.qml",
origin: "main.qml",
start: { line: 1, ch: 15 },
end: { line: 1, ch: 16 },
file: "test1.qml",
file: "main.qml",
contextOffset: 24
});
testDefinition("Window {\n\tfunction test(a) {\n\t\tte|st(3)\n\t}\n}", {
origin: "test1.qml",
origin: "main.qml",
start: { line: 1, ch: 10 },
end: { line: 1, ch: 14 },
file: "test1.qml",
file: "main.qml",
contextOffset: 19
});
testDefinition("Window {\n\tfunction test(a) {}\n\ts: te|st(3)\n}", {
origin: "test1.qml",
origin: "main.qml",
start: { line: 1, ch: 10 },
end: { line: 1, ch: 14 },
file: "test1.qml",
file: "main.qml",
contextOffset: 19
});
testDefinition("Window {\n\tfunction test(a) {}\n\ts: {\n\t\tte|st(3)\n\t}\n}", {
origin: "test1.qml",
origin: "main.qml",
start: { line: 1, ch: 10 },
end: { line: 1, ch: 14 },
file: "test1.qml",
file: "main.qml",
contextOffset: 19
});
testDefinition("Window {\n\tfunction test(a) {}\n\tid: wind\n\ts: {\n\t\twind.te|st(3)\n\t}\n}", {
origin: "test1.qml",
origin: "main.qml",
start: { line: 1, ch: 10 },
end: { line: 1, ch: 14 },
file: "test1.qml",
file: "main.qml",
contextOffset: 19
});
@ -215,10 +299,10 @@ testDefinition("Window {\n\tfunction test(a) {}\n\tte|st: 3;\n}", {
});
testDefinition('Window {\n\tfunction test(a) {\n\t\ta|\n\t}\n}\n\tproperty int a', {
origin: "test1.qml",
origin: "main.qml",
start: { line: 1, ch: 15 },
end: { line: 1, ch: 16 },
file: "test1.qml",
file: "main.qml",
contextOffset: 24
});

View file

@ -0,0 +1,409 @@
/*******************************************************************************
* Copyright (c) 2015 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* QNX Software Systems - Initial API and implementation
*******************************************************************************/
"use strict";
var plugin = require("../qml.js");
var infer = require("tern/lib/infer");
var driver = require("./driver.js");
var test = driver.test;
var groupStart = driver.groupStart;
var groupEnd = driver.groupEnd;
var group = exports.group = "Custom Scoping";
groupStart(group);
test("QMLObjScope::defProp()", function (server, callback, name) {
infer.withContext(new infer.Context([], server), function () {
// Create the scope and objects to test
var fileScope = new infer.Scope();
var obj = new infer.Obj(null, "MyObject");
var scope = new plugin.QMLObjScope(fileScope, null, obj);
// Define some properties
scope.defProp("first", null);
scope.defProp("second", null);
// Make sure there are no properties in the scopes themselves
if (fileScope.props && fileScope.props.length > 0) {
return callback("fail", name, "- File scope contained properties (none expected)");
}
if (scope.props && scope.props.length > 0) {
return callback("fail", name, "- QMLObjScope contained properties (none expected)");
}
// Check the Obj Type for the props we created
if (!obj.props.first) {
return callback("fail", name, "- Obj did not contain property 'first'");
}
if (!obj.props.second) {
return callback("fail", name, "- Obj did not contain property 'second'");
}
return callback("ok", name);
});
});
test("QMLObjScope::hasProp()", function (server, callback, name) {
infer.withContext(new infer.Context([], server), function () {
// Create the scope and objects to test
var fileScope = new infer.Scope();
var obj = new infer.Obj(null, "MyObject");
var scope = new plugin.QMLObjScope(fileScope, null, obj);
// Define a property on the Obj Type
obj.defProp("first", null);
// Query the scope for the prop we created and make sure it returns the right one
var prop = scope.hasProp("first", true);
if (!prop) {
return callback("fail", name, "- hasProp('first') returned null");
} else if (prop.propertyName !== "first") {
return callback("fail", name, "- hasProp('first') returned invalid property");
}
return callback("ok", name);
});
});
test("QMLObjScope::removeProp()", function (server, callback, name) {
infer.withContext(new infer.Context([], server), function () {
// Create the scope and objects to test
var fileScope = new infer.Scope();
var obj = new infer.Obj(null, "MyObject");
var scope = new plugin.QMLObjScope(fileScope, null, obj);
// Define some properties
scope.defProp("first", null);
scope.defProp("second", null);
// Remove the properties we defined
scope.removeProp("first");
scope.removeProp("second");
// Check the Obj Type for the props we created
if (obj.props && obj.props.length > 0) {
return callback("fail", name, "- Obj contained properties (none expected)");
}
return callback("ok", name);
});
});
test("QMLObjScope::gatherProperties()", function (server, callback, name) {
infer.withContext(new infer.Context([], server), function () {
// Create the scope and objects to test
var fileScope = new infer.Scope();
var obj = new infer.Obj(null, "MyObject");
var scope = new plugin.QMLObjScope(fileScope, null, obj);
// Define some properties
fileScope.defProp("third", null);
scope.defProp("first", null);
scope.defProp("second", null);
// Gather the properties and store them in the order they were received
var props = [];
scope.gatherProperties(function (prop, obj, depth) {
props.push(prop);
});
// Check the gathered properties for correctness (order matters)
if (props.length !== 3) {
return callback("fail", name, "- Invalid number of properties gathered (" + props.length + ")");
}
if (props[0] !== "first") {
return callback("fail", name, "- props[0] was not property 'first'");
}
if (props[1] !== "second") {
return callback("fail", name, "- props[1] was not property 'second'");
}
if (props[2] !== "third") {
return callback("fail", name, "- props[2] was not property 'third'");
}
return callback("ok", name);
});
});
test("QMLMemScope::defProp()", function (server, callback, name) {
infer.withContext(new infer.Context([], server), function () {
// Create the scope and objects to test
var fileScope = new infer.Scope();
var obj = new infer.Obj(null, "MyObject");
var objScope = new plugin.QMLObjScope(fileScope, null, obj);
var scope = new plugin.QMLMemScope(objScope, null, fileScope);
// Define some properties
scope.defProp("first", null);
scope.defProp("second", null);
// Make sure there are no properties in the scopes themselves
if (fileScope.props && fileScope.props.length > 0) {
return callback("fail", name, "- File scope contained properties (none expected)");
}
if (scope.props && scope.props.length > 0) {
return callback("fail", name, "- QMLMemScope contained properties (none expected)");
}
// Check the Obj Type for the props we created
if (!obj.props.first) {
return callback("fail", name, "- Obj did not contain property 'first'");
}
if (!obj.props.second) {
return callback("fail", name, "- Obj did not contain property 'second'");
}
return callback("ok", name);
});
});
test("QMLMemScope::hasProp()", function (server, callback, name) {
infer.withContext(new infer.Context([], server), function () {
// Create the scope and objects to test
var fileScope = new infer.Scope();
var obj = new infer.Obj(null, "MyObject");
var objScope = new plugin.QMLObjScope(fileScope, null, obj);
var scope = new plugin.QMLMemScope(objScope, null, fileScope);
// Define a property on the Obj Type and File Scope
obj.defProp("first", null);
fileScope.defProp("second", null);
// Query the scope for the prop we created and make sure it returns the right one
var prop = scope.hasProp("first", true);
if (!prop) {
return callback("fail", name, "- hasProp('first') returned null");
} else if (prop.propertyName !== "first") {
return callback("fail", name, "- hasProp('first') returned invalid property");
}
prop = scope.hasProp("second", true);
if (!prop) {
return callback("fail", name, "- hasProp('second') returned null");
} else if (prop.propertyName !== "second") {
return callback("fail", name, "- hasProp('second') returned invalid property");
}
return callback("ok", name);
});
});
test("QMLMemScope::hasProp() [Multiple Parent Scopes]", function (server, callback, name) {
infer.withContext(new infer.Context([], server), function () {
// Create the scope and objects to test
var fileScope = new infer.Scope();
var rootObj = new infer.Obj(null, "Root");
var rootObjScope = new plugin.QMLObjScope(fileScope, null, rootObj);
var obj = new infer.Obj(null, "MyObject");
var objScope = new plugin.QMLObjScope(rootObjScope, null, obj);
var scope = new plugin.QMLMemScope(objScope, null, fileScope);
// Define a property on the Root Obj Type and Obj Type
rootObj.defProp("notVisible", null);
obj.defProp("visible", null);
// Query the scope for the prop we created and make sure it returns the right one
var prop = scope.hasProp("notVisible", true);
if (prop) {
return callback("fail", name, "- found property 'notVisible'");
}
prop = scope.hasProp("visible", true);
if (!prop) {
return callback("fail", name, "- hasProp('visible') returned null");
} else if (prop.propertyName !== "visible") {
return callback("fail", name, "- hasProp('visible') returned invalid property");
}
return callback("ok", name);
});
});
test("QMLMemScope::removeProp()", function (server, callback, name) {
infer.withContext(new infer.Context([], server), function () {
// Create the scope and objects to test
var fileScope = new infer.Scope();
var obj = new infer.Obj(null, "MyObject");
var objScope = new plugin.QMLObjScope(fileScope, null, obj);
var scope = new plugin.QMLMemScope(objScope, null, fileScope);
// Define some properties
scope.defProp("first", null);
scope.defProp("second", null);
// Remove the properties we defined
scope.removeProp("first");
scope.removeProp("second");
// Check the Obj Type for the props we created
if (obj.props && obj.props.length > 0) {
return callback("fail", name, "- Obj contained properties (none expected)");
}
return callback("ok", name);
});
});
test("QMLMemScope::gatherProperties()", function (server, callback, name) {
infer.withContext(new infer.Context([], server), function () {
// Create the scope and objects to test
var fileScope = new infer.Scope();
var obj = new infer.Obj(null, "MyObject");
var objScope = new plugin.QMLObjScope(fileScope, null, obj);
var scope = new plugin.QMLMemScope(objScope, null, fileScope);
// Define some properties
fileScope.defProp("third", null);
scope.defProp("first", null);
scope.defProp("second", null);
// Gather the properties and store them in the order they were received
var props = [];
scope.gatherProperties(function (prop, obj, depth) {
props.push(prop);
});
// Check the gathered properties for correctness (order matters)
if (props.length !== 3) {
return callback("fail", name, "- Invalid number of properties gathered (" + props.length + ")");
}
if (props[0] !== "first") {
return callback("fail", name, "- props[0] was not property 'first'");
}
if (props[1] !== "second") {
return callback("fail", name, "- props[1] was not property 'second'");
}
if (props[2] !== "third") {
return callback("fail", name, "- props[2] was not property 'third'");
}
return callback("ok", name);
});
});
test("QMLMemScope::gatherProperties() [Multiple Parent Scopes]", function (server, callback, name) {
infer.withContext(new infer.Context([], server), function () {
// Create the scope and objects to test
var fileScope = new infer.Scope();
var rootObj = new infer.Obj(null, "Root");
var rootObjScope = new plugin.QMLObjScope(fileScope, null, rootObj);
var obj = new infer.Obj(null, "MyObject");
var objScope = new plugin.QMLObjScope(rootObjScope, null, obj);
var scope = new plugin.QMLMemScope(objScope, null, fileScope);
// Define a property on the Root Obj Type and Obj Type
rootObj.defProp("notVisible", null);
obj.defProp("visible", null);
// Gather the properties and store them in the order they were received
var props = [];
scope.gatherProperties(function (prop, obj, depth) {
props.push(prop);
});
// Check the gathered properties for correctness (order matters)
if (props.length !== 1) {
return callback("fail", name, "- Invalid number of properties gathered (" + props.length + ")");
}
if (props[0] !== "visible") {
return callback("fail", name, "- props[0] was not property 'visible'");
}
return callback("ok", name);
});
});
test("QMLJSScope::hasProp()", function (server, callback, name) {
infer.withContext(new infer.Context([], server), function () {
// Create the scope and objects to test
var fileScope = new infer.Scope();
var idScope = new infer.Scope(null, "<qml-id>");
var jsScope = new infer.Scope(null, "<qml-js>");
var fnScope = new infer.Scope(null, "<qml-fn>");
var scope = new plugin.QMLJSScope(fileScope, null, idScope, jsScope, fnScope);
// Define properties in each scope
fileScope.defProp("first", null);
idScope.defProp("second", null);
jsScope.defProp("third", null);
fnScope.defProp("fourth", null);
scope.defProp("fifth", null);
// Query the scope for the prop we created and make sure it returns the right one
var prop = scope.hasProp("first", true);
if (!prop) {
return callback("fail", name, "- hasProp('first') returned null");
} else if (prop.propertyName !== "first") {
return callback("fail", name, "- hasProp('first') returned invalid property");
}
prop = scope.hasProp("second", true);
if (!prop) {
return callback("fail", name, "- hasProp('second') returned null");
} else if (prop.propertyName !== "second") {
return callback("fail", name, "- hasProp('second') returned invalid property");
}
prop = scope.hasProp("third", true);
if (!prop) {
return callback("fail", name, "- hasProp('third') returned null");
} else if (prop.propertyName !== "third") {
return callback("fail", name, "- hasProp('third') returned invalid property");
}
prop = scope.hasProp("fourth", true);
if (!prop) {
return callback("fail", name, "- hasProp('fourth') returned null");
} else if (prop.propertyName !== "fourth") {
return callback("fail", name, "- hasProp('fourth') returned invalid property");
}
prop = scope.hasProp("fifth", true);
if (!prop) {
return callback("fail", name, "- hasProp('fifth') returned null");
} else if (prop.propertyName !== "fifth") {
return callback("fail", name, "- hasProp('fifth') returned invalid property");
}
return callback("ok", name);
});
});
test("QMLJSScope::gatherProperties()", function (server, callback, name) {
infer.withContext(new infer.Context([], server), function () {
// Create the scope and objects to test
// Create the scope and objects to test
var fileScope = new infer.Scope();
var idScope = new infer.Scope(null, "<qml-id>");
var jsScope = new infer.Scope(null, "<qml-js>");
var fnScope = new infer.Scope(null, "<qml-fn>");
var scope = new plugin.QMLJSScope(fileScope, null, idScope, jsScope, fnScope);
// Define properties in each scope
fileScope.defProp("fifth", null);
idScope.defProp("first", null);
jsScope.defProp("fourth", null);
fnScope.defProp("third", null);
scope.defProp("second", null);
// Gather the properties and store them in the order they were received
var props = [];
scope.gatherProperties(function (prop, obj, depth) {
props.push(prop);
});
// Check the gathered properties for correctness (order matters)
if (props.length !== 5) {
return callback("fail", name, "- Invalid number of properties gathered (" + props.length + ")");
}
if (props[0] !== "first") {
return callback("fail", name, "- props[0] was not property 'first'");
}
if (props[1] !== "second") {
return callback("fail", name, "- props[1] was not property 'second'");
}
if (props[2] !== "third") {
return callback("fail", name, "- props[2] was not property 'third'");
}
if (props[3] !== "fourth") {
return callback("fail", name, "- props[3] was not property 'fourth'");
}
if (props[4] !== "fifth") {
return callback("fail", name, "- props[4] was not property 'fifth'");
}
return callback("ok", name);
});
});
groupEnd();