From 54ac1f862363a38086c79d758dbbb26926241448 Mon Sep 17 00:00:00 2001 From: soderlind Date: Thu, 4 Jan 2018 16:31:45 +0100 Subject: [PATCH 1/3] Add link to Symfony phpcs rules --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e0cd5b0..892ca94 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ This extension has the following settings: * `phpcbf.standard`: [ Optional | Default: `null` ]. The formatting standard. * When `null`, phpcbf will use, if it's set, the `default_standard`, otherwise fallback to `Pear`. * By default, the following standards are available: `PEAR`, `Zend`, `PSR2`, `MySource`, `Squiz` and `PSR1` - * If you add a standard to phpcs, it will be available for phpcbf, eg the [Drupal](https://github.com/klausi/coder), [WordPress](https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards), [Yii2](https://github.com/yiisoft/yii2-coding-standards), and [Magento](https://github.com/magento/marketplace-eqp) extensions. + * If you add a standard to phpcs, it will be available for phpcbf, eg [Drupal](https://github.com/klausi/coder), [WordPress](https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards), [Yii2](https://github.com/yiisoft/yii2-coding-standards), [Magento](https://github.com/magento/marketplace-eqp), [Symfony](https://github.com/djoos/Symfony-coding-standard) etc. * You can also point to a [phpcs.xml rules file](https://github.com/squizlabs/PHP_CodeSniffer/wiki/Annotated-ruleset.xml), eg: `"phpcbf.standard": "/file/path/phpcs.xml"` The default settings are From 8e19a54fb6ab2402eab1f3c8acf01d11c95c8971 Mon Sep 17 00:00:00 2001 From: soderlind Date: Thu, 4 Jan 2018 16:55:34 +0100 Subject: [PATCH 2/3] For relative links in settings executablePath, add support for multi-root workspaces, i.e. will look for phpcbf in all workspaces Add support for period in the path: { "phpcbf.executablePath" : "./vendor/bin/phpcbf" }, i,e, the period is workspace root --- CHANGELOG.md | 3 + extension.js | 388 +++++++++++++++++++++++++++++---------------------- 2 files changed, 221 insertions(+), 170 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1700f43..eaf173b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ # Change Log +## 0.0.3 +- For relative links in settings executablePath, add support for multi-root workspaces, i.e. will look for phpcbf in all workspaces +- Add support for period in the path: `{ "phpcbf.executablePath" : "./vendor/bin/phpcbf" }`, i,e, the period is the workspace root ## 0.0.2 - Update documentation about the `phpcbf.executablePath` setting. - Add credits, copyright and license. diff --git a/extension.js b/extension.js index 5c51681..4e043a4 100644 --- a/extension.js +++ b/extension.js @@ -1,195 +1,243 @@ "use strict"; -// const { -// html_beautify -// } = require('./js-beautify/beautify-html'); const vscode = require("vscode"); const { commands, workspace, window, languages, Range, Position } = vscode; const fs = require("fs"); const os = require("os"); const cp = require("child_process"); const TmpDir = os.tmpdir(); -let autoFixing = false; class PHPCBF { - constructor() { - this.loadSettings(); - } - - loadSettings() { - let config = workspace.getConfiguration("phpcbf"); - if (!config.get("enable") == true) { - return; + constructor() { + this.loadSettings(); } - this.onsave = config.get("onsave", true); - this.executablePath = config.get( - "executablePath", - process.platform === "win32" ? "php-cbf.bat" : "phpcbf" - ); - if ( - process.platform == "win32" && - config.has("executablePathWindows") && - config.get("executablePathWindows").length > 0 - ) { - this.executablePath = config.get("executablePathWindows"); - } - if (workspace.rootPath != undefined) { - this.executablePath = this.executablePath.replace( - "${workspaceRoot}", - workspace.rootPath - ); - } - this.executablePath = this.executablePath.replace( - /^~\//, - os.homedir() + "/" - ); - this.standard = config.get("standard", null); - - this.documentFormattingProvider = config.get( - "documentFormattingProvider", - true - ); - } - - getArgs(fileName) { - let args = ["-lq", fileName]; - if (this.standard) { - args.push("--standard=" + this.standard); + loadSettings() { + let config = workspace.getConfiguration("phpcbf"); + if (!config.get("enable") == true) { + return; + } + this.onsave = config.get("onsave", false); + + this.executablePath = config.get( + "executablePath", + process.platform === "win32" ? "php-cbf.bat" : "phpcbf" + ); + + // relative paths? + if (this.executablePath.startsWith("${workspaceRoot}")) { + this.addRootPath("${workspaceRoot}"); + } + if (this.executablePath.startsWith(".")) { + this.addRootPath("."); + } + if (this.executablePath.startsWith("~")) { + this.executablePath = this.executablePath.replace( + /^~\//, + os.homedir() + "/" + ); + } + + this.standard = config.get("standard", null); + + this.documentFormattingProvider = config.get( + "documentFormattingProvider", + true + ); } - return args; - } - - format(text) { - autoFixing = true; - - let fileName = - TmpDir + - "/temp-" + - Math.random() - .toString(36) - .replace(/[^a-z]+/g, "") - .substr(0, 10) + - ".php"; - fs.writeFileSync(fileName, text); - - let exec = cp.spawn(this.executablePath, this.getArgs(fileName)); - - let promise = new Promise((resolve, reject) => { - exec.on("error", err => { - reject(); - autoFixing = false; - console.log(err); - if (err.code == "ENOENT") { - window.showErrorMessage( - "PHPCBF: " + err.message + ". executablePath not found." - ); + + getArgs(fileName) { + let args = ["-lq", fileName]; + if (this.standard) { + args.push("--standard=" + this.standard); } - }); - exec.on("exit", code => { - /* phpcbf exit codes: + return args; + } + + format(text) { + // autoFixing = true; + // phpcbfError = false; + let fileName = + TmpDir + + "/temp-" + + Math.random() + .toString(36) + .replace(/[^a-z]+/g, "") + .substr(0, 10) + + ".php"; + console.log(fileName); + fs.writeFileSync(fileName, text); + console.log(this.executablePath); + if (process.platform === "win32") { + let exec = cp.spawn(this.executablePath, this.getArgs(fileName),(error, stdout, stderr) => { + if (error) { + console.error(error); + return; + }); + } else { + let exec = cp.execFile(this.executablePath, this.getArgs(fileName), (error, stdout, stderr) => { + if (error) { + console.error(error); + throw error; + } + console.log(stdout); + }); + } + + let promise = new Promise((resolve, reject) => { + exec.on("error", err => { + reject(); + console.log(err); + if (err.code == "ENOENT") { + window.showErrorMessage( + "PHPCBF: " + err.message + ". executablePath not found." + ); + } + }); + exec.on("exit", code => { + /* phpcbf exit codes: Exit code 0 is used to indicate that no fixable errors were found, so nothing was fixed Exit code 1 is used to indicate that all fixable errors were fixed correctly Exit code 2 is used to indicate that PHPCBF failed to fix some of the fixable errors it found Exit code 3 is used for general script execution errors - */ - switch (code) { - case 0: - break; - case 1: - case 2: - let fixed = fs.readFileSync(fileName, "utf-8"); - if (fixed.length > 0) { - resolve(fixed); - } else { - reject(); + */ + switch (code) { + case 0: + break; + case 1: + case 2: + let fixed = fs.readFileSync(fileName, "utf-8"); + if (fixed.length > 0) { + resolve(fixed); + } else { + reject(); + } + break; + // case 3: + // phpcbfError = true; + // break; + default: + let msgs = { + 3: "PHPCBF: general script execution errors.", + 16: "PHPCBF: Configuration error of the application.", + 32: "PHPCBF: Configuration error of a Fixer.", + 64: "PHPCBF: Exception raised within the application." + }; + window.showErrorMessage(msgs[code]); + reject(); + break; + } + + fs.unlink(fileName, function(err) {}); + }); + }); + + // if (phpcbfError) { + exec.stdout.on("data", buffer => { + console.log(buffer.toString()); + // window.showErrorMessage(buffer.toString()); + }); + // } + exec.stderr.on("data", buffer => { + console.log(buffer.toString()); + }); + exec.on("close", code => { + console.log(code); + }); + + return promise; + } + + addRootPath(prefix) { + const resources = []; + if (workspace.workspaceFolders) { + for (let wsFolder of workspace.workspaceFolders) { + resources.push(wsFolder.uri); + } + } else { + const editor = window.activeTextEditor; + if (editor) { + resources.push(editor.document.uri); } - break; - - default: - let msgs = { - 16: "PHPCBF: Configuration error of the application.", - 32: "PHPCBF: Configuration error of a Fixer.", - 64: "PHPCBF: Exception raised within the application." - }; - window.showErrorMessage(msgs[code]); - reject(); - break; } - - fs.unlink(fileName, function(err) {}); - autoFixing = false; - }); - }); - - exec.stdout.on("data", buffer => { - // console.log(buffer.toString()); - }); - exec.stderr.on("data", buffer => { - console.log(buffer.toString()); - }); - exec.on("close", code => { - // console.log(code); - }); - - return promise; - } + for (let resource of resources) { + if (resource.scheme === "file") { + const folder = workspace.getWorkspaceFolder(resource); + if (folder) { + const rootPath = folder.uri.fsPath; + let tmpExecutablePath = this.executablePath.replace( + prefix, + rootPath + ); + fs.exists(tmpExecutablePath, exists => { + if (exists) { + this.executablePath = tmpExecutablePath; + } + }); + } + } + } + } } exports.activate = context => { - let phpcbf = new PHPCBF(); - - context.subscriptions.push( - workspace.onWillSaveTextDocument(event => { - if ( - event.document.languageId == "php" && - phpcbf.onsave /*&& workspace.getConfiguration('editor').get('formatOnSave') == false*/ - ) { - event.waitUntil( - commands.executeCommand("editor.action.formatDocument") - ); - } - }) - ); - - context.subscriptions.push( - commands.registerTextEditorCommand("phpcbf-soderlind", textEditor => { - if (textEditor.document.languageId == "php") { - commands.executeCommand("editor.action.formatDocument"); - } - }) - ); - - context.subscriptions.push( - workspace.onDidChangeConfiguration(() => { - phpcbf.loadSettings(); - }) - ); - - if (phpcbf.documentFormattingProvider) { + let phpcbf = new PHPCBF(); + context.subscriptions.push( - languages.registerDocumentFormattingEditProvider("php", { - provideDocumentFormattingEdits: (document, options, token) => { - autoFixing = false; - return new Promise((resolve, reject) => { - let originalText = document.getText(); - let lastLine = document.lineAt(document.lineCount - 1); - let range = new Range(new Position(0, 0), lastLine.range.end); - phpcbf - .format(originalText) - .then(text => { - if (text != originalText) { - resolve([new vscode.TextEdit(range, text)]); - } else { - reject(); - } - }) - .catch(err => { - console.log(err); - reject(); - }); - }); - } - }) + workspace.onWillSaveTextDocument(event => { + if ( + event.document.languageId == "php" && + phpcbf.onsave /*&& + workspace.getConfiguration("editor").get("formatOnSave") == + false*/ + ) { + event.waitUntil( + commands.executeCommand("editor.action.formatDocument") + ); + } + }) + ); + + context.subscriptions.push( + commands.registerTextEditorCommand("phpcbf-soderlind", textEditor => { + if (textEditor.document.languageId == "php") { + commands.executeCommand("editor.action.formatDocument"); + } + }) + ); + + context.subscriptions.push( + workspace.onDidChangeConfiguration(() => { + phpcbf.loadSettings(); + }) ); - } + + if (phpcbf.documentFormattingProvider) { + context.subscriptions.push( + languages.registerDocumentFormattingEditProvider("php", { + provideDocumentFormattingEdits: (document, options, token) => { + return new Promise((resolve, reject) => { + let originalText = document.getText(); + let lastLine = document.lineAt(document.lineCount - 1); + let range = new Range( + new Position(0, 0), + lastLine.range.end + ); + phpcbf + .format(originalText) + .then(text => { + if (text != originalText) { + resolve([new vscode.TextEdit(range, text)]); + } else { + reject(); + } + }) + .catch(err => { + console.log(err); + reject(); + }); + }); + } + }) + ); + } }; From 7167949c5aa7bc402def1f9b732bac6452a5ab36 Mon Sep 17 00:00:00 2001 From: soderlind Date: Thu, 4 Jan 2018 17:57:46 +0100 Subject: [PATCH 3/3] Fix phpcbf hanging issue by closing stdin #2 --- CHANGELOG.md | 1 + extension.js | 50 +++++++++++++++++--------------------------------- 2 files changed, 18 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eaf173b..8a1617b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Change Log ## 0.0.3 +- Fix phpcbf hanging issue by closing stdin [@shivanandwp](https://github.com/shivanandwp) [#2](https://github.com/soderlind/vscode-phpcbf/issues/2) - For relative links in settings executablePath, add support for multi-root workspaces, i.e. will look for phpcbf in all workspaces - Add support for period in the path: `{ "phpcbf.executablePath" : "./vendor/bin/phpcbf" }`, i,e, the period is the workspace root ## 0.0.2 diff --git a/extension.js b/extension.js index 4e043a4..d3269bc 100644 --- a/extension.js +++ b/extension.js @@ -54,8 +54,8 @@ class PHPCBF { } format(text) { - // autoFixing = true; - // phpcbfError = false; + console.time("phpcbf"); + phpcbfError = false; let fileName = TmpDir + "/temp-" + @@ -63,26 +63,9 @@ class PHPCBF { .toString(36) .replace(/[^a-z]+/g, "") .substr(0, 10) + - ".php"; - console.log(fileName); + ".php"; fs.writeFileSync(fileName, text); - console.log(this.executablePath); - if (process.platform === "win32") { - let exec = cp.spawn(this.executablePath, this.getArgs(fileName),(error, stdout, stderr) => { - if (error) { - console.error(error); - return; - }); - } else { - let exec = cp.execFile(this.executablePath, this.getArgs(fileName), (error, stdout, stderr) => { - if (error) { - console.error(error); - throw error; - } - console.log(stdout); - }); - } - + let exec = cp.spawn(this.executablePath, this.getArgs(fileName)); let promise = new Promise((resolve, reject) => { exec.on("error", err => { reject(); @@ -112,9 +95,9 @@ class PHPCBF { reject(); } break; - // case 3: - // phpcbfError = true; - // break; + case 3: + phpcbfError = true; + break; default: let msgs = { 3: "PHPCBF: general script execution errors.", @@ -130,19 +113,20 @@ class PHPCBF { fs.unlink(fileName, function(err) {}); }); }); + exec.stdin.end(); - // if (phpcbfError) { - exec.stdout.on("data", buffer => { - console.log(buffer.toString()); - // window.showErrorMessage(buffer.toString()); - }); - // } + if (phpcbfError) { + exec.stdout.on("data", buffer => { + console.log(buffer.toString()); + window.showErrorMessage(buffer.toString()); + }); + } exec.stderr.on("data", buffer => { console.log(buffer.toString()); }); - exec.on("close", code => { - console.log(code); - }); + // exec.on("close", code => { + // // console.log(code); + // }); return promise; }