PocketMine-IDE/out/src/phpCompletionItem.js
Ad5001 0d1b9ffc31 *facepalm* messing with some old code.
Thanks windows for taking the way no ones does...
2017-11-16 22:42:58 +01:00

410 lines
18 KiB
JavaScript
Executable file

const vscode = require("vscode");
const ext = require("./extension");
const path = require('path');
const fs = require('fs');
const PROPERTY_NORMAL = 0;
const PROPERTY_STATIC = 1;
const PROPERTY_CONST = 2;
exports.Indexer = {
/** @var {Object} */
phpFileUses: {},
/** @var {Object} */
phpFileFunctions: {},
/** @var {Object} */
phpFileStaticFunctions: {},
/** @var {Object} */
phpFileProperties: {},
/** @var {Object} */
done: {},
/**
* Gets all functions in a completion item form
*
* @param {String} file
* @param {vscode.CompletionItem[]} suggestions
* @param {String} currentWord
* @param {String} execute
* @return {vscode.CompletionItem[]}
*/
getFunctionsFromFile(file, suggestions, currentWord, execute) {
for (var func in exports.Indexer.phpFileFunctions[file]) {
func = exports.Indexer.phpFileFunctions[file][func];
if (func.function.startsWith(currentWord) && execute[1] == currentWord && (func.functionModifiers["public"] || file == ext.currentPath)) {
if (typeof exports.Indexer.done[func.function] == "undefined" /*|| exports.Indexer.done[func.function].params !== func.params */ ) { // Preventing from spamming same method over and over
var newSuggestion = new vscode.CompletionItem(func.function, vscode.CompletionItemKind.Function);
params = func.params;
var parameters = [];
params.forEach(function(value, key) {
if (value) {
params[key] = "$" + value[1];
parameters[key] = (typeof value[2] !== "undefined" ? value[2] + " " : "") + value[1];
parameters[key] += typeof value[3] !== "undefined" ? " = " + value[3] : "";
}
});
newSuggestion.insertText = func.function+"(" + params.join(", ") + ")";
newSuggestion.documentation = func.comment;
newSuggestion.detail = "(function) (" + parameters.join(", ") + ")";
suggestions.push(newSuggestion);
exports.Indexer.done[func.function] = func;
}
}
};
return suggestions;
},
/**
* Returns all indexed static functions of file
*
* @param {string} file
* @param {vscode.CompletionItem[]} suggestions
* @param {String} currentWord
* @param {String} executeStatic
* @return {vscode.CompletionItem[]}
*/
getStaticFunctionsFromFile(file, suggestions, currentWord, executeStatic) {
for (var func in exports.Indexer.phpFileStaticFunctions[file]) {
func = exports.Indexer.phpFileStaticFunctions[file][func];
if (func.function.startsWith(currentWord) && executeStatic[1] == currentWord) {
if (typeof exports.Indexer.done[func.function] == "undefined" /*|| exports.Indexer.done[func.function].params !== func.params*/ ) { // Preventing from spamming same method over and over
var newSuggestion = new vscode.CompletionItem(func.function, vscode.CompletionItemKind.Function);
var params = func.params;
var parameters = [];
params.forEach(function(value, key) {
if (value) {
params[key] = "$" + value[1];
parameters[key] = (typeof value[2] !== "undefined" ? value[2] + " " : "") + value[1];
parameters[key] += typeof value[3] !== "undefined" ? " = " + value[3] : "";
}
})
newSuggestion.insertText = func.function+"(" + params.join(", ") + ")";
newSuggestion.documentation = func.comment;
newSuggestion.detail = "(function) (" + parameters.join(", ") + ")";
suggestions.push(newSuggestion);
exports.Indexer.done[func.function] = func;
}
}
};
return suggestions;
},
/**
* Gets all properties in a completion item form
*
* @param {String} file
* @param {vscode.CompletionItem[]} suggestions
* @param {String} currentWord
* @param {String} execute
* @return {vscode.CompletionItem[]}
*/
getPropertiesFromFile(file, suggestions, currentWord, execute) {
for (var func in exports.Indexer.phpFileProperties[file]) {
func = exports.Indexer.phpFileProperties[file][func];
if (func[0].startsWith(currentWord) && execute[1] == currentWord && func[1] == PROPERTY_NORMAL) {
if (typeof exports.Indexer.done[func[0]] == "undefined") { // Preventing from spamming same method over and over
var newSuggestion = new vscode.CompletionItem(func[0], vscode.CompletionItemKind.Property);
newSuggestion.insertText = func[0];
newSuggestion.detail = "(property) " + file.substr(0, file.length - 4).replace(new RegExp("\/", "g"), "\\");
suggestions.push(newSuggestion);
exports.Indexer.done[func[0]] = true;
}
}
};
return suggestions;
},
/**
* Returns all indexed static properties of file
*
* @param {string} file
* @param {vscode.CompletionItem[]} suggestions
* @param {String} currentWord
* @param {String} executeStatic
* @return {vscode.CompletionItem[]}
*/
getStaticPropertiesFromFile(file, suggestions, currentWord, executeStatic) {
for (var func in exports.Indexer.phpFileProperties[file]) {
func = exports.Indexer.phpFileProperties[file][func];
if (func[0].startsWith(currentWord) && executeStatic[1] == currentWord) {
if (typeof exports.Indexer.done[func[0]] == "undefined") { // Preventing from spamming same method over and over
if (func[1] == PROPERTY_STATIC) {
var newSuggestion = new vscode.CompletionItem("$" + func[0], vscode.CompletionItemKind.Property);
newSuggestion.insertText = "$" + func[0];
newSuggestion.detail = "(property) " + file.substr(0, file.length - 4).replace(new RegExp("\/", "g"), "\\");
exports.Indexer.done[func[0]] = true;
} else if (func[1] == PROPERTY_CONST) {
var newSuggestion = new vscode.CompletionItem(func[0], vscode.CompletionItemKind.Constant);
newSuggestion.insertText = func[0];
newSuggestion.detail = "(constant) " + file.substr(0, file.length - 4).replace(new RegExp("\/", "g"), "\\");
exports.Indexer.done[func[0]] = true;
}
if (newSuggestion) suggestions.push(newSuggestion);
}
}
};
return suggestions;
},
/**
* Gets completion class for a file in format "use ns\class;"
*
* @param {string} file
* @param {vscode.CompletionItem[]} suggestions
* @return {vscode.CompletionItem[]}
*/
getClassUse(file, suggestions) {
var currentClass = file.substr(0, file.length - 4);
currentClass = currentClass.replace(new RegExp("\/", "g"), "\\");
if (currentClass.startsWith("\\")) currentClass = currentClass.substr(1);
var newSuggestion = new vscode.CompletionItem(currentClass, vscode.CompletionItemKind.Class);
newSuggestion.detail = "(class) " + currentClass;
newSuggestion.insertText = currentClass + ";\n";
suggestions.push(newSuggestion);
return suggestions;
},
/**
* Gets a class completion (new instance) item from it's class name
*
* @param {string} file
* @param {vscode.CompletionItem[]} suggestions
* @param {string} currentPath
* @param {array} clas
* @return {vscode.CompletionItem[]}
*
*/
getClassNew(file, suggestions, currentPath, clas) {
var currentClass = file.substr(0, file.length - 4).replace(new RegExp("\/", "g"), "\\");
var params = [];
if (typeof exports.Indexer.phpFileFunctions[file]["__construct"] !== "undefined") {
params = exports.Indexer.phpFileFunctions[file]["__construct"].params;
}
params.forEach(function(value, key) {
if (value) params[key] = "$" + value[2];
});
if (currentClass.startsWith("\\")) currentClass = currentClass.substr(1);
var newSuggestion = new vscode.CompletionItem(currentClass, vscode.CompletionItemKind.Class);
if (typeof clas[1] == "undefined" &&
typeof exports.Indexer.phpFileUses[currentPath] !== "undefined" &&
typeof exports.Indexer.phpFileUses[currentPath][currentClass] !== "undefined") {
newSuggestion.insertText = currentClass.split("\\")[currentClass.split("\\").length - 1] + "(" + params.join(", ") + ");";
} else {
newSuggestion.insertText = "\\" + currentClass + "(" + params.join(", ") + ");";
}
newSuggestion.detail = "(class) " + currentClass;
suggestions.push(newSuggestion);
return suggestions;
},
/**
* Gets a class completion (static class) item from it's class name
*
* @param {string} file
* @param {vscode.CompletionItem[]} suggestions
* @param {string} currentPath
* @return {vscode.CompletionItem[]}
*
*/
getClassNormal(file, suggestions, currentPath) {
var currentClass = file.substr(0, file.length - 4).replace(new RegExp("\/", "g"), "\\");
var currentPath2 = currentPath.substr(1);
// currentClass = currentClass.replace(new RegExp("\/", "g"), "\\");
if (currentClass.startsWith("\\")) currentClass = currentClass.substr(1);
var newSuggestion = new vscode.CompletionItem(currentClass, vscode.CompletionItemKind.Class);
newSuggestion.detail = "(class) " + currentClass;
console.log(currentClass, exports.Indexer.phpFileUses[currentPath], exports.Indexer.phpFileUses[currentPath][currentClass]);
if (typeof exports.Indexer.phpFileUses[currentPath] !== "undefined" &&
typeof exports.Indexer.phpFileUses[currentPath][currentClass] !== "undefined") {
newSuggestion.insertText = currentClass.split("\\")[currentClass.split("\\").length - 1];
} else {
newSuggestion.insertText = "\\" + currentClass;
}
suggestions.push(newSuggestion);
return suggestions;
},
/**
* Funcion that handles PHP file registering.
*
* @return {Void}
*/
indexPhpFiles() {
// Clear out the cached data
exports.Indexer.phpFileUses = {};
exports.Indexer.phpFileFunctions = {};
exports.Indexer.phpFileStaticFunctions = {};
exports.Indexer.phpFileProperties = {};
var libraryResult = [];
if (fs.existsSync(vscode.workspace.getConfiguration('php')['pocketMinePath'])) {
libraryResult = exports.Indexer.findFilesInDir(vscode.workspace.getConfiguration('php')['pocketMinePath'], ".php");
}
if (vscode.workspace.rootPath !== undefined) {
var c = exports.Indexer.findFilesInDir(vscode.workspace.rootPath, ".php");
libraryResult = libraryResult.concat(c);
}
libraryResult.forEach(function(path) {
if (fs.existsSync(path)) {
var fileName = path.replace(vscode.workspace.rootPath, "").replace(vscode.workspace.getConfiguration('php')['pocketMinePath'], "").replace("src", "").replace("//", "/").replace("\\\\", "\\");
// Creating the default properties
var fileProperties = ["phpFileFunctions", "phpFileStaticFunctions", "phpFileUses", "phpFileProperties"];
fileProperties.forEach(function(func) {
if (typeof exports.Indexer[func][fileName] == "undefined") {
exports.Indexer[func][fileName] = {};
}
})
// Read through the PHP file for includes/requires and function definitions
var read = fs.readFileSync(path, 'utf8');
// Parsing class regexr
var fileBaseName = (path.indexOf("/") ? path.split("/") : (path.indexOf("\\") ? path.split("\\") : [path]));
fileBaseName = fileBaseName[fileBaseName.length - 1].replace(/\.php$/, "");
// if (!read.match(new RegExp("(class|interface)\\s+" + fileBaseName, "mi"))) return;
// var classRegexr = new RegExp("(class|interface)\\s+" + fileBaseName + "(\\s+extends ([\w_]+))?(\\s+implements ([\w_\\\\]+))?", "mi");
var lineReader = read.split(/(\r|\n)/gim);
lineReader.forEach(function(line) {
// Parsing functions:
exports.Indexer.parseFunction(line, fileName);
// Parsing properties:
exports.Indexer.parseProperty(line, fileName);
// Check for uses
exports.Indexer.parseUse(line, fileName);
});
}
});
},
/**
* Find all files recursively in specific folder with specific extension, e.g:
* findFilesInDir('./project/src', '.html') ==> ['./project/src/a.html','./project/src/build/index.html']
* @param {String} startPath Path relative to exports.Indexer file or other file which requires exports.Indexer files
* @param {String} filter Extension name, e.g: '.html'
* @return {Array} Result files with path string in an array
*/
findFilesInDir(startPath, filter) {
var results = [];
if (!fs.existsSync(startPath)) {
console.log("no dir ", startPath);
return;
}
var files = fs.readdirSync(startPath);
for (var i = 0; i < files.length; i++) {
var filename = path.join(startPath, files[i]);
var stat = fs.lstatSync(filename);
if (stat.isDirectory()) {
results = results.concat(exports.Indexer.findFilesInDir(filename, filter)); //recurse
} else if (filename.indexOf(filter) >= 0) {
results.push(filename);
}
}
return results;
},
/**
* Parses and exports.Indexer functions from a line.
* @param {String} line
* @param {String} fileName
*/
parseFunction(line, fileName) {
// Thats a bit messy for exports.Indexer one so: $2 = optionnal description comment, $4 = functions specifications (static, public, abstract, final,...), $7 = function name, $8 = arguments, $14 = return of function
var functionRegex = /(\/\*\*?((\s|.|\n)+)\*\/)?\s*(((abstract|public|protected|private|final|static)\s*)*)function\s+(\w+)\(((\s*\w+)?\s*\$\w+\s*(,(\s*\w+)?\s*\$\w+\s*)*\s*)?\)\s*(:\s*(\w+)\s*)?({|;)/mig
var match = functionRegex.exec(line);
if (match) {
// Matching function modifiers
var functionModifiersLitteral = match[4].replace(/\s/, " ").split(" ");
var functionModifiers = {
"abstract": false,
"public": false,
"protected": false,
"private": false,
"final": false,
"static": false
};
functionModifiersLitteral.forEach(function(modifier) {
functionModifiers[modifier] = true;
})
var comment = typeof match[3] !== "undefined" ? match[3].replace(/[*]/gim, "") : "From " + fileName;
// Parameters
var params = [];
if (typeof match[8] !== "undefined") match[8].replace(/\s*,\s*/, ",").split(",").forEach(function(m) {
var paramers = /((\w+)\s+)?(\$\w+)(\s*\=[^,)]+)?/.exec(m)
if (typeof paramers !== "undefined" && paramers !== null) params.push([paramers[0], paramers[3], paramers[2], paramers[5]]); // Later use of knowning which equals to what.
});
// Exporting function
if (!functionModifiers.static) {
exports.Indexer.phpFileFunctions[fileName][match[7]] = {
function: match[7],
params: params,
functionModifiers: functionModifiers,
comment: comment
};
} else {
exports.Indexer.phpFileStaticFunctions[fileName][match[7]] = {
function: match[7],
params: params,
functionModifiers: functionModifiers,
comment: comment
};
}
}
},
/**
* Parses and exports.Indexer uses from a line.
* @param {String} line
* @param {String} fileName
*/
parseUse(line, fileName) {
var includeRegex = /use\s+((\w+\\)*)(\w+)(\s+as\s+(\w+)\s*)?;/;
var match = includeRegex.exec(line);
if (match) {
// Check if there is a match of "as" to set it.
var classType = '';
if (typeof match[4] !== "undefined") {
classType = match[5];
} else {
classType = match[3];
}
exports.Indexer.phpFileUses[fileName][match[1] + match[3]] = classType;
}
},
/**
* Parses and exports Indexer properties (also static one) from a line.
* @param {String} line
* @param {String} fileName
*/
parseProperty(line, fileName) {
var propertiesRegexr = /(protected|private|public|static|const)\s+(\$)?([\w_]+)\s*(;|=)/;
var match = propertiesRegexr.exec(line);
if (match) {
if (match[1] == "static" && match[2] == "$") {
exports.Indexer.phpFileProperties[fileName][match[3]] = [match[3], PROPERTY_STATIC];
} else if (match[1] == "const") {
exports.Indexer.phpFileProperties[fileName][match[3]] = [match[3], PROPERTY_CONST];
} else {
exports.Indexer.phpFileProperties[fileName][match[3]] = [match[3], PROPERTY_NORMAL];
}
}
},
}