1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-23 08:55:25 +02:00

Bug 481126 - QML Parse Query Type

Added two new query types to tern-qml: 'parseFile' and 'parseString'
which will return an AST for the given file or string respectively.

Change-Id: I4608866c002d43defb4d462c4a981282ed97e1c6
Signed-off-by: Matthew Bastien <mbastien@blackberry.com>
This commit is contained in:
Matthew Bastien 2015-12-07 12:08:33 -05:00
parent 42e3859b68
commit d6bba126d8
5 changed files with 151 additions and 13 deletions

View file

@ -926,6 +926,9 @@
qmlImportHandler.reset();
}
/*
* Called when a completions query is made to the server
*/
function completions(file, query) {
// We can get relatively simple completions on QML Object Types for free if we
// update the Context.paths variable. Tern uses this variable to complete
@ -939,6 +942,35 @@
}
}
/*
* Called when a parse query is made to the server.
*/
function parse(srv, query, file) {
var ast = null;
if (query.file) {
// Get the file's AST. It should have been parsed already by the server.
ast = file.ast;
} else if (query.text) {
// Parse the file manually and get the AST.
var text = query.text;
var options = {
allowReturnOutsideFunction: true,
allowImportExportEverywhere: true,
ecmaVersion: srv.options.ecmaVersion
};
srv.signal("preParse", text, options);
try {
ast = acorn.parse(text, options);
} catch (e) {
ast = acorn.parse_dammit(text, options);
}
srv.signal("postParse", ast, text);
}
return {
ast: ast
};
}
// Register the QML plugin in Tern
tern.registerPlugin("qml", function (server) {
// First we want to replace the top-level defs array with our own and save the
@ -955,6 +987,18 @@
// Create the QML Import Handler
qmlImportHandler = exports.importHandler = new ImportHandler(server);
// Define the 'parseFile' and 'parseString' query types. The reason we need
// two separate queries for these is that Tern will not allow us to resolve
// a file without 'takesFile' being true. However, if we set 'takesFile' to
// true, Tern will not allow a null file in the query.
tern.defineQueryType("parseFile", {
takesFile: true,
run: parse
});
tern.defineQueryType("parseString", {
run: parse
});
// Hook into server signals
server.on("preParse", preParse);
server.on("beforeLoad", beforeLoad);

View file

@ -15,7 +15,7 @@ var ternQML = require("../qml.js");
var tern = require("tern");
var projectDir = path.resolve(__dirname, "..");
var resolve = function(pth) {
var resolve = function (pth) {
return path.resolve(projectDir, pth);
};
var testCases = [];
@ -108,8 +108,8 @@ function createServer(defs) {
plugins.qml = true;
var server = new tern.Server({
ecmaVersion: 5,
plugins : plugins,
defs : [ require("./ecma5-defs.js") ]
plugins: plugins,
defs: [ require("./ecma5-defs.js") ]
});
return server;
}
@ -117,7 +117,14 @@ function createServer(defs) {
var assertCompletion = exports.assertCompletion = function (server, code, expected, pos, callback) {
server.addFile("main.qml", code);
server.request({
query : {
files: [
{
name: "main.qml",
text: code,
type: "full"
}
],
query: {
type: "completions",
file: "main.qml",
end: pos,
@ -130,7 +137,7 @@ var assertCompletion = exports.assertCompletion = function (server, code, expect
expandWordForward: false,
guess: false
}
}, function(err, resp) {
}, function (err, resp) {
if (err) {
throw err;
}
@ -140,9 +147,15 @@ var assertCompletion = exports.assertCompletion = function (server, code, expect
};
var assertDefinition = exports.assertDefinition = function (server, code, expected, pos, callback) {
server.addFile("main.qml", code);
server.request({
query : {
files: [
{
name: "main.qml",
text: code,
type: "full"
}
],
query: {
type: "definition",
file: "main.qml",
end: pos,
@ -155,7 +168,7 @@ var assertDefinition = exports.assertDefinition = function (server, code, expect
expandWordForward: false,
guess: false
}
}, function(err, resp) {
}, function (err, resp) {
if (err) {
throw err;
}
@ -169,8 +182,8 @@ function ppJSON(v) {
}
function addPath(str, pt) {
if (str.charAt(str.length-1) == ")")
return str.slice(0, str.length-1) + "/" + pt + ")";
if (str.charAt(str.length - 1) == ")")
return str.slice(0, str.length - 1) + "/" + pt + ")";
return str + " (" + pt + ")";
}

View file

@ -32,6 +32,7 @@ var stats, tests = [];
tests.push(require("./test-scoping.js"));
tests.push(require("./test-finddef.js"));
tests.push(require("./test-completions.js"));
tests.push(require("./test-parse.js"));
function report(state, code, message) {
if (state != "ok") {++stats.failed; log(code, message);}

View file

@ -202,13 +202,13 @@ test("{Add File After Import}", function (server, callback, name) {
return callback("fail", name, "- failed on initial file " + failed);
}
server.addFile("MyObject.qml", "QtObject {\n\tproperty var test\n}");
assertCompletion(server, "M", {
assertCompletion(server, "", {
start: { line: 0, ch: 0 },
end: { line: 0, ch: 1 },
end: { line: 0, ch: 0 },
isProperty: false,
isObjectKey: false,
completions: [{ name: "MyObject", type: "MyObject", origin: "MyObject.qml" }]
}, 1, function (mis) {
}, 0, function (mis) {
failed = mis;
});
if (failed) {

View file

@ -0,0 +1,80 @@
/*******************************************************************************
* 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 driver = require("./driver.js");
var test = driver.test;
var groupStart = driver.groupStart;
var groupEnd = driver.groupEnd;
var group = exports.group = "Parse Query";
groupStart(group);
test("{Parse existing file}", function (server, callback, name) {
server.addFile("main.qml", "import QtQuick 2.0\nModule {\n\tComponent {\n\t}\n}");
server.request({
query: {
type: "parseFile",
file: "main.qml"
}
}, function (err, resp) {
if (err) {
throw err;
}
if (!resp.ast && resp.ast.type === "QMLProgram") {
return callback("fail", name, "AST could not be found in response");
}
return callback("ok", name);
});
});
test("{Parse given file}", function (server, callback, name) {
server.request({
files: [
{
name: "main.qml",
text: "import QtQuick 2.0\nModule {\n\tComponent {\n\t}\n}",
type: "full"
}
],
query: {
type: "parseFile",
file: "main.qml"
}
}, function (err, resp) {
if (err) {
throw err;
}
if (!resp.ast && resp.ast.type === "QMLProgram") {
return callback("fail", name, "AST could not be found in response");
}
return callback("ok", name);
});
});
test("{Parse text}", function (server, callback, name) {
server.request({
query: {
type: "parseString",
text: "import QtQuick 2.0\nModule {\n\tComponent {\n\t}\n}"
}
}, function (err, resp) {
if (err) {
throw err;
}
if (!resp.ast && resp.ast.type === "QMLProgram") {
return callback("fail", name, "AST could not be found in response");
}
return callback("ok", name);
});
});
groupEnd();