From 3491158766865daca7e4ef107175a3413d90b255 Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Sun, 12 Feb 2023 15:42:53 +0100 Subject: [PATCH] feat: [WIP] convert Maven XML dependencies on paste Signed-off-by: Fred Bricon --- .vscode/launch.json | 1 - package-lock.json | 397 ++--------------------------- package.json | 9 +- src/DependencyPasteEventHandler.ts | 100 ++++++++ src/extension.ts | 3 +- vscode.proposed.documentPaste.d.ts | 111 ++++++++ 6 files changed, 242 insertions(+), 379 deletions(-) create mode 100644 src/DependencyPasteEventHandler.ts create mode 100644 vscode.proposed.documentPaste.d.ts diff --git a/.vscode/launch.json b/.vscode/launch.json index 06a0c7a..3b1235b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -23,7 +23,6 @@ "request": "launch", "runtimeExecutable": "${execPath}", "args": ["--extensionDevelopmentPath=${workspaceRoot}" ], - "stopOnEntry": false, "sourceMaps": true, "outFiles": [ "${workspaceRoot}/out/**/*.js" ], "env": { diff --git a/package-lock.json b/package-lock.json index 23baa5e..990b985 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,12 +13,12 @@ "fast-xml-parser": "^4.3.1", "lru-cache": "10.1.0", "shelljs": "^0.8.5", - "vscode-languageclient": "^8.1.0" + "vscode-languageclient": "^9.0.1" }, "devDependencies": { "@types/mocha": "10.0.2", "@types/node": "18.15.0", - "@types/vscode": "1.65.0", + "@types/vscode": "1.85.0", "@typescript-eslint/eslint-plugin": "6.13.0", "@typescript-eslint/parser": "6.13.0", "@vscode/test-electron": "2.3.4", @@ -31,7 +31,7 @@ "typescript": "5.2.2" }, "engines": { - "vscode": "^1.65.0" + "vscode": "^1.85.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -43,86 +43,6 @@ "node": ">=0.10.0" } }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.10.tgz", - "integrity": "sha512-Q+mk96KJ+FZ30h9fsJl+67IjNJm3x2eX+GBWGmocAKgzp27cowCOOqSdscX80s0SpdFXZnIv/+1xD1EctFx96Q==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.10.tgz", - "integrity": "sha512-7W0bK7qfkw1fc2viBfrtAEkDKHatYfHzr/jKAHNr9BvkYDXPcC6bodtm8AyLJNNuqClLNaeTLuwURt4PRT9d7w==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.10.tgz", - "integrity": "sha512-1X4CClKhDgC3by7k8aOWZeBXQX8dHT5QAMCAQDArCLaYfkppoARvh0fit3X2Qs+MXDngKcHv6XXyQCpY0hkK1Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.10.tgz", - "integrity": "sha512-O/nO/g+/7NlitUxETkUv/IvADKuZXyH4BHf/g/7laqKC4i/7whLpB0gvpPc2zpF0q9Q6FXS3TS75QHac9MvVWw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.10.tgz", - "integrity": "sha512-YSRRs2zOpwypck+6GL3wGXx2gNP7DXzetmo5pHXLrY/VIMsS59yKfjPizQ4lLt5vEI80M41gjm2BxrGZ5U+VMA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@esbuild/darwin-x64": { "version": "0.19.10", "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.10.tgz", @@ -139,278 +59,6 @@ "node": ">=12" } }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.10.tgz", - "integrity": "sha512-dMtk1wc7FSH8CCkE854GyGuNKCewlh+7heYP/sclpOG6Cectzk14qdUIY5CrKDbkA/OczXq9WesqnPl09mj5dg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.10.tgz", - "integrity": "sha512-G5UPPspryHu1T3uX8WiOEUa6q6OlQh6gNl4CO4Iw5PS+Kg5bVggVFehzXBJY6X6RSOMS8iXDv2330VzaObm4Ag==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.10.tgz", - "integrity": "sha512-j6gUW5aAaPgD416Hk9FHxn27On28H4eVI9rJ4az7oCGTFW48+LcgNDBN+9f8rKZz7EEowo889CPKyeaD0iw9Kg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.10.tgz", - "integrity": "sha512-QxaouHWZ+2KWEj7cGJmvTIHVALfhpGxo3WLmlYfJ+dA5fJB6lDEIg+oe/0//FuyVHuS3l79/wyBxbHr0NgtxJQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.10.tgz", - "integrity": "sha512-4ub1YwXxYjj9h1UIZs2hYbnTZBtenPw5NfXCRgEkGb0b6OJ2gpkMvDqRDYIDRjRdWSe/TBiZltm3Y3Q8SN1xNg==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.10.tgz", - "integrity": "sha512-lo3I9k+mbEKoxtoIbM0yC/MZ1i2wM0cIeOejlVdZ3D86LAcFXFRdeuZmh91QJvUTW51bOK5W2BznGNIl4+mDaA==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.10.tgz", - "integrity": "sha512-J4gH3zhHNbdZN0Bcr1QUGVNkHTdpijgx5VMxeetSk6ntdt+vR1DqGmHxQYHRmNb77tP6GVvD+K0NyO4xjd7y4A==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.10.tgz", - "integrity": "sha512-tgT/7u+QhV6ge8wFMzaklOY7KqiyitgT1AUHMApau32ZlvTB/+efeCtMk4eXS+uEymYK249JsoiklZN64xt6oQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.10.tgz", - "integrity": "sha512-0f/spw0PfBMZBNqtKe5FLzBDGo0SKZKvMl5PHYQr3+eiSscfJ96XEknCe+JoOayybWUFQbcJTrk946i3j9uYZA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.10.tgz", - "integrity": "sha512-pZFe0OeskMHzHa9U38g+z8Yx5FNCLFtUnJtQMpwhS+r4S566aK2ci3t4NCP4tjt6d5j5uo4h7tExZMjeKoehAA==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.10.tgz", - "integrity": "sha512-SpYNEqg/6pZYoc+1zLCjVOYvxfZVZj6w0KROZ3Fje/QrM3nfvT2llI+wmKSrWuX6wmZeTapbarvuNNK/qepSgA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.10.tgz", - "integrity": "sha512-ACbZ0vXy9zksNArWlk2c38NdKg25+L9pr/mVaj9SUq6lHZu/35nx2xnQVRGLrC1KKQqJKRIB0q8GspiHI3J80Q==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.10.tgz", - "integrity": "sha512-PxcgvjdSjtgPMiPQrM3pwSaG4kGphP+bLSb+cihuP0LYdZv1epbAIecHVl5sD3npkfYBZ0ZnOjR878I7MdJDFg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.10.tgz", - "integrity": "sha512-ZkIOtrRL8SEJjr+VHjmW0znkPs+oJXhlJbNwfI37rvgeMtk3sxOQevXPXjmAPZPigVTncvFqLMd+uV0IBSEzqA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.10.tgz", - "integrity": "sha512-+Sa4oTDbpBfGpl3Hn3XiUe4f8TU2JF7aX8cOfqFYMMjXp6ma6NJDztl5FDG8Ezx0OjwGikIHw+iA54YLDNNVfw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.10.tgz", - "integrity": "sha512-EOGVLK1oWMBXgfttJdPHDTiivYSjX6jDNaATeNOaCOFEVcfMjtbx7WVQwPSE1eIfCp/CaSF2nSrDtzc4I9f8TQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.10.tgz", - "integrity": "sha512-whqLG6Sc70AbU73fFYvuYzaE4MNMBIlR1Y/IrUeOXFrWHxBEjjbZaQ3IXIQS8wJdAzue2GwYZCjOrgrU1oUHoA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -663,9 +311,10 @@ "dev": true }, "node_modules/@types/vscode": { - "version": "1.65.0", - "dev": true, - "license": "MIT" + "version": "1.85.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.85.0.tgz", + "integrity": "sha512-CF/RBon/GXwdfmnjZj0WTUMZN5H6YITOfBCP4iEZlOtVQXuzw6t7Le7+cR+7JzdMrnlm7Mfp49Oj2TuSXIWo3g==", + "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "6.13.0", @@ -4103,24 +3752,24 @@ } }, "node_modules/vscode-jsonrpc": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.1.0.tgz", - "integrity": "sha512-6TDy/abTQk+zDGYazgbIPc+4JoXdwC8NHU9Pbn4UJP1fehUyZmM4RHp5IthX7A6L5KS30PRui+j+tbbMMMafdw==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", "engines": { "node": ">=14.0.0" } }, "node_modules/vscode-languageclient": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-8.1.0.tgz", - "integrity": "sha512-GL4QdbYUF/XxQlAsvYWZRV3V34kOkpRlvV60/72ghHfsYFnS/v2MANZ9P6sHmxFcZKOse8O+L9G7Czg0NUWing==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-9.0.1.tgz", + "integrity": "sha512-JZiimVdvimEuHh5olxhxkht09m3JzUGwggb5eRUkzzJhZ2KjCN0nh55VfiED9oez9DyF8/fz1g1iBV3h+0Z2EA==", "dependencies": { "minimatch": "^5.1.0", "semver": "^7.3.7", - "vscode-languageserver-protocol": "3.17.3" + "vscode-languageserver-protocol": "3.17.5" }, "engines": { - "vscode": "^1.67.0" + "vscode": "^1.82.0" } }, "node_modules/vscode-languageclient/node_modules/brace-expansion": { @@ -4143,18 +3792,18 @@ } }, "node_modules/vscode-languageserver-protocol": { - "version": "3.17.3", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.3.tgz", - "integrity": "sha512-924/h0AqsMtA5yK22GgMtCYiMdCOtWTSGgUOkgEDX+wk2b0x4sAfLiO4NxBxqbiVtz7K7/1/RgVrVI0NClZwqA==", + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", "dependencies": { - "vscode-jsonrpc": "8.1.0", - "vscode-languageserver-types": "3.17.3" + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" } }, "node_modules/vscode-languageserver-types": { - "version": "3.17.3", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.3.tgz", - "integrity": "sha512-SYU4z1dL0PyIMd4Vj8YOqFvHu7Hz/enbWtpfnVbJHU4Nd1YNYx8u0ennumc6h48GQNeOLxmwySmnADouT/AuZA==" + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==" }, "node_modules/which": { "version": "2.0.2", diff --git a/package.json b/package.json index 4b17009..0c6138e 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,11 @@ "url": "https://github.com/jbangdev/jbang-vscode" }, "engines": { - "vscode": "^1.65.0" + "vscode": "^1.85.0" }, + "enabledApiProposals": [ + "documentPaste" + ], "categories": [ "Other" ], @@ -240,7 +243,7 @@ "devDependencies": { "@types/mocha": "10.0.2", "@types/node": "18.15.0", - "@types/vscode": "1.65.0", + "@types/vscode": "1.85.0", "@typescript-eslint/eslint-plugin": "6.13.0", "@typescript-eslint/parser": "6.13.0", "@vscode/test-electron": "2.3.4", @@ -257,6 +260,6 @@ "fast-xml-parser": "^4.3.1", "lru-cache": "10.1.0", "shelljs": "^0.8.5", - "vscode-languageclient": "^8.1.0" + "vscode-languageclient": "^9.0.1" } } diff --git a/src/DependencyPasteEventHandler.ts b/src/DependencyPasteEventHandler.ts new file mode 100644 index 0000000..c9ad16f --- /dev/null +++ b/src/DependencyPasteEventHandler.ts @@ -0,0 +1,100 @@ +import { XMLParser } from "fast-xml-parser"; +import { CancellationToken, DataTransfer, DocumentPasteEdit, DocumentPasteEditProvider, DocumentPasteProviderMetadata, ExtensionContext, languages, Range, TextDocument } from "vscode"; +import { isJBangFile, SUPPORTED_LANGUAGES } from "./JBangUtils"; + +const TEXT_MIMETYPE: string = "text/plain"; +const MIMETYPES: DocumentPasteProviderMetadata = { + id: 'JBangPasteProvider', + pasteMimeTypes: [TEXT_MIMETYPE] +}; + +/** + * `DocumentPasteEditProvider` that converts Maven's XML dependencies to matching JBang //DEPS + */ +export class DependencyPasteEditProvider implements DocumentPasteEditProvider { + + async provideDocumentPasteEdits(document: TextDocument, ranges: readonly Range[], dataTransfer: DataTransfer, token: CancellationToken): Promise { + if (!isJBangFile(document.getText())){ + return undefined; + } + const pasteContent = dataTransfer.get(TEXT_MIMETYPE); + if (!pasteContent) { + return undefined; + } + const pastedText: string = (await pasteContent.asString()).trim(); + + // don't try to provide for multi character inserts; the implementation will get messy and the feature won't be that helpful + if (!pastedText || token.isCancellationRequested || ranges.length !== 1) { + return undefined; + } + + const range = ranges[0]; + if (range.start.character > 0) { + //Only paste on the 1st column, for now + return undefined; + } + const line = range.start.line; + const targetLine = document.lineAt(line); + if (!targetLine.isEmptyOrWhitespace) { + return undefined; + } + let dependencies:any; + let xml: any; + if (pastedText.startsWith("") + || pastedText.startsWith("") + || pastedText.startsWith("")) { + xml = new XMLParser().parse(pastedText); + if (xml.dependency) { + dependencies = xml.dependency; + } else if (xml.dependencies?.dependency) { + dependencies = xml.dependencies.dependency; + } else if (xml.dependencyManagement?.dependencies?.dependency) { + dependencies = xml.dependencyManagement.dependencies.dependency; + } + } + + if (!dependencies) { + return undefined; + } + let convertedDependencies: string | undefined; + + if (Array.isArray(dependencies)){ + convertedDependencies = dependencies.map(d => this.toJBangDependency(d)).filter(d => d !== undefined).join('\n'); + } else { + convertedDependencies = this.toJBangDependency(dependencies); + } + if (convertedDependencies) { + return new DocumentPasteEdit(convertedDependencies, "Paste as JBang //DEPS"); + } + // either the handler returns null or encounters problems, fall back to return undefined to let VS Code ignore this handler + return undefined; + } + + + private toJBangDependency(dependency: any): string | undefined { + if (!dependency.groupId || !dependency.artifactId) { + return undefined; + } + const suffix = dependency?.type === 'pom'? '@pom':''; + const version = dependency?.version ? dependency.version: "LATEST"; + return `//DEPS ${dependency.groupId}:${dependency.artifactId}:${version}${suffix}`; + } + + /** + * Registers the DependencyPasteEditProvider and sets it up to be disposed. + * + * @param context the extension context + */ + public initialize(context: ExtensionContext) { + if (languages.registerDocumentPasteEditProvider) { + const dependencyPasteEditProvider = new DependencyPasteEditProvider(); + SUPPORTED_LANGUAGES.forEach(languageId => { + context.subscriptions.push( + languages.registerDocumentPasteEditProvider(languageId, dependencyPasteEditProvider, MIMETYPES) + ); + }); + } + } +} + +export default new DependencyPasteEditProvider(); \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index 00548f2..e3738df 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -3,6 +3,7 @@ import { Assets } from "./Assets"; import CodeLensProvider from "./CodeLensProvider"; import CommandManager from "./CommandManager"; import JBangCompletionProvider from "./CompletionProvider"; +import DependencyPasteEventProvider from "./DependencyPasteEventHandler"; import EditorListener from "./EditorListener"; import JBangConfig from "./JBangConfig"; import JBangDebugger from "./JBangDebugger"; @@ -24,7 +25,7 @@ export async function activate(context: ExtensionContext) { JBangCompletionProvider.initialize(context); JBangHoverProvider.initialize(context); JBangCodeActions.initialize(context); + DependencyPasteEventProvider.initialize(context); console.log(`${context.extension.packageJSON.name} ${version} is now active!`); } - export function deactivate() {} diff --git a/vscode.proposed.documentPaste.d.ts b/vscode.proposed.documentPaste.d.ts new file mode 100644 index 0000000..284aabc --- /dev/null +++ b/vscode.proposed.documentPaste.d.ts @@ -0,0 +1,111 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +declare module 'vscode' { + + // https://github.com/microsoft/vscode/issues/30066/ + + /** + * Provider invoked when the user copies and pastes code. + */ + interface DocumentPasteEditProvider { + + /** + * Optional method invoked after the user copies text in a file. + * + * During {@link prepareDocumentPaste}, an extension can compute metadata that is attached to + * a {@link DataTransfer} and is passed back to the provider in {@link provideDocumentPasteEdits}. + * + * @param document Document where the copy took place. + * @param ranges Ranges being copied in the `document`. + * @param dataTransfer The data transfer associated with the copy. You can store additional values on this for later use in {@link provideDocumentPasteEdits}. + * @param token A cancellation token. + */ + prepareDocumentPaste?(document: TextDocument, ranges: readonly Range[], dataTransfer: DataTransfer, token: CancellationToken): void | Thenable; + + /** + * Invoked before the user pastes into a document. + * + * In this method, extensions can return a workspace edit that replaces the standard pasting behavior. + * + * @param document Document being pasted into + * @param ranges Currently selected ranges in the document. + * @param dataTransfer The data transfer associated with the paste. + * @param token A cancellation token. + * + * @return Optional workspace edit that applies the paste. Return undefined to use standard pasting. + */ + provideDocumentPasteEdits?(document: TextDocument, ranges: readonly Range[], dataTransfer: DataTransfer, token: CancellationToken): ProviderResult; + } + + /** + * An operation applied on paste + */ + class DocumentPasteEdit { + + /** + * Human readable label that describes the edit. + */ + label: string; + + /** + * Controls the ordering or multiple paste edits. If this provider yield to edits, it will be shown lower in the list. + */ + yieldTo?: ReadonlyArray< + | { readonly extensionId: string; readonly providerId: string } + | { readonly mimeType: string } + >; + + /** + * The text or snippet to insert at the pasted locations. + */ + insertText: string | SnippetString; + + /** + * An optional additional edit to apply on paste. + */ + additionalEdit?: WorkspaceEdit; + + /** + * @param insertText The text or snippet to insert at the pasted locations. + * + * TODO: Reverse args, but this will break existing consumers :( + */ + constructor(insertText: string | SnippetString, label: string); + } + + interface DocumentPasteProviderMetadata { + /** + * Identifies the provider. + * + * This id is used when users configure the default provider for paste. + * + * This id should be unique within the extension but does not need to be unique across extensions. + */ + readonly id: string; + + /** + * Mime types that {@link DocumentPasteEditProvider.prepareDocumentPaste provideDocumentPasteEdits} may add on copy. + */ + readonly copyMimeTypes?: readonly string[]; + + /** + * Mime types that {@link DocumentPasteEditProvider.provideDocumentPasteEdits provideDocumentPasteEdits} should be invoked for. + * + * This can either be an exact mime type such as `image/png`, or a wildcard pattern such as `image/*`. + * + * Use `text/uri-list` for resources dropped from the explorer or other tree views in the workbench. + * + * Use `files` to indicate that the provider should be invoked if any {@link DataTransferFile files} are present in the {@link DataTransfer}. + * Note that {@link DataTransferFile} entries are only created when dropping content from outside the editor, such as + * from the operating system. + */ + readonly pasteMimeTypes?: readonly string[]; + } + + namespace languages { + export function registerDocumentPasteEditProvider(selector: DocumentSelector, provider: DocumentPasteEditProvider, metadata: DocumentPasteProviderMetadata): Disposable; + } +} \ No newline at end of file