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:
parent
42e3859b68
commit
d6bba126d8
5 changed files with 151 additions and 13 deletions
|
@ -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);
|
||||
|
|
|
@ -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 + ")";
|
||||
}
|
||||
|
||||
|
|
|
@ -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);}
|
||||
|
|
|
@ -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) {
|
||||
|
|
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