From bee1125a73c60ccc1a62fcf57269019beb4f45af Mon Sep 17 00:00:00 2001 From: theodejager Date: Fri, 4 Dec 2020 17:07:59 +0100 Subject: [PATCH 1/2] new feature: added capability to format selection --- extension.js | 193 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 124 insertions(+), 69 deletions(-) diff --git a/extension.js b/extension.js index 975f27c..fe3cfa4 100644 --- a/extension.js +++ b/extension.js @@ -1,15 +1,8 @@ "use strict"; const vscode = require("vscode"); -const { - commands, - workspace, - window, - languages, - Range, - Position -} = vscode; -const path = require("path"); +const { commands, workspace, window, languages, Range, Position } = vscode; const fs = require("fs"); +const lazy = require("lazy"); const os = require("os"); const cp = require("child_process"); const TmpDir = os.tmpdir(); @@ -67,16 +60,14 @@ class PHPCBF { this.debug = config.get("debug", false); } - getArgs(document, tmpFileName) { + getArgs(fileName) { let args = []; if (this.debug) { args.push("-l"); } else { args.push("-lq"); } - args.push(tmpFileName); - - this.standard = this.getStandard(document); + args.push(fileName); if (this.standard) { args.push("--standard=" + this.standard); @@ -90,68 +81,26 @@ class PHPCBF { return args; } - getStandard(document) { - // Check if a config file exists and handle it - let standard = null; - const folder = workspace.getWorkspaceFolder(document.uri); - const workspaceRoot = folder ? folder.uri.fsPath : null; - const filePath = document.fileName; - if (this.configSearch && workspaceRoot !== null && filePath !== undefined) { - const confFileNames = [ - '.phpcs.xml', '.phpcs.xml.dist', 'phpcs.xml', 'phpcs.xml.dist', - 'phpcs.ruleset.xml', 'ruleset.xml', - ]; - - const fileDir = path.relative(workspaceRoot, path.dirname(filePath)); - const confFile = this.findFiles(workspaceRoot, fileDir, confFileNames); - - standard = confFile || this.standard; - } else { - standard = this.standard; - } - - return standard; - } - - findFiles(parent, directory, name) { - const names = [].concat(name); - const chunks = path.resolve(parent, directory).split(path.sep); - - while (chunks.length) { - let currentDir = chunks.join(path.sep); - for (const fileName of names) { - const filePath = path.join(currentDir, fileName); - if (fs.existsSync(filePath)) { - return filePath; - } - } - if (parent === currentDir) { - break; - } - chunks.pop(); - } - - return null; - } - - format(document) { + format(text, range) { if (this.debug) { console.time("phpcbf"); } - let text = document.getText(); - + if (range) { + text = this.insertAtLine(text, range); + } + // console.log(text); let phpcbfError = false; let fileName = TmpDir + "/temp-" + Math.random() - .toString(36) - .replace(/[^a-z]+/g, "") - .substr(0, 10) + + .toString(36) + .replace(/[^a-z]+/g, "") + .substr(0, 10) + ".php"; fs.writeFileSync(fileName, text); - let exec = cp.spawn(this.executablePath, this.getArgs(document, fileName)); + let exec = cp.spawn(this.executablePath, this.getArgs(fileName)); if (!this.debug) { exec.stdin.end(); } @@ -200,7 +149,7 @@ class PHPCBF { break; } - fs.unlink(fileName, function (err) {}); + fs.unlink(fileName, function (err) { }); }); }); @@ -259,6 +208,58 @@ class PHPCBF { } } } + + insertAtLine(text, range) { + var nLines = 0; + var length = text.length; + var tag = '\n// everthingbetweenthesetagsiscollected\n'; + var offset = 1; + var start = false; + var end = false; + var lastLine = vscode.window.activeTextEditor.document.lineCount - 1; + var i = 0; + if (parseInt(range.start.line) === 0) { + // console.log('added tag at 0'); + text = this.insert(0, tag, text); + length += tag.length; + nLines++; + start = true; + i += tag.length; + } + if (parseInt(range.end.line) === lastLine || parseInt(range.end.line) === lastLine - 1) { + // console.log('added tag at end'); + end = true; + length += tag.length; + text = this.insert(length, tag, text); + } + for (i; i < length; i++) { + if (parseInt(range.start.line) === nLines && nLines !== 0 && ! start ) { + console.log(nLines); + text = this.insert(i - offset, tag, text); + length += tag.length; + i += tag.length; + nLines++; + } + if (nLines === parseInt(range.end.line) + 2 && ! end ) { + console.log(nLines); + text = this.insert(i, tag, text); + length += tag.length; + i += tag.length; + nLines++; + } + if (text[i] === '\n') { + nLines++; + } + } + return text; + } + + insert(index, string, text) { + if (index > 0) { + return text.substring(0, index) + string + text.substring(index, text.length); + } + return string + text; + } } exports.activate = context => { @@ -271,8 +272,8 @@ exports.activate = context => { event.document.languageId == "php" && phpcbf.onsave && workspace - .getConfiguration("editor", editor.document.uri) - .get("formatOnSave") === false + .getConfiguration("editor", editor.document.uri) + .get("formatOnSave") === false ) { event.waitUntil( commands.executeCommand("editor.action.formatDocument") @@ -285,6 +286,7 @@ exports.activate = context => { commands.registerTextEditorCommand("phpcbf-soderlind", textEditor => { if (textEditor.document.languageId == "php") { commands.executeCommand("editor.action.formatDocument"); + commands.executeCommand("editor.action.formatSelection"); } }) ); @@ -300,14 +302,14 @@ exports.activate = context => { languages.registerDocumentFormattingEditProvider("php", { provideDocumentFormattingEdits: (document, options, token) => { return new Promise((resolve, reject) => { - const originalText = document.getText(); + let originalText = document.getText(); let lastLine = document.lineAt(document.lineCount - 1); let range = new Range( new Position(0, 0), lastLine.range.end ); phpcbf - .format(document) + .format(originalText) .then(text => { if (text != originalText) { resolve([new vscode.TextEdit(range, text)]); @@ -321,6 +323,59 @@ exports.activate = context => { }); }); } + }), + languages.registerDocumentRangeFormattingEditProvider("php", { + provideDocumentRangeFormattingEdits: (document, range, options, token) => { + const editor = vscode.window.activeTextEditor; + let allText = editor.document.getText(); + return new Promise((resolve, reject) => { + phpcbf + .format(allText, range) + .then(text => { + const regex = /\/\/ everthingbetweenthesetagsiscollected([\S\s]*?)\/\/ everthingbetweenthesetagsiscollected/gm; + const str = text; + let m; + while ((m = regex.exec(str)) !== null) { + if (m.index === regex.lastIndex) { + regex.lastIndex++; + } + m.forEach((match, groupIndex) => { + text = match; + }); + } + // remove leading linebreaks + text = text.replace(/^[\r|\n|\r\n]+/, ''); + // remove trailing whitespace/linebreaks + var lastSelectedLine = editor.document.lineAt(range.end.line); + var lastLine = editor.document.lineCount - 1; + + if (lastSelectedLine._line !== lastLine && lastSelectedLine._line !== lastLine - 1) { + console.log('removing useless whitespace'); + text = text.trimEnd(); + // text += '\n'; + } else { + text = text.trimEnd(); + text += '\n'; + } + + if (text != allText) { + let lastCharPos = Math.max(lastSelectedLine.text.length, 0); + var newRange = new vscode.Range( + new Position(range.start.line, 0), + new Position(range.end.line, lastCharPos), + ); + resolve([new vscode.TextEdit(newRange, text)]); + } else { + reject(); + } + }) + .catch(err => { + console.log('error'); + console.log(err); + reject(); + }); + }); + } }) ); } From 73daea3e990a1b003d187a7b9a46858f39c6c436 Mon Sep 17 00:00:00 2001 From: theodejager Date: Sat, 5 Dec 2020 14:05:14 +0100 Subject: [PATCH 2/2] Reverted unintended modifications to other functionalities, some code cleanup --- extension.js | 124 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 89 insertions(+), 35 deletions(-) diff --git a/extension.js b/extension.js index fe3cfa4..5fec6df 100644 --- a/extension.js +++ b/extension.js @@ -1,8 +1,15 @@ "use strict"; const vscode = require("vscode"); -const { commands, workspace, window, languages, Range, Position } = vscode; +const { + commands, + workspace, + window, + languages, + Range, + Position +} = vscode; +const path = require("path"); const fs = require("fs"); -const lazy = require("lazy"); const os = require("os"); const cp = require("child_process"); const TmpDir = os.tmpdir(); @@ -60,14 +67,16 @@ class PHPCBF { this.debug = config.get("debug", false); } - getArgs(fileName) { + getArgs(document, tmpFileName) { let args = []; if (this.debug) { args.push("-l"); } else { args.push("-lq"); } - args.push(fileName); + args.push(tmpFileName); + + this.standard = this.getStandard(document); if (this.standard) { args.push("--standard=" + this.standard); @@ -79,28 +88,75 @@ class PHPCBF { ); } return args; - } + } + + getStandard(document) { + // Check if a config file exists and handle it + let standard = null; + const folder = workspace.getWorkspaceFolder(document.uri); + const workspaceRoot = folder ? folder.uri.fsPath : null; + const filePath = document.fileName; + if (this.configSearch && workspaceRoot !== null && filePath !== undefined) { + const confFileNames = [ + '.phpcs.xml', '.phpcs.xml.dist', 'phpcs.xml', 'phpcs.xml.dist', + 'phpcs.ruleset.xml', 'ruleset.xml', + ]; + + const fileDir = path.relative(workspaceRoot, path.dirname(filePath)); + const confFile = this.findFiles(workspaceRoot, fileDir, confFileNames); + + standard = confFile || this.standard; + } else { + standard = this.standard; + } + + return standard; + } - format(text, range) { + findFiles(parent, directory, name) { + const names = [].concat(name); + const chunks = path.resolve(parent, directory).split(path.sep); + + while (chunks.length) { + let currentDir = chunks.join(path.sep); + for (const fileName of names) { + const filePath = path.join(currentDir, fileName); + if (fs.existsSync(filePath)) { + return filePath; + } + } + if (parent === currentDir) { + break; + } + chunks.pop(); + } + + return null; + } + + format(document, range) { if (this.debug) { console.time("phpcbf"); - } + } + let text = document.getText(); if (range) { text = this.insertAtLine(text, range); - } - // console.log(text); + } + if (this.debug) { + console.log(text); + } let phpcbfError = false; let fileName = TmpDir + "/temp-" + Math.random() - .toString(36) - .replace(/[^a-z]+/g, "") - .substr(0, 10) + + .toString(36) + .replace(/[^a-z]+/g, "") + .substr(0, 10) + ".php"; fs.writeFileSync(fileName, text); - let exec = cp.spawn(this.executablePath, this.getArgs(fileName)); + let exec = cp.spawn(this.executablePath, this.getArgs(document, fileName)); if (!this.debug) { exec.stdin.end(); } @@ -210,14 +266,14 @@ class PHPCBF { } insertAtLine(text, range) { - var nLines = 0; - var length = text.length; - var tag = '\n// everthingbetweenthesetagsiscollected\n'; - var offset = 1; - var start = false; - var end = false; - var lastLine = vscode.window.activeTextEditor.document.lineCount - 1; - var i = 0; + let nLines = 0; + let length = text.length; + let tag = '\n// everythingbetweenthesetagsiscollected\n'; + let offset = 1; + let start = false; + let end = false; + let lastLine = vscode.window.activeTextEditor.document.lineCount - 1; + let i = 0; if (parseInt(range.start.line) === 0) { // console.log('added tag at 0'); text = this.insert(0, tag, text); @@ -234,14 +290,14 @@ class PHPCBF { } for (i; i < length; i++) { if (parseInt(range.start.line) === nLines && nLines !== 0 && ! start ) { - console.log(nLines); + // console.log(nLines); text = this.insert(i - offset, tag, text); length += tag.length; i += tag.length; nLines++; } if (nLines === parseInt(range.end.line) + 2 && ! end ) { - console.log(nLines); + // console.log(nLines); text = this.insert(i, tag, text); length += tag.length; i += tag.length; @@ -272,8 +328,8 @@ exports.activate = context => { event.document.languageId == "php" && phpcbf.onsave && workspace - .getConfiguration("editor", editor.document.uri) - .get("formatOnSave") === false + .getConfiguration("editor", editor.document.uri) + .get("formatOnSave") === false ) { event.waitUntil( commands.executeCommand("editor.action.formatDocument") @@ -302,14 +358,14 @@ exports.activate = context => { languages.registerDocumentFormattingEditProvider("php", { provideDocumentFormattingEdits: (document, options, token) => { return new Promise((resolve, reject) => { - let originalText = document.getText(); + const originalText = document.getText(); let lastLine = document.lineAt(document.lineCount - 1); let range = new Range( new Position(0, 0), lastLine.range.end ); phpcbf - .format(originalText) + .format(document) .then(text => { if (text != originalText) { resolve([new vscode.TextEdit(range, text)]); @@ -330,9 +386,9 @@ exports.activate = context => { let allText = editor.document.getText(); return new Promise((resolve, reject) => { phpcbf - .format(allText, range) + .format(document, range) .then(text => { - const regex = /\/\/ everthingbetweenthesetagsiscollected([\S\s]*?)\/\/ everthingbetweenthesetagsiscollected/gm; + const regex = /\/\/ everythingbetweenthesetagsiscollected([\S\s]*?)\/\/ everythingbetweenthesetagsiscollected/gm; const str = text; let m; while ((m = regex.exec(str)) !== null) { @@ -346,13 +402,12 @@ exports.activate = context => { // remove leading linebreaks text = text.replace(/^[\r|\n|\r\n]+/, ''); // remove trailing whitespace/linebreaks - var lastSelectedLine = editor.document.lineAt(range.end.line); - var lastLine = editor.document.lineCount - 1; + let lastSelectedLine = editor.document.lineAt(range.end.line); + let lastLine = editor.document.lineCount - 1; if (lastSelectedLine._line !== lastLine && lastSelectedLine._line !== lastLine - 1) { - console.log('removing useless whitespace'); + //console.log('removing useless whitespace'); text = text.trimEnd(); - // text += '\n'; } else { text = text.trimEnd(); text += '\n'; @@ -360,7 +415,7 @@ exports.activate = context => { if (text != allText) { let lastCharPos = Math.max(lastSelectedLine.text.length, 0); - var newRange = new vscode.Range( + let newRange = new vscode.Range( new Position(range.start.line, 0), new Position(range.end.line, lastCharPos), ); @@ -370,7 +425,6 @@ exports.activate = context => { } }) .catch(err => { - console.log('error'); console.log(err); reject(); });