mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-31 12:55:40 +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:
parent
42e3859b68
commit
d6bba126d8
5 changed files with 151 additions and 13 deletions
|
@ -926,6 +926,9 @@
|
||||||
qmlImportHandler.reset();
|
qmlImportHandler.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called when a completions query is made to the server
|
||||||
|
*/
|
||||||
function completions(file, query) {
|
function completions(file, query) {
|
||||||
// We can get relatively simple completions on QML Object Types for free if we
|
// 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
|
// 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
|
// Register the QML plugin in Tern
|
||||||
tern.registerPlugin("qml", function (server) {
|
tern.registerPlugin("qml", function (server) {
|
||||||
// First we want to replace the top-level defs array with our own and save the
|
// 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
|
// Create the QML Import Handler
|
||||||
qmlImportHandler = exports.importHandler = new ImportHandler(server);
|
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
|
// Hook into server signals
|
||||||
server.on("preParse", preParse);
|
server.on("preParse", preParse);
|
||||||
server.on("beforeLoad", beforeLoad);
|
server.on("beforeLoad", beforeLoad);
|
||||||
|
|
|
@ -15,7 +15,7 @@ var ternQML = require("../qml.js");
|
||||||
var tern = require("tern");
|
var tern = require("tern");
|
||||||
|
|
||||||
var projectDir = path.resolve(__dirname, "..");
|
var projectDir = path.resolve(__dirname, "..");
|
||||||
var resolve = function(pth) {
|
var resolve = function (pth) {
|
||||||
return path.resolve(projectDir, pth);
|
return path.resolve(projectDir, pth);
|
||||||
};
|
};
|
||||||
var testCases = [];
|
var testCases = [];
|
||||||
|
@ -108,8 +108,8 @@ function createServer(defs) {
|
||||||
plugins.qml = true;
|
plugins.qml = true;
|
||||||
var server = new tern.Server({
|
var server = new tern.Server({
|
||||||
ecmaVersion: 5,
|
ecmaVersion: 5,
|
||||||
plugins : plugins,
|
plugins: plugins,
|
||||||
defs : [ require("./ecma5-defs.js") ]
|
defs: [ require("./ecma5-defs.js") ]
|
||||||
});
|
});
|
||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,14 @@ function createServer(defs) {
|
||||||
var assertCompletion = exports.assertCompletion = function (server, code, expected, pos, callback) {
|
var assertCompletion = exports.assertCompletion = function (server, code, expected, pos, callback) {
|
||||||
server.addFile("main.qml", code);
|
server.addFile("main.qml", code);
|
||||||
server.request({
|
server.request({
|
||||||
query : {
|
files: [
|
||||||
|
{
|
||||||
|
name: "main.qml",
|
||||||
|
text: code,
|
||||||
|
type: "full"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
query: {
|
||||||
type: "completions",
|
type: "completions",
|
||||||
file: "main.qml",
|
file: "main.qml",
|
||||||
end: pos,
|
end: pos,
|
||||||
|
@ -130,7 +137,7 @@ var assertCompletion = exports.assertCompletion = function (server, code, expect
|
||||||
expandWordForward: false,
|
expandWordForward: false,
|
||||||
guess: false
|
guess: false
|
||||||
}
|
}
|
||||||
}, function(err, resp) {
|
}, function (err, resp) {
|
||||||
if (err) {
|
if (err) {
|
||||||
throw 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) {
|
var assertDefinition = exports.assertDefinition = function (server, code, expected, pos, callback) {
|
||||||
server.addFile("main.qml", code);
|
|
||||||
server.request({
|
server.request({
|
||||||
query : {
|
files: [
|
||||||
|
{
|
||||||
|
name: "main.qml",
|
||||||
|
text: code,
|
||||||
|
type: "full"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
query: {
|
||||||
type: "definition",
|
type: "definition",
|
||||||
file: "main.qml",
|
file: "main.qml",
|
||||||
end: pos,
|
end: pos,
|
||||||
|
@ -155,7 +168,7 @@ var assertDefinition = exports.assertDefinition = function (server, code, expect
|
||||||
expandWordForward: false,
|
expandWordForward: false,
|
||||||
guess: false
|
guess: false
|
||||||
}
|
}
|
||||||
}, function(err, resp) {
|
}, function (err, resp) {
|
||||||
if (err) {
|
if (err) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
@ -169,8 +182,8 @@ function ppJSON(v) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function addPath(str, pt) {
|
function addPath(str, pt) {
|
||||||
if (str.charAt(str.length-1) == ")")
|
if (str.charAt(str.length - 1) == ")")
|
||||||
return str.slice(0, str.length-1) + "/" + pt + ")";
|
return str.slice(0, str.length - 1) + "/" + pt + ")";
|
||||||
return str + " (" + pt + ")";
|
return str + " (" + pt + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ var stats, tests = [];
|
||||||
tests.push(require("./test-scoping.js"));
|
tests.push(require("./test-scoping.js"));
|
||||||
tests.push(require("./test-finddef.js"));
|
tests.push(require("./test-finddef.js"));
|
||||||
tests.push(require("./test-completions.js"));
|
tests.push(require("./test-completions.js"));
|
||||||
|
tests.push(require("./test-parse.js"));
|
||||||
|
|
||||||
function report(state, code, message) {
|
function report(state, code, message) {
|
||||||
if (state != "ok") {++stats.failed; log(code, message);}
|
if (state != "ok") {++stats.failed; log(code, message);}
|
||||||
|
|
|
@ -202,13 +202,13 @@ test("{Add File After Import}", function (server, callback, name) {
|
||||||
return callback("fail", name, "- failed on initial file " + failed);
|
return callback("fail", name, "- failed on initial file " + failed);
|
||||||
}
|
}
|
||||||
server.addFile("MyObject.qml", "QtObject {\n\tproperty var test\n}");
|
server.addFile("MyObject.qml", "QtObject {\n\tproperty var test\n}");
|
||||||
assertCompletion(server, "M", {
|
assertCompletion(server, "", {
|
||||||
start: { line: 0, ch: 0 },
|
start: { line: 0, ch: 0 },
|
||||||
end: { line: 0, ch: 1 },
|
end: { line: 0, ch: 0 },
|
||||||
isProperty: false,
|
isProperty: false,
|
||||||
isObjectKey: false,
|
isObjectKey: false,
|
||||||
completions: [{ name: "MyObject", type: "MyObject", origin: "MyObject.qml" }]
|
completions: [{ name: "MyObject", type: "MyObject", origin: "MyObject.qml" }]
|
||||||
}, 1, function (mis) {
|
}, 0, function (mis) {
|
||||||
failed = mis;
|
failed = mis;
|
||||||
});
|
});
|
||||||
if (failed) {
|
if (failed) {
|
||||||
|
|
80
qt/org.eclipse.cdt.qt.core/tern-qml/test/test-parse.js
Normal file
80
qt/org.eclipse.cdt.qt.core/tern-qml/test/test-parse.js
Normal 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();
|
Loading…
Add table
Reference in a new issue