Browse Source

Adding 0.0.4

master
Ad5001 2 years ago
parent
commit
fec35ea067
No known key found for this signature in database
9 changed files with 523 additions and 365 deletions
  1. 32
    0
      .vsixmanifest
  2. 12
    1
      README.md
  3. BIN
      icon.png
  4. BIN
      icon.xcf
  5. 60
    269
      out/src/extension.js
  6. 417
    0
      out/src/phpCompletionItem.js
  7. 1
    2
      out/src/phpDeclaration.js
  8. 0
    91
      out/src/phpFunctionSuggestions.js
  9. 1
    2
      package.json

+ 32
- 0
.vsixmanifest View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
<Metadata>
<Identity Language="en-US" Id="pocketmine-ide" Version="0.0.1" Publisher="Ad5001"/>
<DisplayName>PocketMine IDE</DisplayName>
<Description xml:space="preserve">Implementation of external PocketMine/PHP libs for Visual Studio Code</Description>
<Tags>PocketMine,IDE,PHP,Lib,php</Tags>
<Categories>Other</Categories>
<GalleryFlags>Public</GalleryFlags>
<Badges></Badges>
<Properties>
<Property Id="Microsoft.VisualStudio.Code.Engine" Value="^1.5.0" />
<Property Id="Microsoft.VisualStudio.Code.ExtensionDependencies" Value="" />
<Property Id="Microsoft.VisualStudio.Services.Links.Learn" Value="https://github.com/Ad5001/PocketMine-IDE" />
<Property Id="Microsoft.VisualStudio.Services.GitHubFlavoredMarkdown" Value="true" />
</Properties>
<Icon>extension/icon.png</Icon>
</Metadata>
<Installation>
<InstallationTarget Id="Microsoft.VisualStudio.Code"/>
</Installation>
<Dependencies/>
<Assets>
<Asset Type="Microsoft.VisualStudio.Code.Manifest" Path="extension/package.json" Addressable="true" />
<Asset Type="Microsoft.VisualStudio.Services.Content.Details" Path="extension/README.md" Addressable="true" /><Asset Type="Microsoft.VisualStudio.Services.Icons.Default" Path="extension/icon.png" Addressable="true" />
</Assets>
</PackageManifest>

+ 12
- 1
README.md View File

@@ -1,6 +1,6 @@
# PocketMine-IDE
Add all pocketmine functions & classes from a src. Based on [https://github.com/bschulte/PHP-Autocomplete](https://github.com/bschulte/PHP-Autocomplete)
Add all pocketmine functions & classes from a src.
## Features
@@ -22,6 +22,17 @@ None so far
## Release Notes
## 0.0.4
Rewriting original extension from (almost) stratch providing an easier reading.
Introducing Properties (class properties, static properties and constants).
Fixed anyoing method duplication.
## 0.0.3
Fixed bugs on Windows
Fixed bug with autocompleting class not carring about uses.
## 0.0.2
Fixing compatibility bug with original extension.

BIN
icon.png View File


BIN
icon.xcf View File


+ 60
- 269
out/src/extension.js View File

@@ -1,22 +1,30 @@
/**
* Main file for extension
* Almost entiry rewritten by (C) Ad5001 2017
*/
'use strict';
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
const vscode = require('vscode');
const phpFunctionSuggestions_1 = require('./phpFunctionSuggestions');
exports.phpFileFunctions = {};
exports.phpFileStaticFunctions = {};
exports.phpFileUses = {};
// const phpFuncSuggestion = require('./phpFunctionSuggestions');
const Indexer = (require('./phpCompletionItem')).Indexer;
exports.PHP_MODE = { language: 'php', scheme: 'file' };
// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
exports.currentPath = "";
/**
* Initial extension activation
*
* @param {*} context
*/
function activate(context) {
// Do the initial indexing
indexPhpFiles();
console.log(exports.phpFileFunctions);
console.log(Object.keys(exports.phpFileUses));
vscode.workspace.onDidSaveTextDocument(function(document) {
indexPhpFiles();
Indexer.indexPhpFiles();
// require("fs").appendFileSync("/home/ad5001/echo.txt", JSON.stringify(Indexer.phpFileProperties))
vscode.workspace.onDidSaveTextDocument(function (document) {
Indexer.indexPhpFiles();
});
// Setup our class as a compvarion item provider for function autocompvare
context.subscriptions.push(vscode.languages.registerCompletionItemProvider(exports.PHP_MODE, {
provideCompletionItems(document, position, token) {
@@ -30,290 +38,73 @@ function activate(context) {
currentWord = word.substr(0, position.character - wordAtPosition.start.character);
}
// Checking for commun regexps
var clas = /new\s+(\\)?(\w+)(\\\w+)*/.exec(lineText);
var use = /use\s+(\w+)(\\\w+)*/.exec(lineText);
var execute = /->(\w+)/.exec(lineText);
var executeStatic = /::(\w+)/.exec(lineText);
var classInFunc = /(\(|,\s*)((\\\w+)+)/.exec(lineText);
// Check through the list of functions that are included in this file and see if any match
// the starting varter of the word we have so far
var suggestions = [];
// Check what files the current document includes/requires
var currentFileName = document.uri.fsPath.replace(vscode.workspace.rootPath, '').slice(1);
var currentPath = document.uri.fsPath.replace(vscode.workspace.rootPath, '').replace("src/", "");
// Look through all included/required files for the current document
for (var f in exports.phpFileFunctions) {
for (var f in Indexer.phpFileFunctions) {
// Checking normal functions
if (execute)
for (var func in exports.phpFileFunctions[f]) {
func = exports.phpFileFunctions[f][func];
if (func.function.indexOf(currentWord) > 0 && execute[1] == currentWord && (func.functionModifiers["public"] || f == currentPath)) {
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 = "(" + parameters.join(", ") + ")";
suggestions.push(newSuggestion);
}
};
if (execute) {
suggestions = Indexer.getFunctionsFromFile(f, suggestions, currentWord, execute);
suggestions = Indexer.getPropertiesFromFile(f, suggestions, currentWord, execute);
}
// Checking static functions
if (executeStatic)
for (var func in exports.phpFileStaticFunctions[f]) {
func = exports.phpFileStaticFunctions[f][func];
if (func.function.indexOf(currentWord) > 0 && executeStatic[1] == currentWord) {
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 = "(" + parameters.join(", ") + ")";
suggestions.push(newSuggestion);
}
};
if (executeStatic) {
suggestions = Indexer.getStaticFunctionsFromFile(f, suggestions, currentWord, executeStatic);
suggestions = Indexer.getStaticPropertiesFromFile(f, suggestions, currentWord, executeStatic);
}
// Checking for class name
if (f.indexOf(currentWord) > 0) {
if (clas && (clas[2] == currentWord || clas[3] == "\\" + currentWord)) { // New instance
var currentClass = f.substr(0, f.length - 4).replace(new RegExp("\/", "g"), "\\");
var params = [];
if (typeof exports.phpFileFunctions[f]["__construct"] !== "undefined") {
params = exports.phpFileFunctions[f]["__construct"].params;
}
params.forEach(function(value, key) {
if (value) params[key] = "$" + value[1];
});
if (currentClass.startsWith("\\")) currentClass = currentClass.substr(1);
var newSuggestion = new vscode.CompletionItem(currentClass, vscode.CompletionItemKind.Class);
if (typeof clas[1] == "undefined" && typeof exports.phpFileUses[currentPath] !== "undefined" && typeof exports.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);
// New instance
if (clas && (clas[2] == currentWord || clas[3] == "\\" + currentWord)) {
suggestions = Indexer.getClassNew(f, suggestions, currentPath, clas);
} else if (use && (use[1] == currentWord || use[2] == "\\" + currentWord)) { // Use
var currentClass = f.substr(0, f.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);
suggestions = Indexer.getClassUse(f, suggestions);
} else if (!(execute && execute[1] == currentWord) && !(executeStatic && executeStatic[1] == currentWord)) { // static classes
var currentClass = f.substr(0, f.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;
if (typeof exports.phpFileUses[currentPath] !== "undefined" && typeof exports.phpFileUses[currentPath][currentClass] !== "undefined") {
newSuggestion.insertText = currentClass.split("\\")[currentClass.split("\\").length - 1] + "::";
} else {
newSuggestion.insertText = "\\" + currentClass + "::";
}
suggestions.push(newSuggestion);
suggestions = Indexer.getClassNormal(f, suggestions, currentPath);
}
}
};
Indexer.done = {};// Reseting cache
return suggestions;
}
}));
// Setup our plugin to help with function signatures
context.subscriptions.push(vscode.languages.registerSignatureHelpProvider(exports.PHP_MODE, new phpFunctionSuggestions_1.PhpSignatureHelpProvider(vscode.workspace.getConfiguration('php')['docsTool']), '(', ','));
// The command has been defined in the package.json file
// Now provide the implementation of the command with registerCommand
// The commandId parameter must match the command field in package.json
var indexDisposable = vscode.commands.registerCommand('pmide.indexPhpFiles', () => {
// The code you place here will be executed every time your command is executed
indexPhpFiles();
// context.subscriptions.push(vscode.languages.registerSignatureHelpProvider(exports.PHP_MODE, new phpFuncSuggestion.PhpSignatureHelpProvider(vscode.workspace.getConfiguration('php')['docsTool']), '(', ','));
// Commands registered by plugin
/**
* Reindex php files command
*/
var indexDisposable = vscode.commands.registerCommand('pmide.indexPhpFiles', function () {
Indexer.indexPhpFiles();
});
var printDisposable = vscode.commands.registerCommand('pmide.printPhpFiles', () => {
console.log(Object.keys(exports.phpFileFunctions).length);
console.log(exports.phpFileUses);
/**
* Prints everything about PHP files.
*/
var printDisposable = vscode.commands.registerCommand('pmide.printPhpFiles', function () {
console.log(Object.keys(Indexer.phpFileFunctions).length);
console.log(Indexer.phpFileUses);
});
context.subscriptions.push(indexDisposable);
context.subscriptions.push(printDisposable);
}
exports.activate = activate;
// this method is called when your extension is deactivated
function deactivate() {}
exports.deactivate = deactivate;
// Function to handle the indexing of PHP files
function indexPhpFiles() {
// Clear out the cached data
exports.phpFileUses = {};
exports.phpFileFunctions = {};
var indexResult = vscode.workspace.findFiles("**/*.php", "", 1000).then(function(list) {
if (list) {
var p = new Promise(function(resolve, reject) {
list.forEach((phpFile) => {
var path = phpFile.fsPath;
var fileName = path.replace(vscode.workspace.rootPath, "").replace("src/", "").slice(1);
if (!(fileName in exports.phpFileFunctions)) {
exports.phpFileFunctions[fileName] = [];
}
if (!(fileName in exports.phpFileStaticFunctions)) {
exports.phpFileStaticFunctions[fileName] = [];
}
// Read through the PHP file for includes/requires and function definitions
var read = require('fs').readFileSync(path, 'utf8');
var lineReader = read.split("\n");
try {
lineReader.forEach(function(line) {
// Thats a bit messy for this 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.phpFileFunctions[fileName][match[7]] = {
function: match[7],
params: params,
functionModifiers: functionModifiers,
comment: comment
};
} else {
exports.phpFileStaticFunctions[fileName][match[7]] = {
function: match[7],
params: params,
functionModifiers: functionModifiers,
comment: comment
};
}
}
// Check for uses
var includeRegex = /use\s+((\w+\\)*)(\w+)(\s+as\s+(\w+)\s*)?;/;
match = includeRegex.exec(line);
if (match) {
if (!(fileName in exports.phpFileUses)) {
exports.phpFileUses[fileName] = [];
}
// 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.phpFileUses[fileName][match[1] + match[3]] = classType;
}
});
} catch (e) {
console.error(e);
}
});
})
} else {
console.log("No workspace defined");
}
}, function(reason) {
console.log("Error: " + reason);
});
// Libraries
if (require('fs').existsSync(vscode.workspace.getConfiguration('php')['pocketMinePath'])) {
var libraryResult = require("child_process").execSync("find " + vscode.workspace.getConfiguration('php')['pocketMinePath'] + " -maxdepth 10 -type f | fgrep .php").toString().split("\n");
if (libraryResult) {
libraryResult.forEach(function(path) {
if (require('fs').existsSync(path)) {
var fileName = path.replace(vscode.workspace.getConfiguration('php')['pocketMinePath'], "").slice(1);
if (!(fileName in exports.phpFileFunctions)) {
exports.phpFileFunctions[fileName] = {};
}
if (!(fileName in exports.phpFileStaticFunctions)) {
exports.phpFileStaticFunctions[fileName] = [];
}
// Read through the PHP file for includes/requires and function definitions
var read = require('fs').readFileSync(path, 'utf8');
try {
var lineReader = read.split("\n");
lineReader.forEach(function(line) {
// Thats a bit messy for this 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.phpFileFunctions[fileName][match[7]] = {
function: match[7],
params: params,
functionModifiers: functionModifiers,
comment: comment
};
} else {
exports.phpFileStaticFunctions[fileName][match[7]] = {
function: match[7],
params: params,
functionModifiers: functionModifiers,
comment: comment
};
}
}
});
} catch (err) {
console.error(err); // Fails silently later
}
}
});
} else {
console.log("No workspace defined");
}
}
}
//# sourceMappingURL=extension.js.map
exports.deactivate = function () { };

+ 417
- 0
out/src/phpCompletionItem.js View File

@@ -0,0 +1,417 @@
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;
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", "").slice(1);
if (typeof exports.Indexer.phpFileFunctions[fileName] == "undefined") {
exports.Indexer.phpFileFunctions[fileName] = {};
}
if (typeof exports.Indexer.phpFileStaticFunctions[fileName] == "undefined") {
exports.Indexer.phpFileStaticFunctions[fileName] = {};
}
if (typeof exports.Indexer.phpFileUses[fileName] == "undefined") {
exports.Indexer.phpFileUses[fileName] = {};
}
if (typeof exports.Indexer.phpFileProperties[fileName] == "undefined") {
exports.Indexer.phpFileProperties[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");
try {
var lineReader = read.split("\n");
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);
});
} catch (err) {
console.error(err);
}
}
});
},



/**
* 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*)?;/;
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*(;|=)/;
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];
}
}
},
}

+ 1
- 2
out/src/phpDeclaration.js View File

@@ -149,5 +149,4 @@ class GoDefinitionProvider {
});
}
}
exports.GoDefinitionProvider = GoDefinitionProvider;
//# sourceMappingURL=phpDeclaration.js.map
exports.GoDefinitionProvider = GoDefinitionProvider;

+ 0
- 91
out/src/phpFunctionSuggestions.js View File

@@ -1,91 +0,0 @@
'use strict';
const vscode = require('vscode');
const vscode_1 = require('vscode');
// import { definitionLocation } from './phpDeclaration';
// import { parameters } from './util';
const extension_1 = require('./extension');
class PhpSignatureHelpProvider {
constructor(toolForDocs) {
this.toolForDocs = 'phpdoc';
this.toolForDocs = toolForDocs;
}
provideSignatureHelp(document, position, token) {
let theCall = this.walkBackwardsToBeginningOfCall(document, position);
if (theCall == null) {
return Promise.resolve(null);
}
// Find the name of the function that's being called
let functionNameRange = this.previousTokenPosition(document, theCall.openParen);
let functionName = document.getText(functionNameRange);
let result = new vscode_1.SignatureHelp();
let declarationText, sig;
let si;
let currentFileName = document.uri.fsPath.replace(vscode.workspace.rootPath, '').slice(1).replace('\\', '/');
if (currentFileName in extension_1.phpFileIncludes) {
extension_1.phpFileIncludes[currentFileName].forEach(function (file) {
if (file in extension_1.phpFileFunctions) {
// Look through all the functions declared in the included/required file
extension_1.phpFileFunctions[file].forEach(function (func) {
// If the included/required function starts with the letter of our current word then add it to the set of suggestions
if (func.function == functionName) {
si = new vscode_1.SignatureInformation(func.function);
si.parameters = [];
func.params.forEach(function (param) {
si.parameters.push(param);
});
// Set the documentation of the SignatureInformation to be the full function signature
si.documentation = file + " : " + func.function + "(" + si.parameters.join(',') + ')';
result.signatures = [si];
result.activeSignature = 0;
result.activeParameter = Math.min(theCall.commas.length, si.parameters.length - 1);
result.signatures[0].label = functionName + ": " + result.signatures[0].parameters[result.activeParameter];
}
});
}
});
// console.log("Result: ", result);
return Promise.resolve(result);
}
else {
return Promise.resolve([]);
}
}
previousTokenPosition(document, position) {
while (position.character > 0) {
let word = document.getWordRangeAtPosition(position);
if (word) {
return word;
}
position = position.translate(0, -1);
}
return null;
}
walkBackwardsToBeginningOfCall(document, position) {
let currentLine = document.lineAt(position.line).text.substring(0, position.character);
let parenBalance = 0;
let commas = [];
for (let char = position.character; char >= 0; char--) {
switch (currentLine[char]) {
case '(':
parenBalance--;
if (parenBalance < 0) {
return {
openParen: new vscode_1.Position(position.line, char),
commas: commas
};
}
break;
case ')':
parenBalance++;
break;
case ',':
if (parenBalance === 0) {
commas.push(new vscode_1.Position(position.line, char));
}
}
}
return null;
}
}
exports.PhpSignatureHelpProvider = PhpSignatureHelpProvider;
//# sourceMappingURL=phpFunctionSuggestions.js.map

+ 1
- 2
package.json View File

@@ -2,7 +2,7 @@
"name": "pocketmine-ide",
"displayName": "PocketMine IDE",
"description": "Implementation of external PocketMine/PHP libs for Visual Studio Code",
"version": "0.0.2",
"version": "0.0.4",
"publisher": "Ad5001",
"homepage": "https://github.com/Ad5001/PocketMine-IDE",
"keywords": [
@@ -55,7 +55,6 @@
"postinstall": "node ./node_modules/vscode/bin/install"
},
"devDependencies": {
"typescript": "^2.0.3",
"vscode": "^1.0.0",
"mocha": "^2.3.3",
"@types/node": "^6.0.40",

Loading…
Cancel
Save