From b17640d9982f6cc745a64640df97ddf8c855ed68 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Mar 2023 15:04:19 +0000 Subject: [PATCH 001/141] build(deps-dev): bump webpack from 5.75.0 to 5.76.1 in /code Bumps [webpack](https://github.com/webpack/webpack) from 5.75.0 to 5.76.1. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.75.0...v5.76.1) --- updated-dependencies: - dependency-name: webpack dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- code/package-lock.json | 18 +++++++++--------- code/package.json | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/code/package-lock.json b/code/package-lock.json index 2a7077fe3..9151f2dfa 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -1,12 +1,12 @@ { "name": "esbonio", - "version": "0.10.6", + "version": "0.11.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "esbonio", - "version": "0.10.6", + "version": "0.11.0", "license": "MIT", "dependencies": { "semver": "^7.3.8", @@ -23,7 +23,7 @@ "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", "typescript": "^4.9.5", - "webpack": "^5.75.0", + "webpack": "^5.76.1", "webpack-cli": "^5.0.1" }, "engines": { @@ -3446,9 +3446,9 @@ } }, "node_modules/webpack": { - "version": "5.75.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", - "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", + "version": "5.76.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz", + "integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", @@ -6484,9 +6484,9 @@ } }, "webpack": { - "version": "5.75.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", - "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", + "version": "5.76.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz", + "integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.3", diff --git a/code/package.json b/code/package.json index 14db1bc9a..0b804f1eb 100644 --- a/code/package.json +++ b/code/package.json @@ -45,7 +45,7 @@ "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", "typescript": "^4.9.5", - "webpack": "^5.75.0", + "webpack": "^5.76.1", "webpack-cli": "^5.0.1" }, "engines": { From 41bc8e8f04ae0b2adef168e40e46041eef4039e5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 13 Mar 2023 20:48:37 +0000 Subject: [PATCH 002/141] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.0.1 → v1.1.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.0.1...v1.1.1) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ecdaa924d..1ef9a17f7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -26,7 +26,7 @@ repos: args: [--settings-file=lib/esbonio/pyproject.toml] - repo: https://github.com/pre-commit/mirrors-mypy - rev: 'v1.0.1' + rev: 'v1.1.1' hooks: - id: mypy name: mypy (esbonio) From 45458aae7bef1d344f47c17cef04fe68ce1a8457 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Mar 2023 15:05:00 +0000 Subject: [PATCH 003/141] build(deps-dev): bump typescript from 4.9.5 to 5.0.2 in /code Bumps [typescript](https://github.com/Microsoft/TypeScript) from 4.9.5 to 5.0.2. - [Release notes](https://github.com/Microsoft/TypeScript/releases) - [Commits](https://github.com/Microsoft/TypeScript/compare/v4.9.5...v5.0.2) --- updated-dependencies: - dependency-name: typescript dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- code/package-lock.json | 16 ++++++++-------- code/package.json | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/code/package-lock.json b/code/package-lock.json index 9151f2dfa..c693948ff 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -22,7 +22,7 @@ "mocha": "^10.2.0", "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", - "typescript": "^4.9.5", + "typescript": "^5.0.2", "webpack": "^5.76.1", "webpack-cli": "^5.0.1" }, @@ -3332,16 +3332,16 @@ } }, "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz", + "integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=12.20" } }, "node_modules/uc.micro": { @@ -6387,9 +6387,9 @@ } }, "typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz", + "integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==", "dev": true }, "uc.micro": { diff --git a/code/package.json b/code/package.json index 0b804f1eb..6b3da403a 100644 --- a/code/package.json +++ b/code/package.json @@ -44,7 +44,7 @@ "mocha": "^10.2.0", "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", - "typescript": "^4.9.5", + "typescript": "^5.0.2", "webpack": "^5.76.1", "webpack-cli": "^5.0.1" }, From 28de2f3e91b780ecefb02c72e7d9cb3a8b52dc74 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Mar 2023 18:33:15 +0000 Subject: [PATCH 004/141] build(deps-dev): bump webpack from 5.76.1 to 5.76.2 in /code Bumps [webpack](https://github.com/webpack/webpack) from 5.76.1 to 5.76.2. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.76.1...v5.76.2) --- updated-dependencies: - dependency-name: webpack dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- code/package-lock.json | 14 +++++++------- code/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/code/package-lock.json b/code/package-lock.json index c693948ff..d7b86f5d0 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -23,7 +23,7 @@ "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", "typescript": "^5.0.2", - "webpack": "^5.76.1", + "webpack": "^5.76.2", "webpack-cli": "^5.0.1" }, "engines": { @@ -3446,9 +3446,9 @@ } }, "node_modules/webpack": { - "version": "5.76.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz", - "integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==", + "version": "5.76.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.2.tgz", + "integrity": "sha512-Th05ggRm23rVzEOlX8y67NkYCHa9nTNcwHPBhdg+lKG+mtiW7XgggjAeeLnADAe7mLjJ6LUNfgHAuRRh+Z6J7w==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", @@ -6484,9 +6484,9 @@ } }, "webpack": { - "version": "5.76.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz", - "integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==", + "version": "5.76.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.2.tgz", + "integrity": "sha512-Th05ggRm23rVzEOlX8y67NkYCHa9nTNcwHPBhdg+lKG+mtiW7XgggjAeeLnADAe7mLjJ6LUNfgHAuRRh+Z6J7w==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.3", diff --git a/code/package.json b/code/package.json index 6b3da403a..da5bb0643 100644 --- a/code/package.json +++ b/code/package.json @@ -45,7 +45,7 @@ "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", "typescript": "^5.0.2", - "webpack": "^5.76.1", + "webpack": "^5.76.2", "webpack-cli": "^5.0.1" }, "engines": { From 692b1c364944615fc64f405a1b943e3a81afebe5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 14:16:29 +0000 Subject: [PATCH 005/141] build(deps-dev): bump webpack from 5.76.2 to 5.76.3 in /code Bumps [webpack](https://github.com/webpack/webpack) from 5.76.2 to 5.76.3. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.76.2...v5.76.3) --- updated-dependencies: - dependency-name: webpack dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- code/package-lock.json | 14 +++++++------- code/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/code/package-lock.json b/code/package-lock.json index d7b86f5d0..6dd8d656a 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -23,7 +23,7 @@ "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", "typescript": "^5.0.2", - "webpack": "^5.76.2", + "webpack": "^5.76.3", "webpack-cli": "^5.0.1" }, "engines": { @@ -3446,9 +3446,9 @@ } }, "node_modules/webpack": { - "version": "5.76.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.2.tgz", - "integrity": "sha512-Th05ggRm23rVzEOlX8y67NkYCHa9nTNcwHPBhdg+lKG+mtiW7XgggjAeeLnADAe7mLjJ6LUNfgHAuRRh+Z6J7w==", + "version": "5.76.3", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.3.tgz", + "integrity": "sha512-18Qv7uGPU8b2vqGeEEObnfICyw2g39CHlDEK4I7NK13LOur1d0HGmGNKGT58Eluwddpn3oEejwvBPoP4M7/KSA==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", @@ -6484,9 +6484,9 @@ } }, "webpack": { - "version": "5.76.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.2.tgz", - "integrity": "sha512-Th05ggRm23rVzEOlX8y67NkYCHa9nTNcwHPBhdg+lKG+mtiW7XgggjAeeLnADAe7mLjJ6LUNfgHAuRRh+Z6J7w==", + "version": "5.76.3", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.3.tgz", + "integrity": "sha512-18Qv7uGPU8b2vqGeEEObnfICyw2g39CHlDEK4I7NK13LOur1d0HGmGNKGT58Eluwddpn3oEejwvBPoP4M7/KSA==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.3", diff --git a/code/package.json b/code/package.json index da5bb0643..1d2ca9c3d 100644 --- a/code/package.json +++ b/code/package.json @@ -45,7 +45,7 @@ "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", "typescript": "^5.0.2", - "webpack": "^5.76.2", + "webpack": "^5.76.3", "webpack-cli": "^5.0.1" }, "engines": { From d39a1f5f773ccf5a70fede37ec1a9519d3fe1f61 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 3 Apr 2023 21:34:46 +0000 Subject: [PATCH 006/141] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/psf/black: 23.1.0 → 23.3.0](https://github.com/psf/black/compare/23.1.0...23.3.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1ef9a17f7..5b0ee23af 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,7 +8,7 @@ repos: - id: trailing-whitespace - repo: https://github.com/psf/black - rev: 23.1.0 + rev: 23.3.0 hooks: - id: black From fd919c7f34d4d5ea9e8974c9272f1d227729e9e7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Apr 2023 15:02:11 +0000 Subject: [PATCH 007/141] build(deps-dev): bump typescript from 5.0.2 to 5.0.3 in /code Bumps [typescript](https://github.com/Microsoft/TypeScript) from 5.0.2 to 5.0.3. - [Release notes](https://github.com/Microsoft/TypeScript/releases) - [Commits](https://github.com/Microsoft/TypeScript/commits) --- updated-dependencies: - dependency-name: typescript dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- code/package-lock.json | 14 +++++++------- code/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/code/package-lock.json b/code/package-lock.json index 6dd8d656a..cce0c6792 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -22,7 +22,7 @@ "mocha": "^10.2.0", "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", - "typescript": "^5.0.2", + "typescript": "^5.0.3", "webpack": "^5.76.3", "webpack-cli": "^5.0.1" }, @@ -3332,9 +3332,9 @@ } }, "node_modules/typescript": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz", - "integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.3.tgz", + "integrity": "sha512-xv8mOEDnigb/tN9PSMTwSEqAnUvkoXMQlicOb0IUVDBSQCgBSaAAROUZYy2IcUy5qU6XajK5jjjO7TMWqBTKZA==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -6387,9 +6387,9 @@ } }, "typescript": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz", - "integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.3.tgz", + "integrity": "sha512-xv8mOEDnigb/tN9PSMTwSEqAnUvkoXMQlicOb0IUVDBSQCgBSaAAROUZYy2IcUy5qU6XajK5jjjO7TMWqBTKZA==", "dev": true }, "uc.micro": { diff --git a/code/package.json b/code/package.json index 1d2ca9c3d..743c8f08d 100644 --- a/code/package.json +++ b/code/package.json @@ -44,7 +44,7 @@ "mocha": "^10.2.0", "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", - "typescript": "^5.0.2", + "typescript": "^5.0.3", "webpack": "^5.76.3", "webpack-cli": "^5.0.1" }, From 193745e85ffcfb0ccf6f9943be403b1831284bc7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Apr 2023 10:02:36 +0000 Subject: [PATCH 008/141] build(deps-dev): bump webpack from 5.76.3 to 5.77.0 in /code Bumps [webpack](https://github.com/webpack/webpack) from 5.76.3 to 5.77.0. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.76.3...v5.77.0) --- updated-dependencies: - dependency-name: webpack dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- code/package-lock.json | 14 +++++++------- code/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/code/package-lock.json b/code/package-lock.json index cce0c6792..18b622118 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -23,7 +23,7 @@ "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", "typescript": "^5.0.3", - "webpack": "^5.76.3", + "webpack": "^5.77.0", "webpack-cli": "^5.0.1" }, "engines": { @@ -3446,9 +3446,9 @@ } }, "node_modules/webpack": { - "version": "5.76.3", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.3.tgz", - "integrity": "sha512-18Qv7uGPU8b2vqGeEEObnfICyw2g39CHlDEK4I7NK13LOur1d0HGmGNKGT58Eluwddpn3oEejwvBPoP4M7/KSA==", + "version": "5.77.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.77.0.tgz", + "integrity": "sha512-sbGNjBr5Ya5ss91yzjeJTLKyfiwo5C628AFjEa6WSXcZa4E+F57om3Cc8xLb1Jh0b243AWuSYRf3dn7HVeFQ9Q==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", @@ -6484,9 +6484,9 @@ } }, "webpack": { - "version": "5.76.3", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.3.tgz", - "integrity": "sha512-18Qv7uGPU8b2vqGeEEObnfICyw2g39CHlDEK4I7NK13LOur1d0HGmGNKGT58Eluwddpn3oEejwvBPoP4M7/KSA==", + "version": "5.77.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.77.0.tgz", + "integrity": "sha512-sbGNjBr5Ya5ss91yzjeJTLKyfiwo5C628AFjEa6WSXcZa4E+F57om3Cc8xLb1Jh0b243AWuSYRf3dn7HVeFQ9Q==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.3", diff --git a/code/package.json b/code/package.json index 743c8f08d..433c3efc4 100644 --- a/code/package.json +++ b/code/package.json @@ -45,7 +45,7 @@ "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", "typescript": "^5.0.3", - "webpack": "^5.76.3", + "webpack": "^5.77.0", "webpack-cli": "^5.0.1" }, "engines": { From d0f4d432d560669ea5bd1bb53dd48bbdfd1e5e32 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Apr 2023 15:02:15 +0000 Subject: [PATCH 009/141] build(deps-dev): bump typescript from 5.0.3 to 5.0.4 in /code Bumps [typescript](https://github.com/Microsoft/TypeScript) from 5.0.3 to 5.0.4. - [Release notes](https://github.com/Microsoft/TypeScript/releases) - [Commits](https://github.com/Microsoft/TypeScript/compare/v5.0.3...v5.0.4) --- updated-dependencies: - dependency-name: typescript dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- code/package-lock.json | 14 +++++++------- code/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/code/package-lock.json b/code/package-lock.json index 18b622118..ea1451627 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -22,7 +22,7 @@ "mocha": "^10.2.0", "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", - "typescript": "^5.0.3", + "typescript": "^5.0.4", "webpack": "^5.77.0", "webpack-cli": "^5.0.1" }, @@ -3332,9 +3332,9 @@ } }, "node_modules/typescript": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.3.tgz", - "integrity": "sha512-xv8mOEDnigb/tN9PSMTwSEqAnUvkoXMQlicOb0IUVDBSQCgBSaAAROUZYy2IcUy5qU6XajK5jjjO7TMWqBTKZA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -6387,9 +6387,9 @@ } }, "typescript": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.3.tgz", - "integrity": "sha512-xv8mOEDnigb/tN9PSMTwSEqAnUvkoXMQlicOb0IUVDBSQCgBSaAAROUZYy2IcUy5qU6XajK5jjjO7TMWqBTKZA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", "dev": true }, "uc.micro": { diff --git a/code/package.json b/code/package.json index 433c3efc4..6c04c33d2 100644 --- a/code/package.json +++ b/code/package.json @@ -44,7 +44,7 @@ "mocha": "^10.2.0", "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", - "typescript": "^5.0.3", + "typescript": "^5.0.4", "webpack": "^5.77.0", "webpack-cli": "^5.0.1" }, From 413a7c4cd1943b7c4af4f21a2204411256b1c050 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 10 Apr 2023 20:38:55 +0000 Subject: [PATCH 010/141] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.1.1 → v1.2.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.1.1...v1.2.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5b0ee23af..3f78a5ced 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -26,7 +26,7 @@ repos: args: [--settings-file=lib/esbonio/pyproject.toml] - repo: https://github.com/pre-commit/mirrors-mypy - rev: 'v1.1.1' + rev: 'v1.2.0' hooks: - id: mypy name: mypy (esbonio) From 03905f64ba73259b6904d20a52b06e7dfbcc93dc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Apr 2023 17:45:33 +0000 Subject: [PATCH 011/141] build(deps-dev): bump webpack from 5.77.0 to 5.79.0 in /code Bumps [webpack](https://github.com/webpack/webpack) from 5.77.0 to 5.79.0. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.77.0...v5.79.0) --- updated-dependencies: - dependency-name: webpack dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- code/package-lock.json | 192 ++++++++++++++++++++++------------------- code/package.json | 2 +- 2 files changed, 106 insertions(+), 88 deletions(-) diff --git a/code/package-lock.json b/code/package-lock.json index ea1451627..99ac50159 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -23,7 +23,7 @@ "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", "typescript": "^5.0.4", - "webpack": "^5.77.0", + "webpack": "^5.79.0", "webpack-cli": "^5.0.1" }, "engines": { @@ -40,9 +40,9 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", "dev": true, "dependencies": { "@jridgewell/set-array": "^1.0.1", @@ -72,9 +72,9 @@ } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.3.tgz", + "integrity": "sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==", "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.0", @@ -88,13 +88,13 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.14", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", - "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" } }, "node_modules/@types/eslint": { @@ -118,9 +118,9 @@ } }, "node_modules/@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", + "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==", "dev": true }, "node_modules/@types/glob": { @@ -1190,9 +1190,9 @@ } }, "node_modules/es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.2.1.tgz", + "integrity": "sha512-9978wrXM50Y4rTMmW5kXIC09ZdXQZqkE4mxhwkd8VbzsGkXGPgV4zWuqQJgCEzYngdo2dYDa0l8xhX4fkSwJSg==", "dev": true }, "node_modules/escalade": { @@ -1783,9 +1783,9 @@ } }, "node_modules/jest-worker": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.2.0.tgz", - "integrity": "sha512-laB0ZVIBz+voh/QQy9dmUuuDsadixeerrKqyVpgPz+CCWiOYjOBabUXHIXZhsdvkWbLqSHbgkAHWl5cg24Q6RA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, "dependencies": { "@types/node": "*", @@ -2613,9 +2613,9 @@ } }, "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", "dev": true, "engines": { "node": ">=6" @@ -2977,9 +2977,9 @@ } }, "node_modules/source-map-support": { - "version": "0.5.20", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz", - "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==", + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, "dependencies": { "buffer-from": "^1.0.0", @@ -3121,9 +3121,9 @@ } }, "node_modules/terser": { - "version": "5.14.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", - "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", + "version": "5.16.9", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.9.tgz", + "integrity": "sha512-HPa/FdTB9XGI2H1/keLFZHxl6WNvAI4YalHGtDQTlMnJcoqSab1UwL4l1hGEhs6/GmLHBZIg/YgB++jcbzoOEg==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.2", @@ -3139,17 +3139,16 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.2.4.tgz", - "integrity": "sha512-E2CkNMN+1cho04YpdANyRrn8CyN4yMy+WdFKZIySFZrGXZxJwJP6PMNGGc/Mcr6qygQHUUqRxnAPmi0M9f00XA==", + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz", + "integrity": "sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==", "dev": true, "dependencies": { - "jest-worker": "^27.0.6", - "p-limit": "^3.1.0", + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1", - "terser": "^5.7.2" + "serialize-javascript": "^6.0.1", + "terser": "^5.16.5" }, "engines": { "node": ">= 10.13.0" @@ -3173,6 +3172,15 @@ } } }, + "node_modules/terser-webpack-plugin/node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, "node_modules/terser/node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -3446,13 +3454,13 @@ } }, "node_modules/webpack": { - "version": "5.77.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.77.0.tgz", - "integrity": "sha512-sbGNjBr5Ya5ss91yzjeJTLKyfiwo5C628AFjEa6WSXcZa4E+F57om3Cc8xLb1Jh0b243AWuSYRf3dn7HVeFQ9Q==", + "version": "5.79.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.79.0.tgz", + "integrity": "sha512-3mN4rR2Xq+INd6NnYuL9RC9GAmc1ROPKJoHhrZ4pAjdMFEkJJWrsPw8o2JjCIyQyTu7rTXYn4VG6OpyB3CobZg==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", + "@types/estree": "^1.0.0", "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/wasm-edit": "1.11.1", "@webassemblyjs/wasm-parser": "1.11.1", @@ -3461,7 +3469,7 @@ "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.10.0", - "es-module-lexer": "^0.9.0", + "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", @@ -3472,7 +3480,7 @@ "neo-async": "^2.6.2", "schema-utils": "^3.1.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", + "terser-webpack-plugin": "^5.3.7", "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" }, @@ -3873,9 +3881,9 @@ "dev": true }, "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", "dev": true, "requires": { "@jridgewell/set-array": "^1.0.1", @@ -3896,9 +3904,9 @@ "dev": true }, "@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.3.tgz", + "integrity": "sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==", "dev": true, "requires": { "@jridgewell/gen-mapping": "^0.3.0", @@ -3912,13 +3920,13 @@ "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.14", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", - "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", "dev": true, "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" } }, "@types/eslint": { @@ -3942,9 +3950,9 @@ } }, "@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", + "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==", "dev": true }, "@types/glob": { @@ -4784,9 +4792,9 @@ "dev": true }, "es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.2.1.tgz", + "integrity": "sha512-9978wrXM50Y4rTMmW5kXIC09ZdXQZqkE4mxhwkd8VbzsGkXGPgV4zWuqQJgCEzYngdo2dYDa0l8xhX4fkSwJSg==", "dev": true }, "escalade": { @@ -5230,9 +5238,9 @@ "dev": true }, "jest-worker": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.2.0.tgz", - "integrity": "sha512-laB0ZVIBz+voh/QQy9dmUuuDsadixeerrKqyVpgPz+CCWiOYjOBabUXHIXZhsdvkWbLqSHbgkAHWl5cg24Q6RA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, "requires": { "@types/node": "*", @@ -5868,9 +5876,9 @@ } }, "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", "dev": true }, "qs": { @@ -6121,9 +6129,9 @@ "dev": true }, "source-map-support": { - "version": "0.5.20", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz", - "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==", + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -6239,9 +6247,9 @@ } }, "terser": { - "version": "5.14.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", - "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", + "version": "5.16.9", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.9.tgz", + "integrity": "sha512-HPa/FdTB9XGI2H1/keLFZHxl6WNvAI4YalHGtDQTlMnJcoqSab1UwL4l1hGEhs6/GmLHBZIg/YgB++jcbzoOEg==", "dev": true, "requires": { "@jridgewell/source-map": "^0.3.2", @@ -6259,17 +6267,27 @@ } }, "terser-webpack-plugin": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.2.4.tgz", - "integrity": "sha512-E2CkNMN+1cho04YpdANyRrn8CyN4yMy+WdFKZIySFZrGXZxJwJP6PMNGGc/Mcr6qygQHUUqRxnAPmi0M9f00XA==", + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz", + "integrity": "sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==", "dev": true, "requires": { - "jest-worker": "^27.0.6", - "p-limit": "^3.1.0", + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1", - "terser": "^5.7.2" + "serialize-javascript": "^6.0.1", + "terser": "^5.16.5" + }, + "dependencies": { + "serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + } } }, "tmp": { @@ -6484,13 +6502,13 @@ } }, "webpack": { - "version": "5.77.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.77.0.tgz", - "integrity": "sha512-sbGNjBr5Ya5ss91yzjeJTLKyfiwo5C628AFjEa6WSXcZa4E+F57om3Cc8xLb1Jh0b243AWuSYRf3dn7HVeFQ9Q==", + "version": "5.79.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.79.0.tgz", + "integrity": "sha512-3mN4rR2Xq+INd6NnYuL9RC9GAmc1ROPKJoHhrZ4pAjdMFEkJJWrsPw8o2JjCIyQyTu7rTXYn4VG6OpyB3CobZg==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", + "@types/estree": "^1.0.0", "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/wasm-edit": "1.11.1", "@webassemblyjs/wasm-parser": "1.11.1", @@ -6499,7 +6517,7 @@ "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.10.0", - "es-module-lexer": "^0.9.0", + "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", @@ -6510,7 +6528,7 @@ "neo-async": "^2.6.2", "schema-utils": "^3.1.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", + "terser-webpack-plugin": "^5.3.7", "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" } diff --git a/code/package.json b/code/package.json index 6c04c33d2..89b2c23fc 100644 --- a/code/package.json +++ b/code/package.json @@ -45,7 +45,7 @@ "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", "typescript": "^5.0.4", - "webpack": "^5.77.0", + "webpack": "^5.79.0", "webpack-cli": "^5.0.1" }, "engines": { From e5777029b25cc9200c6d25df48bf7a32972a2a49 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Apr 2023 15:03:25 +0000 Subject: [PATCH 012/141] build(deps): bump semver from 7.3.8 to 7.4.0 in /code Bumps [semver](https://github.com/npm/node-semver) from 7.3.8 to 7.4.0. - [Release notes](https://github.com/npm/node-semver/releases) - [Changelog](https://github.com/npm/node-semver/blob/main/CHANGELOG.md) - [Commits](https://github.com/npm/node-semver/compare/v7.3.8...v7.4.0) --- updated-dependencies: - dependency-name: semver dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- code/package-lock.json | 14 +++++++------- code/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/code/package-lock.json b/code/package-lock.json index 99ac50159..1006a67f3 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -9,7 +9,7 @@ "version": "0.11.0", "license": "MIT", "dependencies": { - "semver": "^7.3.8", + "semver": "^7.4.0", "vscode-languageclient": "^8.1.0" }, "devDependencies": { @@ -2837,9 +2837,9 @@ } }, "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.4.0.tgz", + "integrity": "sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -6038,9 +6038,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.4.0.tgz", + "integrity": "sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==", "requires": { "lru-cache": "^6.0.0" } diff --git a/code/package.json b/code/package.json index 89b2c23fc..2178b6782 100644 --- a/code/package.json +++ b/code/package.json @@ -31,7 +31,7 @@ "main": "dist/node/extension", "browser": "dist/browser/extension", "dependencies": { - "semver": "^7.3.8", + "semver": "^7.4.0", "vscode-languageclient": "^8.1.0" }, "devDependencies": { From 17c022123ec625d28ba0f566f05728b2cdeb90fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Apr 2023 15:03:52 +0000 Subject: [PATCH 013/141] build(deps-dev): bump @vscode/vsce from 2.18.0 to 2.19.0 in /code Bumps [@vscode/vsce](https://github.com/Microsoft/vsce) from 2.18.0 to 2.19.0. - [Release notes](https://github.com/Microsoft/vsce/releases) - [Commits](https://github.com/Microsoft/vsce/compare/v2.18.0...v2.19.0) --- updated-dependencies: - dependency-name: "@vscode/vsce" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- code/package-lock.json | 30 +++++++++++++++--------------- code/package.json | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/code/package-lock.json b/code/package-lock.json index 1006a67f3..0473f3e1b 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -18,7 +18,7 @@ "@types/node": "^14.17.15", "@types/semver": "^7.3.13", "@types/vscode": "1.66.0", - "@vscode/vsce": "^2.18.0", + "@vscode/vsce": "^2.19.0", "mocha": "^10.2.0", "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", @@ -170,9 +170,9 @@ "dev": true }, "node_modules/@vscode/vsce": { - "version": "2.18.0", - "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-2.18.0.tgz", - "integrity": "sha512-tUA3XoKx5xjoi3EDcngk0VUYMhvfXLhS4s7CntpLPh1qtLYtgSCexTIMUHkCy6MqyozRW98bdW3a2yHPEADRnQ==", + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-2.19.0.tgz", + "integrity": "sha512-dAlILxC5ggOutcvJY24jxz913wimGiUrHaPkk16Gm9/PGFbz1YezWtrXsTKUtJws4fIlpX2UIlVlVESWq8lkfQ==", "dev": true, "dependencies": { "azure-devops-node-api": "^11.0.1", @@ -192,7 +192,7 @@ "tmp": "^0.2.1", "typed-rest-client": "^1.8.4", "url-join": "^4.0.1", - "xml2js": "^0.4.23", + "xml2js": "^0.5.0", "yauzl": "^2.3.1", "yazl": "^2.2.2" }, @@ -3720,9 +3720,9 @@ "dev": true }, "node_modules/xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", "dev": true, "dependencies": { "sax": ">=0.6.0", @@ -4002,9 +4002,9 @@ "dev": true }, "@vscode/vsce": { - "version": "2.18.0", - "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-2.18.0.tgz", - "integrity": "sha512-tUA3XoKx5xjoi3EDcngk0VUYMhvfXLhS4s7CntpLPh1qtLYtgSCexTIMUHkCy6MqyozRW98bdW3a2yHPEADRnQ==", + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-2.19.0.tgz", + "integrity": "sha512-dAlILxC5ggOutcvJY24jxz913wimGiUrHaPkk16Gm9/PGFbz1YezWtrXsTKUtJws4fIlpX2UIlVlVESWq8lkfQ==", "dev": true, "requires": { "azure-devops-node-api": "^11.0.1", @@ -4025,7 +4025,7 @@ "tmp": "^0.2.1", "typed-rest-client": "^1.8.4", "url-join": "^4.0.1", - "xml2js": "^0.4.23", + "xml2js": "^0.5.0", "yauzl": "^2.3.1", "yazl": "^2.2.2" }, @@ -6691,9 +6691,9 @@ "dev": true }, "xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", "dev": true, "requires": { "sax": ">=0.6.0", diff --git a/code/package.json b/code/package.json index 2178b6782..cbbf4ce49 100644 --- a/code/package.json +++ b/code/package.json @@ -40,7 +40,7 @@ "@types/node": "^14.17.15", "@types/semver": "^7.3.13", "@types/vscode": "1.66.0", - "@vscode/vsce": "^2.18.0", + "@vscode/vsce": "^2.19.0", "mocha": "^10.2.0", "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", From 93ccb9e95f4c12d4305fd27ba4b7b097df49a334 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Apr 2023 15:03:47 +0000 Subject: [PATCH 014/141] build(deps-dev): bump webpack from 5.79.0 to 5.80.0 in /code Bumps [webpack](https://github.com/webpack/webpack) from 5.79.0 to 5.80.0. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.79.0...v5.80.0) --- updated-dependencies: - dependency-name: webpack dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- code/package-lock.json | 366 ++++++++++++++++++++--------------------- code/package.json | 2 +- 2 files changed, 184 insertions(+), 184 deletions(-) diff --git a/code/package-lock.json b/code/package-lock.json index 0473f3e1b..1fd716f06 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -23,7 +23,7 @@ "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", "typescript": "^5.0.4", - "webpack": "^5.79.0", + "webpack": "^5.80.0", "webpack-cli": "^5.0.1" }, "engines": { @@ -216,148 +216,148 @@ } }, "node_modules/@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.5.tgz", + "integrity": "sha512-LHY/GSAZZRpsNQH+/oHqhRQ5FT7eoULcBqgfyTB5nQHogFnK3/7QoN7dLnwSE/JkUAF0SrRuclT7ODqMFtWxxQ==", "dev": true, "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + "@webassemblyjs/helper-numbers": "1.11.5", + "@webassemblyjs/helper-wasm-bytecode": "1.11.5" } }, "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.5.tgz", + "integrity": "sha512-1j1zTIC5EZOtCplMBG/IEwLtUojtwFVwdyVMbL/hwWqbzlQoJsWCOavrdnLkemwNoC/EOwtUFch3fuo+cbcXYQ==", "dev": true }, "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.5.tgz", + "integrity": "sha512-L65bDPmfpY0+yFrsgz8b6LhXmbbs38OnwDCf6NpnMUYqa+ENfE5Dq9E42ny0qz/PdR0LJyq/T5YijPnU8AXEpA==", "dev": true }, "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.5.tgz", + "integrity": "sha512-fDKo1gstwFFSfacIeH5KfwzjykIE6ldh1iH9Y/8YkAZrhmu4TctqYjSh7t0K2VyDSXOZJ1MLhht/k9IvYGcIxg==", "dev": true }, "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.5.tgz", + "integrity": "sha512-DhykHXM0ZABqfIGYNv93A5KKDw/+ywBFnuWybZZWcuzWHfbp21wUfRkbtz7dMGwGgT4iXjWuhRMA2Mzod6W4WA==", "dev": true, "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/floating-point-hex-parser": "1.11.5", + "@webassemblyjs/helper-api-error": "1.11.5", "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.5.tgz", + "integrity": "sha512-oC4Qa0bNcqnjAowFn7MPCETQgDYytpsfvz4ujZz63Zu/a/v71HeCAAmZsgZ3YVKec3zSPYytG3/PrRCqbtcAvA==", "dev": true }, "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.5.tgz", + "integrity": "sha512-uEoThA1LN2NA+K3B9wDo3yKlBfVtC6rh0i4/6hvbz071E8gTNZD/pT0MsBf7MeD6KbApMSkaAK0XeKyOZC7CIA==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" + "@webassemblyjs/ast": "1.11.5", + "@webassemblyjs/helper-buffer": "1.11.5", + "@webassemblyjs/helper-wasm-bytecode": "1.11.5", + "@webassemblyjs/wasm-gen": "1.11.5" } }, "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.5.tgz", + "integrity": "sha512-37aGq6qVL8A8oPbPrSGMBcp38YZFXcHfiROflJn9jxSdSMMM5dS5P/9e2/TpaJuhE+wFrbukN2WI6Hw9MH5acg==", "dev": true, "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "node_modules/@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.5.tgz", + "integrity": "sha512-ajqrRSXaTJoPW+xmkfYN6l8VIeNnR4vBOTQO9HzR7IygoCcKWkICbKFbVTNMjMgMREqXEr0+2M6zukzM47ZUfQ==", "dev": true, "dependencies": { "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.5.tgz", + "integrity": "sha512-WiOhulHKTZU5UPlRl53gHR8OxdGsSOxqfpqWeA2FmcwBMaoEdz6b2x2si3IwC9/fSPLfe8pBMRTHVMk5nlwnFQ==", "dev": true }, "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.5.tgz", + "integrity": "sha512-C0p9D2fAu3Twwqvygvf42iGCQ4av8MFBLiTb+08SZ4cEdwzWx9QeAHDo1E2k+9s/0w1DM40oflJOpkZ8jW4HCQ==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" + "@webassemblyjs/ast": "1.11.5", + "@webassemblyjs/helper-buffer": "1.11.5", + "@webassemblyjs/helper-wasm-bytecode": "1.11.5", + "@webassemblyjs/helper-wasm-section": "1.11.5", + "@webassemblyjs/wasm-gen": "1.11.5", + "@webassemblyjs/wasm-opt": "1.11.5", + "@webassemblyjs/wasm-parser": "1.11.5", + "@webassemblyjs/wast-printer": "1.11.5" } }, "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.5.tgz", + "integrity": "sha512-14vteRlRjxLK9eSyYFvw1K8Vv+iPdZU0Aebk3j6oB8TQiQYuO6hj9s4d7qf6f2HJr2khzvNldAFG13CgdkAIfA==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.11.5", + "@webassemblyjs/helper-wasm-bytecode": "1.11.5", + "@webassemblyjs/ieee754": "1.11.5", + "@webassemblyjs/leb128": "1.11.5", + "@webassemblyjs/utf8": "1.11.5" } }, "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.5.tgz", + "integrity": "sha512-tcKwlIXstBQgbKy1MlbDMlXaxpucn42eb17H29rawYLxm5+MsEmgPzeCP8B1Cl69hCice8LeKgZpRUAPtqYPgw==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" + "@webassemblyjs/ast": "1.11.5", + "@webassemblyjs/helper-buffer": "1.11.5", + "@webassemblyjs/wasm-gen": "1.11.5", + "@webassemblyjs/wasm-parser": "1.11.5" } }, "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.5.tgz", + "integrity": "sha512-SVXUIwsLQlc8srSD7jejsfTU83g7pIGr2YYNb9oHdtldSxaOhvA5xwvIiWIfcX8PlSakgqMXsLpLfbbJ4cBYew==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.11.5", + "@webassemblyjs/helper-api-error": "1.11.5", + "@webassemblyjs/helper-wasm-bytecode": "1.11.5", + "@webassemblyjs/ieee754": "1.11.5", + "@webassemblyjs/leb128": "1.11.5", + "@webassemblyjs/utf8": "1.11.5" } }, "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.5.tgz", + "integrity": "sha512-f7Pq3wvg3GSPUPzR0F6bmI89Hdb+u9WXrSKc4v+N0aV0q6r42WoF92Jp2jEorBEBRoRNXgjp53nBniDXcqZYPA==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/ast": "1.11.5", "@xtuc/long": "4.2.2" } }, @@ -1156,9 +1156,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", - "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", + "version": "5.13.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.13.0.tgz", + "integrity": "sha512-eyV8f0y1+bzyfh8xAwW/WTSZpLbjhqc4ne9eGSH4Zo2ejdyiNG9pU6mf9DG8a7+Auk6MFTlNOT4Y2y/9k8GKVg==", "dev": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -2819,9 +2819,9 @@ "dev": true }, "node_modules/schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", + "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.8", @@ -3454,21 +3454,21 @@ } }, "node_modules/webpack": { - "version": "5.79.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.79.0.tgz", - "integrity": "sha512-3mN4rR2Xq+INd6NnYuL9RC9GAmc1ROPKJoHhrZ4pAjdMFEkJJWrsPw8o2JjCIyQyTu7rTXYn4VG6OpyB3CobZg==", + "version": "5.80.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.80.0.tgz", + "integrity": "sha512-OIMiq37XK1rWO8mH9ssfFKZsXg4n6klTEDL7S8/HqbAOBBaiy8ABvXvz0dDCXeEF9gqwxSvVk611zFPjS8hJxA==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.0", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", "acorn": "^8.7.1", "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.10.0", + "enhanced-resolve": "^5.13.0", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -3478,7 +3478,7 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", + "schema-utils": "^3.1.2", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.3.7", "watchpack": "^2.4.0", @@ -4039,148 +4039,148 @@ } }, "@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.5.tgz", + "integrity": "sha512-LHY/GSAZZRpsNQH+/oHqhRQ5FT7eoULcBqgfyTB5nQHogFnK3/7QoN7dLnwSE/JkUAF0SrRuclT7ODqMFtWxxQ==", "dev": true, "requires": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + "@webassemblyjs/helper-numbers": "1.11.5", + "@webassemblyjs/helper-wasm-bytecode": "1.11.5" } }, "@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.5.tgz", + "integrity": "sha512-1j1zTIC5EZOtCplMBG/IEwLtUojtwFVwdyVMbL/hwWqbzlQoJsWCOavrdnLkemwNoC/EOwtUFch3fuo+cbcXYQ==", "dev": true }, "@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.5.tgz", + "integrity": "sha512-L65bDPmfpY0+yFrsgz8b6LhXmbbs38OnwDCf6NpnMUYqa+ENfE5Dq9E42ny0qz/PdR0LJyq/T5YijPnU8AXEpA==", "dev": true }, "@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.5.tgz", + "integrity": "sha512-fDKo1gstwFFSfacIeH5KfwzjykIE6ldh1iH9Y/8YkAZrhmu4TctqYjSh7t0K2VyDSXOZJ1MLhht/k9IvYGcIxg==", "dev": true }, "@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.5.tgz", + "integrity": "sha512-DhykHXM0ZABqfIGYNv93A5KKDw/+ywBFnuWybZZWcuzWHfbp21wUfRkbtz7dMGwGgT4iXjWuhRMA2Mzod6W4WA==", "dev": true, "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/floating-point-hex-parser": "1.11.5", + "@webassemblyjs/helper-api-error": "1.11.5", "@xtuc/long": "4.2.2" } }, "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.5.tgz", + "integrity": "sha512-oC4Qa0bNcqnjAowFn7MPCETQgDYytpsfvz4ujZz63Zu/a/v71HeCAAmZsgZ3YVKec3zSPYytG3/PrRCqbtcAvA==", "dev": true }, "@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.5.tgz", + "integrity": "sha512-uEoThA1LN2NA+K3B9wDo3yKlBfVtC6rh0i4/6hvbz071E8gTNZD/pT0MsBf7MeD6KbApMSkaAK0XeKyOZC7CIA==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" + "@webassemblyjs/ast": "1.11.5", + "@webassemblyjs/helper-buffer": "1.11.5", + "@webassemblyjs/helper-wasm-bytecode": "1.11.5", + "@webassemblyjs/wasm-gen": "1.11.5" } }, "@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.5.tgz", + "integrity": "sha512-37aGq6qVL8A8oPbPrSGMBcp38YZFXcHfiROflJn9jxSdSMMM5dS5P/9e2/TpaJuhE+wFrbukN2WI6Hw9MH5acg==", "dev": true, "requires": { "@xtuc/ieee754": "^1.2.0" } }, "@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.5.tgz", + "integrity": "sha512-ajqrRSXaTJoPW+xmkfYN6l8VIeNnR4vBOTQO9HzR7IygoCcKWkICbKFbVTNMjMgMREqXEr0+2M6zukzM47ZUfQ==", "dev": true, "requires": { "@xtuc/long": "4.2.2" } }, "@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.5.tgz", + "integrity": "sha512-WiOhulHKTZU5UPlRl53gHR8OxdGsSOxqfpqWeA2FmcwBMaoEdz6b2x2si3IwC9/fSPLfe8pBMRTHVMk5nlwnFQ==", "dev": true }, "@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.5.tgz", + "integrity": "sha512-C0p9D2fAu3Twwqvygvf42iGCQ4av8MFBLiTb+08SZ4cEdwzWx9QeAHDo1E2k+9s/0w1DM40oflJOpkZ8jW4HCQ==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" + "@webassemblyjs/ast": "1.11.5", + "@webassemblyjs/helper-buffer": "1.11.5", + "@webassemblyjs/helper-wasm-bytecode": "1.11.5", + "@webassemblyjs/helper-wasm-section": "1.11.5", + "@webassemblyjs/wasm-gen": "1.11.5", + "@webassemblyjs/wasm-opt": "1.11.5", + "@webassemblyjs/wasm-parser": "1.11.5", + "@webassemblyjs/wast-printer": "1.11.5" } }, "@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.5.tgz", + "integrity": "sha512-14vteRlRjxLK9eSyYFvw1K8Vv+iPdZU0Aebk3j6oB8TQiQYuO6hj9s4d7qf6f2HJr2khzvNldAFG13CgdkAIfA==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.11.5", + "@webassemblyjs/helper-wasm-bytecode": "1.11.5", + "@webassemblyjs/ieee754": "1.11.5", + "@webassemblyjs/leb128": "1.11.5", + "@webassemblyjs/utf8": "1.11.5" } }, "@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.5.tgz", + "integrity": "sha512-tcKwlIXstBQgbKy1MlbDMlXaxpucn42eb17H29rawYLxm5+MsEmgPzeCP8B1Cl69hCice8LeKgZpRUAPtqYPgw==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" + "@webassemblyjs/ast": "1.11.5", + "@webassemblyjs/helper-buffer": "1.11.5", + "@webassemblyjs/wasm-gen": "1.11.5", + "@webassemblyjs/wasm-parser": "1.11.5" } }, "@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.5.tgz", + "integrity": "sha512-SVXUIwsLQlc8srSD7jejsfTU83g7pIGr2YYNb9oHdtldSxaOhvA5xwvIiWIfcX8PlSakgqMXsLpLfbbJ4cBYew==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.11.5", + "@webassemblyjs/helper-api-error": "1.11.5", + "@webassemblyjs/helper-wasm-bytecode": "1.11.5", + "@webassemblyjs/ieee754": "1.11.5", + "@webassemblyjs/leb128": "1.11.5", + "@webassemblyjs/utf8": "1.11.5" } }, "@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "version": "1.11.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.5.tgz", + "integrity": "sha512-f7Pq3wvg3GSPUPzR0F6bmI89Hdb+u9WXrSKc4v+N0aV0q6r42WoF92Jp2jEorBEBRoRNXgjp53nBniDXcqZYPA==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/ast": "1.11.5", "@xtuc/long": "4.2.2" } }, @@ -4770,9 +4770,9 @@ } }, "enhanced-resolve": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", - "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", + "version": "5.13.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.13.0.tgz", + "integrity": "sha512-eyV8f0y1+bzyfh8xAwW/WTSZpLbjhqc4ne9eGSH4Zo2ejdyiNG9pU6mf9DG8a7+Auk6MFTlNOT4Y2y/9k8GKVg==", "dev": true, "requires": { "graceful-fs": "^4.2.4", @@ -6027,9 +6027,9 @@ "dev": true }, "schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", + "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", "dev": true, "requires": { "@types/json-schema": "^7.0.8", @@ -6502,21 +6502,21 @@ } }, "webpack": { - "version": "5.79.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.79.0.tgz", - "integrity": "sha512-3mN4rR2Xq+INd6NnYuL9RC9GAmc1ROPKJoHhrZ4pAjdMFEkJJWrsPw8o2JjCIyQyTu7rTXYn4VG6OpyB3CobZg==", + "version": "5.80.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.80.0.tgz", + "integrity": "sha512-OIMiq37XK1rWO8mH9ssfFKZsXg4n6klTEDL7S8/HqbAOBBaiy8ABvXvz0dDCXeEF9gqwxSvVk611zFPjS8hJxA==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.0", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", "acorn": "^8.7.1", "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.10.0", + "enhanced-resolve": "^5.13.0", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -6526,7 +6526,7 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", + "schema-utils": "^3.1.2", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.3.7", "watchpack": "^2.4.0", diff --git a/code/package.json b/code/package.json index cbbf4ce49..47b8de0a7 100644 --- a/code/package.json +++ b/code/package.json @@ -45,7 +45,7 @@ "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", "typescript": "^5.0.4", - "webpack": "^5.79.0", + "webpack": "^5.80.0", "webpack-cli": "^5.0.1" }, "engines": { From 9da429ebbeddbc59338323fbe01b439dc5b37592 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Apr 2023 15:04:04 +0000 Subject: [PATCH 015/141] build(deps): bump semver from 7.4.0 to 7.5.0 in /code Bumps [semver](https://github.com/npm/node-semver) from 7.4.0 to 7.5.0. - [Release notes](https://github.com/npm/node-semver/releases) - [Changelog](https://github.com/npm/node-semver/blob/main/CHANGELOG.md) - [Commits](https://github.com/npm/node-semver/compare/v7.4.0...v7.5.0) --- updated-dependencies: - dependency-name: semver dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- code/package-lock.json | 14 +++++++------- code/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/code/package-lock.json b/code/package-lock.json index 1fd716f06..36d0c6baa 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -9,7 +9,7 @@ "version": "0.11.0", "license": "MIT", "dependencies": { - "semver": "^7.4.0", + "semver": "^7.5.0", "vscode-languageclient": "^8.1.0" }, "devDependencies": { @@ -2837,9 +2837,9 @@ } }, "node_modules/semver": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.4.0.tgz", - "integrity": "sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -6038,9 +6038,9 @@ } }, "semver": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.4.0.tgz", - "integrity": "sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", "requires": { "lru-cache": "^6.0.0" } diff --git a/code/package.json b/code/package.json index 47b8de0a7..5f9157fe8 100644 --- a/code/package.json +++ b/code/package.json @@ -31,7 +31,7 @@ "main": "dist/node/extension", "browser": "dist/browser/extension", "dependencies": { - "semver": "^7.4.0", + "semver": "^7.5.0", "vscode-languageclient": "^8.1.0" }, "devDependencies": { From 2d0f8d9dbf08d621d7843e2296fcb9970903afa3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Apr 2023 18:35:05 +0000 Subject: [PATCH 016/141] build(deps-dev): bump webpack-cli from 5.0.1 to 5.0.2 in /code Bumps [webpack-cli](https://github.com/webpack/webpack-cli) from 5.0.1 to 5.0.2. - [Release notes](https://github.com/webpack/webpack-cli/releases) - [Changelog](https://github.com/webpack/webpack-cli/blob/master/CHANGELOG.md) - [Commits](https://github.com/webpack/webpack-cli/compare/webpack-cli@5.0.1...webpack-cli@5.0.2) --- updated-dependencies: - dependency-name: webpack-cli dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- code/package-lock.json | 48 +++++++++++++++++++++--------------------- code/package.json | 2 +- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/code/package-lock.json b/code/package-lock.json index 36d0c6baa..f11f6f403 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -24,7 +24,7 @@ "ts-loader": "^9.4.2", "typescript": "^5.0.4", "webpack": "^5.80.0", - "webpack-cli": "^5.0.1" + "webpack-cli": "^5.0.2" }, "engines": { "vscode": "^1.66.0" @@ -388,9 +388,9 @@ } }, "node_modules/@webpack-cli/serve": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.1.tgz", - "integrity": "sha512-0G7tNyS+yW8TdgHwZKlDWYXFA6OJQnoLCQvYKkQP0Q2X205PSQ6RNUj0M+1OB/9gRQaUZ/ccYfaxd0nhaWKfjw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.2.tgz", + "integrity": "sha512-S9h3GmOmzUseyeFW3tYNnWS7gNUuwxZ3mmMq0JyW78Vx1SGKPSkt5bT4pB0rUnVfHjP0EL9gW2bOzmtiTfQt0A==", "dev": true, "engines": { "node": ">=14.15.0" @@ -3501,17 +3501,17 @@ } }, "node_modules/webpack-cli": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.1.tgz", - "integrity": "sha512-S3KVAyfwUqr0Mo/ur3NzIp6jnerNpo7GUO6so51mxLi1spqsA17YcMXy0WOIJtBSnj748lthxC6XLbNKh/ZC+A==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.2.tgz", + "integrity": "sha512-4y3W5Dawri5+8dXm3+diW6Mn1Ya+Dei6eEVAdIduAmYNLzv1koKVAqsfgrrc9P2mhrYHQphx5htnGkcNwtubyQ==", "dev": true, "dependencies": { "@discoveryjs/json-ext": "^0.5.0", "@webpack-cli/configtest": "^2.0.1", "@webpack-cli/info": "^2.0.1", - "@webpack-cli/serve": "^2.0.1", + "@webpack-cli/serve": "^2.0.2", "colorette": "^2.0.14", - "commander": "^9.4.1", + "commander": "^10.0.1", "cross-spawn": "^7.0.3", "envinfo": "^7.7.3", "fastest-levenshtein": "^1.0.12", @@ -3552,12 +3552,12 @@ "dev": true }, "node_modules/webpack-cli/node_modules/commander": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", - "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "dev": true, "engines": { - "node": "^12.20.0 || >=14" + "node": ">=14" } }, "node_modules/webpack-merge": { @@ -4199,9 +4199,9 @@ "requires": {} }, "@webpack-cli/serve": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.1.tgz", - "integrity": "sha512-0G7tNyS+yW8TdgHwZKlDWYXFA6OJQnoLCQvYKkQP0Q2X205PSQ6RNUj0M+1OB/9gRQaUZ/ccYfaxd0nhaWKfjw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.2.tgz", + "integrity": "sha512-S9h3GmOmzUseyeFW3tYNnWS7gNUuwxZ3mmMq0JyW78Vx1SGKPSkt5bT4pB0rUnVfHjP0EL9gW2bOzmtiTfQt0A==", "dev": true, "requires": {} }, @@ -6534,17 +6534,17 @@ } }, "webpack-cli": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.1.tgz", - "integrity": "sha512-S3KVAyfwUqr0Mo/ur3NzIp6jnerNpo7GUO6so51mxLi1spqsA17YcMXy0WOIJtBSnj748lthxC6XLbNKh/ZC+A==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.2.tgz", + "integrity": "sha512-4y3W5Dawri5+8dXm3+diW6Mn1Ya+Dei6eEVAdIduAmYNLzv1koKVAqsfgrrc9P2mhrYHQphx5htnGkcNwtubyQ==", "dev": true, "requires": { "@discoveryjs/json-ext": "^0.5.0", "@webpack-cli/configtest": "^2.0.1", "@webpack-cli/info": "^2.0.1", - "@webpack-cli/serve": "^2.0.1", + "@webpack-cli/serve": "^2.0.2", "colorette": "^2.0.14", - "commander": "^9.4.1", + "commander": "^10.0.1", "cross-spawn": "^7.0.3", "envinfo": "^7.7.3", "fastest-levenshtein": "^1.0.12", @@ -6561,9 +6561,9 @@ "dev": true }, "commander": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", - "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "dev": true } } diff --git a/code/package.json b/code/package.json index 5f9157fe8..f02e9ceb9 100644 --- a/code/package.json +++ b/code/package.json @@ -46,7 +46,7 @@ "ts-loader": "^9.4.2", "typescript": "^5.0.4", "webpack": "^5.80.0", - "webpack-cli": "^5.0.1" + "webpack-cli": "^5.0.2" }, "engines": { "vscode": "^1.66.0" From d1ba2e85b86bade40be1289d925f6eb61f9e71c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 May 2023 15:04:05 +0000 Subject: [PATCH 017/141] build(deps-dev): bump webpack from 5.80.0 to 5.81.0 in /code Bumps [webpack](https://github.com/webpack/webpack) from 5.80.0 to 5.81.0. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.80.0...v5.81.0) --- updated-dependencies: - dependency-name: webpack dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- code/package-lock.json | 14 +++++++------- code/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/code/package-lock.json b/code/package-lock.json index f11f6f403..ab8305479 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -23,7 +23,7 @@ "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", "typescript": "^5.0.4", - "webpack": "^5.80.0", + "webpack": "^5.81.0", "webpack-cli": "^5.0.2" }, "engines": { @@ -3454,9 +3454,9 @@ } }, "node_modules/webpack": { - "version": "5.80.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.80.0.tgz", - "integrity": "sha512-OIMiq37XK1rWO8mH9ssfFKZsXg4n6klTEDL7S8/HqbAOBBaiy8ABvXvz0dDCXeEF9gqwxSvVk611zFPjS8hJxA==", + "version": "5.81.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.81.0.tgz", + "integrity": "sha512-AAjaJ9S4hYCVODKLQTgG5p5e11hiMawBwV2v8MYLE0C/6UAGLuAF4n1qa9GOwdxnicaP+5k6M5HrLmD4+gIB8Q==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", @@ -6502,9 +6502,9 @@ } }, "webpack": { - "version": "5.80.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.80.0.tgz", - "integrity": "sha512-OIMiq37XK1rWO8mH9ssfFKZsXg4n6klTEDL7S8/HqbAOBBaiy8ABvXvz0dDCXeEF9gqwxSvVk611zFPjS8hJxA==", + "version": "5.81.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.81.0.tgz", + "integrity": "sha512-AAjaJ9S4hYCVODKLQTgG5p5e11hiMawBwV2v8MYLE0C/6UAGLuAF4n1qa9GOwdxnicaP+5k6M5HrLmD4+gIB8Q==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.3", diff --git a/code/package.json b/code/package.json index f02e9ceb9..ba4c1bc52 100644 --- a/code/package.json +++ b/code/package.json @@ -45,7 +45,7 @@ "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", "typescript": "^5.0.4", - "webpack": "^5.80.0", + "webpack": "^5.81.0", "webpack-cli": "^5.0.2" }, "engines": { From f1349da1e6cc9f194cc32131fb86974b70f3d90c Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Wed, 23 Nov 2022 14:51:20 +0000 Subject: [PATCH 018/141] lsp: Initial flake definition This is an attempt at using Nix to define development environments. --- lib/esbonio/Makefile | 9 +++++++ lib/esbonio/flake.lock | 43 ++++++++++++++++++++++++++++++++++ lib/esbonio/flake.nix | 43 ++++++++++++++++++++++++++++++++++ lib/esbonio/nix/esbonio.nix | 22 +++++++++++++++++ lib/esbonio/nix/pytest-lsp.nix | 24 +++++++++++++++++++ 5 files changed, 141 insertions(+) create mode 100644 lib/esbonio/Makefile create mode 100644 lib/esbonio/flake.lock create mode 100644 lib/esbonio/flake.nix create mode 100644 lib/esbonio/nix/esbonio.nix create mode 100644 lib/esbonio/nix/pytest-lsp.nix diff --git a/lib/esbonio/Makefile b/lib/esbonio/Makefile new file mode 100644 index 000000000..03bcea6f2 --- /dev/null +++ b/lib/esbonio/Makefile @@ -0,0 +1,9 @@ +PY ?= 310 + +.PHONY: develop test + +develop: + nix develop .#py$(PY) + +test: + nix develop .#py$(PY) --command pytest diff --git a/lib/esbonio/flake.lock b/lib/esbonio/flake.lock new file mode 100644 index 000000000..31d6fc23a --- /dev/null +++ b/lib/esbonio/flake.lock @@ -0,0 +1,43 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1668852955, + "narHash": "sha256-1ozaNW9uFRvm3cP9M6FPx+hdqyFQnf49M3HrLQ6nqrk=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "2fb6f9fb0ef3ca727cbd9ae30b90d1ce49d5fcca", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs", + "utils": "utils" + } + }, + "utils": { + "locked": { + "lastModified": 1667395993, + "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/lib/esbonio/flake.nix b/lib/esbonio/flake.nix new file mode 100644 index 000000000..f61d717d0 --- /dev/null +++ b/lib/esbonio/flake.nix @@ -0,0 +1,43 @@ +{ + description = "The Esbonio language server"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, utils }: + + let + eachPythonVersion = versions: f: builtins.listToAttrs (builtins.map (version: {name = "py${version}"; value = f version; }) versions); + in { + + devShells = utils.lib.eachDefaultSystemMap (system: + let + pkgs = import nixpkgs { inherit system; }; + in + eachPythonVersion [ "37" "38" "39" "310" "311" ] (pyVersion: + let + pytest-lsp = pkgs.callPackage ./nix/pytest-lsp.nix { pythonPackages = pkgs."python${pyVersion}Packages"; }; + esbonio = pkgs.callPackage ./nix/esbonio.nix { pythonPackages = pkgs."python${pyVersion}Packages"; }; + in + + with pkgs; mkShell { + name = "py${pyVersion}"; + + packages = [ + pkgs."python${pyVersion}" + + esbonio + + # test suite dependencies + pkgs."python${pyVersion}Packages".mock + pkgs."python${pyVersion}Packages".pytest + pytest-lsp + pkgs."python${pyVersion}Packages".pytest-timeout + ]; + } + ) + ); + }; +} diff --git a/lib/esbonio/nix/esbonio.nix b/lib/esbonio/nix/esbonio.nix new file mode 100644 index 000000000..8df535897 --- /dev/null +++ b/lib/esbonio/nix/esbonio.nix @@ -0,0 +1,22 @@ +{ pythonPackages }: + +pythonPackages.buildPythonPackage rec { + pname = "esbonio"; + version = "0.14.3"; + + src = ./..; + + buildInputs = [ + pythonPackages.pyspellchecker + pythonPackages.typing-extensions + ]; + + propagatedBuildInputs = [ + pythonPackages.appdirs + pythonPackages.pygls + pythonPackages.sphinx + ]; + + # Disable tests + doCheck = false; +} diff --git a/lib/esbonio/nix/pytest-lsp.nix b/lib/esbonio/nix/pytest-lsp.nix new file mode 100644 index 000000000..8f3fed699 --- /dev/null +++ b/lib/esbonio/nix/pytest-lsp.nix @@ -0,0 +1,24 @@ +{ pythonPackages }: + +pythonPackages.buildPythonPackage rec { + pname = "pytest-lsp"; + version = "0.1.3"; + + src = pythonPackages.fetchPypi { + inherit pname version; + sha256 = "sha256-WxTh9G3tWyGzYx1uHufkwg3hN6jTbRjlGLKJR1eUNtY="; + }; + + buildInputs = [ + pythonPackages.appdirs + pythonPackages.pytest + ]; + + propagatedBuildInputs = [ + pythonPackages.pygls + pythonPackages.pytest-asyncio + ]; + + # Disable tests + doCheck = false; +} From fd25f7ebb3d132ad109c185daafeb27a870cd19b Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Tue, 24 Jan 2023 20:53:30 +0000 Subject: [PATCH 019/141] lsp: Update flake definition - Remove local `pytest-lsp` package definition in favour of upstream flake - Replace local `esbonio` package definition with equivalent overlay - Update `flake.lock` --- lib/esbonio/flake.lock | 47 ++++++++++++++++++++++++++--- lib/esbonio/flake.nix | 37 ++++++++++++++--------- lib/esbonio/nix/esbonio-overlay.nix | 31 +++++++++++++++++++ lib/esbonio/nix/esbonio.nix | 22 -------------- lib/esbonio/nix/pytest-lsp.nix | 24 --------------- 5 files changed, 96 insertions(+), 65 deletions(-) create mode 100644 lib/esbonio/nix/esbonio-overlay.nix delete mode 100644 lib/esbonio/nix/esbonio.nix delete mode 100644 lib/esbonio/nix/pytest-lsp.nix diff --git a/lib/esbonio/flake.lock b/lib/esbonio/flake.lock index 31d6fc23a..ea1d37840 100644 --- a/lib/esbonio/flake.lock +++ b/lib/esbonio/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1668852955, - "narHash": "sha256-1ozaNW9uFRvm3cP9M6FPx+hdqyFQnf49M3HrLQ6nqrk=", + "lastModified": 1675698036, + "narHash": "sha256-BgsQkQewdlQi8gapJN4phpxkI/FCE/2sORBaFcYbp/A=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "2fb6f9fb0ef3ca727cbd9ae30b90d1ce49d5fcca", + "rev": "1046c7b92e908a1202c0f1ba3fc21d19e1cf1b62", "type": "github" }, "original": { @@ -16,13 +16,52 @@ "type": "github" } }, + "pytest-lsp": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "utils": "utils" + }, + "locked": { + "dir": "lib/pytest-lsp", + "lastModified": 1680461504, + "narHash": "sha256-yinReEwXWeCstM0+zY0A1JE2N59sdMnBsepEBgtZ9xM=", + "owner": "swyddfa", + "repo": "lsp-devtools", + "rev": "6ae80a24b55d2b6943b9d30805cf02440ebbaf5c", + "type": "github" + }, + "original": { + "dir": "lib/pytest-lsp", + "owner": "swyddfa", + "repo": "lsp-devtools", + "type": "github" + } + }, "root": { "inputs": { "nixpkgs": "nixpkgs", - "utils": "utils" + "pytest-lsp": "pytest-lsp", + "utils": "utils_2" } }, "utils": { + "locked": { + "lastModified": 1678901627, + "narHash": "sha256-U02riOqrKKzwjsxc/400XnElV+UtPUQWpANPlyazjH0=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "93a2b84fc4b70d9e089d029deacc3583435c2ed6", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "utils_2": { "locked": { "lastModified": 1667395993, "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", diff --git a/lib/esbonio/flake.nix b/lib/esbonio/flake.nix index f61d717d0..eb571e99c 100644 --- a/lib/esbonio/flake.nix +++ b/lib/esbonio/flake.nix @@ -3,38 +3,45 @@ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + pytest-lsp.url = "github:swyddfa/lsp-devtools?dir=lib/pytest-lsp"; + pytest-lsp.inputs.nixpkgs.follows = "nixpkgs"; utils.url = "github:numtide/flake-utils"; }; - outputs = { self, nixpkgs, utils }: + outputs = { self, nixpkgs, pytest-lsp, utils }: let - eachPythonVersion = versions: f: builtins.listToAttrs (builtins.map (version: {name = "py${version}"; value = f version; }) versions); + esbonio-overlay = import ./nix/esbonio-overlay.nix; + pytest-lsp-overlay = pytest-lsp.overlays.default; + + eachPythonVersion = versions: f: + builtins.listToAttrs (builtins.map (version: {name = "py${version}"; value = f version; }) versions); in { + overlays.default = esbonio-overlay; + devShells = utils.lib.eachDefaultSystemMap (system: let - pkgs = import nixpkgs { inherit system; }; + pkgs = import nixpkgs { + inherit system; + overlays = [ pytest-lsp-overlay esbonio-overlay ]; + }; in - eachPythonVersion [ "37" "38" "39" "310" "311" ] (pyVersion: + eachPythonVersion [ "38" "39" "310" "311" ] (pyVersion: + let - pytest-lsp = pkgs.callPackage ./nix/pytest-lsp.nix { pythonPackages = pkgs."python${pyVersion}Packages"; }; - esbonio = pkgs.callPackage ./nix/esbonio.nix { pythonPackages = pkgs."python${pyVersion}Packages"; }; + esbonio = pkgs."python${pyVersion}Packages".esbonio.overridePythonAttrs (_: { doCheck = false; }); in - with pkgs; mkShell { + pkgs.mkShell { name = "py${pyVersion}"; - packages = [ - pkgs."python${pyVersion}" - + packages = with pkgs."python${pyVersion}Packages"; [ esbonio - # test suite dependencies - pkgs."python${pyVersion}Packages".mock - pkgs."python${pyVersion}Packages".pytest - pytest-lsp - pkgs."python${pyVersion}Packages".pytest-timeout + mock + pkgs."python${pyVersion}Packages".pytest-lsp + pytest-timeout ]; } ) diff --git a/lib/esbonio/nix/esbonio-overlay.nix b/lib/esbonio/nix/esbonio-overlay.nix new file mode 100644 index 000000000..c1b7da651 --- /dev/null +++ b/lib/esbonio/nix/esbonio-overlay.nix @@ -0,0 +1,31 @@ +final: prev: { + pythonPackagesExtensions = prev.pythonPackagesExtensions ++ [( + python-final: python-prev: { + esbonio = python-prev.buildPythonPackage { + pname = "esbonio"; + version = "0.16.1"; + + src = ./..; + + propagatedBuildInputs = with python-prev; [ + appdirs + pygls + pyspellchecker + sphinx + # typing-extensions; only required for Python 3.7 + ]; + + doCheck = true; + + nativeCheckInputs = with python-prev; [ + mock + pytest-lsp + pytest-timeout + pytestCheckHook + ]; + + pythonImportsCheck = [ "esbonio.lsp" ]; + }; + } + )]; +} diff --git a/lib/esbonio/nix/esbonio.nix b/lib/esbonio/nix/esbonio.nix deleted file mode 100644 index 8df535897..000000000 --- a/lib/esbonio/nix/esbonio.nix +++ /dev/null @@ -1,22 +0,0 @@ -{ pythonPackages }: - -pythonPackages.buildPythonPackage rec { - pname = "esbonio"; - version = "0.14.3"; - - src = ./..; - - buildInputs = [ - pythonPackages.pyspellchecker - pythonPackages.typing-extensions - ]; - - propagatedBuildInputs = [ - pythonPackages.appdirs - pythonPackages.pygls - pythonPackages.sphinx - ]; - - # Disable tests - doCheck = false; -} diff --git a/lib/esbonio/nix/pytest-lsp.nix b/lib/esbonio/nix/pytest-lsp.nix deleted file mode 100644 index 8f3fed699..000000000 --- a/lib/esbonio/nix/pytest-lsp.nix +++ /dev/null @@ -1,24 +0,0 @@ -{ pythonPackages }: - -pythonPackages.buildPythonPackage rec { - pname = "pytest-lsp"; - version = "0.1.3"; - - src = pythonPackages.fetchPypi { - inherit pname version; - sha256 = "sha256-WxTh9G3tWyGzYx1uHufkwg3hN6jTbRjlGLKJR1eUNtY="; - }; - - buildInputs = [ - pythonPackages.appdirs - pythonPackages.pytest - ]; - - propagatedBuildInputs = [ - pythonPackages.pygls - pythonPackages.pytest-asyncio - ]; - - # Disable tests - doCheck = false; -} From d643a6536138e0ae624f13534b8ad2e712211002 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Fri, 21 Apr 2023 20:08:35 +0100 Subject: [PATCH 020/141] Initial nix + neovim configuration It should now be possible to use `nix run` to try the language server from a pre-configured neovim instance! --- docs/lsp/editors/nvim-lspconfig/init.vim | 72 +++++--------- flake.lock | 117 +++++++++++++++++++++++ flake.nix | 48 ++++++++++ lib/esbonio/flake.nix | 7 +- 4 files changed, 193 insertions(+), 51 deletions(-) create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/docs/lsp/editors/nvim-lspconfig/init.vim b/docs/lsp/editors/nvim-lspconfig/init.vim index 98bf6fcda..8f66cf463 100644 --- a/docs/lsp/editors/nvim-lspconfig/init.vim +++ b/docs/lsp/editors/nvim-lspconfig/init.vim @@ -1,28 +1,3 @@ -" --------------- First time setup ------------------ -" There are a few steps you need to perform when setting this up for the -" first time. -" -" 1. Ensure you have vim-plug's `plug.vim` file installed in your autoload -" directory. See https://github.com/junegunn/vim-plug#installation for -" details. -" -" 2. Open a terminal in the directory containing this file and run the -" following command to load this config isolated from your existing -" configuration. -" -" nvim -u init.vim -" -" 3. Install the required plugins. -" -" :PlugInstall -" -" --------------- Subsequent use -------------------- -" -" 1. Open a terminal in the directory containing this file and run the -" following command to load it. -" -" nvim -u init.vim - set expandtab set tabstop=3 set softtabstop=3 @@ -30,36 +5,35 @@ set shiftwidth=3 let mapleader='' -call plug#begin('./plugged') - -Plug 'neovim/nvim-lspconfig' - -call plug#end() - lua << EOF local lspconfig = require('lspconfig') -lspconfig.esbonio.setup { - -- The following is based on the example `on_attach` function found in nvim-lspconfig's README - -- https://github.com/neovim/nvim-lspconfig/#keybindings-and-completion - -- - -- Only the methods currently supported by the language server are bound. - on_attach = function(client, bufnr) - local function buf_set_keymap(...) vim.api.nvim_buf_set_keymap(bufnr, ...) end - local function buf_set_option(...) vim.api.nvim_buf_set_option(bufnr, ...) end +local keymap_opts = { noremap = true, silent = true} +vim.keymap.set('n', 'e', vim.diagnostic.open_float, keymap_opts) +vim.keymap.set('n', '[d', vim.diagnostic.goto_prev, keymap_opts) +vim.keymap.set('n', ']d', vim.diagnostic.goto_next, keymap_opts) +vim.keymap.set('n', 'q', vim.diagnostic.setloclist, keymap_opts) - -- Enable completion triggered by - buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc') +local on_attach = function(client, bufnr) +end - -- Mappings. - local opts = { noremap=true, silent=true } +lspconfig.esbonio.setup { + cmd = { 'esbonio' }, + init_options = { + server = { + completion = { + preferredInsertBehavior = 'insert' + } + } + }, + on_attach = function(client, bufnr) + vim.api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc') - -- See `:help vim.lsp.*` for documentation on any of the below functions - buf_set_keymap('n', 'gd', 'lua vim.lsp.buf.definition()', opts) - buf_set_keymap('n', 'e', 'lua vim.lsp.diagnostic.show_line_diagnostics()', opts) - buf_set_keymap('n', '[d', 'lua vim.lsp.diagnostic.goto_prev()', opts) - buf_set_keymap('n', ']d', 'lua vim.lsp.diagnostic.goto_next()', opts) - buf_set_keymap('n', 'q', 'lua vim.lsp.diagnostic.set_loclist()', opts) + local bufopts = { noremap=true, silent=true, buffer=bufnr } + vim.keymap.set('n', 'gd', vim.lsp.buf.definition, bufopts) + vim.keymap.set('n', 'gi', vim.lsp.buf.implementation, bufopts) + vim.keymap.set('n', 'gh', vim.lsp.buf.hover, bufopts) + vim.keymap.set('n', 'ca', vim.lsp.buf.code_action, bufopts) end } diff --git a/flake.lock b/flake.lock new file mode 100644 index 000000000..7ecf16b71 --- /dev/null +++ b/flake.lock @@ -0,0 +1,117 @@ +{ + "nodes": { + "esbonio": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "pytest-lsp": "pytest-lsp", + "utils": "utils_2" + }, + "locked": { + "lastModified": 1, + "narHash": "sha256-QgSDxOPSrtsaqjeStalef07+bUE3qkzz7pJC4y43ltw=", + "path": "lib/esbonio", + "type": "path" + }, + "original": { + "path": "lib/esbonio", + "type": "path" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1680819799, + "narHash": "sha256-zuHl2LNr1Bll64zfr7805Yvvu23S1e//5Up0oqvjknY=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "144133c526040a5140e89366ff72ac2d387e9bbb", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "pytest-lsp": { + "inputs": { + "nixpkgs": [ + "esbonio", + "nixpkgs" + ], + "utils": "utils" + }, + "locked": { + "dir": "lib/pytest-lsp", + "lastModified": 1680461504, + "narHash": "sha256-yinReEwXWeCstM0+zY0A1JE2N59sdMnBsepEBgtZ9xM=", + "owner": "swyddfa", + "repo": "lsp-devtools", + "rev": "6ae80a24b55d2b6943b9d30805cf02440ebbaf5c", + "type": "github" + }, + "original": { + "dir": "lib/pytest-lsp", + "owner": "swyddfa", + "repo": "lsp-devtools", + "type": "github" + } + }, + "root": { + "inputs": { + "esbonio": "esbonio", + "nixpkgs": "nixpkgs", + "utils": "utils_3" + } + }, + "utils": { + "locked": { + "lastModified": 1678901627, + "narHash": "sha256-U02riOqrKKzwjsxc/400XnElV+UtPUQWpANPlyazjH0=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "93a2b84fc4b70d9e089d029deacc3583435c2ed6", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "utils_2": { + "locked": { + "lastModified": 1667395993, + "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "utils_3": { + "locked": { + "lastModified": 1680776469, + "narHash": "sha256-3CXUDK/3q/kieWtdsYpDOBJw3Gw4Af6x+2EiSnIkNQw=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "411e8764155aa9354dbcd6d5faaeb97e9e3dce24", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 000000000..e7d0c6808 --- /dev/null +++ b/flake.nix @@ -0,0 +1,48 @@ +{ + description = "The Esbonio language server"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + esbonio.url = "path:lib/esbonio"; + esbonio.inputs.nixpkgs.follows = "nixpkgs"; + utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, esbonio, utils }: + + utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { inherit system ; overlays = [ esbonio.overlays.default ];}; + + esbonio-lsp = pkgs.python3Packages.esbonio.overridePythonAttrs (_: { doCheck = false ; }); + paths = pkgs.lib.makeBinPath [ + pkgs.neovim + esbonio-lsp + ]; + + pluginList = with pkgs.vimPlugins; [ + nvim-lspconfig + ]; + plugins = pkgs.stdenv.mkDerivation { + name = "esbonio-nvim-plugins"; + buildCommand = '' + mkdir -p $out/nvim/site/pack/plugins/start/ + ${pkgs.lib.concatMapStringsSep "\n" (path: "ln -s ${path} $out/nvim/site/pack/plugins/start/") pluginList } + ''; + }; + + initVim = builtins.readFile ./docs/lsp/editors/nvim-lspconfig/init.vim; + neovim = pkgs.writeShellScriptBin "nvim" '' + export PATH=${paths}:$PATH + export XDG_CONFIG_DIRS= + export XDG_DATA_DIRS=${plugins.outPath} + nvim --clean --cmd 'source ${pkgs.writeText "init.vim" initVim}' "$@" + ''; + in { + apps.default = { + type = "app"; + program = "${neovim}/bin/nvim"; + }; + } + ); +} diff --git a/lib/esbonio/flake.nix b/lib/esbonio/flake.nix index eb571e99c..a4a3377ef 100644 --- a/lib/esbonio/flake.nix +++ b/lib/esbonio/flake.nix @@ -18,13 +18,16 @@ builtins.listToAttrs (builtins.map (version: {name = "py${version}"; value = f version; }) versions); in { - overlays.default = esbonio-overlay; + overlays.default = self: super: nixpkgs.lib.composeManyExtensions [ + pytest-lsp-overlay + esbonio-overlay + ] self super; devShells = utils.lib.eachDefaultSystemMap (system: let pkgs = import nixpkgs { inherit system; - overlays = [ pytest-lsp-overlay esbonio-overlay ]; + overlays = [ self.overlays.default ]; }; in eachPythonVersion [ "38" "39" "310" "311" ] (pyVersion: From 6defa166ff8e1b4b77e21577a0fdf82d011a25a7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 May 2023 15:01:39 +0000 Subject: [PATCH 021/141] build(deps-dev): bump webpack from 5.81.0 to 5.82.0 in /code Bumps [webpack](https://github.com/webpack/webpack) from 5.81.0 to 5.82.0. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.81.0...v5.82.0) --- updated-dependencies: - dependency-name: webpack dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- code/package-lock.json | 14 +++++++------- code/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/code/package-lock.json b/code/package-lock.json index ab8305479..2bcbf42b7 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -23,7 +23,7 @@ "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", "typescript": "^5.0.4", - "webpack": "^5.81.0", + "webpack": "^5.82.0", "webpack-cli": "^5.0.2" }, "engines": { @@ -3454,9 +3454,9 @@ } }, "node_modules/webpack": { - "version": "5.81.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.81.0.tgz", - "integrity": "sha512-AAjaJ9S4hYCVODKLQTgG5p5e11hiMawBwV2v8MYLE0C/6UAGLuAF4n1qa9GOwdxnicaP+5k6M5HrLmD4+gIB8Q==", + "version": "5.82.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.82.0.tgz", + "integrity": "sha512-iGNA2fHhnDcV1bONdUu554eZx+XeldsaeQ8T67H6KKHl2nUSwX8Zm7cmzOA46ox/X1ARxf7Bjv8wQ/HsB5fxBg==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", @@ -6502,9 +6502,9 @@ } }, "webpack": { - "version": "5.81.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.81.0.tgz", - "integrity": "sha512-AAjaJ9S4hYCVODKLQTgG5p5e11hiMawBwV2v8MYLE0C/6UAGLuAF4n1qa9GOwdxnicaP+5k6M5HrLmD4+gIB8Q==", + "version": "5.82.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.82.0.tgz", + "integrity": "sha512-iGNA2fHhnDcV1bONdUu554eZx+XeldsaeQ8T67H6KKHl2nUSwX8Zm7cmzOA46ox/X1ARxf7Bjv8wQ/HsB5fxBg==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.3", diff --git a/code/package.json b/code/package.json index ba4c1bc52..5d9ae7d12 100644 --- a/code/package.json +++ b/code/package.json @@ -45,7 +45,7 @@ "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", "typescript": "^5.0.4", - "webpack": "^5.81.0", + "webpack": "^5.82.0", "webpack-cli": "^5.0.2" }, "engines": { From 7377ee8fac8e42bc6514fc5468846aed73327ef3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 May 2023 18:17:21 +0000 Subject: [PATCH 022/141] build(deps-dev): bump webpack-cli from 5.0.2 to 5.1.1 in /code Bumps [webpack-cli](https://github.com/webpack/webpack-cli) from 5.0.2 to 5.1.1. - [Release notes](https://github.com/webpack/webpack-cli/releases) - [Changelog](https://github.com/webpack/webpack-cli/blob/master/CHANGELOG.md) - [Commits](https://github.com/webpack/webpack-cli/compare/webpack-cli@5.0.2...webpack-cli@5.1.1) --- updated-dependencies: - dependency-name: webpack-cli dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- code/package-lock.json | 46 +++++++++++++++++++++--------------------- code/package.json | 2 +- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/code/package-lock.json b/code/package-lock.json index 2bcbf42b7..e98500efc 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -24,7 +24,7 @@ "ts-loader": "^9.4.2", "typescript": "^5.0.4", "webpack": "^5.82.0", - "webpack-cli": "^5.0.2" + "webpack-cli": "^5.1.1" }, "engines": { "vscode": "^1.66.0" @@ -362,9 +362,9 @@ } }, "node_modules/@webpack-cli/configtest": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.0.1.tgz", - "integrity": "sha512-njsdJXJSiS2iNbQVS0eT8A/KPnmyH4pv1APj2K0d1wrZcBLw+yppxOy4CGqa0OxDJkzfL/XELDhD8rocnIwB5A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.0.tgz", + "integrity": "sha512-K/vuv72vpfSEZoo5KIU0a2FsEoYdW0DUMtMpB5X3LlUwshetMZRZRxB7sCsVji/lFaSxtQQ3aM9O4eMolXkU9w==", "dev": true, "engines": { "node": ">=14.15.0" @@ -388,9 +388,9 @@ } }, "node_modules/@webpack-cli/serve": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.2.tgz", - "integrity": "sha512-S9h3GmOmzUseyeFW3tYNnWS7gNUuwxZ3mmMq0JyW78Vx1SGKPSkt5bT4pB0rUnVfHjP0EL9gW2bOzmtiTfQt0A==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.4.tgz", + "integrity": "sha512-0xRgjgDLdz6G7+vvDLlaRpFatJaJ69uTalZLRSMX5B3VUrDmXcrVA3+6fXXQgmYz7bY9AAgs348XQdmtLsK41A==", "dev": true, "engines": { "node": ">=14.15.0" @@ -3501,15 +3501,15 @@ } }, "node_modules/webpack-cli": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.2.tgz", - "integrity": "sha512-4y3W5Dawri5+8dXm3+diW6Mn1Ya+Dei6eEVAdIduAmYNLzv1koKVAqsfgrrc9P2mhrYHQphx5htnGkcNwtubyQ==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.1.tgz", + "integrity": "sha512-OLJwVMoXnXYH2ncNGU8gxVpUtm3ybvdioiTvHgUyBuyMLKiVvWy+QObzBsMtp5pH7qQoEuWgeEUQ/sU3ZJFzAw==", "dev": true, "dependencies": { "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^2.0.1", + "@webpack-cli/configtest": "^2.1.0", "@webpack-cli/info": "^2.0.1", - "@webpack-cli/serve": "^2.0.2", + "@webpack-cli/serve": "^2.0.4", "colorette": "^2.0.14", "commander": "^10.0.1", "cross-spawn": "^7.0.3", @@ -4185,9 +4185,9 @@ } }, "@webpack-cli/configtest": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.0.1.tgz", - "integrity": "sha512-njsdJXJSiS2iNbQVS0eT8A/KPnmyH4pv1APj2K0d1wrZcBLw+yppxOy4CGqa0OxDJkzfL/XELDhD8rocnIwB5A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.0.tgz", + "integrity": "sha512-K/vuv72vpfSEZoo5KIU0a2FsEoYdW0DUMtMpB5X3LlUwshetMZRZRxB7sCsVji/lFaSxtQQ3aM9O4eMolXkU9w==", "dev": true, "requires": {} }, @@ -4199,9 +4199,9 @@ "requires": {} }, "@webpack-cli/serve": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.2.tgz", - "integrity": "sha512-S9h3GmOmzUseyeFW3tYNnWS7gNUuwxZ3mmMq0JyW78Vx1SGKPSkt5bT4pB0rUnVfHjP0EL9gW2bOzmtiTfQt0A==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.4.tgz", + "integrity": "sha512-0xRgjgDLdz6G7+vvDLlaRpFatJaJ69uTalZLRSMX5B3VUrDmXcrVA3+6fXXQgmYz7bY9AAgs348XQdmtLsK41A==", "dev": true, "requires": {} }, @@ -6534,15 +6534,15 @@ } }, "webpack-cli": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.2.tgz", - "integrity": "sha512-4y3W5Dawri5+8dXm3+diW6Mn1Ya+Dei6eEVAdIduAmYNLzv1koKVAqsfgrrc9P2mhrYHQphx5htnGkcNwtubyQ==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.1.tgz", + "integrity": "sha512-OLJwVMoXnXYH2ncNGU8gxVpUtm3ybvdioiTvHgUyBuyMLKiVvWy+QObzBsMtp5pH7qQoEuWgeEUQ/sU3ZJFzAw==", "dev": true, "requires": { "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^2.0.1", + "@webpack-cli/configtest": "^2.1.0", "@webpack-cli/info": "^2.0.1", - "@webpack-cli/serve": "^2.0.2", + "@webpack-cli/serve": "^2.0.4", "colorette": "^2.0.14", "commander": "^10.0.1", "cross-spawn": "^7.0.3", diff --git a/code/package.json b/code/package.json index 5d9ae7d12..59606e4e8 100644 --- a/code/package.json +++ b/code/package.json @@ -46,7 +46,7 @@ "ts-loader": "^9.4.2", "typescript": "^5.0.4", "webpack": "^5.82.0", - "webpack-cli": "^5.0.2" + "webpack-cli": "^5.1.1" }, "engines": { "vscode": "^1.66.0" From c112054f84af3cf5a8325374176c60058c4a9355 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 May 2023 15:01:20 +0000 Subject: [PATCH 023/141] build(deps-dev): bump webpack from 5.82.0 to 5.82.1 in /code Bumps [webpack](https://github.com/webpack/webpack) from 5.82.0 to 5.82.1. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.82.0...v5.82.1) --- updated-dependencies: - dependency-name: webpack dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- code/package-lock.json | 30 +++++++++++++++--------------- code/package.json | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/code/package-lock.json b/code/package-lock.json index e98500efc..1af233539 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -23,7 +23,7 @@ "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", "typescript": "^5.0.4", - "webpack": "^5.82.0", + "webpack": "^5.82.1", "webpack-cli": "^5.1.1" }, "engines": { @@ -1156,9 +1156,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.13.0.tgz", - "integrity": "sha512-eyV8f0y1+bzyfh8xAwW/WTSZpLbjhqc4ne9eGSH4Zo2ejdyiNG9pU6mf9DG8a7+Auk6MFTlNOT4Y2y/9k8GKVg==", + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.0.tgz", + "integrity": "sha512-+DCows0XNwLDcUhbFJPdlQEVnT2zXlCv7hPxemTz86/O+B/hCQ+mb7ydkPKiflpVraqLPCAfu7lDy+hBXueojw==", "dev": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -3454,9 +3454,9 @@ } }, "node_modules/webpack": { - "version": "5.82.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.82.0.tgz", - "integrity": "sha512-iGNA2fHhnDcV1bONdUu554eZx+XeldsaeQ8T67H6KKHl2nUSwX8Zm7cmzOA46ox/X1ARxf7Bjv8wQ/HsB5fxBg==", + "version": "5.82.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.82.1.tgz", + "integrity": "sha512-C6uiGQJ+Gt4RyHXXYt+v9f+SN1v83x68URwgxNQ98cvH8kxiuywWGP4XeNZ1paOzZ63aY3cTciCEQJNFUljlLw==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", @@ -3468,7 +3468,7 @@ "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.13.0", + "enhanced-resolve": "^5.14.0", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -4770,9 +4770,9 @@ } }, "enhanced-resolve": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.13.0.tgz", - "integrity": "sha512-eyV8f0y1+bzyfh8xAwW/WTSZpLbjhqc4ne9eGSH4Zo2ejdyiNG9pU6mf9DG8a7+Auk6MFTlNOT4Y2y/9k8GKVg==", + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.0.tgz", + "integrity": "sha512-+DCows0XNwLDcUhbFJPdlQEVnT2zXlCv7hPxemTz86/O+B/hCQ+mb7ydkPKiflpVraqLPCAfu7lDy+hBXueojw==", "dev": true, "requires": { "graceful-fs": "^4.2.4", @@ -6502,9 +6502,9 @@ } }, "webpack": { - "version": "5.82.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.82.0.tgz", - "integrity": "sha512-iGNA2fHhnDcV1bONdUu554eZx+XeldsaeQ8T67H6KKHl2nUSwX8Zm7cmzOA46ox/X1ARxf7Bjv8wQ/HsB5fxBg==", + "version": "5.82.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.82.1.tgz", + "integrity": "sha512-C6uiGQJ+Gt4RyHXXYt+v9f+SN1v83x68URwgxNQ98cvH8kxiuywWGP4XeNZ1paOzZ63aY3cTciCEQJNFUljlLw==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.3", @@ -6516,7 +6516,7 @@ "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.13.0", + "enhanced-resolve": "^5.14.0", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", diff --git a/code/package.json b/code/package.json index 59606e4e8..fa0f9d5c4 100644 --- a/code/package.json +++ b/code/package.json @@ -45,7 +45,7 @@ "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", "typescript": "^5.0.4", - "webpack": "^5.82.0", + "webpack": "^5.82.1", "webpack-cli": "^5.1.1" }, "engines": { From d4800a0d91b1485117b095579d4ea8e804fbd571 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 May 2023 15:01:49 +0000 Subject: [PATCH 024/141] build(deps): bump semver and @types/semver in /code Bumps [semver](https://github.com/npm/node-semver) and [@types/semver](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/semver). These dependencies needed to be updated together. Updates `semver` from 7.5.0 to 7.5.1 - [Release notes](https://github.com/npm/node-semver/releases) - [Changelog](https://github.com/npm/node-semver/blob/main/CHANGELOG.md) - [Commits](https://github.com/npm/node-semver/compare/v7.5.0...v7.5.1) Updates `@types/semver` from 7.3.13 to 7.5.0 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/semver) --- updated-dependencies: - dependency-name: semver dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: "@types/semver" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- code/package-lock.json | 28 ++++++++++++++-------------- code/package.json | 4 ++-- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/code/package-lock.json b/code/package-lock.json index 1af233539..9dd83b77f 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -9,14 +9,14 @@ "version": "0.11.0", "license": "MIT", "dependencies": { - "semver": "^7.5.0", + "semver": "^7.5.1", "vscode-languageclient": "^8.1.0" }, "devDependencies": { "@types/glob": "^8.1.0", "@types/mocha": "^10.0.1", "@types/node": "^14.17.15", - "@types/semver": "^7.3.13", + "@types/semver": "^7.5.0", "@types/vscode": "1.66.0", "@vscode/vsce": "^2.19.0", "mocha": "^10.2.0", @@ -158,9 +158,9 @@ "dev": true }, "node_modules/@types/semver": { - "version": "7.3.13", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", - "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", "dev": true }, "node_modules/@types/vscode": { @@ -2837,9 +2837,9 @@ } }, "node_modules/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -3990,9 +3990,9 @@ "dev": true }, "@types/semver": { - "version": "7.3.13", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", - "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", "dev": true }, "@types/vscode": { @@ -6038,9 +6038,9 @@ } }, "semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", "requires": { "lru-cache": "^6.0.0" } diff --git a/code/package.json b/code/package.json index fa0f9d5c4..162f1b3f9 100644 --- a/code/package.json +++ b/code/package.json @@ -31,14 +31,14 @@ "main": "dist/node/extension", "browser": "dist/browser/extension", "dependencies": { - "semver": "^7.5.0", + "semver": "^7.5.1", "vscode-languageclient": "^8.1.0" }, "devDependencies": { "@types/glob": "^8.1.0", "@types/mocha": "^10.0.1", "@types/node": "^14.17.15", - "@types/semver": "^7.3.13", + "@types/semver": "^7.5.0", "@types/vscode": "1.66.0", "@vscode/vsce": "^2.19.0", "mocha": "^10.2.0", From f787c98a212b1a0b3cd692a8d58a381e66005380 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 15 May 2023 20:42:02 +0000 Subject: [PATCH 025/141] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.2.0 → v1.3.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.2.0...v1.3.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3f78a5ced..aa08a4685 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -26,7 +26,7 @@ repos: args: [--settings-file=lib/esbonio/pyproject.toml] - repo: https://github.com/pre-commit/mirrors-mypy - rev: 'v1.2.0' + rev: 'v1.3.0' hooks: - id: mypy name: mypy (esbonio) From bf86307b60c2a0987c5e67f134e096a1918de153 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Fri, 5 May 2023 20:16:48 +0100 Subject: [PATCH 026/141] lsp: Upgrade to latest pytest-lsp --- lib/esbonio/esbonio/lsp/testing.py | 74 ++- lib/esbonio/setup.cfg | 4 +- lib/esbonio/tests/sphinx-default/conftest.py | 45 +- .../sphinx-default/test_sd_directives.py | 16 +- .../tests/sphinx-default/test_sd_roles.py | 12 +- .../tests/sphinx-default/test_sd_sphinx.py | 542 +++++++++++++----- .../test_sd_sphinx_codeblocks.py | 5 - .../sphinx-default/test_sd_sphinx_domains.py | 12 +- .../sphinx-default/test_sd_sphinx_images.py | 3 - .../sphinx-default/test_sd_sphinx_includes.py | 12 +- .../sphinx-default/test_sd_sphinx_roles.py | 3 - .../tests/sphinx-default/test_sd_symbols.py | 6 +- .../tests/sphinx-extensions/conftest.py | 43 +- .../sphinx-extensions/test_se_directives.py | 7 +- .../tests/sphinx-extensions/test_se_roles.py | 3 - .../tests/sphinx-extensions/test_se_sphinx.py | 9 +- .../test_se_sphinx_codeblocks.py | 3 - .../test_se_sphinx_domains.py | 3 - .../sphinx-extensions/test_se_sphinx_roles.py | 3 - 19 files changed, 546 insertions(+), 259 deletions(-) diff --git a/lib/esbonio/esbonio/lsp/testing.py b/lib/esbonio/esbonio/lsp/testing.py index 9dd644092..8d69511f6 100644 --- a/lib/esbonio/esbonio/lsp/testing.py +++ b/lib/esbonio/esbonio/lsp/testing.py @@ -10,9 +10,18 @@ from lsprotocol.types import ClientCapabilities from lsprotocol.types import CompletionItem from lsprotocol.types import CompletionList +from lsprotocol.types import CompletionParams +from lsprotocol.types import DidChangeTextDocumentParams +from lsprotocol.types import DidCloseTextDocumentParams +from lsprotocol.types import DidOpenTextDocumentParams from lsprotocol.types import Hover +from lsprotocol.types import HoverParams from lsprotocol.types import Position from lsprotocol.types import Range +from lsprotocol.types import TextDocumentContentChangeEvent_Type1 +from lsprotocol.types import TextDocumentIdentifier +from lsprotocol.types import TextDocumentItem +from lsprotocol.types import VersionedTextDocumentIdentifier from pygls.workspace import Document from pytest_lsp import LanguageClient from pytest_lsp import make_test_client @@ -316,18 +325,54 @@ async def completion_request( ext = pathlib.Path(Uri.to_fs_path(test_uri)).suffix lang_id = "python" if ext == ".py" else "rst" - client.notify_did_open(test_uri, lang_id, contents) + client.text_document_did_open( + DidOpenTextDocumentParams( + text_document=TextDocumentItem( + uri=test_uri, language_id=lang_id, version=1, text=contents + ) + ) + ) lines = contents.split("\n") line = len(lines) - 1 insertion_point = len(lines[-1]) - client.notify_did_change(test_uri, text, line, insertion_point), + new_lines = text.split("\n") + num_new_lines = len(new_lines) - 1 + num_new_chars = len(new_lines[-1]) + + if num_new_lines > 0: + end_char = num_new_chars + else: + end_char = insertion_point + num_new_chars + + client.text_document_did_change( + DidChangeTextDocumentParams( + text_document=VersionedTextDocumentIdentifier(uri=test_uri, version=2), + content_changes=[ + TextDocumentContentChangeEvent_Type1( + text=text, + range=Range( + start=Position(line=line, character=insertion_point), + end=Position(line=line + num_new_lines, character=end_char), + ), + ) + ], + ) + ), character = character or insertion_point + len(text) - response = await client.completion_request(test_uri, line, character) + response = await client.text_document_completion_async( + CompletionParams( + text_document=TextDocumentIdentifier(uri=test_uri), + position=Position(line=line, character=character), + ) + ) + + client.text_document_did_close( + DidCloseTextDocumentParams(text_document=TextDocumentIdentifier(uri=test_uri)) + ) - client.notify_did_close(test_uri) return response @@ -361,8 +406,23 @@ async def hover_request( ext = pathlib.Path(Uri.to_fs_path(test_uri)).suffix lang_id = "python" if ext == ".py" else "rst" - client.notify_did_open(test_uri, lang_id, text) - response = await client.hover_request(test_uri, line, character) + client.text_document_did_open( + DidOpenTextDocumentParams( + text_document=TextDocumentItem( + uri=test_uri, language_id=lang_id, version=1, text=text + ) + ) + ) + + response = await client.text_document_hover_async( + HoverParams( + text_document=TextDocumentIdentifier(uri=test_uri), + position=Position(line=line, character=character), + ) + ) + + client.text_document_did_close( + DidCloseTextDocumentParams(text_document=TextDocumentIdentifier(uri=test_uri)) + ) - client.notify_did_close(test_uri) return response diff --git a/lib/esbonio/setup.cfg b/lib/esbonio/setup.cfg index 0fbc69ff7..e14ec3961 100644 --- a/lib/esbonio/setup.cfg +++ b/lib/esbonio/setup.cfg @@ -50,12 +50,12 @@ console_scripts = test = mock; python_version<"3.8" pytest - pytest-lsp + pytest-lsp>=0.3 pytest-cov pytest-timeout typecheck = mypy - pytest-lsp + pytest-lsp>=0.3 types-appdirs types-docutils types-pygments diff --git a/lib/esbonio/tests/sphinx-default/conftest.py b/lib/esbonio/tests/sphinx-default/conftest.py index d7036358f..1439740bc 100644 --- a/lib/esbonio/tests/sphinx-default/conftest.py +++ b/lib/esbonio/tests/sphinx-default/conftest.py @@ -6,9 +6,11 @@ import pygls.uris as uri import pytest import pytest_lsp +from lsprotocol.types import InitializeParams from pygls.protocol import default_converter from pytest_lsp import ClientServerConfig from pytest_lsp import LanguageClient +from pytest_lsp import client_capabilities from esbonio.lsp.sphinx import InitializationOptions from esbonio.lsp.sphinx import SphinxServerConfig @@ -49,27 +51,30 @@ def converter(): @pytest_lsp.fixture( scope="session", - config=[ - ClientServerConfig( - client="visual_studio_code", - client_factory=make_esbonio_client, - server_command=[sys.executable, *SERVER_CMD], - initialization_options=InitializationOptions( - server=SphinxServerConfig(log_level=LOG_LEVEL) - ), - root_uri=uri.from_fs_path(str(root_path)), - ), - ClientServerConfig( - client="neovim", - client_factory=make_esbonio_client, - server_command=[sys.executable, *SERVER_CMD], + params=["visual_studio_code", "neovim"], + config=ClientServerConfig( + client_factory=make_esbonio_client, + server_command=[sys.executable, *SERVER_CMD], + ), +) +async def client(request, lsp_client: LanguageClient): + # Existing test cases depend on this being set. + lsp_client.root_uri = uri.from_fs_path(str(root_path)) + + await lsp_client.initialize_session( + InitializeParams( + capabilities=client_capabilities(request.param), initialization_options=InitializationOptions( server=SphinxServerConfig(log_level=LOG_LEVEL) ), - root_uri=uri.from_fs_path(str(root_path)), - ), - ], -) -async def client(client_: LanguageClient): + root_uri=lsp_client.root_uri, + ) + ) + # Wait for the server to initialize. - await client_.wait_for_notification("esbonio/buildComplete") + await lsp_client.wait_for_notification("esbonio/buildComplete") + + yield + + # Teardown + await lsp_client.shutdown_session() diff --git a/lib/esbonio/tests/sphinx-default/test_sd_directives.py b/lib/esbonio/tests/sphinx-default/test_sd_directives.py index 98dd1b2ca..1a8f60b38 100644 --- a/lib/esbonio/tests/sphinx-default/test_sd_directives.py +++ b/lib/esbonio/tests/sphinx-default/test_sd_directives.py @@ -4,12 +4,13 @@ from typing import Set import pytest +from lsprotocol.types import ImplementationParams from lsprotocol.types import MarkupContent from lsprotocol.types import MarkupKind from lsprotocol.types import Position from lsprotocol.types import Range +from lsprotocol.types import TextDocumentIdentifier from pytest_lsp import LanguageClient -from pytest_lsp import check from esbonio.lsp.testing import completion_request from esbonio.lsp.testing import hover_request @@ -92,8 +93,6 @@ async def test_directive_completions( assert set() == items & unexpected - check.completion_items(client, results.items) - @pytest.mark.asyncio @pytest.mark.parametrize( @@ -176,7 +175,7 @@ async def test_directive_completion_resolve( # Server should not be filling out docs by default assert item.documentation is None, "Unexpected documentation text." - item = await client.completion_item_resolve_request(item) + item = await client.completion_item_resolve_async(item) assert isinstance(item.documentation, MarkupContent) assert item.documentation.kind == MarkupKind.Markdown @@ -253,8 +252,6 @@ async def test_directive_option_completions( assert expected == items & expected assert set() == items & unexpected - check.completion_items(client, results.items) - @pytest.mark.asyncio @pytest.mark.parametrize( @@ -514,7 +511,12 @@ async def test_directive_implementation( test_uri = client.root_uri + f"/{uri}" - results = await client.implementation_request(test_uri, line, character) + results = await client.text_document_implementation_async( + ImplementationParams( + text_document=TextDocumentIdentifier(uri=test_uri), + position=Position(line=line, character=character), + ) + ) if expected is None: assert len(results) == 0 diff --git a/lib/esbonio/tests/sphinx-default/test_sd_roles.py b/lib/esbonio/tests/sphinx-default/test_sd_roles.py index 3a20493ac..948139a1e 100644 --- a/lib/esbonio/tests/sphinx-default/test_sd_roles.py +++ b/lib/esbonio/tests/sphinx-default/test_sd_roles.py @@ -6,10 +6,11 @@ from typing import Tuple import pytest +from lsprotocol.types import ImplementationParams from lsprotocol.types import Position from lsprotocol.types import Range +from lsprotocol.types import TextDocumentIdentifier from pytest_lsp import LanguageClient -from pytest_lsp import check from esbonio.lsp.testing import completion_request from esbonio.lsp.testing import hover_request @@ -94,8 +95,6 @@ async def test_role_completions( assert expected == items & expected assert set() == items & unexpected - check.completion_items(client, results.items) - @pytest.mark.asyncio @pytest.mark.parametrize( @@ -469,7 +468,12 @@ async def test_roles_implementation( test_uri = client.root_uri + f"/{uri}" - results = await client.implementation_request(test_uri, line, character) + results = await client.text_document_implementation_async( + ImplementationParams( + text_document=TextDocumentIdentifier(uri=test_uri), + position=Position(line=line, character=character), + ) + ) if expected is None: assert len(results) == 0 diff --git a/lib/esbonio/tests/sphinx-default/test_sd_sphinx.py b/lib/esbonio/tests/sphinx-default/test_sd_sphinx.py index 1834f7486..89cb86299 100644 --- a/lib/esbonio/tests/sphinx-default/test_sd_sphinx.py +++ b/lib/esbonio/tests/sphinx-default/test_sd_sphinx.py @@ -6,16 +6,29 @@ import appdirs import pygls.uris as uri import pytest +from lsprotocol.types import ClientCapabilities +from lsprotocol.types import DeleteFilesParams from lsprotocol.types import Diagnostic from lsprotocol.types import DiagnosticSeverity +from lsprotocol.types import DidChangeTextDocumentParams +from lsprotocol.types import DidCloseTextDocumentParams +from lsprotocol.types import DidOpenTextDocumentParams +from lsprotocol.types import DidSaveTextDocumentParams from lsprotocol.types import DocumentLink +from lsprotocol.types import DocumentLinkParams +from lsprotocol.types import ExecuteCommandParams +from lsprotocol.types import FileDelete +from lsprotocol.types import InitializeParams from lsprotocol.types import MessageType from lsprotocol.types import Position from lsprotocol.types import Range +from lsprotocol.types import TextDocumentContentChangeEvent_Type2 +from lsprotocol.types import TextDocumentIdentifier +from lsprotocol.types import TextDocumentItem +from lsprotocol.types import VersionedTextDocumentIdentifier from pygls import IS_WIN from pytest_lsp import ClientServerConfig from pytest_lsp import LanguageClient -from pytest_lsp import check from pytest_lsp import make_client_server from pytest_lsp import make_test_client @@ -87,7 +100,9 @@ async def test_document_links( """Ensure that we handle ``textDocument/documentLink`` requests correctly.""" test_uri = client.root_uri + uri - links = await client.document_link_request(test_uri) + links = await client.text_document_document_link_async( + DocumentLinkParams(text_document=TextDocumentIdentifier(uri=test_uri)) + ) assert len(links) == len(expected) @@ -98,8 +113,6 @@ async def test_document_links( assert target == actual.target assert expected.tooltip == actual.tooltip - check.document_links(client, links) - @pytest.mark.asyncio @pytest.mark.timeout(10) @@ -260,19 +273,24 @@ async def test_initialization( setattr(options, to_snake_case(key), str(path)) config = ClientServerConfig( - server_command=command, - root_uri=root_uri, - initialization_options=InitializationOptions(sphinx=options), client_factory=make_esbonio_client, + server_command=command, ) test = make_client_server(config) try: - await test.start() + test.start() + await test.client.initialize_session( + InitializeParams( + capabilities=ClientCapabilities(), + root_uri=root_uri, + initialization_options=InitializationOptions(sphinx=options), + ) + ) await test.client.wait_for_notification("esbonio/buildComplete") - configuration = await test.client.execute_command_request( - ESBONIO_SERVER_CONFIGURATION + configuration = await test.client.workspace_execute_command_async( + ExecuteCommandParams(command=ESBONIO_SERVER_CONFIGURATION) ) # Test some default behaviours. @@ -304,6 +322,7 @@ async def test_initialization( assert actual.src_dir == resolve_path(expected.src_dir, root_path) finally: + await test.client.shutdown_session() await test.stop() @@ -317,21 +336,26 @@ async def test_initialization_build_dir(converter): with tempfile.TemporaryDirectory() as build_dir: config = ClientServerConfig( - server_command=[sys.executable, "-m", "esbonio"], - root_uri=root_uri, - initialization_options=InitializationOptions( - sphinx=SphinxConfig(build_dir=build_dir) - ), client_factory=make_esbonio_client, + server_command=[sys.executable, "-m", "esbonio"], ) test = make_client_server(config) try: - await test.start() + test.start() + await test.client.initialize_session( + InitializeParams( + capabilities=ClientCapabilities(), + root_uri=root_uri, + initialization_options=InitializationOptions( + sphinx=SphinxConfig(build_dir=build_dir) + ), + ) + ) await test.client.wait_for_notification("esbonio/buildComplete") - configuration = await test.client.execute_command_request( - ESBONIO_SERVER_CONFIGURATION, + configuration = await test.client.workspace_execute_command_async( + ExecuteCommandParams(command=ESBONIO_SERVER_CONFIGURATION) ) assert len(test.client.messages) == 0 @@ -356,6 +380,7 @@ async def test_initialization_build_dir(converter): assert actual.build_dir == str(pathlib.Path(build_dir, "html")) finally: + await test.client.shutdown_session() await test.stop() @@ -368,21 +393,26 @@ async def test_initialization_build_dir_workspace_var(converter): root_uri = uri.from_fs_path(str(root_path)) config = ClientServerConfig( - server_command=[sys.executable, "-m", "esbonio"], - root_uri=root_uri, - initialization_options=InitializationOptions( - sphinx=SphinxConfig(build_dir="${workspaceRoot}/_build") - ), client_factory=make_esbonio_client, + server_command=[sys.executable, "-m", "esbonio"], ) test = make_client_server(config) try: - await test.start() + test.start() + await test.client.initialize_session( + InitializeParams( + capabilities=ClientCapabilities(), + root_uri=root_uri, + initialization_options=InitializationOptions( + sphinx=SphinxConfig(build_dir="${workspaceRoot}/_build") + ), + ) + ) - configuration = await test.client.execute_command_request( - ESBONIO_SERVER_CONFIGURATION, + configuration = await test.client.workspace_execute_command_async( + ExecuteCommandParams(command=ESBONIO_SERVER_CONFIGURATION) ) assert len(test.client.messages) == 0 @@ -407,6 +437,7 @@ async def test_initialization_build_dir_workspace_var(converter): assert actual.build_dir == str(pathlib.Path(root_path, "_build", "html")) finally: + await test.client.shutdown_session() await test.stop() @@ -419,21 +450,26 @@ async def test_initialization_build_dir_workspace_folder(converter): root_uri = uri.from_fs_path(str(root_path)) config = ClientServerConfig( - server_command=[sys.executable, "-m", "esbonio"], - root_uri=root_uri, - initialization_options=InitializationOptions( - sphinx=SphinxConfig(build_dir="${workspaceFolder}/_build") - ), client_factory=make_esbonio_client, + server_command=[sys.executable, "-m", "esbonio"], ) test = make_client_server(config) try: - await test.start() + test.start() + await test.client.initialize_session( + InitializeParams( + capabilities=ClientCapabilities(), + root_uri=root_uri, + initialization_options=InitializationOptions( + sphinx=SphinxConfig(build_dir="${workspaceFolder}/_build") + ), + ) + ) - configuration = await test.client.execute_command_request( - ESBONIO_SERVER_CONFIGURATION, + configuration = await test.client.workspace_execute_command_async( + ExecuteCommandParams(command=ESBONIO_SERVER_CONFIGURATION) ) assert len(test.client.messages) == 0 @@ -458,6 +494,7 @@ async def test_initialization_build_dir_workspace_folder(converter): assert actual.build_dir == str(pathlib.Path(root_path, "_build", "html")) finally: + await test.client.shutdown_session() await test.stop() @@ -470,21 +507,26 @@ async def test_initialization_build_dir_confdir(converter): root_uri = uri.from_fs_path(str(root_path)) config = ClientServerConfig( - server_command=[sys.executable, "-m", "esbonio"], - root_uri=root_uri, - initialization_options=InitializationOptions( - sphinx=SphinxConfig(build_dir="${confDir}/../_build") - ), client_factory=make_esbonio_client, + server_command=[sys.executable, "-m", "esbonio"], ) test = make_client_server(config) try: - await test.start() + test.start() + await test.client.initialize_session( + InitializeParams( + capabilities=ClientCapabilities(), + root_uri=root_uri, + initialization_options=InitializationOptions( + sphinx=SphinxConfig(build_dir="${confDir}/../_build") + ), + ) + ) - configuration = await test.client.execute_command_request( - ESBONIO_SERVER_CONFIGURATION, + configuration = await test.client.workspace_execute_command_async( + ExecuteCommandParams(command=ESBONIO_SERVER_CONFIGURATION) ) assert len(test.client.messages) == 0 @@ -506,6 +548,7 @@ async def test_initialization_build_dir_confdir(converter): assert actual.src_dir == str(root_path) assert actual.build_dir == str(expected_dir) finally: + await test.client.shutdown_session() await test.stop() @@ -518,20 +561,25 @@ async def test_initialization_sphinx_error(): root_uri = uri.from_fs_path(str(root_path)) config = ClientServerConfig( - server_command=[sys.executable, "-m", "esbonio"], - root_uri=root_uri, client_factory=make_esbonio_client, - initialization_options=InitializationOptions( - server=SphinxServerConfig(log_level="debug") - ), + server_command=[sys.executable, "-m", "esbonio"], ) test = make_client_server(config) try: - await test.start() + test.start() + await test.client.initialize_session( + InitializeParams( + capabilities=ClientCapabilities(), + root_uri=root_uri, + initialization_options=InitializationOptions( + server=SphinxServerConfig(log_level="debug") + ), + ) + ) - configuration = await test.client.execute_command_request( - ESBONIO_SERVER_CONFIGURATION, + configuration = await test.client.workspace_execute_command_async( + ExecuteCommandParams(command=ESBONIO_SERVER_CONFIGURATION) ) assert "sphinx" in configuration @@ -552,6 +600,7 @@ async def test_initialization_sphinx_error(): ) finally: + await test.client.shutdown_session() await test.stop() @@ -570,20 +619,25 @@ async def test_initialization_build_error(): index_rst.unlink() config = ClientServerConfig( - server_command=[sys.executable, "-m", "esbonio"], - root_uri=root_uri, client_factory=make_esbonio_client, - initialization_options=InitializationOptions( - server=SphinxServerConfig(log_level="debug") - ), + server_command=[sys.executable, "-m", "esbonio"], ) test = make_client_server(config) try: - await test.start() + test.start() + await test.client.initialize_session( + InitializeParams( + capabilities=ClientCapabilities(), + root_uri=root_uri, + initialization_options=InitializationOptions( + server=SphinxServerConfig(log_level="debug") + ), + ) + ) - configuration = await test.client.execute_command_request( - ESBONIO_SERVER_CONFIGURATION, + configuration = await test.client.workspace_execute_command_async( + ExecuteCommandParams(command=ESBONIO_SERVER_CONFIGURATION) ) assert "sphinx" in configuration @@ -595,6 +649,7 @@ async def test_initialization_build_error(): assert diagnostic.severity == DiagnosticSeverity.Error finally: + await test.client.shutdown_session() await test.stop() @@ -607,21 +662,26 @@ async def test_initialization_missing_conf(): root_uri = uri.from_fs_path(root_dir) config = ClientServerConfig( - server_command=[sys.executable, "-m", "esbonio"], - root_uri=root_uri, client_factory=make_esbonio_client, - initialization_options=InitializationOptions( - server=SphinxServerConfig(log_level="debug") - ), + server_command=[sys.executable, "-m", "esbonio"], ) test = make_client_server(config) try: - await test.start() + test.start() + await test.client.initialize_session( + InitializeParams( + capabilities=ClientCapabilities(), + root_uri=root_uri, + initialization_options=InitializationOptions( + server=SphinxServerConfig(log_level="debug") + ), + ) + ) - configuration = await test.client.execute_command_request( - ESBONIO_SERVER_CONFIGURATION, + configuration = await test.client.workspace_execute_command_async( + ExecuteCommandParams(command=ESBONIO_SERVER_CONFIGURATION) ) assert "sphinx" in configuration @@ -633,6 +693,7 @@ async def test_initialization_missing_conf(): assert message.message.startswith("Unable to find your 'conf.py'") finally: + await test.client.shutdown_session() await test.stop() @@ -645,19 +706,26 @@ async def test_initialization_verbosity(converter): root_uri = uri.from_fs_path(str(root_path)) config = ClientServerConfig( - server_command=[sys.executable, "-m", "esbonio"], - root_uri=root_uri, - initialization_options=InitializationOptions(sphinx=SphinxConfig(verbosity=2)), client_factory=make_esbonio_client, + server_command=[sys.executable, "-m", "esbonio"], ) test = make_client_server(config) try: - await test.start() + test.start() + await test.client.initialize_session( + InitializeParams( + capabilities=ClientCapabilities(), + root_uri=root_uri, + initialization_options=InitializationOptions( + sphinx=SphinxConfig(verbosity=2) + ), + ) + ) - configuration = await test.client.execute_command_request( - ESBONIO_SERVER_CONFIGURATION, + configuration = await test.client.workspace_execute_command_async( + ExecuteCommandParams(command=ESBONIO_SERVER_CONFIGURATION) ) assert len(test.client.messages) == 0 @@ -672,6 +740,7 @@ async def test_initialization_verbosity(converter): ) finally: + await test.client.shutdown_session() await test.stop() @@ -684,21 +753,26 @@ async def test_initialization_hide_sphinx_output(converter): root_uri = uri.from_fs_path(str(root_path)) config = ClientServerConfig( - server_command=[sys.executable, "-m", "esbonio"], - root_uri=root_uri, - initialization_options=InitializationOptions( - server=SphinxServerConfig(hide_sphinx_output=True) - ), client_factory=make_esbonio_client, + server_command=[sys.executable, "-m", "esbonio"], ) test = make_client_server(config) try: - await test.start() + test.start() + await test.client.initialize_session( + InitializeParams( + capabilities=ClientCapabilities(), + root_uri=root_uri, + initialization_options=InitializationOptions( + server=SphinxServerConfig(hide_sphinx_output=True) + ), + ) + ) - configuration = await test.client.execute_command_request( - ESBONIO_SERVER_CONFIGURATION, + configuration = await test.client.workspace_execute_command_async( + ExecuteCommandParams(command=ESBONIO_SERVER_CONFIGURATION) ) assert len(test.client.messages) == 0 @@ -710,6 +784,7 @@ async def test_initialization_hide_sphinx_output(converter): assert len(test.client.log_messages) == 0 finally: + await test.client.shutdown_session() await test.stop() @@ -722,19 +797,26 @@ async def test_initialization_silent(converter): root_uri = uri.from_fs_path(str(root_path)) config = ClientServerConfig( - server_command=[sys.executable, "-m", "esbonio"], - root_uri=root_uri, - initialization_options=InitializationOptions(sphinx=SphinxConfig(silent=True)), client_factory=make_esbonio_client, + server_command=[sys.executable, "-m", "esbonio"], ) test = make_client_server(config) try: - await test.start() + test.start() + await test.client.initialize_session( + InitializeParams( + capabilities=ClientCapabilities(), + root_uri=root_uri, + initialization_options=InitializationOptions( + sphinx=SphinxConfig(silent=True) + ), + ) + ) - configuration = await test.client.execute_command_request( - ESBONIO_SERVER_CONFIGURATION, + configuration = await test.client.workspace_execute_command_async( + ExecuteCommandParams(command=ESBONIO_SERVER_CONFIGURATION) ) assert len(test.client.messages) == 0 @@ -746,6 +828,7 @@ async def test_initialization_silent(converter): assert len(test.client.log_messages) == 0 finally: + await test.client.shutdown_session() await test.stop() @@ -758,19 +841,26 @@ async def test_initialization_quiet(converter): root_uri = uri.from_fs_path(str(root_path)) config = ClientServerConfig( - server_command=[sys.executable, "-m", "esbonio"], - root_uri=root_uri, - initialization_options=InitializationOptions(sphinx=SphinxConfig(quiet=True)), client_factory=make_esbonio_client, + server_command=[sys.executable, "-m", "esbonio"], ) test = make_client_server(config) try: - await test.start() + test.start() + await test.client.initialize_session( + InitializeParams( + capabilities=ClientCapabilities(), + root_uri=root_uri, + initialization_options=InitializationOptions( + sphinx=SphinxConfig(quiet=True) + ), + ) + ) - configuration = await test.client.execute_command_request( - ESBONIO_SERVER_CONFIGURATION, + configuration = await test.client.workspace_execute_command_async( + ExecuteCommandParams(command=ESBONIO_SERVER_CONFIGURATION) ) assert len(test.client.messages) == 0 @@ -787,6 +877,7 @@ async def test_initialization_quiet(converter): ) finally: + await test.client.shutdown_session() await test.stop() @@ -864,21 +955,33 @@ async def test_diagnostics(good, bad, expected): f.write(good) config = ClientServerConfig( - server_command=[sys.executable, "-m", "esbonio"], - root_uri=uri.from_fs_path(str(workspace_root)), client_factory=make_esbonio_client, - initialization_options=InitializationOptions( - server=SphinxServerConfig(log_level="debug") - ), + server_command=[sys.executable, "-m", "esbonio"], ) test = make_client_server(config) try: - await test.start() + test.start() + await test.client.initialize_session( + InitializeParams( + capabilities=ClientCapabilities(), + root_uri=uri.from_fs_path(str(workspace_root)), + initialization_options=InitializationOptions( + server=SphinxServerConfig(log_level="debug") + ), + ) + ) + await test.client.wait_for_notification("esbonio/buildComplete") - test.client.notify_did_open(test_uri, "rst", good) + test.client.text_document_did_open( + DidOpenTextDocumentParams( + text_document=TextDocumentItem( + uri=test_uri, language_id="rst", version=1, text=good + ) + ) + ) # Change the file so that it's in the "bad" state, we should see a diagnostic # reporting the issue. @@ -886,8 +989,18 @@ async def test_diagnostics(good, bad, expected): with test_path.open("w") as f: f.write(bad) - test.client.notify_did_change(test_uri, bad) - test.client.notify_did_save(test_uri, bad) + test.client.text_document_did_change( + DidChangeTextDocumentParams( + text_document=VersionedTextDocumentIdentifier(uri=test_uri, version=2), + content_changes=[TextDocumentContentChangeEvent_Type2(text=bad)], + ) + ) + + test.client.text_document_did_save( + DidSaveTextDocumentParams( + text_document=TextDocumentIdentifier(uri=test_uri), text=bad + ) + ) await test.client.lsp.wait_for_notification_async("esbonio/buildComplete") actual = test.client.diagnostics[test_uri][0] @@ -901,18 +1014,34 @@ async def test_diagnostics(good, bad, expected): f.write(good) # Undo the changes, we should see the diagnostic removed. - test.client.notify_did_change(test_uri, good) - test.client.notify_did_save(test_uri, good) + test.client.text_document_did_change( + DidChangeTextDocumentParams( + text_document=VersionedTextDocumentIdentifier(uri=test_uri, version=3), + content_changes=[TextDocumentContentChangeEvent_Type2(text=good)], + ) + ) + + test.client.text_document_did_save( + DidSaveTextDocumentParams( + text_document=TextDocumentIdentifier(uri=test_uri), text=good + ) + ) # Ensure that we remove any resolved diagnostics. await test.client.lsp.wait_for_notification_async("esbonio/buildComplete") assert len(test.client.diagnostics[test_uri]) == 0 - test.client.notify_did_close(test_uri) + test.client.text_document_did_close( + DidCloseTextDocumentParams( + text_document=TextDocumentIdentifier(uri=test_uri) + ) + ) # Cleanup finally: test_path.unlink() + + await test.client.shutdown_session() await test.stop() @@ -973,28 +1102,47 @@ async def test_live_build_clears_diagnostics(good, bad, expected): f.write(good) config = ClientServerConfig( - server_command=[sys.executable, "-m", "esbonio"], - root_uri=uri.from_fs_path(str(workspace_root)), client_factory=make_esbonio_client, - initialization_options=InitializationOptions( - server=SphinxServerConfig(enable_live_preview=True) - ), + server_command=[sys.executable, "-m", "esbonio"], ) test = make_client_server(config) try: - await test.start() + test.start() + await test.client.initialize_session( + InitializeParams( + capabilities=ClientCapabilities(), + root_uri=uri.from_fs_path(str(workspace_root)), + initialization_options=InitializationOptions( + server=SphinxServerConfig(enable_live_preview=True) + ), + ) + ) await test.client.wait_for_notification("esbonio/buildComplete") - test.client.notify_did_open(test_uri, "rst", good) + test.client.text_document_did_open( + DidOpenTextDocumentParams( + text_document=TextDocumentItem( + uri=test_uri, language_id="rst", version=1, text=good + ) + ) + ) # Change the file so that it's in the bad state, we should see a diagnostic # reporting the issue. # Note: We don't have to update the file on disk since in live preview mode the # server should be injecting the latest content into the build. - test.client.notify_did_change(test_uri, bad) - await test.client.execute_command_request(ESBONIO_SERVER_BUILD) + test.client.text_document_did_change( + DidChangeTextDocumentParams( + text_document=VersionedTextDocumentIdentifier(uri=test_uri, version=2), + content_changes=[TextDocumentContentChangeEvent_Type2(text=bad)], + ) + ) + + await test.client.workspace_execute_command_async( + ExecuteCommandParams(command=ESBONIO_SERVER_BUILD) + ) actual = test.client.diagnostics[test_uri][0] @@ -1004,14 +1152,29 @@ async def test_live_build_clears_diagnostics(good, bad, expected): assert actual.source == expected.source # Undo the changes, we should see the diagnostic removed. - test.client.notify_did_change(test_uri, good) - await test.client.execute_command_request(ESBONIO_SERVER_BUILD) + test.client.text_document_did_change( + DidChangeTextDocumentParams( + text_document=VersionedTextDocumentIdentifier(uri=test_uri, version=3), + content_changes=[TextDocumentContentChangeEvent_Type2(text=good)], + ) + ) + + await test.client.workspace_execute_command_async( + ExecuteCommandParams(command=ESBONIO_SERVER_BUILD) + ) + assert len(test.client.diagnostics[test_uri]) == 0 - test.client.notify_did_close(test_uri) + test.client.text_document_did_close( + DidCloseTextDocumentParams( + text_document=TextDocumentIdentifier(uri=test_uri) + ) + ) finally: test_path.unlink() + + await test.client.shutdown_session() await test.stop() @@ -1078,26 +1241,51 @@ async def test_delete_clears_diagnostics(): test_uri = test_uri.lower() config = ClientServerConfig( - server_command=[sys.executable, "-m", "esbonio"], - root_uri=uri.from_fs_path(str(workspace_root)), client_factory=make_esbonio_client, - initialization_options=InitializationOptions( - server=SphinxServerConfig(log_level="debug") - ), + server_command=[sys.executable, "-m", "esbonio"], ) test = make_client_server(config) try: - await test.start() + test.start() + await test.client.initialize_session( + InitializeParams( + capabilities=ClientCapabilities(), + root_uri=uri.from_fs_path(str(workspace_root)), + initialization_options=InitializationOptions( + server=SphinxServerConfig(log_level="debug") + ), + ) + ) await test.client.wait_for_notification("esbonio/buildComplete") - test.client.notify_did_open(test_uri, "rst", good) - test.client.notify_did_change(test_uri, bad) + test.client.text_document_did_open( + DidOpenTextDocumentParams( + text_document=TextDocumentItem( + uri=test_uri, language_id="rst", version=1, text=good + ) + ) + ) + + # Change the file so that it's in the bad state, we should see a diagnostic + # reporting the issue. + # Note: We don't have to update the file on disk since in live preview mode the + # server should be injecting the latest content into the build. + test.client.text_document_did_change( + DidChangeTextDocumentParams( + text_document=VersionedTextDocumentIdentifier(uri=test_uri, version=2), + content_changes=[TextDocumentContentChangeEvent_Type2(text=bad)], + ) + ) with test_path.open("w") as f: f.write(bad) - test.client.notify_did_save(test_uri, text=bad) + test.client.text_document_did_save( + DidSaveTextDocumentParams( + text_document=TextDocumentIdentifier(uri=test_uri), text=bad + ) + ) await test.client.lsp.wait_for_notification_async("esbonio/buildComplete") actual = test.client.diagnostics[test_uri][0] @@ -1109,7 +1297,9 @@ async def test_delete_clears_diagnostics(): # Delete the file, we should see a rebuild and the diagnostic be removed. test_path.unlink() - await test.client.notify_did_delete_files(test_uri) + test.client.workspace_did_delete_files( + DeleteFilesParams(files=[FileDelete(uri=test_uri)]) + ) await test.client.lsp.wait_for_notification_async("esbonio/buildComplete") assert len(test.client.diagnostics[test_uri]) == 0 @@ -1119,6 +1309,8 @@ async def test_delete_clears_diagnostics(): test_path.unlink() index_path.unlink() + + await test.client.shutdown_session() await test.stop() @@ -1132,20 +1324,27 @@ async def test_preview_default(): root_uri = uri.from_fs_path(str(root_path)) config = ClientServerConfig( - server_command=[sys.executable, "-m", "esbonio"], - root_uri=root_uri, client_factory=make_esbonio_client, - initialization_options=InitializationOptions( - server=SphinxServerConfig(log_level="debug") - ), + server_command=[sys.executable, "-m", "esbonio"], ) test = make_client_server(config) try: - await test.start() + test.start() + await test.client.initialize_session( + InitializeParams( + capabilities=ClientCapabilities(), + root_uri=root_uri, + initialization_options=InitializationOptions( + server=SphinxServerConfig(log_level="debug") + ), + ) + ) - result = await test.client.execute_command_request(ESBONIO_SERVER_PREVIEW) + result = await test.client.workspace_execute_command_async( + ExecuteCommandParams(command=ESBONIO_SERVER_PREVIEW) + ) assert "port" in result port = result["port"] @@ -1158,6 +1357,7 @@ async def test_preview_default(): assert params.external, "Expected 'external' flag to be set" finally: + await test.client.shutdown_session() await test.stop() @@ -1171,20 +1371,27 @@ async def test_preview_no_show(): root_uri = uri.from_fs_path(str(root_path)) config = ClientServerConfig( - server_command=[sys.executable, "-m", "esbonio"], - root_uri=root_uri, client_factory=make_esbonio_client, - initialization_options=InitializationOptions( - server=SphinxServerConfig(log_level="debug") - ), + server_command=[sys.executable, "-m", "esbonio"], ) test = make_client_server(config) try: - await test.start() + test.start() + await test.client.initialize_session( + InitializeParams( + capabilities=ClientCapabilities(), + root_uri=root_uri, + initialization_options=InitializationOptions( + server=SphinxServerConfig(log_level="debug") + ), + ) + ) - result = await test.client.execute_command_request( - ESBONIO_SERVER_PREVIEW, {"show": False} + result = await test.client.workspace_execute_command_async( + ExecuteCommandParams( + command=ESBONIO_SERVER_PREVIEW, arguments=[{"show": False}] + ) ) assert "port" in result @@ -1194,6 +1401,7 @@ async def test_preview_no_show(): assert len(test.client.shown_documents) == 0 finally: + await test.client.shutdown_session() await test.stop() @@ -1207,20 +1415,27 @@ async def test_preview_multiple_calls(): root_uri = uri.from_fs_path(str(root_path)) config = ClientServerConfig( - server_command=[sys.executable, "-m", "esbonio"], - root_uri=root_uri, client_factory=make_esbonio_client, - initialization_options=InitializationOptions( - server=SphinxServerConfig(log_level="debug") - ), + server_command=[sys.executable, "-m", "esbonio"], ) test = make_client_server(config) try: - await test.start() + test.start() + await test.client.initialize_session( + InitializeParams( + capabilities=ClientCapabilities(), + root_uri=root_uri, + initialization_options=InitializationOptions( + server=SphinxServerConfig(log_level="debug") + ), + ) + ) - result = await test.client.execute_command_request( - ESBONIO_SERVER_PREVIEW, {"show": False} + result = await test.client.workspace_execute_command_async( + ExecuteCommandParams( + command=ESBONIO_SERVER_PREVIEW, arguments=[{"show": False}] + ) ) assert "port" in result @@ -1230,8 +1445,10 @@ async def test_preview_multiple_calls(): assert len(test.client.messages) == 0 assert len(test.client.shown_documents) == 0 - result = await test.client.execute_command_request( - ESBONIO_SERVER_PREVIEW, {"show": False} + result = await test.client.workspace_execute_command_async( + ExecuteCommandParams( + command=ESBONIO_SERVER_PREVIEW, arguments=[{"show": False}] + ) ) assert "port" in result @@ -1241,6 +1458,7 @@ async def test_preview_multiple_calls(): assert len(test.client.shown_documents) == 0 finally: + await test.client.shutdown_session() await test.stop() @@ -1254,19 +1472,26 @@ async def test_preview_wrong_builder(builder): root_uri = uri.from_fs_path(str(root_path)) config = ClientServerConfig( - server_command=[sys.executable, "-m", "esbonio"], - root_uri=root_uri, client_factory=make_esbonio_client, - initialization_options=InitializationOptions( - sphinx=SphinxConfig(builder_name=builder) - ), + server_command=[sys.executable, "-m", "esbonio"], ) test = make_client_server(config) try: - await test.start() + test.start() + await test.client.initialize_session( + InitializeParams( + capabilities=ClientCapabilities(), + root_uri=root_uri, + initialization_options=InitializationOptions( + sphinx=SphinxConfig(builder_name=builder) + ), + ) + ) - result = await test.client.execute_command_request(ESBONIO_SERVER_PREVIEW) + result = await test.client.workspace_execute_command_async( + ExecuteCommandParams(command=ESBONIO_SERVER_PREVIEW) + ) assert result == {} assert len(test.client.messages) == 1 @@ -1278,6 +1503,7 @@ async def test_preview_wrong_builder(builder): ) finally: + await test.client.shutdown_session() await test.stop() diff --git a/lib/esbonio/tests/sphinx-default/test_sd_sphinx_codeblocks.py b/lib/esbonio/tests/sphinx-default/test_sd_sphinx_codeblocks.py index 6c8c75432..cccaa87e2 100644 --- a/lib/esbonio/tests/sphinx-default/test_sd_sphinx_codeblocks.py +++ b/lib/esbonio/tests/sphinx-default/test_sd_sphinx_codeblocks.py @@ -2,7 +2,6 @@ import pytest from pytest_lsp import LanguageClient -from pytest_lsp import check from esbonio.lsp.testing import completion_request from esbonio.lsp.testing import directive_argument_patterns @@ -48,8 +47,6 @@ async def test_codeblock_completions(client: LanguageClient, text: str, setup): assert expected == items & expected assert set() == items & unexpected - check.completion_items(client, results.items) - @pytest.mark.asyncio @pytest.mark.parametrize( @@ -102,5 +99,3 @@ async def test_include_argument_completions(client: LanguageClient, text, setup) assert expected == items & expected assert set() == items & unexpected - - check.completion_items(client, results.items) diff --git a/lib/esbonio/tests/sphinx-default/test_sd_sphinx_domains.py b/lib/esbonio/tests/sphinx-default/test_sd_sphinx_domains.py index c3b19bdc4..7e88df437 100644 --- a/lib/esbonio/tests/sphinx-default/test_sd_sphinx_domains.py +++ b/lib/esbonio/tests/sphinx-default/test_sd_sphinx_domains.py @@ -1,11 +1,12 @@ import itertools import pytest +from lsprotocol.types import DefinitionParams from lsprotocol.types import Location from lsprotocol.types import Position from lsprotocol.types import Range +from lsprotocol.types import TextDocumentIdentifier from pytest_lsp import LanguageClient -from pytest_lsp import check from esbonio.lsp.testing import completion_request from esbonio.lsp.testing import intersphinx_target_patterns @@ -226,8 +227,6 @@ async def test_role_target_completions(client: LanguageClient, text: str, setup) assert expected == items & expected assert set() == items & unexpected - check.completion_items(client, results.items) - WELCOME_LABEL = Location( uri="index.rst", @@ -306,7 +305,12 @@ async def test_role_target_definitions( """Ensure that we can offer the correct definitions for role targets.""" test_uri = client.root_uri + f"/{path}" - results = await client.definition_request(test_uri, line, character) + results = await client.text_document_definition_async( + DefinitionParams( + text_document=TextDocumentIdentifier(uri=test_uri), + position=Position(line=line, character=character), + ) + ) if expected is None: assert len(results) == 0 diff --git a/lib/esbonio/tests/sphinx-default/test_sd_sphinx_images.py b/lib/esbonio/tests/sphinx-default/test_sd_sphinx_images.py index 1fd0cd1f6..f2f6c3c6c 100644 --- a/lib/esbonio/tests/sphinx-default/test_sd_sphinx_images.py +++ b/lib/esbonio/tests/sphinx-default/test_sd_sphinx_images.py @@ -2,7 +2,6 @@ import pytest from pytest_lsp import LanguageClient -from pytest_lsp import check from esbonio.lsp.testing import completion_request from esbonio.lsp.testing import directive_argument_patterns @@ -75,5 +74,3 @@ async def test_include_argument_completions(client: LanguageClient, text: str, s assert expected == items & expected assert set() == items & unexpected - - check.completion_items(client, results.items) diff --git a/lib/esbonio/tests/sphinx-default/test_sd_sphinx_includes.py b/lib/esbonio/tests/sphinx-default/test_sd_sphinx_includes.py index 6210e9977..1375640bc 100644 --- a/lib/esbonio/tests/sphinx-default/test_sd_sphinx_includes.py +++ b/lib/esbonio/tests/sphinx-default/test_sd_sphinx_includes.py @@ -1,11 +1,12 @@ import itertools import pytest +from lsprotocol.types import DefinitionParams from lsprotocol.types import Location from lsprotocol.types import Position from lsprotocol.types import Range +from lsprotocol.types import TextDocumentIdentifier from pytest_lsp import LanguageClient -from pytest_lsp import check from esbonio.lsp.testing import completion_request from esbonio.lsp.testing import directive_argument_patterns @@ -113,7 +114,12 @@ async def test_include_definitions( ``include::`` directive arguments.""" test_uri = client.root_uri + f"/{path}" - results = await client.definition_request(test_uri, line, character) + results = await client.text_document_definition_async( + DefinitionParams( + text_document=TextDocumentIdentifier(uri=test_uri), + position=Position(line=line, character=character), + ) + ) if expected is None: assert len(results) == 0 @@ -179,5 +185,3 @@ async def test_include_argument_completions(client: LanguageClient, text, setup) assert expected == items & expected assert set() == items & unexpected - - check.completion_items(client, results.items) diff --git a/lib/esbonio/tests/sphinx-default/test_sd_sphinx_roles.py b/lib/esbonio/tests/sphinx-default/test_sd_sphinx_roles.py index 95597d776..ded332e1a 100644 --- a/lib/esbonio/tests/sphinx-default/test_sd_sphinx_roles.py +++ b/lib/esbonio/tests/sphinx-default/test_sd_sphinx_roles.py @@ -2,7 +2,6 @@ import pytest from pytest_lsp import LanguageClient -from pytest_lsp import check from esbonio.lsp.testing import completion_request from esbonio.lsp.testing import role_target_patterns @@ -77,5 +76,3 @@ async def test_download_completions(client: LanguageClient, text, setup): assert expected == items & expected assert set() == items & unexpected - - check.completion_items(client, results.items) diff --git a/lib/esbonio/tests/sphinx-default/test_sd_symbols.py b/lib/esbonio/tests/sphinx-default/test_sd_symbols.py index cd5f58920..1a0e883d2 100644 --- a/lib/esbonio/tests/sphinx-default/test_sd_symbols.py +++ b/lib/esbonio/tests/sphinx-default/test_sd_symbols.py @@ -3,7 +3,9 @@ import pytest from lsprotocol.types import DocumentSymbol +from lsprotocol.types import DocumentSymbolParams from lsprotocol.types import SymbolKind +from lsprotocol.types import TextDocumentIdentifier from pytest_lsp import LanguageClient from esbonio.lsp.testing import range_from_str @@ -153,7 +155,9 @@ async def test_document_symbols( """Ensure that we handle ``textDocument/documentSymbols`` requests correctly""" test_uri = client.root_uri + f"/{filepath}" - actual = await client.document_symbols_request(test_uri) + actual = await client.text_document_document_symbol_async( + DocumentSymbolParams(text_document=TextDocumentIdentifier(uri=test_uri)) + ) if expected is None: assert actual is None diff --git a/lib/esbonio/tests/sphinx-extensions/conftest.py b/lib/esbonio/tests/sphinx-extensions/conftest.py index 1f0f6d748..805f435e7 100644 --- a/lib/esbonio/tests/sphinx-extensions/conftest.py +++ b/lib/esbonio/tests/sphinx-extensions/conftest.py @@ -6,8 +6,10 @@ import pygls.uris as uri import pytest import pytest_lsp +from lsprotocol.types import InitializeParams from pytest_lsp import ClientServerConfig from pytest_lsp import LanguageClient +from pytest_lsp import client_capabilities from esbonio.lsp.sphinx import InitializationOptions from esbonio.lsp.sphinx import SphinxServerConfig @@ -45,27 +47,30 @@ def event_loop(): @pytest_lsp.fixture( scope="session", - config=[ - ClientServerConfig( - client="visual_studio_code", - client_factory=make_esbonio_client, - server_command=[sys.executable, *SERVER_CMD], - initialization_options=InitializationOptions( - server=SphinxServerConfig(log_level=LOG_LEVEL) - ), - root_uri=uri.from_fs_path(str(root_path)), - ), - ClientServerConfig( - client="neovim", - client_factory=make_esbonio_client, - server_command=[sys.executable, *SERVER_CMD], + params=["visual_studio_code", "neovim"], + config=ClientServerConfig( + client_factory=make_esbonio_client, + server_command=[sys.executable, *SERVER_CMD], + ), +) +async def client(request, lsp_client: LanguageClient): + # Existing test cases depend on this being set. + lsp_client.root_uri = uri.from_fs_path(str(root_path)) + + await lsp_client.initialize_session( + InitializeParams( + capabilities=client_capabilities(request.param), initialization_options=InitializationOptions( server=SphinxServerConfig(log_level=LOG_LEVEL) ), - root_uri=uri.from_fs_path(str(root_path)), + root_uri=lsp_client.root_uri, ), - ], -) -async def client(client_: LanguageClient): + ) + # Wait for the server to initialize. - await client_.wait_for_notification("esbonio/buildComplete") + await lsp_client.wait_for_notification("esbonio/buildComplete") + + yield + + # Teardown + await lsp_client.shutdown_session() diff --git a/lib/esbonio/tests/sphinx-extensions/test_se_directives.py b/lib/esbonio/tests/sphinx-extensions/test_se_directives.py index b4364bb7c..5ac21131f 100644 --- a/lib/esbonio/tests/sphinx-extensions/test_se_directives.py +++ b/lib/esbonio/tests/sphinx-extensions/test_se_directives.py @@ -5,7 +5,6 @@ from lsprotocol.types import MarkupContent from lsprotocol.types import MarkupKind from pytest_lsp import LanguageClient -from pytest_lsp import check from esbonio.lsp.testing import completion_request @@ -72,8 +71,6 @@ async def test_directive_completions( assert set() == items & unexpected - check.completion_items(client, results.items) - @pytest.mark.asyncio @pytest.mark.parametrize( @@ -133,7 +130,7 @@ async def test_directive_completion_resolve( # Server should not be filling out docs by default assert item.documentation is None, "Unexpected documentation text." - item = await client.completion_item_resolve_request(item) + item = await client.completion_item_resolve_async(item) assert isinstance(item.documentation, MarkupContent) assert item.documentation.kind == MarkupKind.Markdown @@ -208,5 +205,3 @@ async def test_directive_option_completions( assert expected == items & expected assert set() == items & unexpected - - check.completion_items(client, results.items) diff --git a/lib/esbonio/tests/sphinx-extensions/test_se_roles.py b/lib/esbonio/tests/sphinx-extensions/test_se_roles.py index cdb50e6dd..b88000a3e 100644 --- a/lib/esbonio/tests/sphinx-extensions/test_se_roles.py +++ b/lib/esbonio/tests/sphinx-extensions/test_se_roles.py @@ -5,7 +5,6 @@ import pytest from pytest_lsp import LanguageClient -from pytest_lsp import check from esbonio.lsp.testing import completion_request from esbonio.lsp.testing import role_patterns @@ -84,5 +83,3 @@ async def test_role_completions( assert expected == items & expected assert set() == items & unexpected - - check.completion_items(client, results.items) diff --git a/lib/esbonio/tests/sphinx-extensions/test_se_sphinx.py b/lib/esbonio/tests/sphinx-extensions/test_se_sphinx.py index 8ce5f0ec7..5ed4e3212 100644 --- a/lib/esbonio/tests/sphinx-extensions/test_se_sphinx.py +++ b/lib/esbonio/tests/sphinx-extensions/test_se_sphinx.py @@ -5,10 +5,11 @@ import pytest from lsprotocol.types import DiagnosticSeverity from lsprotocol.types import DocumentLink +from lsprotocol.types import DocumentLinkParams from lsprotocol.types import Position from lsprotocol.types import Range +from lsprotocol.types import TextDocumentIdentifier from pytest_lsp import LanguageClient -from pytest_lsp import check @pytest.mark.asyncio @@ -56,7 +57,9 @@ async def test_document_links( """Ensure that we handle ``textDocument/documentLink`` requests correctly.""" test_uri = client.root_uri + uri - links = await client.document_link_request(test_uri) + links = await client.text_document_document_link_async( + DocumentLinkParams(text_document=TextDocumentIdentifier(uri=test_uri)) + ) expected_links = {link.target: link for link in expected} actual_links = {link.target: link for link in links} @@ -69,8 +72,6 @@ async def test_document_links( assert len(actual_links) == 0, f"Unexpected links {', '.join(actual_links.keys())}" - check.document_links(client, links) - @pytest.mark.asyncio async def test_docstring_diagnostics(client: LanguageClient): diff --git a/lib/esbonio/tests/sphinx-extensions/test_se_sphinx_codeblocks.py b/lib/esbonio/tests/sphinx-extensions/test_se_sphinx_codeblocks.py index 0be4a666a..9efde85b3 100644 --- a/lib/esbonio/tests/sphinx-extensions/test_se_sphinx_codeblocks.py +++ b/lib/esbonio/tests/sphinx-extensions/test_se_sphinx_codeblocks.py @@ -2,7 +2,6 @@ import pytest from pytest_lsp import LanguageClient -from pytest_lsp import check from esbonio.lsp.testing import completion_request from esbonio.lsp.testing import directive_argument_patterns @@ -48,5 +47,3 @@ async def test_include_argument_completions(client: LanguageClient, text, setup) assert expected == items & expected assert set() == items & unexpected - - check.completion_items(client, results.items) diff --git a/lib/esbonio/tests/sphinx-extensions/test_se_sphinx_domains.py b/lib/esbonio/tests/sphinx-extensions/test_se_sphinx_domains.py index 4cf933962..853b60dae 100644 --- a/lib/esbonio/tests/sphinx-extensions/test_se_sphinx_domains.py +++ b/lib/esbonio/tests/sphinx-extensions/test_se_sphinx_domains.py @@ -2,7 +2,6 @@ import pytest from pytest_lsp import LanguageClient -from pytest_lsp import check from esbonio.lsp.testing import completion_request from esbonio.lsp.testing import intersphinx_target_patterns @@ -241,5 +240,3 @@ async def test_role_target_completions(client: LanguageClient, text: str, setup) assert expected == items & expected assert set() == items & unexpected - - check.completion_items(client, results.items) diff --git a/lib/esbonio/tests/sphinx-extensions/test_se_sphinx_roles.py b/lib/esbonio/tests/sphinx-extensions/test_se_sphinx_roles.py index c32b3c980..c90a5df2a 100644 --- a/lib/esbonio/tests/sphinx-extensions/test_se_sphinx_roles.py +++ b/lib/esbonio/tests/sphinx-extensions/test_se_sphinx_roles.py @@ -2,7 +2,6 @@ import pytest from pytest_lsp import LanguageClient -from pytest_lsp import check from esbonio.lsp.testing import completion_request from esbonio.lsp.testing import role_target_patterns @@ -54,5 +53,3 @@ async def test_download_completions(client: LanguageClient, text, setup): assert expected == items & expected assert set() == items & unexpected - - check.completion_items(client, results.items) From bd110687a16df35aa74fe50b6986e396b6557d1f Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Fri, 19 May 2023 20:07:48 +0100 Subject: [PATCH 027/141] lsp: Use single `event_loop` definition --- lib/esbonio/tests/conftest.py | 18 ++++++++++++++++++ lib/esbonio/tests/sphinx-default/conftest.py | 13 ------------- .../tests/sphinx-extensions/conftest.py | 14 -------------- 3 files changed, 18 insertions(+), 27 deletions(-) create mode 100644 lib/esbonio/tests/conftest.py diff --git a/lib/esbonio/tests/conftest.py b/lib/esbonio/tests/conftest.py new file mode 100644 index 000000000..2ac9ce05e --- /dev/null +++ b/lib/esbonio/tests/conftest.py @@ -0,0 +1,18 @@ +import asyncio + +import pytest + + +@pytest.fixture(scope="session") +def event_loop(): + # We need to redefine the event_loop fixture to match the scope of our + # client_server fixture. + # + # https://github.com/pytest-dev/pytest-asyncio/issues/68#issuecomment-334083751 + + loop = asyncio.get_event_loop_policy().new_event_loop() + asyncio.set_event_loop(loop) + + yield loop + + loop.close() diff --git a/lib/esbonio/tests/sphinx-default/conftest.py b/lib/esbonio/tests/sphinx-default/conftest.py index 1439740bc..72ca457c1 100644 --- a/lib/esbonio/tests/sphinx-default/conftest.py +++ b/lib/esbonio/tests/sphinx-default/conftest.py @@ -1,4 +1,3 @@ -import asyncio import os import pathlib import sys @@ -32,18 +31,6 @@ LOG_LEVEL = os.environ.get("SERVER_LOG_LEVEL", "error") -@pytest.fixture(scope="session") -def event_loop(): - # We need to redefine the event_loop fixture to match the scope of our - # client_server fixture. - # - # https://github.com/pytest-dev/pytest-asyncio/issues/68#issuecomment-334083751 - - loop = asyncio.get_event_loop_policy().new_event_loop() - yield loop - loop.close() - - @pytest.fixture(scope="session") def converter(): return default_converter() diff --git a/lib/esbonio/tests/sphinx-extensions/conftest.py b/lib/esbonio/tests/sphinx-extensions/conftest.py index 805f435e7..ad3e30b71 100644 --- a/lib/esbonio/tests/sphinx-extensions/conftest.py +++ b/lib/esbonio/tests/sphinx-extensions/conftest.py @@ -1,10 +1,8 @@ -import asyncio import os import pathlib import sys import pygls.uris as uri -import pytest import pytest_lsp from lsprotocol.types import InitializeParams from pytest_lsp import ClientServerConfig @@ -33,18 +31,6 @@ LOG_LEVEL = os.environ.get("SERVER_LOG_LEVEL", "error") -@pytest.fixture(scope="session") -def event_loop(): - # We need to redefine the event_loop fixture to match the scope of our - # client_server fixture. - # - # https://github.com/pytest-dev/pytest-asyncio/issues/68#issuecomment-334083751 - - loop = asyncio.get_event_loop_policy().new_event_loop() - yield loop - loop.close() - - @pytest_lsp.fixture( scope="session", params=["visual_studio_code", "neovim"], From 95ee623f41e54738d8fdbc0482439101db388727 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Fri, 19 May 2023 20:11:17 +0100 Subject: [PATCH 028/141] lsp: Ensure tests use correct event loop While not strictly required for the tests to function, this prevents the `pytest-asyncio` loop not closed warning --- lib/esbonio/tests/unit_tests/test_rst.py | 48 ++++++++++++------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/lib/esbonio/tests/unit_tests/test_rst.py b/lib/esbonio/tests/unit_tests/test_rst.py index f4fcb1577..009ec3f6c 100644 --- a/lib/esbonio/tests/unit_tests/test_rst.py +++ b/lib/esbonio/tests/unit_tests/test_rst.py @@ -6,11 +6,11 @@ from esbonio.lsp.sphinx import SphinxLanguageServer -def test_get_feature_by_string(): +def test_get_feature_by_string(event_loop): """Ensure that a language feature can be retrieved by a string, but raises a deprecation warning.""" - rst = RstLanguageServer(name="esbonio-test", version="v0.1") + rst = RstLanguageServer(name="esbonio-test", version="v0.1", loop=event_loop) expected = Roles(rst) rst.add_feature(expected) @@ -22,10 +22,10 @@ def test_get_feature_by_string(): assert actual is expected -def test_get_feature_by_cls(): +def test_get_feature_by_cls(event_loop): """Ensure that a language feature can be retrieved via its class definition.""" - rst = RstLanguageServer(name="esbonio-test", version="v0.1") + rst = RstLanguageServer(name="esbonio-test", version="v0.1", loop=event_loop) expected = Roles(rst) rst.add_feature(expected) @@ -34,11 +34,11 @@ def test_get_feature_by_cls(): assert actual is expected -def test_get_missing_feature_by_string(): +def test_get_missing_feature_by_string(event_loop): """Ensure that if a language feature is missing ``None`` is returned, but a deprecation warning is raised.""" - rst = RstLanguageServer(name="esbonio-test", version="v0.1") + rst = RstLanguageServer(name="esbonio-test", version="v0.1", loop=event_loop) with pytest.deprecated_call(): actual = rst.get_feature("xxx") @@ -46,72 +46,72 @@ def test_get_missing_feature_by_string(): assert actual is None -def test_get_missing_feature_by_cls(): +def test_get_missing_feature_by_cls(event_loop): """Ensure that if a language feature is missing ``None`` is returned.""" - rst = RstLanguageServer(name="esbonio-test", version="v0.1") + rst = RstLanguageServer(name="esbonio-test", version="v0.1", loop=event_loop) assert rst.get_feature(Roles) is None -def test_get_setup_arguments_rst_server(): +def test_get_setup_arguments_rst_server(event_loop): """Ensure that we can correctly construct the set of arguments to pass to a module's setup function.""" def setup(rst: RstLanguageServer): ... - server = RstLanguageServer(name="esbonio-test", version="v0.1") + server = RstLanguageServer(name="esbonio-test", version="v0.1", loop=event_loop) args = _get_setup_arguments(server, setup, "modname") assert args == {"rst": server} -def test_get_setup_arguments_server_superclass(): +def test_get_setup_arguments_server_superclass(event_loop): """If the setup function is not compatible with the given server it should be skipped.""" def setup(rst: SphinxLanguageServer): ... - server = RstLanguageServer(name="esbonio-test", version="v0.1") + server = RstLanguageServer(name="esbonio-test", version="v0.1", loop=event_loop) args = _get_setup_arguments(server, setup, "modname") assert args is None -def test_get_setup_arguments_sphinx_server(): +def test_get_setup_arguments_sphinx_server(event_loop): """Ensure that we can correctly construct the set of arguments to pass to a module's setup function.""" def setup(ls: SphinxLanguageServer): ... - server = SphinxLanguageServer(name="esbonio-test", version="v0.1") + server = SphinxLanguageServer(name="esbonio-test", version="v0.1", loop=event_loop) args = _get_setup_arguments(server, setup, "modname") assert args == {"ls": server} -def test_get_setup_arguments_server_subclass(): +def test_get_setup_arguments_server_subclass(event_loop): """Ensure that we can correctly construct the set of arguments to pass to a module's setup function.""" def setup(ls: RstLanguageServer): ... - server = SphinxLanguageServer(name="esbonio-test", version="v0.1") + server = SphinxLanguageServer(name="esbonio-test", version="v0.1", loop=event_loop) args = _get_setup_arguments(server, setup, "modname") assert args == {"ls": server} -def test_get_setup_arguments_server_and_feature(): +def test_get_setup_arguments_server_and_feature(event_loop): """We should also be able to automatically pass the correct language features""" def setup(rst: RstLanguageServer, rs: Roles): ... - server = RstLanguageServer(name="esbonio-test", version="v0.1") + server = RstLanguageServer(name="esbonio-test", version="v0.1", loop=event_loop) roles = Roles(server) server.add_feature(roles) @@ -121,13 +121,13 @@ def setup(rst: RstLanguageServer, rs: Roles): assert args == {"rst": server, "rs": roles} -def test_get_setup_arguments_feature_only(): +def test_get_setup_arguments_feature_only(event_loop): """It should be possible to request just language features.""" def setup(roles: Roles): ... - server = RstLanguageServer(name="esbonio-test", version="v0.1") + server = RstLanguageServer(name="esbonio-test", version="v0.1", loop=event_loop) roles = Roles(server) server.add_feature(roles) @@ -137,25 +137,25 @@ def setup(roles: Roles): assert args == {"roles": roles} -def test_get_setup_arguments_missing_feature(): +def test_get_setup_arguments_missing_feature(event_loop): """If a requested feature is not available the function should be skipped.""" def setup(rst: RstLanguageServer, rs: Roles): ... - server = RstLanguageServer(name="esbonio-test", version="v0.1") + server = RstLanguageServer(name="esbonio-test", version="v0.1", loop=event_loop) args = _get_setup_arguments(server, setup, "modname") assert args is None -def test_get_setup_arguments_wrong_type(): +def test_get_setup_arguments_wrong_type(event_loop): """If an unsupported type is requested it should be skipped.""" def setup(rst: RstLanguageServer, rs: int): ... - server = RstLanguageServer(name="esbonio-test", version="v0.1") + server = RstLanguageServer(name="esbonio-test", version="v0.1", loop=event_loop) args = _get_setup_arguments(server, setup, "modname") assert args is None From 527d17f393912df48b330b94e8d117bce16ba924 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Fri, 19 May 2023 20:11:42 +0100 Subject: [PATCH 029/141] vscode: Add pytest launch configuration --- .vscode/launch.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.vscode/launch.json b/.vscode/launch.json index c3d356b47..59445bf34 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -87,6 +87,16 @@ "python": "${command:python.interpreterPath}", "cwd": "${workspaceFolder}/docs" }, + { + "name": "pytest: esbonio", + "type": "python", + "request": "launch", + "module": "pytest", + "justMyCode": false, + "subProcess": false, + "python": "${command:python.interpreterPath}", + "cwd": "${workspaceFolder}/lib/esbonio" + }, { "name": "Python: Attach", "type": "python", From 3c624591b5f81db87c71879133d461683a242be1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 May 2023 15:00:57 +0000 Subject: [PATCH 030/141] build(deps-dev): bump webpack from 5.82.1 to 5.84.1 in /code Bumps [webpack](https://github.com/webpack/webpack) from 5.82.1 to 5.84.1. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.82.1...v5.84.1) --- updated-dependencies: - dependency-name: webpack dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- code/package-lock.json | 46 +++++++++++++++++++++--------------------- code/package.json | 2 +- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/code/package-lock.json b/code/package-lock.json index 9dd83b77f..7b8ec165c 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -23,7 +23,7 @@ "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", "typescript": "^5.0.4", - "webpack": "^5.82.1", + "webpack": "^5.84.1", "webpack-cli": "^5.1.1" }, "engines": { @@ -430,9 +430,9 @@ } }, "node_modules/acorn-import-assertions": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.7.6.tgz", - "integrity": "sha512-FlVvVFA1TX6l3lp8VjDnYYq7R1nyW6x3svAt4nDgrWQ9SBaSh9CnbwgSUTasgfNfOG5HlM1ehugCvM+hjo56LA==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", "dev": true, "peerDependencies": { "acorn": "^8" @@ -1156,9 +1156,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.14.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.0.tgz", - "integrity": "sha512-+DCows0XNwLDcUhbFJPdlQEVnT2zXlCv7hPxemTz86/O+B/hCQ+mb7ydkPKiflpVraqLPCAfu7lDy+hBXueojw==", + "version": "5.14.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.1.tgz", + "integrity": "sha512-Vklwq2vDKtl0y/vtwjSesgJ5MYS7Etuk5txS8VdKL4AOS1aUlD96zqIfsOSLQsdv3xgMRbtkWM8eG9XDfKUPow==", "dev": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -3454,9 +3454,9 @@ } }, "node_modules/webpack": { - "version": "5.82.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.82.1.tgz", - "integrity": "sha512-C6uiGQJ+Gt4RyHXXYt+v9f+SN1v83x68URwgxNQ98cvH8kxiuywWGP4XeNZ1paOzZ63aY3cTciCEQJNFUljlLw==", + "version": "5.84.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.84.1.tgz", + "integrity": "sha512-ZP4qaZ7vVn/K8WN/p990SGATmrL1qg4heP/MrVneczYtpDGJWlrgZv55vxaV2ul885Kz+25MP2kSXkPe3LZfmg==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", @@ -3465,10 +3465,10 @@ "@webassemblyjs/wasm-edit": "^1.11.5", "@webassemblyjs/wasm-parser": "^1.11.5", "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", + "acorn-import-assertions": "^1.9.0", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.14.0", + "enhanced-resolve": "^5.14.1", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -4224,9 +4224,9 @@ "dev": true }, "acorn-import-assertions": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.7.6.tgz", - "integrity": "sha512-FlVvVFA1TX6l3lp8VjDnYYq7R1nyW6x3svAt4nDgrWQ9SBaSh9CnbwgSUTasgfNfOG5HlM1ehugCvM+hjo56LA==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", "dev": true, "requires": {} }, @@ -4770,9 +4770,9 @@ } }, "enhanced-resolve": { - "version": "5.14.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.0.tgz", - "integrity": "sha512-+DCows0XNwLDcUhbFJPdlQEVnT2zXlCv7hPxemTz86/O+B/hCQ+mb7ydkPKiflpVraqLPCAfu7lDy+hBXueojw==", + "version": "5.14.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.1.tgz", + "integrity": "sha512-Vklwq2vDKtl0y/vtwjSesgJ5MYS7Etuk5txS8VdKL4AOS1aUlD96zqIfsOSLQsdv3xgMRbtkWM8eG9XDfKUPow==", "dev": true, "requires": { "graceful-fs": "^4.2.4", @@ -6502,9 +6502,9 @@ } }, "webpack": { - "version": "5.82.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.82.1.tgz", - "integrity": "sha512-C6uiGQJ+Gt4RyHXXYt+v9f+SN1v83x68URwgxNQ98cvH8kxiuywWGP4XeNZ1paOzZ63aY3cTciCEQJNFUljlLw==", + "version": "5.84.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.84.1.tgz", + "integrity": "sha512-ZP4qaZ7vVn/K8WN/p990SGATmrL1qg4heP/MrVneczYtpDGJWlrgZv55vxaV2ul885Kz+25MP2kSXkPe3LZfmg==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.3", @@ -6513,10 +6513,10 @@ "@webassemblyjs/wasm-edit": "^1.11.5", "@webassemblyjs/wasm-parser": "^1.11.5", "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", + "acorn-import-assertions": "^1.9.0", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.14.0", + "enhanced-resolve": "^5.14.1", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", diff --git a/code/package.json b/code/package.json index 162f1b3f9..b327f0d5e 100644 --- a/code/package.json +++ b/code/package.json @@ -45,7 +45,7 @@ "path-browserify": "^1.0.1", "ts-loader": "^9.4.2", "typescript": "^5.0.4", - "webpack": "^5.82.1", + "webpack": "^5.84.1", "webpack-cli": "^5.1.1" }, "engines": { From e8da48bc408cdfd7b468a2d02d1a4655ce21cc33 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 May 2023 15:01:14 +0000 Subject: [PATCH 031/141] build(deps-dev): bump ts-loader from 9.4.2 to 9.4.3 in /code Bumps [ts-loader](https://github.com/TypeStrong/ts-loader) from 9.4.2 to 9.4.3. - [Release notes](https://github.com/TypeStrong/ts-loader/releases) - [Changelog](https://github.com/TypeStrong/ts-loader/blob/main/CHANGELOG.md) - [Commits](https://github.com/TypeStrong/ts-loader/compare/v9.4.2...v9.4.3) --- updated-dependencies: - dependency-name: ts-loader dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- code/package-lock.json | 14 +++++++------- code/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/code/package-lock.json b/code/package-lock.json index 7b8ec165c..ed0d69650 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -21,7 +21,7 @@ "@vscode/vsce": "^2.19.0", "mocha": "^10.2.0", "path-browserify": "^1.0.1", - "ts-loader": "^9.4.2", + "ts-loader": "^9.4.3", "typescript": "^5.0.4", "webpack": "^5.84.1", "webpack-cli": "^5.1.1" @@ -3212,9 +3212,9 @@ } }, "node_modules/ts-loader": { - "version": "9.4.2", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.2.tgz", - "integrity": "sha512-OmlC4WVmFv5I0PpaxYb+qGeGOdm5giHU7HwDDUjw59emP2UYMHy9fFSDcYgSNoH8sXcj4hGCSEhlDZ9ULeDraA==", + "version": "9.4.3", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.3.tgz", + "integrity": "sha512-n3hBnm6ozJYzwiwt5YRiJZkzktftRpMiBApHaJPoWLA+qetQBAXkHqCLM6nwSdRDimqVtA5ocIkcTRLMTt7yzA==", "dev": true, "dependencies": { "chalk": "^4.1.0", @@ -6309,9 +6309,9 @@ } }, "ts-loader": { - "version": "9.4.2", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.2.tgz", - "integrity": "sha512-OmlC4WVmFv5I0PpaxYb+qGeGOdm5giHU7HwDDUjw59emP2UYMHy9fFSDcYgSNoH8sXcj4hGCSEhlDZ9ULeDraA==", + "version": "9.4.3", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.3.tgz", + "integrity": "sha512-n3hBnm6ozJYzwiwt5YRiJZkzktftRpMiBApHaJPoWLA+qetQBAXkHqCLM6nwSdRDimqVtA5ocIkcTRLMTt7yzA==", "dev": true, "requires": { "chalk": "^4.1.0", diff --git a/code/package.json b/code/package.json index b327f0d5e..435a90266 100644 --- a/code/package.json +++ b/code/package.json @@ -43,7 +43,7 @@ "@vscode/vsce": "^2.19.0", "mocha": "^10.2.0", "path-browserify": "^1.0.1", - "ts-loader": "^9.4.2", + "ts-loader": "^9.4.3", "typescript": "^5.0.4", "webpack": "^5.84.1", "webpack-cli": "^5.1.1" From 6afa8b916aa5514d9508aad999be337cb9857e26 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Mon, 29 May 2023 18:36:07 +0100 Subject: [PATCH 032/141] lsp: Search workspace folders when creating a Sphinx app instance --- lib/esbonio/changes/467.enhancement.rst | 2 ++ lib/esbonio/esbonio/lsp/sphinx/__init__.py | 21 ++++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 lib/esbonio/changes/467.enhancement.rst diff --git a/lib/esbonio/changes/467.enhancement.rst b/lib/esbonio/changes/467.enhancement.rst new file mode 100644 index 000000000..d88ec2531 --- /dev/null +++ b/lib/esbonio/changes/467.enhancement.rst @@ -0,0 +1,2 @@ +When creating a Sphinx application instance, the language server will now look in all workspace folders choosing the first valid configuration it finds. +Failing that it will revert to its original behavior of looking in the ``workspaceRoot`` given by the client. diff --git a/lib/esbonio/esbonio/lsp/sphinx/__init__.py b/lib/esbonio/esbonio/lsp/sphinx/__init__.py index 05ab4ee13..57478bba4 100644 --- a/lib/esbonio/esbonio/lsp/sphinx/__init__.py +++ b/lib/esbonio/esbonio/lsp/sphinx/__init__.py @@ -313,13 +313,28 @@ def create_sphinx_app(self, options: InitializationOptions) -> Optional[Sphinx]: """Create a Sphinx application instance with the given config.""" sphinx = options.sphinx server = options.server - - self.logger.debug("Workspace root '%s'", self.workspace.root_uri) self.logger.debug( "User Config %s", json.dumps(self.converter.unstructure(sphinx), indent=2) ) - sphinx_config = sphinx.resolve(self.workspace.root_uri) + # Until true multi-root support can be implemented let's try each workspace + # folder and use the first valid configuration we can find. + for folder_uri in self.workspace.folders.keys(): + self.logger.debug("Workspace Folder: '%s'", folder_uri) + + try: + sphinx_config = sphinx.resolve(folder_uri) + break + except MissingConfigError: + self.logger.debug( + "No Sphinx conifg found in workspace folder: '%s'", folder_uri + ) + + # Not all clients use/support workspace folders, as a fallback, try the root_uri. + else: + self.logger.debug("Workspace root '%s'", self.workspace.root_uri) + sphinx_config = sphinx.resolve(self.workspace.root_uri) + self.sphinx_args = sphinx_config.to_application_args() self.logger.debug("Sphinx Args %s", json.dumps(self.sphinx_args, indent=2)) From 587cc9ae8debb0b12c5bae41308a40edf4dbefcd Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Wed, 31 May 2023 17:47:19 +0100 Subject: [PATCH 033/141] lsp: Correctly handle `initializationOptions` = `null` --- lib/esbonio/changes/586.fix.rst | 1 + lib/esbonio/esbonio/lsp/rst/__init__.py | 2 +- lib/esbonio/esbonio/lsp/sphinx/__init__.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 lib/esbonio/changes/586.fix.rst diff --git a/lib/esbonio/changes/586.fix.rst b/lib/esbonio/changes/586.fix.rst new file mode 100644 index 000000000..475878e0e --- /dev/null +++ b/lib/esbonio/changes/586.fix.rst @@ -0,0 +1 @@ +The server will no longer fail to handle the ``initialize`` request when clients set ``initializationOptions`` to ``null`` diff --git a/lib/esbonio/esbonio/lsp/rst/__init__.py b/lib/esbonio/esbonio/lsp/rst/__init__.py index f2494adf9..aa02a288a 100644 --- a/lib/esbonio/esbonio/lsp/rst/__init__.py +++ b/lib/esbonio/esbonio/lsp/rst/__init__.py @@ -429,7 +429,7 @@ def configuration(self) -> Dict[str, Any]: def initialize(self, params: InitializeParams): self.user_config = converter.structure( - params.initialization_options, InitializationOptions + params.initialization_options or {}, InitializationOptions ) setup_logging(self, self.user_config.server) diff --git a/lib/esbonio/esbonio/lsp/sphinx/__init__.py b/lib/esbonio/esbonio/lsp/sphinx/__init__.py index 57478bba4..3ab7f81fc 100644 --- a/lib/esbonio/esbonio/lsp/sphinx/__init__.py +++ b/lib/esbonio/esbonio/lsp/sphinx/__init__.py @@ -137,7 +137,7 @@ def configuration(self) -> Dict[str, Any]: def initialize(self, params: InitializeParams): super().initialize(params) self.user_config = self.converter.structure( - params.initialization_options, InitializationOptions + params.initialization_options or {}, InitializationOptions ) def initialized(self, params: InitializedParams): From a74f19322a23bbb7501440f4ba0a43e8753902f6 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Mon, 29 May 2023 23:35:34 +0100 Subject: [PATCH 034/141] Fix mypy pre-commit hook --- .pre-commit-config.yaml | 2 +- lib/esbonio/esbonio/lsp/testing.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index aa08a4685..7753a0e38 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -33,7 +33,7 @@ repos: args: [--config,lib/esbonio/pyproject.toml] additional_dependencies: - pygls - - pytest_lsp + - pytest_lsp>=0.3 - sphinx - types-appdirs - types-docutils diff --git a/lib/esbonio/esbonio/lsp/testing.py b/lib/esbonio/esbonio/lsp/testing.py index 8d69511f6..7ebd603cd 100644 --- a/lib/esbonio/esbonio/lsp/testing.py +++ b/lib/esbonio/esbonio/lsp/testing.py @@ -359,7 +359,7 @@ async def completion_request( ) ], ) - ), + ) character = character or insertion_point + len(text) response = await client.text_document_completion_async( From 301177f47dcb74c885bd6d45b4b0b5a971d0f239 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Jun 2023 15:03:04 +0000 Subject: [PATCH 035/141] build(deps-dev): bump typescript from 5.0.4 to 5.1.3 in /code Bumps [typescript](https://github.com/Microsoft/TypeScript) from 5.0.4 to 5.1.3. - [Release notes](https://github.com/Microsoft/TypeScript/releases) - [Commits](https://github.com/Microsoft/TypeScript/compare/v5.0.4...v5.1.3) --- updated-dependencies: - dependency-name: typescript dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- code/package-lock.json | 16 ++++++++-------- code/package.json | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/code/package-lock.json b/code/package-lock.json index ed0d69650..a6be332ce 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -22,7 +22,7 @@ "mocha": "^10.2.0", "path-browserify": "^1.0.1", "ts-loader": "^9.4.3", - "typescript": "^5.0.4", + "typescript": "^5.1.3", "webpack": "^5.84.1", "webpack-cli": "^5.1.1" }, @@ -3340,16 +3340,16 @@ } }, "node_modules/typescript": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz", + "integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=12.20" + "node": ">=14.17" } }, "node_modules/uc.micro": { @@ -6405,9 +6405,9 @@ } }, "typescript": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz", + "integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==", "dev": true }, "uc.micro": { diff --git a/code/package.json b/code/package.json index 435a90266..f079a17bd 100644 --- a/code/package.json +++ b/code/package.json @@ -44,7 +44,7 @@ "mocha": "^10.2.0", "path-browserify": "^1.0.1", "ts-loader": "^9.4.3", - "typescript": "^5.0.4", + "typescript": "^5.1.3", "webpack": "^5.84.1", "webpack-cli": "^5.1.1" }, From 4ba5351139d021c71c0f31fe9e511d1d5ca890f7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jun 2023 19:45:14 +0000 Subject: [PATCH 036/141] build(deps-dev): bump webpack-cli from 5.1.1 to 5.1.4 in /code Bumps [webpack-cli](https://github.com/webpack/webpack-cli) from 5.1.1 to 5.1.4. - [Release notes](https://github.com/webpack/webpack-cli/releases) - [Changelog](https://github.com/webpack/webpack-cli/blob/master/CHANGELOG.md) - [Commits](https://github.com/webpack/webpack-cli/compare/webpack-cli@5.1.1...webpack-cli@5.1.4) --- updated-dependencies: - dependency-name: webpack-cli dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- code/package-lock.json | 62 +++++++++++++++++++++--------------------- code/package.json | 2 +- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/code/package-lock.json b/code/package-lock.json index a6be332ce..2eb27c45b 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -24,7 +24,7 @@ "ts-loader": "^9.4.3", "typescript": "^5.1.3", "webpack": "^5.84.1", - "webpack-cli": "^5.1.1" + "webpack-cli": "^5.1.4" }, "engines": { "vscode": "^1.66.0" @@ -362,9 +362,9 @@ } }, "node_modules/@webpack-cli/configtest": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.0.tgz", - "integrity": "sha512-K/vuv72vpfSEZoo5KIU0a2FsEoYdW0DUMtMpB5X3LlUwshetMZRZRxB7sCsVji/lFaSxtQQ3aM9O4eMolXkU9w==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", "dev": true, "engines": { "node": ">=14.15.0" @@ -375,9 +375,9 @@ } }, "node_modules/@webpack-cli/info": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.1.tgz", - "integrity": "sha512-fE1UEWTwsAxRhrJNikE7v4EotYflkEhBL7EbajfkPlf6E37/2QshOy/D48Mw8G5XMFlQtS6YV42vtbG9zBpIQA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", "dev": true, "engines": { "node": ">=14.15.0" @@ -388,9 +388,9 @@ } }, "node_modules/@webpack-cli/serve": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.4.tgz", - "integrity": "sha512-0xRgjgDLdz6G7+vvDLlaRpFatJaJ69uTalZLRSMX5B3VUrDmXcrVA3+6fXXQgmYz7bY9AAgs348XQdmtLsK41A==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", "dev": true, "engines": { "node": ">=14.15.0" @@ -3501,15 +3501,15 @@ } }, "node_modules/webpack-cli": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.1.tgz", - "integrity": "sha512-OLJwVMoXnXYH2ncNGU8gxVpUtm3ybvdioiTvHgUyBuyMLKiVvWy+QObzBsMtp5pH7qQoEuWgeEUQ/sU3ZJFzAw==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", "dev": true, "dependencies": { "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^2.1.0", - "@webpack-cli/info": "^2.0.1", - "@webpack-cli/serve": "^2.0.4", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", "colorette": "^2.0.14", "commander": "^10.0.1", "cross-spawn": "^7.0.3", @@ -4185,23 +4185,23 @@ } }, "@webpack-cli/configtest": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.0.tgz", - "integrity": "sha512-K/vuv72vpfSEZoo5KIU0a2FsEoYdW0DUMtMpB5X3LlUwshetMZRZRxB7sCsVji/lFaSxtQQ3aM9O4eMolXkU9w==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", "dev": true, "requires": {} }, "@webpack-cli/info": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.1.tgz", - "integrity": "sha512-fE1UEWTwsAxRhrJNikE7v4EotYflkEhBL7EbajfkPlf6E37/2QshOy/D48Mw8G5XMFlQtS6YV42vtbG9zBpIQA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", "dev": true, "requires": {} }, "@webpack-cli/serve": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.4.tgz", - "integrity": "sha512-0xRgjgDLdz6G7+vvDLlaRpFatJaJ69uTalZLRSMX5B3VUrDmXcrVA3+6fXXQgmYz7bY9AAgs348XQdmtLsK41A==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", "dev": true, "requires": {} }, @@ -6534,15 +6534,15 @@ } }, "webpack-cli": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.1.tgz", - "integrity": "sha512-OLJwVMoXnXYH2ncNGU8gxVpUtm3ybvdioiTvHgUyBuyMLKiVvWy+QObzBsMtp5pH7qQoEuWgeEUQ/sU3ZJFzAw==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", "dev": true, "requires": { "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^2.1.0", - "@webpack-cli/info": "^2.0.1", - "@webpack-cli/serve": "^2.0.4", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", "colorette": "^2.0.14", "commander": "^10.0.1", "cross-spawn": "^7.0.3", diff --git a/code/package.json b/code/package.json index f079a17bd..52f15e016 100644 --- a/code/package.json +++ b/code/package.json @@ -46,7 +46,7 @@ "ts-loader": "^9.4.3", "typescript": "^5.1.3", "webpack": "^5.84.1", - "webpack-cli": "^5.1.1" + "webpack-cli": "^5.1.4" }, "engines": { "vscode": "^1.66.0" From 103fc22e3b639bd5bb51f0f1e2996ccb5b9a4f77 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Jun 2023 19:46:48 +0000 Subject: [PATCH 037/141] build(deps-dev): bump webpack from 5.84.1 to 5.86.0 in /code Bumps [webpack](https://github.com/webpack/webpack) from 5.84.1 to 5.86.0. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.84.1...v5.86.0) --- updated-dependencies: - dependency-name: webpack dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- code/package-lock.json | 14 +++++++------- code/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/code/package-lock.json b/code/package-lock.json index 2eb27c45b..5da793ce4 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -23,7 +23,7 @@ "path-browserify": "^1.0.1", "ts-loader": "^9.4.3", "typescript": "^5.1.3", - "webpack": "^5.84.1", + "webpack": "^5.86.0", "webpack-cli": "^5.1.4" }, "engines": { @@ -3454,9 +3454,9 @@ } }, "node_modules/webpack": { - "version": "5.84.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.84.1.tgz", - "integrity": "sha512-ZP4qaZ7vVn/K8WN/p990SGATmrL1qg4heP/MrVneczYtpDGJWlrgZv55vxaV2ul885Kz+25MP2kSXkPe3LZfmg==", + "version": "5.86.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.86.0.tgz", + "integrity": "sha512-3BOvworZ8SO/D4GVP+GoRC3fVeg5MO4vzmq8TJJEkdmopxyazGDxN8ClqN12uzrZW9Tv8EED8v5VSb6Sqyi0pg==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", @@ -6502,9 +6502,9 @@ } }, "webpack": { - "version": "5.84.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.84.1.tgz", - "integrity": "sha512-ZP4qaZ7vVn/K8WN/p990SGATmrL1qg4heP/MrVneczYtpDGJWlrgZv55vxaV2ul885Kz+25MP2kSXkPe3LZfmg==", + "version": "5.86.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.86.0.tgz", + "integrity": "sha512-3BOvworZ8SO/D4GVP+GoRC3fVeg5MO4vzmq8TJJEkdmopxyazGDxN8ClqN12uzrZW9Tv8EED8v5VSb6Sqyi0pg==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.3", diff --git a/code/package.json b/code/package.json index 52f15e016..cdf949104 100644 --- a/code/package.json +++ b/code/package.json @@ -45,7 +45,7 @@ "path-browserify": "^1.0.1", "ts-loader": "^9.4.3", "typescript": "^5.1.3", - "webpack": "^5.84.1", + "webpack": "^5.86.0", "webpack-cli": "^5.1.4" }, "engines": { From 58180da4351a26302ad6e0be7d19d5588b467761 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Fri, 2 Jun 2023 20:04:15 +0100 Subject: [PATCH 038/141] lsp: Scaffold next generation server This commit introduces what hopefully will become the language server that ships in `esbonio` v1. Currently, the server only does enough to accept an `initialize` request from a client while keeping most of the "good bits" from the previous architecture. --- lib/esbonio/esbonio/server/__main__.py | 5 + lib/esbonio/esbonio/server/cli.py | 103 +++++++++ lib/esbonio/esbonio/server/feature.py | 14 ++ lib/esbonio/esbonio/server/log.py | 182 +++++++++++++++ lib/esbonio/esbonio/server/server.py | 309 +++++++++++++++++++++++++ lib/esbonio/esbonio/server/setup.py | 76 ++++++ 6 files changed, 689 insertions(+) create mode 100644 lib/esbonio/esbonio/server/__main__.py create mode 100644 lib/esbonio/esbonio/server/cli.py create mode 100644 lib/esbonio/esbonio/server/feature.py create mode 100644 lib/esbonio/esbonio/server/log.py create mode 100644 lib/esbonio/esbonio/server/server.py create mode 100644 lib/esbonio/esbonio/server/setup.py diff --git a/lib/esbonio/esbonio/server/__main__.py b/lib/esbonio/esbonio/server/__main__.py new file mode 100644 index 000000000..0346df67d --- /dev/null +++ b/lib/esbonio/esbonio/server/__main__.py @@ -0,0 +1,5 @@ +import sys + +from esbonio.server.cli import main + +sys.exit(main()) diff --git a/lib/esbonio/esbonio/server/cli.py b/lib/esbonio/esbonio/server/cli.py new file mode 100644 index 000000000..5fef082f7 --- /dev/null +++ b/lib/esbonio/esbonio/server/cli.py @@ -0,0 +1,103 @@ +import argparse +import logging +import sys +import warnings +from typing import Optional +from typing import Sequence + +from pygls.protocol import default_converter + +from .log import LOG_NAMESPACE +from .log import MemoryHandler +from .server import EsbonioLanguageServer +from .server import __version__ +from .setup import create_language_server + + +def build_parser() -> argparse.ArgumentParser: + """Return an argument parser with the default command line options required for + main. + """ + + cli = argparse.ArgumentParser(description="The Esbonio language server") + cli.add_argument( + "-p", + "--port", + type=int, + default=None, + help="start a TCP instance of the language server listening on the given port.", + ) + cli.add_argument( + "--version", + action="version", + version=__version__, + help="print the current version and exit.", + ) + + modules = cli.add_argument_group( + "modules", "include/exclude language server modules." + ) + modules.add_argument( + "-i", + "--include", + metavar="MOD", + action="append", + default=[], + dest="included_modules", + help="include an additional module in the server configuration, can be given multiple times.", + ) + modules.add_argument( + "-e", + "--exclude", + metavar="MOD", + action="append", + default=[], + dest="excluded_modules", + help="exclude a module from the server configuration, can be given multiple times.", + ) + + return cli + + +def main(argv: Optional[Sequence[str]] = None): + """Standard main function for each of the default language servers.""" + + # Put these here to avoid circular import issues. + + cli = build_parser() + args = cli.parse_args(argv) + + modules = list() + + for mod in args.included_modules: + modules.append(mod) + + for mod in args.excluded_modules: + if mod in modules: + modules.remove(mod) + + # Ensure we can capture warnings. + logging.captureWarnings(True) + warnlog = logging.getLogger("py.warnings") + + if not sys.warnoptions: + warnings.simplefilter("default") # Enable capture of DeprecationWarnings + + # Setup a temporary logging handler that can cache messages until the language server + # is ready to forward them onto the client. + logger = logging.getLogger(LOG_NAMESPACE) + logger.setLevel(logging.DEBUG) + + handler = MemoryHandler() + handler.setLevel(logging.DEBUG) + logger.addHandler(handler) + warnlog.addHandler(handler) + + server = create_language_server( + EsbonioLanguageServer, modules, converter_factory=default_converter + ) + + if args.port: + server.start_tcp("localhost", args.port) + else: + server.start_io() diff --git a/lib/esbonio/esbonio/server/feature.py b/lib/esbonio/esbonio/server/feature.py new file mode 100644 index 000000000..4a5195c5c --- /dev/null +++ b/lib/esbonio/esbonio/server/feature.py @@ -0,0 +1,14 @@ +from __future__ import annotations + +import typing + +if typing.TYPE_CHECKING: + from .server import EsbonioLanguageServer + + +class LanguageFeature: + """Base class for language features.""" + + def __init__(self, server: EsbonioLanguageServer): + self.server = server + self.logger = server.logger.getChild(self.__class__.__name__) diff --git a/lib/esbonio/esbonio/server/log.py b/lib/esbonio/esbonio/server/log.py new file mode 100644 index 000000000..b8c08bcc3 --- /dev/null +++ b/lib/esbonio/esbonio/server/log.py @@ -0,0 +1,182 @@ +from __future__ import annotations + +import logging +import pathlib +import traceback +import typing +from typing import List +from typing import Tuple + +import pygls.uris as uri +from lsprotocol.types import Diagnostic +from lsprotocol.types import DiagnosticSeverity +from lsprotocol.types import DiagnosticTag +from lsprotocol.types import Position +from lsprotocol.types import Range + +if typing.TYPE_CHECKING: + from .server import EsbonioLanguageServer + from .server import ServerConfig + + +LOG_NAMESPACE = "esbonio" +LOG_LEVELS = { + "debug": logging.DEBUG, + "error": logging.ERROR, + "info": logging.INFO, +} + + +class LogFilter(logging.Filter): + """A log filter that accepts message from any of the listed logger names.""" + + def __init__(self, names): + self.names = names + + def filter(self, record): + return any(record.name == name for name in self.names) + + +class MemoryHandler(logging.Handler): + """A logging handler that caches messages in memory.""" + + def __init__(self): + super().__init__() + self.records: List[logging.LogRecord] = [] + + def emit(self, record: logging.LogRecord) -> None: + self.records.append(record) + + +class LspHandler(logging.Handler): + """A logging handler that will send log records to an LSP client.""" + + def __init__( + self, server: EsbonioLanguageServer, show_deprecation_warnings: bool = False + ): + super().__init__() + self.server = server + self.show_deprecation_warnings = show_deprecation_warnings + + def get_warning_path(self, warning: str) -> Tuple[str, List[str]]: + """Determine the filepath that the warning was emitted from.""" + + path, *parts = warning.split(":") + + # On windows the rest of the path will be in the first element of parts. + if pathlib.Path(warning).drive: + path += f":{parts.pop(0)}" + + return path, parts + + def handle_warning(self, record: logging.LogRecord): + """Publish warnings to the client as diagnostics.""" + + if not isinstance(record.args, tuple): + self.server.logger.debug( + "Unable to handle warning, expected tuple got: %s", record.args + ) + return + + # The way warnings are logged is different in Python 3.11+ + if len(record.args) == 0: + argument = record.msg + else: + argument = record.args[0] # type: ignore + + if not isinstance(argument, str): + self.server.logger.debug( + "Unable to handle warning, expected string got: %s", argument + ) + return + + warning, *_ = argument.split("\n") + path, (linenum, category, *msg) = self.get_warning_path(warning) + + category = category.strip() + message = ":".join(msg).strip() + + try: + line = int(linenum) + except ValueError: + line = 1 + self.server.logger.debug( + "Unable to parse line number: '%s'\n%s", linenum, traceback.format_exc() + ) + + tags = [] + if category == "DeprecationWarning": + tags.append(DiagnosticTag.Deprecated) + + diagnostic = Diagnostic( + range=Range( + start=Position(line=line - 1, character=0), + end=Position(line=line, character=0), + ), + message=message, + severity=DiagnosticSeverity.Warning, + tags=tags, + ) + + self.server.add_diagnostics("esbonio", uri.from_fs_path(path), diagnostic) + self.server.sync_diagnostics() + + def emit(self, record: logging.LogRecord) -> None: + """Sends the record to the client.""" + + # To avoid infinite recursions, it's simpler to just ignore all log records + # coming from pygls... + if "pygls" in record.name: + return + + if record.name == "py.warnings": + if not self.show_deprecation_warnings: + return + + self.handle_warning(record) + + log = self.format(record).strip() + self.server.show_message_log(log) + + +def setup_logging(server: EsbonioLanguageServer, config: ServerConfig): + """Setup logging to route log messages to the language client as + ``window/logMessage`` messages. + + Parameters + ---------- + server + The server to use to send messages + + config + The configuration to use + """ + + level = LOG_LEVELS[config.log_level] + + warnlog = logging.getLogger("py.warnings") + logger = logging.getLogger(LOG_NAMESPACE) + logger.setLevel(level) + + lsp_handler = LspHandler(server, config.show_deprecation_warnings) + lsp_handler.setLevel(level) + + if len(config.log_filter) > 0: + lsp_handler.addFilter(LogFilter(config.log_filter)) + + formatter = logging.Formatter("[%(name)s] %(message)s") + lsp_handler.setFormatter(formatter) + + # Look to see if there are any cached messages we should forward to the client. + for handler in logger.handlers: + if not isinstance(handler, MemoryHandler): + continue + + for record in handler.records: + if logger.isEnabledFor(record.levelno): + lsp_handler.emit(record) + + logger.removeHandler(handler) + + logger.addHandler(lsp_handler) + warnlog.addHandler(lsp_handler) diff --git a/lib/esbonio/esbonio/server/server.py b/lib/esbonio/esbonio/server/server.py new file mode 100644 index 000000000..8830f8209 --- /dev/null +++ b/lib/esbonio/esbonio/server/server.py @@ -0,0 +1,309 @@ +from __future__ import annotations + +import collections +import inspect +import logging +import typing +from typing import Any +from typing import Callable +from typing import Dict +from typing import List +from typing import Optional +from typing import Tuple +from typing import Type +from typing import TypeVar + +import attrs +import pygls.uris as Uri +from lsprotocol.types import Diagnostic +from lsprotocol.types import InitializeParams +from lsprotocol.types import LSPAny +from pygls import IS_WIN +from pygls.server import LanguageServer + +from .log import setup_logging + +if typing.TYPE_CHECKING: + from .feature import LanguageFeature + +__version__ = "0.16.1" +LF = TypeVar("LF", bound="LanguageFeature") + + +@attrs.define +class ServerConfig: + """Configuration options for the server.""" + + log_filter: List[str] = attrs.field(factory=list) + """A list of logger names to restrict output to.""" + + log_level: str = attrs.field(default="error") + """The logging level of server messages to display.""" + + show_deprecation_warnings: bool = attrs.field(default=False) + """Developer flag to enable deprecation warnings.""" + + +class EsbonioLanguageServer(LanguageServer): + """The Esbonio language server""" + + def __init__(self, logger: Optional[logging.Logger] = None, *args, **kwargs): + if "name" not in kwargs: + kwargs["name"] = "esbonio" + + if "version" not in kwargs: + kwargs["version"] = __version__ + + super().__init__(*args, **kwargs) + + self._diagnostics: Dict[Tuple[str, str], List[Diagnostic]] = {} + """Where we store and manage diagnostics.""" + + self._loaded_extensions: Dict[str, Any] = {} + """Record of server modules that have been loaded.""" + + self._features: Dict[Type[LanguageFeature], LanguageFeature] = {} + """The collection of language features registered with the server.""" + + self.logger = logger or logging.getLogger(__name__) + """The logger instance to use.""" + + self.converter = self.lsp._converter + """The cattrs converter instance we should use.""" + + self.initialization_options: Optional[LSPAny] = None + """The received initializaion options (if any)""" + + def initialize(self, params: InitializeParams): + self.initialization_options = params.initialization_options + + server_config = ServerConfig() + if self.initialization_options is not None: + try: + config = self.initialization_options.get("server", {}) + server_config = self.converter.structure(config, ServerConfig) + except Exception: + self.logger.error("Unable to parse server config", exc_info=True) + + setup_logging(self, server_config) + + def load_extension(self, name: str, setup: Callable): + """Load the given setup function as an extension. + + If an extension with the given ``name`` already exists, the given setup function + will be ignored. + + The ``setup`` function can declare dependencies in the form of type + annotations. + + .. code-block:: python + + from esbonio.lsp.roles import Roles + from esbonio.lsp.sphinx import SphinxLanguageServer + + def esbonio_setup(rst: SphinxLanguageServer, roles: Roles): + ... + + In this example the setup function is requesting instances of the + :class:`~esbonio.lsp.sphinx.SphinxLanguageServer` and the + :class:`~esbonio.lsp.roles.Roles` language feature. + + Parameters + ---------- + name + The name to give the extension + + setup + The setup function to call + """ + + if name in self._loaded_extensions: + self.logger.debug("Skipping extension '%s', already loaded", name) + return + + arguments = _get_setup_arguments(self, setup, name) + if not arguments: + return + + try: + setup(**arguments) + + self.logger.debug("Loaded extension '%s'", name) + self._loaded_extensions[name] = setup + except Exception: + self.logger.error("Unable to load extension '%s'", name, exc_info=True) + + def add_feature(self, feature: LanguageFeature): + """Register a language feature with the server. + + Parameters + ---------- + feature + The language feature + """ + feature_cls = type(feature) + if feature_cls in self._features: + name = f"{feature_cls.__module__}.{feature_cls.__name__}" + raise RuntimeError(f"Feature '{name}' has already been registered") + + self._features[feature_cls] = feature + + def get_feature(self, feature_cls: Type[LF]) -> Optional[LF]: + """Returns the requested language feature if it exists, otherwise it returns + ``None``. + + Parameters + ---------- + feature_cls + The class definiion of the feature to retrieve + """ + return self._features.get(feature_cls, None) # type: ignore + + def clear_diagnostics(self, source: str, uri: Optional[str] = None) -> None: + """Clear diagnostics from the given source. + + Parameters + ---------- + source: + The source from which to clear diagnostics. + uri: + If given, clear diagnostics from within just this uri. Otherwise, all + diagnostics from the given source are cleared. + """ + + if uri: + uri = normalise_uri(uri) + + for key in self._diagnostics.keys(): + clear_source = source == key[0] + clear_uri = uri == key[1] or uri is None + + if clear_source and clear_uri: + self._diagnostics[key] = [] + + def add_diagnostics(self, source: str, uri, diagnostic: Diagnostic): + """Add a diagnostic to the given source and uri. + + Parameters + ---------- + source + The source the diagnostics are from + uri + The uri the diagnostics are associated with + diagnostic + The diagnostic to add + """ + key = (source, normalise_uri(uri)) + self._diagnostics.setdefault(key, []).append(diagnostic) + + def set_diagnostics( + self, source: str, uri: str, diagnostics: List[Diagnostic] + ) -> None: + """Set the diagnostics for the given source and uri. + + Parameters + ---------- + source: + The source the diagnostics are from + uri: + The uri the diagnostics are associated with + diagnostics: + The diagnostics themselves + """ + uri = normalise_uri(uri) + self._diagnostics[(source, uri)] = diagnostics + + def sync_diagnostics(self) -> None: + """Update the client with the currently stored diagnostics.""" + + uris = {uri for _, uri in self._diagnostics.keys()} + diagnostics = {uri: DiagnosticList() for uri in uris} + + for (source, uri), diags in self._diagnostics.items(): + for diag in diags: + diag.source = source + diagnostics[uri].append(diag) + + for uri, diag_list in diagnostics.items(): + self.logger.debug("Publishing %d diagnostics for: %s", len(diag_list), uri) + self.publish_diagnostics(uri, diag_list.data) + + +class DiagnosticList(collections.UserList): + """A list type dedicated to holding diagnostics. + + This is mainly to ensure that only one instance of a diagnostic ever gets + reported. + """ + + def append(self, item: Diagnostic): + if not isinstance(item, Diagnostic): + raise TypeError("Expected Diagnostic") + + for existing in self.data: + fields = [ + existing.range == item.range, + existing.message == item.message, + existing.severity == item.severity, + existing.code == item.code, + existing.source == item.source, + ] + + if all(fields): + # Item already added, nothing to do. + return + + self.data.append(item) + + +def normalise_uri(uri: str) -> str: + uri = Uri.from_fs_path(Uri.to_fs_path(uri)) + + # Paths on windows are case insensitive. + if IS_WIN: + uri = uri.lower() + + return uri + + +def _get_setup_arguments( + server: EsbonioLanguageServer, setup: Callable, modname: str +) -> Optional[Dict[str, Any]]: + """Given a setup function, try to construct the collection of arguments to pass to + it. + """ + annotations = typing.get_type_hints(setup) + parameters = { + p.name: annotations[p.name] + for p in inspect.signature(setup).parameters.values() + } + + args = {} + for name, type_ in parameters.items(): + if issubclass(server.__class__, type_): + args[name] = server + continue + + if issubclass(type_, LanguageFeature): + # Try and obtain an instance of the requested language feature. + feature = server.get_feature(type_) + if feature is not None: + args[name] = feature + continue + + server.logger.debug( + "Skipping extension '%s', server missing requested feature: '%s'", + modname, + type_, + ) + return None + + server.logger.error( + "Skipping extension '%s', parameter '%s' has unsupported type: '%s'", + modname, + name, + type_, + ) + return None + + return args diff --git a/lib/esbonio/esbonio/server/setup.py b/lib/esbonio/esbonio/server/setup.py new file mode 100644 index 000000000..45411be93 --- /dev/null +++ b/lib/esbonio/esbonio/server/setup.py @@ -0,0 +1,76 @@ +from __future__ import annotations + +import importlib +import json +import typing +from typing import Iterable +from typing import Type + +from lsprotocol.types import INITIALIZE +from lsprotocol.types import InitializeParams + +if typing.TYPE_CHECKING: + from .server import EsbonioLanguageServer + + +def create_language_server( + server_cls: Type[EsbonioLanguageServer], modules: Iterable[str], *args, **kwargs +) -> EsbonioLanguageServer: + """Create a new language server instance. + + Parameters + ---------- + server_cls: + The class definition to create the server from. + modules: + The list of modules that should be loaded. + args, kwargs: + Any additional arguments that should be passed to the language server's + constructor. + """ + + server = server_cls(*args, **kwargs) + + for module in modules: + _load_module(server, module) + + return _configure_lsp_methods(server) + + +def _configure_lsp_methods(server: EsbonioLanguageServer) -> EsbonioLanguageServer: + """Configure method handlers for the portions of the LSP spec we support.""" + + @server.feature(INITIALIZE) + def on_initialize(ls: EsbonioLanguageServer, params: InitializeParams): + client = params.client_info + client_capabilities = ls.converter.unstructure(params.capabilities) + + if client is not None: + ls.logger.info("Language client: %s %s", client.name, client.version) + + ls.logger.debug( + "Client capabilities:\n%s", json.dumps(client_capabilities, indent=2) + ) + + ls.initialize(params) + + return server + + +def _load_module(server: EsbonioLanguageServer, modname: str): + """Load an extension module by calling its ``esbonio_setup`` function, if it exists.""" + + try: + module = importlib.import_module(modname) + except ImportError: + server.logger.error("Unable to import module '%s'", modname, exc_info=True) + return None + + setup = getattr(module, "esbonio_setup", None) + if setup is None: + server.logger.debug( + "Skipping module '%s', missing 'esbonio_setup' function", modname + ) + return None + + server.load_extension(modname, setup) From 512e34c26f5e074c999d132c985d9d978c27b269 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Mon, 12 Jun 2023 22:49:29 +0100 Subject: [PATCH 039/141] lsp: Add basic text synchronisation methods Employing the await-me-maybe[1] pattern, `LanguageFeatures` can opt to provide async handlers for these notifications and everything, in theory, should just work... [1]: https://textual.textualize.io/blog/2023/03/15/no-async-async-with-python/#await-me-maybe --- lib/esbonio/esbonio/server/__init__.py | 7 ++++ lib/esbonio/esbonio/server/feature.py | 17 +++++++++ lib/esbonio/esbonio/server/server.py | 3 ++ lib/esbonio/esbonio/server/setup.py | 52 +++++++++++++++++++++++++- 4 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 lib/esbonio/esbonio/server/__init__.py diff --git a/lib/esbonio/esbonio/server/__init__.py b/lib/esbonio/esbonio/server/__init__.py new file mode 100644 index 000000000..fedc34817 --- /dev/null +++ b/lib/esbonio/esbonio/server/__init__.py @@ -0,0 +1,7 @@ +from .feature import LanguageFeature +from .server import EsbonioLanguageServer + +__all__ = [ + "EsbonioLanguageServer", + "LanguageFeature", +] diff --git a/lib/esbonio/esbonio/server/feature.py b/lib/esbonio/esbonio/server/feature.py index 4a5195c5c..b2ada7c95 100644 --- a/lib/esbonio/esbonio/server/feature.py +++ b/lib/esbonio/esbonio/server/feature.py @@ -2,6 +2,11 @@ import typing +from lsprotocol.types import DidChangeTextDocumentParams +from lsprotocol.types import DidCloseTextDocumentParams +from lsprotocol.types import DidOpenTextDocumentParams +from lsprotocol.types import DidSaveTextDocumentParams + if typing.TYPE_CHECKING: from .server import EsbonioLanguageServer @@ -12,3 +17,15 @@ class LanguageFeature: def __init__(self, server: EsbonioLanguageServer): self.server = server self.logger = server.logger.getChild(self.__class__.__name__) + + def document_change(self, params: DidChangeTextDocumentParams): + """Called when a text document is changed.""" + + def document_close(self, params: DidCloseTextDocumentParams): + """Called when a text document is closed.""" + + def document_open(self, params: DidOpenTextDocumentParams): + """Called when a text document is opened.""" + + def document_save(self, params: DidSaveTextDocumentParams): + """Called when a text document is saved.""" diff --git a/lib/esbonio/esbonio/server/server.py b/lib/esbonio/esbonio/server/server.py index 8830f8209..fafa991b1 100644 --- a/lib/esbonio/esbonio/server/server.py +++ b/lib/esbonio/esbonio/server/server.py @@ -74,6 +74,9 @@ def __init__(self, logger: Optional[logging.Logger] = None, *args, **kwargs): self.initialization_options: Optional[LSPAny] = None """The received initializaion options (if any)""" + def __iter__(self): + return iter(self._features.items()) + def initialize(self, params: InitializeParams): self.initialization_options = params.initialization_options diff --git a/lib/esbonio/esbonio/server/setup.py b/lib/esbonio/esbonio/server/setup.py index 45411be93..0d59de054 100644 --- a/lib/esbonio/esbonio/server/setup.py +++ b/lib/esbonio/esbonio/server/setup.py @@ -1,12 +1,21 @@ from __future__ import annotations import importlib +import inspect import json import typing from typing import Iterable from typing import Type from lsprotocol.types import INITIALIZE +from lsprotocol.types import TEXT_DOCUMENT_DID_CHANGE +from lsprotocol.types import TEXT_DOCUMENT_DID_CLOSE +from lsprotocol.types import TEXT_DOCUMENT_DID_OPEN +from lsprotocol.types import TEXT_DOCUMENT_DID_SAVE +from lsprotocol.types import DidChangeTextDocumentParams +from lsprotocol.types import DidCloseTextDocumentParams +from lsprotocol.types import DidOpenTextDocumentParams +from lsprotocol.types import DidSaveTextDocumentParams from lsprotocol.types import InitializeParams if typing.TYPE_CHECKING: @@ -28,7 +37,6 @@ def create_language_server( Any additional arguments that should be passed to the language server's constructor. """ - server = server_cls(*args, **kwargs) for module in modules: @@ -41,7 +49,7 @@ def _configure_lsp_methods(server: EsbonioLanguageServer) -> EsbonioLanguageServ """Configure method handlers for the portions of the LSP spec we support.""" @server.feature(INITIALIZE) - def on_initialize(ls: EsbonioLanguageServer, params: InitializeParams): + async def on_initialize(ls: EsbonioLanguageServer, params: InitializeParams): client = params.client_info client_capabilities = ls.converter.unstructure(params.capabilities) @@ -54,9 +62,49 @@ def on_initialize(ls: EsbonioLanguageServer, params: InitializeParams): ls.initialize(params) + @server.feature(TEXT_DOCUMENT_DID_CHANGE) + async def on_document_change( + ls: EsbonioLanguageServer, params: DidChangeTextDocumentParams + ): + await call_features(ls, "document_change", params) + + @server.feature(TEXT_DOCUMENT_DID_CLOSE) + async def on_document_close( + ls: EsbonioLanguageServer, params: DidCloseTextDocumentParams + ): + await call_features(ls, "document_close", params) + + @server.feature(TEXT_DOCUMENT_DID_OPEN) + async def on_document_open( + ls: EsbonioLanguageServer, params: DidOpenTextDocumentParams + ): + await call_features(ls, "document_open", params) + + @server.feature(TEXT_DOCUMENT_DID_SAVE) + async def on_document_save( + ls: EsbonioLanguageServer, params: DidSaveTextDocumentParams + ): + await call_features(ls, "document_save", params) + return server +async def call_features(ls: EsbonioLanguageServer, method: str, *args, **kwargs): + """Call all features.""" + + for cls, feature in ls: + try: + impl = getattr(feature, method) + + result = impl(*args, **kwargs) + if inspect.isawaitable(result): + await result + + except Exception: + name = f"{cls.__module__}.{cls.__name__}" + ls.logger.error("Error in '%s.%s' handler", name, method, exc_info=True) + + def _load_module(server: EsbonioLanguageServer, modname: str): """Load an extension module by calling its ``esbonio_setup`` function, if it exists.""" From a52e6af6fabecf1a37d4704c5e76799fc6855aa4 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Mon, 12 Jun 2023 23:17:17 +0100 Subject: [PATCH 040/141] lsp: Scaffold the `sphinx_agent` The sphinx agent will be launched as a subprocess and wrap a Sphinx application object, exposing a JSON-RPC API allowing the parent process to remotely inspect and control it. The agent process will be launched from the python interpreter used to build the user's documentation with the agent itself being injected into the environment with the `PYTHONPATH` env variable. For this reason and to maximise compatibility, the agent itself can only depend on the standard library and sphinx. This does mean having to re-invent some of the JSON-RPC machinery, but hopefully `asyncio` and `dataclasses` should make that relatively straightforward. Fingers crossed it all works out! --- lib/esbonio/esbonio/server/cli.py | 7 +- .../esbonio/server/features/sphinx_manager.py | 88 ++++++ lib/esbonio/esbonio/sphinx_agent/__init__.py | 107 ++++++++ lib/esbonio/esbonio/sphinx_agent/__main__.py | 5 + lib/esbonio/esbonio/sphinx_agent/config.py | 250 ++++++++++++++++++ lib/esbonio/esbonio/sphinx_agent/handlers.py | 75 ++++++ lib/esbonio/esbonio/sphinx_agent/log.py | 159 +++++++++++ lib/esbonio/esbonio/sphinx_agent/types.py | 44 +++ lib/esbonio/esbonio/sphinx_agent/util.py | 23 ++ 9 files changed, 756 insertions(+), 2 deletions(-) create mode 100644 lib/esbonio/esbonio/server/features/sphinx_manager.py create mode 100644 lib/esbonio/esbonio/sphinx_agent/__init__.py create mode 100644 lib/esbonio/esbonio/sphinx_agent/__main__.py create mode 100644 lib/esbonio/esbonio/sphinx_agent/config.py create mode 100644 lib/esbonio/esbonio/sphinx_agent/handlers.py create mode 100644 lib/esbonio/esbonio/sphinx_agent/log.py create mode 100644 lib/esbonio/esbonio/sphinx_agent/types.py create mode 100644 lib/esbonio/esbonio/sphinx_agent/util.py diff --git a/lib/esbonio/esbonio/server/cli.py b/lib/esbonio/esbonio/server/cli.py index 5fef082f7..51e78e68f 100644 --- a/lib/esbonio/esbonio/server/cli.py +++ b/lib/esbonio/esbonio/server/cli.py @@ -67,7 +67,7 @@ def main(argv: Optional[Sequence[str]] = None): cli = build_parser() args = cli.parse_args(argv) - modules = list() + modules = ["esbonio.server.features.sphinx_manager"] for mod in args.included_modules: modules.append(mod) @@ -94,7 +94,10 @@ def main(argv: Optional[Sequence[str]] = None): warnlog.addHandler(handler) server = create_language_server( - EsbonioLanguageServer, modules, converter_factory=default_converter + EsbonioLanguageServer, + modules, + logger=logger, + converter_factory=default_converter, ) if args.port: diff --git a/lib/esbonio/esbonio/server/features/sphinx_manager.py b/lib/esbonio/esbonio/server/features/sphinx_manager.py new file mode 100644 index 000000000..848f760ed --- /dev/null +++ b/lib/esbonio/esbonio/server/features/sphinx_manager.py @@ -0,0 +1,88 @@ +from __future__ import annotations + +import asyncio +import sys +from typing import Callable +from typing import Type + +from lsprotocol.types import DidChangeTextDocumentParams +from lsprotocol.types import DidCloseTextDocumentParams +from lsprotocol.types import DidOpenTextDocumentParams +from lsprotocol.types import DidSaveTextDocumentParams +from pygls.client import Client + +from esbonio.server import EsbonioLanguageServer +from esbonio.server import LanguageFeature + + +class SphinxClient(Client): + """JSON-RPC client used to drive a Sphinx application instance hosted in + a separate subprocess.""" + + def __init__(self, logger, *args, **kwargs): + super().__init__(*args, **kwargs) + self.logger = logger + self.alive = True + + async def server_exit(self, server: asyncio.subprocess.Process): + self.logger.debug(f"Process exited with code: {server.returncode}") + self.alive = False + + if server.returncode != 0: + stderr = await server.stderr.read() + self.logger.debug("Stderr:\n%s", stderr.decode("utf8")) + + +def make_client(logger): + client = SphinxClient(logger=logger) + + @client.feature("window/logMessage") + def on_msg(ls: SphinxClient, params): + ls.logger.info(params.message) + + return client + + +class SphinxManager(LanguageFeature): + """Responsible for managing Sphinx application instances.""" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.client = None + + def document_change(self, params: DidChangeTextDocumentParams): + self.logger.debug("Changed document '%s'", params.text_document.uri) + + def document_close(self, params: DidCloseTextDocumentParams): + self.logger.debug("Closed document '%s'", params.text_document.uri) + + async def document_open(self, params: DidOpenTextDocumentParams): + self.logger.debug("Opened document '%s'", params.text_document.uri) + if self.client is None: + python = "/var/home/alex/Projects/esbonio/.env/bin/python" + command = [python, "-m", "esbonio.sphinx_agent"] + self.logger.debug("Starting client: %s", " ".join(command)) + self.client = make_client(self.logger) + + await self.client.start_io( + *command, + env={ + "PYTHONPATH": "/var/home/alex/Projects/esbonio-beta/code/bundled/lib/" + }, + ) + + if self.client.alive: + self.logger.debug("Creating app") + await self.client.protocol.send_request_async( + "sphinx/createApp", {"command": ["-M", "dirhtml", ".", "./_build"]} + ) + self.logger.debug("done.") + + def document_save(self, params: DidSaveTextDocumentParams): + self.logger.debug("Saved document '%s'", params.text_document.uri) + + +def esbonio_setup(server: EsbonioLanguageServer): + manager = SphinxManager(server) + server.add_feature(manager) diff --git a/lib/esbonio/esbonio/sphinx_agent/__init__.py b/lib/esbonio/esbonio/sphinx_agent/__init__.py new file mode 100644 index 000000000..7872985cf --- /dev/null +++ b/lib/esbonio/esbonio/sphinx_agent/__init__.py @@ -0,0 +1,107 @@ +"""This module implements the Sphinx agent. + +It wraps a Sphinx application object, allowing the main language server process to +interact with it. + +Whereas the language server originally had to be installed within the same Python +environment as Sphinx, the agent allows the server to run in a completely separate +Python environment and still gather the information it needs. + +This is possible by taking advantage of the ``PYTHONPATH`` environment variable, using +it to expose *just this module* to the Python environment hosting Sphinx. To prevent +a potential clash of dependencies, this module is written with only what is available +in the stdlib and Sphinx itself. + +Unfortunately, this does mean re-inventing some wheels, but hopefully what we gain in +portability makes it worth the trade off. +""" +import asyncio +import dataclasses +import json +import logging +import re +import sys +import threading +from concurrent.futures import ThreadPoolExecutor +from typing import Dict +from typing import Type +from typing import TypeVar + +from .handlers import HANDLERS + +logger = logging.getLogger(__name__) + + +T = TypeVar("T") + + +def parse_message(obj: Dict, cls: Type[T]) -> T: + """Convert a raw dict into the given type""" + + if dataclasses.is_dataclass(cls): + kwargs = {} + fields = {f.name: f for f in dataclasses.fields(cls)} + + for key, value in obj.items(): + kwargs[key] = parse_message(value, fields[key].type) + + return cls(**kwargs) + + return obj + + +def handle_message(data: bytes): + message = json.loads(data.decode("utf8")) + + method = message.get("method", None) + if not method: + raise TypeError("Invalid message") + + type_, handler = HANDLERS.get(method, (None, None)) + if type_ is None or handler is None: + raise TypeError(f"Unknown method: '{method}'") + + obj = parse_message(message, type_) + handler(obj) + + +async def main_loop(loop, executor, stop_event, rfile, proxy): + """Originally taken from ``pygls``""" + + CONTENT_LENGTH_PATTERN = re.compile(rb"^Content-Length: (\d+)\r\n$") + + # Initialize message buffer + content_length = 0 + + while not stop_event.is_set() and not rfile.closed: + # Read a header line + header = await loop.run_in_executor(executor, rfile.readline) + if not header: + break + + # Extract content length if possible + if not content_length: + match = CONTENT_LENGTH_PATTERN.fullmatch(header) + if match: + content_length = int(match.group(1)) + logger.debug("Content length: %s", content_length) + + # Check if all headers have been read (as indicated by an empty line \r\n) + if content_length and not header.strip(): + # Read body + body = await loop.run_in_executor(executor, rfile.read, content_length) + if not body: + break + + proxy(body) + + # Reset the buffer + content_length = 0 + + +async def main(): + loop = asyncio.get_running_loop() + event = threading.Event() + executor = ThreadPoolExecutor(max_workers=2) + + await main_loop(loop, executor, event, sys.stdin.buffer, handle_message) diff --git a/lib/esbonio/esbonio/sphinx_agent/__main__.py b/lib/esbonio/esbonio/sphinx_agent/__main__.py new file mode 100644 index 000000000..266ee281b --- /dev/null +++ b/lib/esbonio/esbonio/sphinx_agent/__main__.py @@ -0,0 +1,5 @@ +import asyncio + +from esbonio.sphinx_agent import main + +asyncio.run(main()) diff --git a/lib/esbonio/esbonio/sphinx_agent/config.py b/lib/esbonio/esbonio/sphinx_agent/config.py new file mode 100644 index 000000000..c2552adc2 --- /dev/null +++ b/lib/esbonio/esbonio/sphinx_agent/config.py @@ -0,0 +1,250 @@ +import dataclasses +import inspect +import pathlib +import re +from typing import Any +from typing import Dict +from typing import List +from typing import Literal +from typing import Optional +from typing import Union +from unittest import mock + +from sphinx.application import Sphinx +from sphinx.cmd.build import main as sphinx_build + +PATH_VAR_PATTERN = re.compile(r"^\${(\w+)}/?.*") + + +@dataclasses.dataclass +class SphinxConfig: + """Configuration values to pass to the Sphinx application instance.""" + + build_dir: Optional[str] = dataclasses.field(default=None) + """The directory to write build outputs into.""" + + builder_name: str = dataclasses.field(default="html") + """The currently used builder name.""" + + conf_dir: Optional[str] = dataclasses.field(default=None) + """The directory containing the project's ``conf.py``.""" + + config_overrides: Dict[str, Any] = dataclasses.field(default_factory=dict) + """Any overrides to configuration values.""" + + doctree_dir: Optional[str] = dataclasses.field(default=None) + """The directory to write doctrees into.""" + + force_full_build: bool = dataclasses.field(default=False) + """Force a full build on startup.""" + + keep_going: bool = dataclasses.field(default=False) + """Continue building when errors (from warnings) are encountered.""" + + make_mode: bool = dataclasses.field(default=True) + """Flag indicating if the server should align to "make mode" behavior.""" + + num_jobs: Union[Literal["auto"], int] = dataclasses.field(default=1) + """The number of jobs to use for parallel builds.""" + + quiet: bool = dataclasses.field(default=False) + """Hide standard Sphinx output messages""" + + silent: bool = dataclasses.field(default=False) + """Hide all Sphinx output.""" + + src_dir: Optional[str] = dataclasses.field(default=None) + """The directory containing the project's source.""" + + tags: List[str] = dataclasses.field(default_factory=list) + """Tags to enable during a build.""" + + verbosity: int = dataclasses.field(default=0) + """The verbosity of Sphinx's output.""" + + version: Optional[str] = dataclasses.field(default=None) + """Sphinx's version number.""" + + warning_is_error: bool = dataclasses.field(default=False) + """Treat any warning as an error""" + + @property + def parallel(self) -> int: + """The parsed value of the ``num_jobs`` field.""" + + if self.num_jobs == "auto": + import multiprocessing + + return multiprocessing.cpu_count() + + return self.num_jobs + + @classmethod + def fromcli(cls, args: List[str]): + """Return the ``SphinxConfig`` instance that's equivalent to the given arguments. + + Parameters + ---------- + args + The cli arguments you would normally pass to ``sphinx-build`` + + Returns + ------- + Optional[SphinxConfig] + ``None`` if the arguments could not be parsed, otherwise the set configuration + options derived from the sphinx build command. + """ + + # The easiest way to handle this is to just call sphinx-build but with + # the Sphinx app object patched out - then we just use all the args it + # was given! + with mock.patch("sphinx.cmd.build.Sphinx") as m_Sphinx: + sphinx_build(args) + + if m_Sphinx.call_args is None: + return None + + signature = inspect.signature(Sphinx) + keys = signature.parameters.keys() + + values = m_Sphinx.call_args[0] + sphinx_args = {k: v for k, v in zip(keys, values)} + + # `-M` has to be the first argument passed to `sphinx-build` + # https://github.com/sphinx-doc/sphinx/blob/1222bed88eb29cde43a81dd208448dc903c53de2/sphinx/cmd/build.py#L287 + make_mode = args[0] == "-M" + if make_mode and sphinx_args["outdir"].endswith(sphinx_args["buildername"]): + build_dir = pathlib.Path(sphinx_args["outdir"]).parts[:-1] + sphinx_args["outdir"] = str(pathlib.Path(*build_dir)) + + if sphinx_args is None: + return None + + return cls( + conf_dir=sphinx_args.get("confdir", None), + config_overrides=sphinx_args.get("confoverrides", {}), + build_dir=sphinx_args.get("outdir", None), + builder_name=sphinx_args.get("buildername", "html"), + doctree_dir=sphinx_args.get("doctreedir", None), + force_full_build=sphinx_args.get("freshenv", False), + keep_going=sphinx_args.get("keep_going", False), + make_mode=make_mode, + num_jobs=sphinx_args.get("parallel", 1), + quiet=sphinx_args.get("status", 1) is None, + silent=sphinx_args.get("warning", 1) is None, + src_dir=sphinx_args.get("srcdir", None), + tags=sphinx_args.get("tags", []), + verbosity=sphinx_args.get("verbosity", 0), + warning_is_error=sphinx_args.get("warningiserror", False), + ) + + def to_cli_args(self) -> List[str]: + """Convert this into the equivalent ``sphinx-build`` cli arguments.""" + + if self.make_mode: + return self._build_make_cli_args() + + return self._build_cli_args() + + def _build_make_cli_args(self) -> List[str]: + args = ["-M", self.builder_name] + conf_dir = self.conf_dir or "${workspaceRoot}" + src_dir = self.src_dir or conf_dir + + if self.build_dir is None: + build_dir = pathlib.Path(src_dir, "_build") + else: + build_dir = pathlib.Path(self.build_dir) + + args += [src_dir, str(build_dir)] + + args += self._build_standard_args() + default_dtree_dir = str(pathlib.Path(build_dir, "doctrees")) + if self.doctree_dir is not None and self.doctree_dir != default_dtree_dir: + args += ["-d", self.doctree_dir] + + return args + + def _build_cli_args(self) -> List[str]: + args = ["-b", self.builder_name] + + conf_dir = self.conf_dir or "${workspaceRoot}" + src_dir = self.src_dir or conf_dir + + build_dir = self.build_dir or pathlib.Path(src_dir, "_build") + default_dtree_dir = str(pathlib.Path(build_dir, ".doctrees")) + + if self.doctree_dir is not None and self.doctree_dir != default_dtree_dir: + args += ["-d", self.doctree_dir] + + args += self._build_standard_args() + args += [src_dir, str(build_dir)] + return args + + def _build_standard_args(self) -> List[str]: + args: List[str] = [] + + conf_dir = self.conf_dir or "${workspaceRoot}" + src_dir = self.src_dir or self.conf_dir + + if conf_dir != src_dir: + args += ["-c", conf_dir] + + if self.force_full_build: + args += ["-E"] + + if self.parallel > 1: + args += ["-j", str(self.num_jobs)] + + if self.silent: + args += ["-Q"] + + if self.quiet and not self.silent: + args += ["-q"] + + if self.warning_is_error: + args += ["-W"] + + if self.keep_going: + args += ["--keep-going"] + + if self.verbosity > 0: + args += ["-" + ("v" * self.verbosity)] + + for key, value in self.config_overrides.items(): + if key == "nitpicky": + args += ["-n"] + continue + + if key.startswith("html_context."): + char = "A" + key = key.replace("html_context.", "") + else: + char = "D" + + args += [f"-{char}{key}={value}"] + + for tag in self.tags: + args += ["-t", tag] + + return args + + def to_application_args(self) -> Dict[str, Any]: + """Convert this into the equivalent Sphinx application arguments.""" + + return { + "buildername": self.builder_name, + "confdir": self.conf_dir, + "confoverrides": self.config_overrides, + "doctreedir": self.doctree_dir, + "freshenv": self.force_full_build, + "keep_going": self.keep_going, + "outdir": self.build_dir, + "parallel": self.parallel, + "srcdir": self.src_dir, + "status": None, + "tags": self.tags, + "verbosity": self.verbosity, + "warning": None, + "warningiserror": self.warning_is_error, + } diff --git a/lib/esbonio/esbonio/sphinx_agent/handlers.py b/lib/esbonio/esbonio/sphinx_agent/handlers.py new file mode 100644 index 000000000..3cf6df606 --- /dev/null +++ b/lib/esbonio/esbonio/sphinx_agent/handlers.py @@ -0,0 +1,75 @@ +import logging +from functools import partial +from typing import IO +from typing import Optional +from typing import Type + +from sphinx.application import Sphinx +from sphinx.util import console +from sphinx.util import logging as sphinx_logging_module +from sphinx.util.logging import NAMESPACE as SPHINX_LOG_NAMESPACE +from sphinx.util.logging import VERBOSITY_MAP + +from .config import SphinxConfig +from .log import SphinxLogHandler +from .types import CreateApplicationRequest + +HANDLERS = {} + +# Global state.... for now +sphinx_app: Optional[Sphinx] = None +sphinx_log: Optional[SphinxLogHandler] = None + + +def handler(t: Type): + def wrapper(f): + HANDLERS[t.method] = (t, f) + return f + + return wrapper + + +@handler(CreateApplicationRequest) +def create_sphinx_app(request: CreateApplicationRequest): + sphinx_config = SphinxConfig.fromcli(request.params.command) + if sphinx_config is None: + raise ValueError("Invalid build command") + + sphinx_args = sphinx_config.to_application_args() + + # Override Sphinx's logging setup with our own. + sphinx_logging_module.setup = partial(logging_setup, sphinx_config) + + app = Sphinx(**sphinx_args) + app.build() + + +def logging_setup(config: SphinxConfig, app: Sphinx, status: IO, warning: IO): + """Setup Sphinx's logging so that it integrates well with the parent language + server.""" + + # Disable color escape codes in Sphinx's log messages + console.nocolor() + + if not config.silent: + sphinx_logger = logging.getLogger(SPHINX_LOG_NAMESPACE) + + # Be sure to remove any old handlers + for handler in sphinx_logger.handlers: + if isinstance(handler, SphinxLogHandler): + sphinx_logger.handlers.remove(handler) + sphinx_log = None + + sphinx_log = SphinxLogHandler(app) + sphinx_logger.addHandler(sphinx_log) + + if config.quiet: + level = logging.WARNING + else: + level = VERBOSITY_MAP[app.verbosity] + + sphinx_logger.setLevel(level) + sphinx_log.setLevel(level) + + formatter = logging.Formatter("%(message)s") + sphinx_log.setFormatter(formatter) diff --git a/lib/esbonio/esbonio/sphinx_agent/log.py b/lib/esbonio/esbonio/sphinx_agent/log.py new file mode 100644 index 000000000..69125efff --- /dev/null +++ b/lib/esbonio/esbonio/sphinx_agent/log.py @@ -0,0 +1,159 @@ +import logging +import os +import pathlib +import sys +from types import ModuleType +from typing import Any +from typing import List +from typing import Optional +from typing import Tuple +from typing import Union + +from sphinx.util.logging import OnceFilter +from sphinx.util.logging import SphinxLogRecord +from sphinx.util.logging import WarningLogRecordTranslator + +from .types import LogMessage +from .types import LogMessageParams +from .util import logger +from .util import send_message + + +class SphinxLogHandler(logging.Handler): + """A logging handler that can extract errors from Sphinx's build output.""" + + def __init__(self, app, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.app = app + self.translator = WarningLogRecordTranslator(app) + self.only_once = OnceFilter() + # self.diagnostics: Dict[str, List[Diagnostic]] = {} + + def get_location(self, location: str) -> Tuple[str, Optional[int]]: + if not location: + conf = pathlib.Path(self.app.confdir, "conf.py") + return (str(conf), None) + + lineno = None + path, parts = self.get_location_path(location) + + if len(parts) == 1: + try: + lineno = int(parts[0]) + except ValueError: + pass + + if len(parts) == 2 and parts[0].startswith("docstring of "): + target = parts[0].replace("docstring of ", "") + lineno = self.get_docstring_location(target, parts[1]) + + return (path, lineno) + + def get_location_path(self, location: str) -> Tuple[str, List[str]]: + """Determine the filepath from the given location.""" + + if location.startswith("internal padding before "): + location = location.replace("internal padding before ", "") + + if location.startswith("internal padding after "): + location = location.replace("internal padding after ", "") + + path, *parts = location.split(":") + + # On windows the rest of the path will be the first element of parts + if pathlib.Path(location).drive: + path += f":{parts.pop(0)}" + + # Diagnostics in .. included:: files are reported relative to the process' + # working directory, so ensure the path is absolute. + path = os.path.abspath(path) + + return path, parts + + def get_docstring_location(self, target: str, offset: str) -> Optional[int]: + # The containing module will be the longest substring we can find in target + candidates = [m for m in sys.modules.keys() if target.startswith(m)] + [""] + module = sys.modules.get(sorted(candidates, key=len, reverse=True)[0], None) + + if module is None: + return None + + obj: Union[ModuleType, Any, None] = module + dotted_name = target.replace(module.__name__ + ".", "") + + for name in dotted_name.split("."): + obj = getattr(obj, name, None) + if obj is None: + return None + + try: + _, line = inspect.getsourcelines(obj) # type: ignore + + # Correct off by one error for docstrings that don't start with a newline. + nl = (obj.__doc__ or "").startswith("\n") + return line + int(offset) - (not nl) + except Exception: + logger.debug("Unable to determine diagnostic location\n%s", exc_info=True) + return None + + def emit(self, record: logging.LogRecord) -> None: + conditions = [ + "sphinx" not in record.name, + record.levelno not in {logging.WARNING, logging.ERROR}, + not self.translator, + ] + + if any(conditions): + # Log the record as normal + self.do_emit(record) + return + + # Only process errors/warnings once. + if not self.only_once.filter(record): + return + + # Let sphinx do what it does to warning/error messages + self.translator.filter(record) # type: ignore + + loc = record.location if isinstance(record, SphinxLogRecord) else "" + doc, lineno = self.get_location(loc) + line = lineno or 1 + logger.debug("Reporting diagnostic at %s:%s", doc, line) + + try: + # Not every message contains a string... + if not isinstance(record.msg, str): + message = str(record.msg) + else: + message = record.msg + + # Only attempt to format args if there are args to format + if record.args is not None and len(record.args) > 0: + message = message % record.args + + except Exception: + message = str(record.msg) + logger.error("Unable to format diagnostic message: %s", exc_info=True) + + # diagnostic = Diagnostic( + # range=Range( + # start=Position(line=line - 1, character=0), + # end=Position(line=line, character=0), + # ), + # message=message, + # severity=DIAGNOSTIC_SEVERITY.get( + # record.levelno, DiagnosticSeverity.Warning + # ), + # ) + + # if doc not in self.diagnostics: + # self.diagnostics[doc] = [diagnostic] + # else: + # self.diagnostics[doc].append(diagnostic) + + self.do_emit(record) + + def do_emit(self, record): + params = LogMessageParams(message=self.format(record).strip(), type=4) + send_message(LogMessage(params=params)) diff --git a/lib/esbonio/esbonio/sphinx_agent/types.py b/lib/esbonio/esbonio/sphinx_agent/types.py new file mode 100644 index 000000000..d202181e9 --- /dev/null +++ b/lib/esbonio/esbonio/sphinx_agent/types.py @@ -0,0 +1,44 @@ +import dataclasses +from typing import List +from typing import Union + + +@dataclasses.dataclass +class CreateApplicationParams: + """Parameters of a ``sphinx/createApp`` request.""" + + command: List[str] + """The ``sphinx-build`` command to base the app instance on.""" + + +@dataclasses.dataclass +class CreateApplicationRequest: + """A ``sphinx/createApp`` request.""" + + id: Union[int, str] + + params: CreateApplicationParams + + method: str = "sphinx/createApp" + + jsonrpc: str = dataclasses.field(default="2.0") + + +@dataclasses.dataclass +class LogMessageParams: + """Parameters of a ``window/logMessage`` notification.""" + + type: int + + message: str + + +@dataclasses.dataclass +class LogMessage: + """A ``window/logMessage`` notification""" + + params: LogMessageParams + + method: str = "window/logMessage" + + jsonrpc: str = dataclasses.field(default="2.0") diff --git a/lib/esbonio/esbonio/sphinx_agent/util.py b/lib/esbonio/esbonio/sphinx_agent/util.py new file mode 100644 index 000000000..8421bd113 --- /dev/null +++ b/lib/esbonio/esbonio/sphinx_agent/util.py @@ -0,0 +1,23 @@ +import dataclasses +import json +import logging +import sys +from typing import Any + +logger = logging.getLogger("esbonio.sphinx_agent") + + +def format_message(data: Any) -> str: + if dataclasses.is_dataclass(data): + data = dataclasses.asdict(data) + + content = json.dumps(data) + content_length = len(content) + + return f"Content-Length: {content_length}\r\n\r\n{content}" + + +def send_message(data: Any): + content = format_message(data).encode("utf8") + sys.stdout.buffer.write(content) + sys.stdout.flush() From 85256619aa95795731a92e88efe88054a1463520 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Wed, 14 Jun 2023 23:36:54 +0100 Subject: [PATCH 041/141] lsp: Use `workspace/configuration` to request config from the client When creating the sphinx agent process - Use `importlib.utils.find_spec` to lookup the location of the sphinx agent on disk - Set the working directory of the agent process to the workspace folder we are creating it for. - Ask the client for configuration values and base the agent's configuration based on the result --- lib/esbonio/esbonio/server/feature.py | 1 + .../esbonio/server/features/sphinx_manager.py | 88 ---------- .../features/sphinx_manager/__init__.py | 10 ++ .../server/features/sphinx_manager/client.py | 36 ++++ .../server/features/sphinx_manager/manager.py | 154 ++++++++++++++++++ lib/esbonio/esbonio/server/log.py | 26 +++ lib/esbonio/esbonio/sphinx_agent/config.py | 3 + 7 files changed, 230 insertions(+), 88 deletions(-) delete mode 100644 lib/esbonio/esbonio/server/features/sphinx_manager.py create mode 100644 lib/esbonio/esbonio/server/features/sphinx_manager/__init__.py create mode 100644 lib/esbonio/esbonio/server/features/sphinx_manager/client.py create mode 100644 lib/esbonio/esbonio/server/features/sphinx_manager/manager.py diff --git a/lib/esbonio/esbonio/server/feature.py b/lib/esbonio/esbonio/server/feature.py index b2ada7c95..d7efee471 100644 --- a/lib/esbonio/esbonio/server/feature.py +++ b/lib/esbonio/esbonio/server/feature.py @@ -16,6 +16,7 @@ class LanguageFeature: def __init__(self, server: EsbonioLanguageServer): self.server = server + self.converter = server.converter self.logger = server.logger.getChild(self.__class__.__name__) def document_change(self, params: DidChangeTextDocumentParams): diff --git a/lib/esbonio/esbonio/server/features/sphinx_manager.py b/lib/esbonio/esbonio/server/features/sphinx_manager.py deleted file mode 100644 index 848f760ed..000000000 --- a/lib/esbonio/esbonio/server/features/sphinx_manager.py +++ /dev/null @@ -1,88 +0,0 @@ -from __future__ import annotations - -import asyncio -import sys -from typing import Callable -from typing import Type - -from lsprotocol.types import DidChangeTextDocumentParams -from lsprotocol.types import DidCloseTextDocumentParams -from lsprotocol.types import DidOpenTextDocumentParams -from lsprotocol.types import DidSaveTextDocumentParams -from pygls.client import Client - -from esbonio.server import EsbonioLanguageServer -from esbonio.server import LanguageFeature - - -class SphinxClient(Client): - """JSON-RPC client used to drive a Sphinx application instance hosted in - a separate subprocess.""" - - def __init__(self, logger, *args, **kwargs): - super().__init__(*args, **kwargs) - self.logger = logger - self.alive = True - - async def server_exit(self, server: asyncio.subprocess.Process): - self.logger.debug(f"Process exited with code: {server.returncode}") - self.alive = False - - if server.returncode != 0: - stderr = await server.stderr.read() - self.logger.debug("Stderr:\n%s", stderr.decode("utf8")) - - -def make_client(logger): - client = SphinxClient(logger=logger) - - @client.feature("window/logMessage") - def on_msg(ls: SphinxClient, params): - ls.logger.info(params.message) - - return client - - -class SphinxManager(LanguageFeature): - """Responsible for managing Sphinx application instances.""" - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - self.client = None - - def document_change(self, params: DidChangeTextDocumentParams): - self.logger.debug("Changed document '%s'", params.text_document.uri) - - def document_close(self, params: DidCloseTextDocumentParams): - self.logger.debug("Closed document '%s'", params.text_document.uri) - - async def document_open(self, params: DidOpenTextDocumentParams): - self.logger.debug("Opened document '%s'", params.text_document.uri) - if self.client is None: - python = "/var/home/alex/Projects/esbonio/.env/bin/python" - command = [python, "-m", "esbonio.sphinx_agent"] - self.logger.debug("Starting client: %s", " ".join(command)) - self.client = make_client(self.logger) - - await self.client.start_io( - *command, - env={ - "PYTHONPATH": "/var/home/alex/Projects/esbonio-beta/code/bundled/lib/" - }, - ) - - if self.client.alive: - self.logger.debug("Creating app") - await self.client.protocol.send_request_async( - "sphinx/createApp", {"command": ["-M", "dirhtml", ".", "./_build"]} - ) - self.logger.debug("done.") - - def document_save(self, params: DidSaveTextDocumentParams): - self.logger.debug("Saved document '%s'", params.text_document.uri) - - -def esbonio_setup(server: EsbonioLanguageServer): - manager = SphinxManager(server) - server.add_feature(manager) diff --git a/lib/esbonio/esbonio/server/features/sphinx_manager/__init__.py b/lib/esbonio/esbonio/server/features/sphinx_manager/__init__.py new file mode 100644 index 000000000..7492c38c9 --- /dev/null +++ b/lib/esbonio/esbonio/server/features/sphinx_manager/__init__.py @@ -0,0 +1,10 @@ +from __future__ import annotations + +from esbonio.server import EsbonioLanguageServer + +from .manager import SphinxManager + + +def esbonio_setup(server: EsbonioLanguageServer): + manager = SphinxManager(server) + server.add_feature(manager) diff --git a/lib/esbonio/esbonio/server/features/sphinx_manager/client.py b/lib/esbonio/esbonio/server/features/sphinx_manager/client.py new file mode 100644 index 000000000..52f6095bf --- /dev/null +++ b/lib/esbonio/esbonio/server/features/sphinx_manager/client.py @@ -0,0 +1,36 @@ +from __future__ import annotations + +import asyncio +import typing + +from pygls.client import Client + +if typing.TYPE_CHECKING: + from .manager import SphinxManager + + +class SphinxClient(Client): + """JSON-RPC client used to drive a Sphinx application instance hosted in + a separate subprocess.""" + + def __init__(self, manager: SphinxManager, *args, **kwargs): + super().__init__(*args, **kwargs) + self.manager = manager + self.logger = manager.logger + + async def server_exit(self, server: asyncio.subprocess.Process): + self.logger.debug(f"Process exited with code: {server.returncode}") + + if server.returncode != 0: + stderr = await server.stderr.read() + self.logger.debug("Stderr:\n%s", stderr.decode("utf8")) + + +def make_sphinx_client(manager: SphinxManager): + client = SphinxClient(manager=manager) + + @client.feature("window/logMessage") + def on_msg(ls: SphinxClient, params): + ls.manager.server.show_message_log(params.message) + + return client diff --git a/lib/esbonio/esbonio/server/features/sphinx_manager/manager.py b/lib/esbonio/esbonio/server/features/sphinx_manager/manager.py new file mode 100644 index 000000000..8b37ccd2a --- /dev/null +++ b/lib/esbonio/esbonio/server/features/sphinx_manager/manager.py @@ -0,0 +1,154 @@ +from __future__ import annotations + +import importlib.util +import logging +import pathlib +import typing +from typing import List +from typing import Optional + +import attrs +import lsprotocol.types as lsp +import pygls.uris as Uri +from pygls.workspace import Workspace + +from esbonio.server import LanguageFeature + +from .client import make_sphinx_client + +if typing.TYPE_CHECKING: + from .client import SphinxClient + + +def get_python_path() -> Optional[pathlib.Path]: + spec = importlib.util.find_spec("esbonio.sphinx_agent") + if spec is None: + return None + + if spec.origin is None: + return None + + # origin = .../esbonio/sphinx_agent/__init__.py + agent = pathlib.Path(spec.origin) + return agent.parent.parent + + +@attrs.define +class SphinxConfig: + """Configuration for the sphinx application instance.""" + + python_command: List[str] = attrs.field(factory=list) + """The command to use when launching the python interpreter.""" + + build_command: List[str] = attrs.field(factory=list) + """The sphinx-build command to use.""" + + cwd: str = attrs.field(default="") + """The working directory to use.""" + + python_path: Optional[pathlib.Path] = attrs.field(default=get_python_path()) + """The value of ``PYTHONPATH`` to use when injecting the sphinx agent into the + target environment""" + + def resolve( + self, + uri: str, + workspace: Workspace, + logger: logging.Logger, + ) -> "Optional[SphinxConfig]": + """Resolve the configuration based on user provided values.""" + + if self.python_path is None: + logger.error("Unable to locate the sphinx agent") + return None + + cwd = self._resolve_cwd(uri, workspace, logger) + if cwd is None: + return None + + build_command = self.build_command + if len(build_command) == 0: + build_command = ["-M", "dirhtml", ".", "./_build"] + + return SphinxConfig( + cwd=cwd, + python_command=self.python_command, + build_command=build_command, + python_path=self.python_path, + ) + + def _resolve_cwd(self, uri: str, workspace: Workspace, logger: logging.Logger): + for folder_uri in workspace.folders.keys(): + if uri.startswith(folder_uri): + break + else: + folder_uri = workspace.root_uri + + cwd = Uri.to_fs_path(folder_uri) + if cwd is None: + logger.error("Unable to determine working directory from '%s'", folder_uri) + return None + + logger.debug("Cwd: %s", cwd) + return cwd + + +class SphinxManager(LanguageFeature): + """Responsible for managing Sphinx application instances.""" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.client = None + + def document_change(self, params: lsp.DidChangeTextDocumentParams): + self.logger.debug("Changed document '%s'", params.text_document.uri) + + def document_close(self, params: lsp.DidCloseTextDocumentParams): + self.logger.debug("Closed document '%s'", params.text_document.uri) + + async def document_open(self, params: lsp.DidOpenTextDocumentParams): + self.logger.debug("Opened document '%s'", params.text_document.uri) + await self.get_client(params.text_document.uri) + + def document_save(self, params: lsp.DidSaveTextDocumentParams): + self.logger.debug("Saved document '%s'", params.text_document.uri) + + async def get_client(self, uri: str) -> Optional[SphinxClient]: + """Given a uri, return the relevant sphinx client instance for it.""" + if self.client is not None: + return self.client + + self.logger.debug("Creating new Sphinx instance.") + params = lsp.ConfigurationParams( + items=[lsp.ConfigurationItem(section="esbonio.sphinx", scope_uri=uri)] + ) + result = await self.server.get_configuration_async(params) + try: + config = self.converter.structure(result[0], SphinxConfig) + self.logger.debug("User config: %s", config) + except Exception: + self.logger.error( + "Unable to parse sphinx configuration options", exc_info=True + ) + return None + + resolved = config.resolve(uri, self.server.workspace, self.logger) + if resolved is None: + return None + + command = [*resolved.python_command, "-m", "sphinx_agent"] + self.logger.debug("Starting sphinx agent: %s", " ".join(command)) + + self.client = make_sphinx_client(self) + await self.client.start_io( + *command, env={"PYTHONPATH": resolved.python_path}, cwd=resolved.cwd + ) + + if not self.client.stopped: + self.logger.debug("Starting sphinx: %s", " ".join(resolved.build_command)) + await self.client.protocol.send_request_async( + "sphinx/createApp", {"command": resolved.build_command} + ) + + return self.client diff --git a/lib/esbonio/esbonio/server/log.py b/lib/esbonio/esbonio/server/log.py index b8c08bcc3..5fb9d7925 100644 --- a/lib/esbonio/esbonio/server/log.py +++ b/lib/esbonio/esbonio/server/log.py @@ -1,7 +1,10 @@ from __future__ import annotations +import enum +import json import logging import pathlib +import textwrap import traceback import typing from typing import List @@ -180,3 +183,26 @@ def setup_logging(server: EsbonioLanguageServer, config: ServerConfig): logger.addHandler(lsp_handler) warnlog.addHandler(lsp_handler) + + +def dump(obj) -> str: + """Debug helper function that converts an object to JSON.""" + + def default(o): + if isinstance(o, enum.Enum): + return o.value + + fields = {} + for k, v in o.__dict__.items(): + if v is None: + continue + + # Truncate long strings - but not uris! + if isinstance(v, str) and not k.lower().endswith("uri"): + v = textwrap.shorten(v, width=25) + + fields[k] = v + + return fields + + return json.dumps(obj, default=default, indent=2) diff --git a/lib/esbonio/esbonio/sphinx_agent/config.py b/lib/esbonio/esbonio/sphinx_agent/config.py index c2552adc2..c19ba3767 100644 --- a/lib/esbonio/esbonio/sphinx_agent/config.py +++ b/lib/esbonio/esbonio/sphinx_agent/config.py @@ -95,6 +95,9 @@ def fromcli(cls, args: List[str]): options derived from the sphinx build command. """ + if args[0] == "sphinx-build": + args = args[1:] + # The easiest way to handle this is to just call sphinx-build but with # the Sphinx app object patched out - then we just use all the args it # was given! From 65ef6a09407406d678fa15493731a84090a7d41e Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Thu, 15 Jun 2023 20:52:56 +0100 Subject: [PATCH 042/141] lsp: Guess build command if none given Similiar to the current version, if no explicit configuration is given the language server will attempt to guess a valid configuration --- .../server/features/sphinx_manager/manager.py | 34 ++++++++++++++++++- lib/esbonio/esbonio/server/setup.py | 2 +- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/lib/esbonio/esbonio/server/features/sphinx_manager/manager.py b/lib/esbonio/esbonio/server/features/sphinx_manager/manager.py index 8b37ccd2a..09851e167 100644 --- a/lib/esbonio/esbonio/server/features/sphinx_manager/manager.py +++ b/lib/esbonio/esbonio/server/features/sphinx_manager/manager.py @@ -1,5 +1,6 @@ from __future__ import annotations +import hashlib import importlib.util import logging import pathlib @@ -7,6 +8,7 @@ from typing import List from typing import Optional +import appdirs import attrs import lsprotocol.types as lsp import pygls.uris as Uri @@ -68,7 +70,7 @@ def resolve( build_command = self.build_command if len(build_command) == 0: - build_command = ["-M", "dirhtml", ".", "./_build"] + build_command = self._guess_build_command(uri, logger) return SphinxConfig( cwd=cwd, @@ -92,6 +94,32 @@ def _resolve_cwd(self, uri: str, workspace: Workspace, logger: logging.Logger): logger.debug("Cwd: %s", cwd) return cwd + def _guess_build_command(self, uri: str, logger: logging.Logger) -> List[str]: + """Try and guess something a sensible build command given the uri.""" + + path = Uri.to_fs_path(uri) + if path is None: + return [] + + # Search upwards from the given uri to see if we find something that looks like + # a sphinx conf.py file. + previous = None + current = pathlib.Path(path) + + while previous != current: + previous = current + current = previous.parent + + conf_py = current / "conf.py" + logger.debug("Trying path: %s", current) + if conf_py.exists(): + cache = appdirs.user_cache_dir("esbonio", "swyddfa") + project = hashlib.md5(str(current).encode()).hexdigest() + build_dir = str(pathlib.Path(cache, project)) + return ["sphinx-build", "-M", "dirhtml", str(current), str(build_dir)] + + return [] + class SphinxManager(LanguageFeature): """Responsible for managing Sphinx application instances.""" @@ -137,6 +165,10 @@ async def get_client(self, uri: str) -> Optional[SphinxClient]: if resolved is None: return None + if len(resolved.build_command) == 0: + self.logger.error("Unable to start Sphinx: missing build command") + return None + command = [*resolved.python_command, "-m", "sphinx_agent"] self.logger.debug("Starting sphinx agent: %s", " ".join(command)) diff --git a/lib/esbonio/esbonio/server/setup.py b/lib/esbonio/esbonio/server/setup.py index 0d59de054..5b4cef978 100644 --- a/lib/esbonio/esbonio/server/setup.py +++ b/lib/esbonio/esbonio/server/setup.py @@ -101,7 +101,7 @@ async def call_features(ls: EsbonioLanguageServer, method: str, *args, **kwargs) await result except Exception: - name = f"{cls.__module__}.{cls.__name__}" + name = f"{cls.__name__}" ls.logger.error("Error in '%s.%s' handler", name, method, exc_info=True) From 7fc5e43dfa6fca12e26d412af230ca6d16b9f606 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Fri, 16 Jun 2023 19:38:23 +0100 Subject: [PATCH 043/141] sphinx-agent: Basic error handling --- lib/esbonio/esbonio/sphinx_agent/__init__.py | 14 +++++++++++++- lib/esbonio/esbonio/sphinx_agent/util.py | 11 +++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/lib/esbonio/esbonio/sphinx_agent/__init__.py b/lib/esbonio/esbonio/sphinx_agent/__init__.py index 7872985cf..ce61620e8 100644 --- a/lib/esbonio/esbonio/sphinx_agent/__init__.py +++ b/lib/esbonio/esbonio/sphinx_agent/__init__.py @@ -22,12 +22,14 @@ import re import sys import threading +import traceback from concurrent.futures import ThreadPoolExecutor from typing import Dict from typing import Type from typing import TypeVar from .handlers import HANDLERS +from .util import send_error logger = logging.getLogger(__name__) @@ -62,7 +64,17 @@ def handle_message(data: bytes): raise TypeError(f"Unknown method: '{method}'") obj = parse_message(message, type_) - handler(obj) + try: + handler(obj) + except Exception as e: + msg_id = message.get("id", None) + if msg_id is not None: + send_error( + id=msg_id, + code=-32602, + message=f"{e}", + data=dict(traceback=traceback.format_exc()), + ) async def main_loop(loop, executor, stop_event, rfile, proxy): diff --git a/lib/esbonio/esbonio/sphinx_agent/util.py b/lib/esbonio/esbonio/sphinx_agent/util.py index 8421bd113..29867c60f 100644 --- a/lib/esbonio/esbonio/sphinx_agent/util.py +++ b/lib/esbonio/esbonio/sphinx_agent/util.py @@ -3,6 +3,7 @@ import logging import sys from typing import Any +from typing import Union logger = logging.getLogger("esbonio.sphinx_agent") @@ -17,6 +18,16 @@ def format_message(data: Any) -> str: return f"Content-Length: {content_length}\r\n\r\n{content}" +def send_error(id: Union[str, int], code: int, message: str, data=None): + send_message( + dict( + id=id, + jsonrpc="2.0", + error=dict(code=code, message=message, data=data), + ) + ) + + def send_message(data: Any): content = format_message(data).encode("utf8") sys.stdout.buffer.write(content) From 848f5965506e707fc556ac96c8d917c4c7b857ab Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Fri, 16 Jun 2023 19:39:21 +0100 Subject: [PATCH 044/141] sphinx-agent: Send a response to the `sphinx/createApp` request --- lib/esbonio/esbonio/sphinx_agent/handlers.py | 25 ++++++++++++++----- lib/esbonio/esbonio/sphinx_agent/types.py | 26 ++++++++++++++++++++ 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/lib/esbonio/esbonio/sphinx_agent/handlers.py b/lib/esbonio/esbonio/sphinx_agent/handlers.py index 3cf6df606..f4f4a9461 100644 --- a/lib/esbonio/esbonio/sphinx_agent/handlers.py +++ b/lib/esbonio/esbonio/sphinx_agent/handlers.py @@ -4,15 +4,17 @@ from typing import Optional from typing import Type +from sphinx import __version__ as __sphinx_version__ from sphinx.application import Sphinx from sphinx.util import console from sphinx.util import logging as sphinx_logging_module from sphinx.util.logging import NAMESPACE as SPHINX_LOG_NAMESPACE from sphinx.util.logging import VERBOSITY_MAP +from . import types from .config import SphinxConfig from .log import SphinxLogHandler -from .types import CreateApplicationRequest +from .util import send_message HANDLERS = {} @@ -29,8 +31,8 @@ def wrapper(f): return wrapper -@handler(CreateApplicationRequest) -def create_sphinx_app(request: CreateApplicationRequest): +@handler(types.CreateApplicationRequest) +def create_sphinx_app(request: types.CreateApplicationRequest): sphinx_config = SphinxConfig.fromcli(request.params.command) if sphinx_config is None: raise ValueError("Invalid build command") @@ -39,9 +41,20 @@ def create_sphinx_app(request: CreateApplicationRequest): # Override Sphinx's logging setup with our own. sphinx_logging_module.setup = partial(logging_setup, sphinx_config) - - app = Sphinx(**sphinx_args) - app.build() + sphinx_app = Sphinx(**sphinx_args) + + response = types.CreateApplicationResponse( + id=request.id, + result=types.SphinxInfo( + version=__sphinx_version__, + conf_dir=sphinx_app.confdir, + build_dir=sphinx_app.outdir, + builder_name=sphinx_app.builder.name, + src_dir=sphinx_app.srcdir, + ), + jsonrpc=request.jsonrpc, + ) + send_message(response) def logging_setup(config: SphinxConfig, app: Sphinx, status: IO, warning: IO): diff --git a/lib/esbonio/esbonio/sphinx_agent/types.py b/lib/esbonio/esbonio/sphinx_agent/types.py index d202181e9..3f8b71fc5 100644 --- a/lib/esbonio/esbonio/sphinx_agent/types.py +++ b/lib/esbonio/esbonio/sphinx_agent/types.py @@ -24,6 +24,32 @@ class CreateApplicationRequest: jsonrpc: str = dataclasses.field(default="2.0") +@dataclasses.dataclass +class SphinxInfo: + """Represents information about an instance of the Sphinx application.""" + + version: str + + conf_dir: str + + build_dir: str + + builder_name: str + + src_dir: str + + +@dataclasses.dataclass +class CreateApplicationResponse: + """A ``sphinx/createApp`` response.""" + + id: Union[int, str] + + result: SphinxInfo + + jsonrpc: str = dataclasses.field(default="2.0") + + @dataclasses.dataclass class LogMessageParams: """Parameters of a ``window/logMessage`` notification.""" From a4beae9d788dfe7839d7ac0a6369cefde2e0c0e0 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Fri, 16 Jun 2023 19:40:01 +0100 Subject: [PATCH 045/141] sphinx-agent: Cleanup `SphinxConfig` class - Remove unecessary code - Fix output paths when make mode is in use --- lib/esbonio/esbonio/sphinx_agent/config.py | 103 ++------------------- 1 file changed, 8 insertions(+), 95 deletions(-) diff --git a/lib/esbonio/esbonio/sphinx_agent/config.py b/lib/esbonio/esbonio/sphinx_agent/config.py index c19ba3767..c9c6b21f8 100644 --- a/lib/esbonio/esbonio/sphinx_agent/config.py +++ b/lib/esbonio/esbonio/sphinx_agent/config.py @@ -1,7 +1,6 @@ import dataclasses import inspect import pathlib -import re from typing import Any from typing import Dict from typing import List @@ -13,8 +12,6 @@ from sphinx.application import Sphinx from sphinx.cmd.build import main as sphinx_build -PATH_VAR_PATTERN = re.compile(r"^\${(\w+)}/?.*") - @dataclasses.dataclass class SphinxConfig: @@ -141,108 +138,24 @@ def fromcli(cls, args: List[str]): warning_is_error=sphinx_args.get("warningiserror", False), ) - def to_cli_args(self) -> List[str]: - """Convert this into the equivalent ``sphinx-build`` cli arguments.""" + def to_application_args(self) -> Dict[str, Any]: + """Convert this into the equivalent Sphinx application arguments.""" if self.make_mode: - return self._build_make_cli_args() - - return self._build_cli_args() - - def _build_make_cli_args(self) -> List[str]: - args = ["-M", self.builder_name] - conf_dir = self.conf_dir or "${workspaceRoot}" - src_dir = self.src_dir or conf_dir - - if self.build_dir is None: - build_dir = pathlib.Path(src_dir, "_build") + outdir = str(pathlib.Path(self.build_dir, self.builder_name)) + doctree_dir = str(pathlib.Path(self.build_dir, "doctrees")) else: - build_dir = pathlib.Path(self.build_dir) - - args += [src_dir, str(build_dir)] - - args += self._build_standard_args() - default_dtree_dir = str(pathlib.Path(build_dir, "doctrees")) - if self.doctree_dir is not None and self.doctree_dir != default_dtree_dir: - args += ["-d", self.doctree_dir] - - return args - - def _build_cli_args(self) -> List[str]: - args = ["-b", self.builder_name] - - conf_dir = self.conf_dir or "${workspaceRoot}" - src_dir = self.src_dir or conf_dir - - build_dir = self.build_dir or pathlib.Path(src_dir, "_build") - default_dtree_dir = str(pathlib.Path(build_dir, ".doctrees")) - - if self.doctree_dir is not None and self.doctree_dir != default_dtree_dir: - args += ["-d", self.doctree_dir] - - args += self._build_standard_args() - args += [src_dir, str(build_dir)] - return args - - def _build_standard_args(self) -> List[str]: - args: List[str] = [] - - conf_dir = self.conf_dir or "${workspaceRoot}" - src_dir = self.src_dir or self.conf_dir - - if conf_dir != src_dir: - args += ["-c", conf_dir] - - if self.force_full_build: - args += ["-E"] - - if self.parallel > 1: - args += ["-j", str(self.num_jobs)] - - if self.silent: - args += ["-Q"] - - if self.quiet and not self.silent: - args += ["-q"] - - if self.warning_is_error: - args += ["-W"] - - if self.keep_going: - args += ["--keep-going"] - - if self.verbosity > 0: - args += ["-" + ("v" * self.verbosity)] - - for key, value in self.config_overrides.items(): - if key == "nitpicky": - args += ["-n"] - continue - - if key.startswith("html_context."): - char = "A" - key = key.replace("html_context.", "") - else: - char = "D" - - args += [f"-{char}{key}={value}"] - - for tag in self.tags: - args += ["-t", tag] - - return args - - def to_application_args(self) -> Dict[str, Any]: - """Convert this into the equivalent Sphinx application arguments.""" + outdir = self.build_dir + doctree_dir = self.doctree_dir return { "buildername": self.builder_name, "confdir": self.conf_dir, "confoverrides": self.config_overrides, - "doctreedir": self.doctree_dir, + "doctreedir": doctree_dir, "freshenv": self.force_full_build, "keep_going": self.keep_going, - "outdir": self.build_dir, + "outdir": outdir, "parallel": self.parallel, "srcdir": self.src_dir, "status": None, From c50475e427a5340cd0cfef2b7497b39f0a6a424a Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Fri, 16 Jun 2023 19:41:19 +0100 Subject: [PATCH 046/141] lsp: Basic multi-project support! Now when creating a client, the client is stored on the `SphinxManager` class in a dictionary, using the Sphinx app's `srcdir` (converted to uri) as the key. That way, when using `get_client` to obtain the correct client for the given uri all we have to do is check if its key is a prefix of the given uri. I can think of plenty of edge cases where this wouldn't necessarily work well, but this *probably* is good enough for the 80% use case? --- .../server/features/sphinx_manager/manager.py | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/lib/esbonio/esbonio/server/features/sphinx_manager/manager.py b/lib/esbonio/esbonio/server/features/sphinx_manager/manager.py index 09851e167..c3e771d4c 100644 --- a/lib/esbonio/esbonio/server/features/sphinx_manager/manager.py +++ b/lib/esbonio/esbonio/server/features/sphinx_manager/manager.py @@ -5,6 +5,7 @@ import logging import pathlib import typing +from typing import Dict from typing import List from typing import Optional @@ -127,7 +128,7 @@ class SphinxManager(LanguageFeature): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.client = None + self.clients: Dict[str, SphinxClient] = {} def document_change(self, params: lsp.DidChangeTextDocumentParams): self.logger.debug("Changed document '%s'", params.text_document.uri) @@ -144,10 +145,11 @@ def document_save(self, params: lsp.DidSaveTextDocumentParams): async def get_client(self, uri: str) -> Optional[SphinxClient]: """Given a uri, return the relevant sphinx client instance for it.""" - if self.client is not None: - return self.client - self.logger.debug("Creating new Sphinx instance.") + for srcdir, client in self.clients.items(): + if uri.startswith(srcdir): + return client + params = lsp.ConfigurationParams( items=[lsp.ConfigurationItem(section="esbonio.sphinx", scope_uri=uri)] ) @@ -172,15 +174,25 @@ async def get_client(self, uri: str) -> Optional[SphinxClient]: command = [*resolved.python_command, "-m", "sphinx_agent"] self.logger.debug("Starting sphinx agent: %s", " ".join(command)) - self.client = make_sphinx_client(self) - await self.client.start_io( + client = make_sphinx_client(self) + await client.start_io( *command, env={"PYTHONPATH": resolved.python_path}, cwd=resolved.cwd ) - if not self.client.stopped: - self.logger.debug("Starting sphinx: %s", " ".join(resolved.build_command)) - await self.client.protocol.send_request_async( - "sphinx/createApp", {"command": resolved.build_command} - ) + if client.stopped: + return None + + self.logger.debug("Starting sphinx: %s", " ".join(resolved.build_command)) + response = await client.protocol.send_request_async( + "sphinx/createApp", {"command": resolved.build_command} + ) + self.logger.debug("Sphinx started: %s", response) + + src_uri = Uri.from_fs_path(response.src_dir) + if src_uri is None: + self.logger.error("Invalid srcdir '%s'", response.src_dir) + await client.stop() + return None - return self.client + self.clients[src_uri] = client + return client From de9b9c79df8cd56be0c97a3098c6234f6550cbee Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Fri, 16 Jun 2023 22:50:17 +0100 Subject: [PATCH 047/141] sphinx-agent: Add `sphinx/build` request --- lib/esbonio/esbonio/sphinx_agent/handlers.py | 23 ++++++++++ lib/esbonio/esbonio/sphinx_agent/types.py | 46 ++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/lib/esbonio/esbonio/sphinx_agent/handlers.py b/lib/esbonio/esbonio/sphinx_agent/handlers.py index f4f4a9461..1d48e0805 100644 --- a/lib/esbonio/esbonio/sphinx_agent/handlers.py +++ b/lib/esbonio/esbonio/sphinx_agent/handlers.py @@ -14,6 +14,7 @@ from . import types from .config import SphinxConfig from .log import SphinxLogHandler +from .util import send_error from .util import send_message HANDLERS = {} @@ -33,6 +34,7 @@ def wrapper(f): @handler(types.CreateApplicationRequest) def create_sphinx_app(request: types.CreateApplicationRequest): + """Create a new sphinx application instance.""" sphinx_config = SphinxConfig.fromcli(request.params.command) if sphinx_config is None: raise ValueError("Invalid build command") @@ -41,6 +43,7 @@ def create_sphinx_app(request: types.CreateApplicationRequest): # Override Sphinx's logging setup with our own. sphinx_logging_module.setup = partial(logging_setup, sphinx_config) + global sphinx_app sphinx_app = Sphinx(**sphinx_args) response = types.CreateApplicationResponse( @@ -57,6 +60,26 @@ def create_sphinx_app(request: types.CreateApplicationRequest): send_message(response) +@handler(types.BuildRequest) +def build_sphinx_app(request: types.BuildRequest): + """Trigger a Sphinx build.""" + + if sphinx_app is None: + send_error(id=request.id, code=-32803, message="Sphinx app not initialzied") + return + + try: + sphinx_app.build() + response = types.BuildResponse( + id=request.id, + result=types.BuildResult(), + jsonrpc=request.jsonrpc, + ) + send_message(response) + except Exception: + send_error(id=request.id, code=-32602, message="Sphinx build failed.") + + def logging_setup(config: SphinxConfig, app: Sphinx, status: IO, warning: IO): """Setup Sphinx's logging so that it integrates well with the parent language server.""" diff --git a/lib/esbonio/esbonio/sphinx_agent/types.py b/lib/esbonio/esbonio/sphinx_agent/types.py index 3f8b71fc5..e164c0f15 100644 --- a/lib/esbonio/esbonio/sphinx_agent/types.py +++ b/lib/esbonio/esbonio/sphinx_agent/types.py @@ -1,5 +1,11 @@ +"""Type definitions for the sphinx agent. + +This is the *only* file shared between the agent itself and the parent language server. +For this reason this file *cannot* import anything from Sphinx. +""" import dataclasses from typing import List +from typing import Optional from typing import Union @@ -24,6 +30,46 @@ class CreateApplicationRequest: jsonrpc: str = dataclasses.field(default="2.0") +@dataclasses.dataclass +class BuildParams: + """Parameters of a ``sphinx/build`` request.""" + + filenames: Optional[List[str]] = dataclasses.field(default_factory=list) + + force_all: bool = False + + +@dataclasses.dataclass +class BuildResult: + """Results from a ``sphinx/build`` request.""" + + placeholder: str = "TODO: Real results" + + +@dataclasses.dataclass +class BuildRequest: + """A ``sphinx/build`` request.""" + + id: Union[int, str] + + params: BuildParams + + method: str = "sphinx/build" + + jsonrpc: str = dataclasses.field(default="2.0") + + +@dataclasses.dataclass +class BuildResponse: + """A ``sphinx/build`` response.""" + + id: Union[int, str] + + result: BuildResult + + jsonrpc: str = dataclasses.field(default="2.0") + + @dataclasses.dataclass class SphinxInfo: """Represents information about an instance of the Sphinx application.""" From e23fe39632704e1630efebc38838f613a70097f1 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Fri, 16 Jun 2023 22:52:23 +0100 Subject: [PATCH 048/141] lsp: Trigger builds on save and on initial creation --- .../server/features/sphinx_manager/manager.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/esbonio/esbonio/server/features/sphinx_manager/manager.py b/lib/esbonio/esbonio/server/features/sphinx_manager/manager.py index c3e771d4c..cc47e5717 100644 --- a/lib/esbonio/esbonio/server/features/sphinx_manager/manager.py +++ b/lib/esbonio/esbonio/server/features/sphinx_manager/manager.py @@ -129,6 +129,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.clients: Dict[str, SphinxClient] = {} + self.jobs = set() def document_change(self, params: lsp.DidChangeTextDocumentParams): self.logger.debug("Changed document '%s'", params.text_document.uri) @@ -140,9 +141,16 @@ async def document_open(self, params: lsp.DidOpenTextDocumentParams): self.logger.debug("Opened document '%s'", params.text_document.uri) await self.get_client(params.text_document.uri) - def document_save(self, params: lsp.DidSaveTextDocumentParams): + async def document_save(self, params: lsp.DidSaveTextDocumentParams): self.logger.debug("Saved document '%s'", params.text_document.uri) + client = await self.get_client(params.text_document.uri) + if client is None: + return + + result = await client.protocol.send_request_async("sphinx/build", {}) + self.logger.debug("Build result: %s", result) + async def get_client(self, uri: str) -> Optional[SphinxClient]: """Given a uri, return the relevant sphinx client instance for it.""" @@ -195,4 +203,10 @@ async def get_client(self, uri: str) -> Optional[SphinxClient]: return None self.clients[src_uri] = client + + # Do an initial build in the background so that we're free to do other things. + build_task = client.protocol.send_request_async("sphinx/build", {}) + self.jobs.add(build_task) + build_task.add_done_callback(self.jobs.discard) + return client From a9cd64d5b8180136c45c0856f23fa31bc4114226 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Jun 2023 15:01:53 +0000 Subject: [PATCH 049/141] build(deps): bump semver from 7.5.1 to 7.5.2 in /code Bumps [semver](https://github.com/npm/node-semver) from 7.5.1 to 7.5.2. - [Release notes](https://github.com/npm/node-semver/releases) - [Changelog](https://github.com/npm/node-semver/blob/main/CHANGELOG.md) - [Commits](https://github.com/npm/node-semver/compare/v7.5.1...v7.5.2) --- updated-dependencies: - dependency-name: semver dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- code/package-lock.json | 14 +++++++------- code/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/code/package-lock.json b/code/package-lock.json index 5da793ce4..64fa64f1f 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -9,7 +9,7 @@ "version": "0.11.0", "license": "MIT", "dependencies": { - "semver": "^7.5.1", + "semver": "^7.5.2", "vscode-languageclient": "^8.1.0" }, "devDependencies": { @@ -2837,9 +2837,9 @@ } }, "node_modules/semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz", + "integrity": "sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -6038,9 +6038,9 @@ } }, "semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz", + "integrity": "sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==", "requires": { "lru-cache": "^6.0.0" } diff --git a/code/package.json b/code/package.json index cdf949104..2ab7aa3a2 100644 --- a/code/package.json +++ b/code/package.json @@ -31,7 +31,7 @@ "main": "dist/node/extension", "browser": "dist/browser/extension", "dependencies": { - "semver": "^7.5.1", + "semver": "^7.5.2", "vscode-languageclient": "^8.1.0" }, "devDependencies": { From 39ee918a300d9831c3a164d9f5a953156864a54b Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Mon, 19 Jun 2023 19:31:06 +0100 Subject: [PATCH 050/141] lsp: Move some logic into `SphinxClient` This commit moves some of the details of starting the sphinx agent and creating the application object into the `SphinxClient`. It also records the response to the `sphinx/createApp` request and defines some properties allowing easy access to variables like `srcdir`, `confdir` etc. --- .../server/features/sphinx_manager/client.py | 79 +++++++++++ .../server/features/sphinx_manager/config.py | 110 +++++++++++++++ .../server/features/sphinx_manager/manager.py | 130 ++---------------- 3 files changed, 197 insertions(+), 122 deletions(-) create mode 100644 lib/esbonio/esbonio/server/features/sphinx_manager/config.py diff --git a/lib/esbonio/esbonio/server/features/sphinx_manager/client.py b/lib/esbonio/esbonio/server/features/sphinx_manager/client.py index 52f6095bf..31896859b 100644 --- a/lib/esbonio/esbonio/server/features/sphinx_manager/client.py +++ b/lib/esbonio/esbonio/server/features/sphinx_manager/client.py @@ -2,9 +2,13 @@ import asyncio import typing +from typing import Optional +import pygls.uris as Uri from pygls.client import Client +from .config import SphinxConfig + if typing.TYPE_CHECKING: from .manager import SphinxManager @@ -18,13 +22,88 @@ def __init__(self, manager: SphinxManager, *args, **kwargs): self.manager = manager self.logger = manager.logger + self.sphinx_info = None + + @property + def src_dir(self) -> Optional[str]: + """The src directory of the Sphinx application.""" + if self.sphinx_info is None: + return None + + return self.sphinx_info.src_dir + + @property + def src_uri(self) -> Optional[str]: + """The src uri of the Sphinx application.""" + src_dir = self.src_dir + if src_dir is None: + return None + + return Uri.from_fs_path(src_dir) + + @property + def conf_dir(self) -> Optional[str]: + """The conf directory of the Sphinx application.""" + if self.sphinx_info is None: + return None + + return self.sphinx_info.conf_dir + + @property + def conf_uri(self) -> Optional[str]: + """The conf uri of the Sphinx application.""" + conf_dir = self.conf_dir + if conf_dir is None: + return None + + return Uri.from_fs_path(conf_dir) + + @property + def build_dir(self) -> Optional[str]: + """The build directory of the Sphinx application.""" + if self.sphinx_info is None: + return None + + return self.sphinx_info.build_dir + + @property + def build_uri(self) -> Optional[str]: + """The build uri of the Sphinx application.""" + build_dir = self.build_dir + if build_dir is None: + return None + + return Uri.from_fs_path(build_dir) + + async def start(self, config: SphinxConfig): + """Start the sphinx agent.""" + command = [*config.python_command, "-m", "sphinx_agent"] + self.logger.debug("Starting sphinx agent: %s", " ".join(command)) + + await self.start_io( + *command, env={"PYTHONPATH": config.python_path}, cwd=config.cwd + ) + async def server_exit(self, server: asyncio.subprocess.Process): + """Called when the sphinx agent process exits.""" self.logger.debug(f"Process exited with code: {server.returncode}") if server.returncode != 0: stderr = await server.stderr.read() self.logger.debug("Stderr:\n%s", stderr.decode("utf8")) + async def create_application(self, config: SphinxConfig): + """Create a sphinx application object.""" + + if self.stopped: + raise RuntimeError("Client is stopped.") + + self.logger.debug("Starting sphinx: %s", " ".join(config.build_command)) + self.sphinx_info = await self.protocol.send_request_async( + "sphinx/createApp", {"command": config.build_command} + ) + return self.sphinx_info + def make_sphinx_client(manager: SphinxManager): client = SphinxClient(manager=manager) diff --git a/lib/esbonio/esbonio/server/features/sphinx_manager/config.py b/lib/esbonio/esbonio/server/features/sphinx_manager/config.py new file mode 100644 index 000000000..e6d9db42b --- /dev/null +++ b/lib/esbonio/esbonio/server/features/sphinx_manager/config.py @@ -0,0 +1,110 @@ +import hashlib +import importlib.util +import logging +import pathlib +from typing import List +from typing import Optional + +import appdirs +import attrs +import pygls.uris as Uri +from pygls.workspace import Workspace + + +def get_python_path() -> Optional[pathlib.Path]: + spec = importlib.util.find_spec("esbonio.sphinx_agent") + if spec is None: + return None + + if spec.origin is None: + return None + + # origin = .../esbonio/sphinx_agent/__init__.py + agent = pathlib.Path(spec.origin) + return agent.parent.parent + + +@attrs.define +class SphinxConfig: + """Configuration for the sphinx application instance.""" + + python_command: List[str] = attrs.field(factory=list) + """The command to use when launching the python interpreter.""" + + build_command: List[str] = attrs.field(factory=list) + """The sphinx-build command to use.""" + + cwd: str = attrs.field(default="") + """The working directory to use.""" + + python_path: Optional[pathlib.Path] = attrs.field(default=get_python_path()) + """The value of ``PYTHONPATH`` to use when injecting the sphinx agent into the + target environment""" + + def resolve( + self, + uri: str, + workspace: Workspace, + logger: logging.Logger, + ) -> "Optional[SphinxConfig]": + """Resolve the configuration based on user provided values.""" + + if self.python_path is None: + logger.error("Unable to locate the sphinx agent") + return None + + cwd = self._resolve_cwd(uri, workspace, logger) + if cwd is None: + return None + + build_command = self.build_command + if len(build_command) == 0: + build_command = self._guess_build_command(uri, logger) + + return SphinxConfig( + cwd=cwd, + python_command=self.python_command, + build_command=build_command, + python_path=self.python_path, + ) + + def _resolve_cwd(self, uri: str, workspace: Workspace, logger: logging.Logger): + for folder_uri in workspace.folders.keys(): + if uri.startswith(folder_uri): + break + else: + folder_uri = workspace.root_uri + + cwd = Uri.to_fs_path(folder_uri) + if cwd is None: + logger.error("Unable to determine working directory from '%s'", folder_uri) + return None + + logger.debug("Cwd: %s", cwd) + return cwd + + def _guess_build_command(self, uri: str, logger: logging.Logger) -> List[str]: + """Try and guess something a sensible build command given the uri.""" + + path = Uri.to_fs_path(uri) + if path is None: + return [] + + # Search upwards from the given uri to see if we find something that looks like + # a sphinx conf.py file. + previous = None + current = pathlib.Path(path) + + while previous != current: + previous = current + current = previous.parent + + conf_py = current / "conf.py" + logger.debug("Trying path: %s", current) + if conf_py.exists(): + cache = appdirs.user_cache_dir("esbonio", "swyddfa") + project = hashlib.md5(str(current).encode()).hexdigest() + build_dir = str(pathlib.Path(cache, project)) + return ["sphinx-build", "-M", "dirhtml", str(current), str(build_dir)] + + return [] diff --git a/lib/esbonio/esbonio/server/features/sphinx_manager/manager.py b/lib/esbonio/esbonio/server/features/sphinx_manager/manager.py index cc47e5717..d3fba86c8 100644 --- a/lib/esbonio/esbonio/server/features/sphinx_manager/manager.py +++ b/lib/esbonio/esbonio/server/features/sphinx_manager/manager.py @@ -1,127 +1,21 @@ from __future__ import annotations -import hashlib -import importlib.util -import logging -import pathlib import typing from typing import Dict -from typing import List from typing import Optional -import appdirs -import attrs import lsprotocol.types as lsp import pygls.uris as Uri -from pygls.workspace import Workspace from esbonio.server import LanguageFeature from .client import make_sphinx_client +from .config import SphinxConfig if typing.TYPE_CHECKING: from .client import SphinxClient -def get_python_path() -> Optional[pathlib.Path]: - spec = importlib.util.find_spec("esbonio.sphinx_agent") - if spec is None: - return None - - if spec.origin is None: - return None - - # origin = .../esbonio/sphinx_agent/__init__.py - agent = pathlib.Path(spec.origin) - return agent.parent.parent - - -@attrs.define -class SphinxConfig: - """Configuration for the sphinx application instance.""" - - python_command: List[str] = attrs.field(factory=list) - """The command to use when launching the python interpreter.""" - - build_command: List[str] = attrs.field(factory=list) - """The sphinx-build command to use.""" - - cwd: str = attrs.field(default="") - """The working directory to use.""" - - python_path: Optional[pathlib.Path] = attrs.field(default=get_python_path()) - """The value of ``PYTHONPATH`` to use when injecting the sphinx agent into the - target environment""" - - def resolve( - self, - uri: str, - workspace: Workspace, - logger: logging.Logger, - ) -> "Optional[SphinxConfig]": - """Resolve the configuration based on user provided values.""" - - if self.python_path is None: - logger.error("Unable to locate the sphinx agent") - return None - - cwd = self._resolve_cwd(uri, workspace, logger) - if cwd is None: - return None - - build_command = self.build_command - if len(build_command) == 0: - build_command = self._guess_build_command(uri, logger) - - return SphinxConfig( - cwd=cwd, - python_command=self.python_command, - build_command=build_command, - python_path=self.python_path, - ) - - def _resolve_cwd(self, uri: str, workspace: Workspace, logger: logging.Logger): - for folder_uri in workspace.folders.keys(): - if uri.startswith(folder_uri): - break - else: - folder_uri = workspace.root_uri - - cwd = Uri.to_fs_path(folder_uri) - if cwd is None: - logger.error("Unable to determine working directory from '%s'", folder_uri) - return None - - logger.debug("Cwd: %s", cwd) - return cwd - - def _guess_build_command(self, uri: str, logger: logging.Logger) -> List[str]: - """Try and guess something a sensible build command given the uri.""" - - path = Uri.to_fs_path(uri) - if path is None: - return [] - - # Search upwards from the given uri to see if we find something that looks like - # a sphinx conf.py file. - previous = None - current = pathlib.Path(path) - - while previous != current: - previous = current - current = previous.parent - - conf_py = current / "conf.py" - logger.debug("Trying path: %s", current) - if conf_py.exists(): - cache = appdirs.user_cache_dir("esbonio", "swyddfa") - project = hashlib.md5(str(current).encode()).hexdigest() - build_dir = str(pathlib.Path(cache, project)) - return ["sphinx-build", "-M", "dirhtml", str(current), str(build_dir)] - - return [] - - class SphinxManager(LanguageFeature): """Responsible for managing Sphinx application instances.""" @@ -179,26 +73,18 @@ async def get_client(self, uri: str) -> Optional[SphinxClient]: self.logger.error("Unable to start Sphinx: missing build command") return None - command = [*resolved.python_command, "-m", "sphinx_agent"] - self.logger.debug("Starting sphinx agent: %s", " ".join(command)) - client = make_sphinx_client(self) - await client.start_io( - *command, env={"PYTHONPATH": resolved.python_path}, cwd=resolved.cwd - ) + await client.start(resolved) - if client.stopped: + sphinx_info = await client.create_application(resolved) + if sphinx_info is None: + self.logger.error("No application object!") + await client.stop() return None - self.logger.debug("Starting sphinx: %s", " ".join(resolved.build_command)) - response = await client.protocol.send_request_async( - "sphinx/createApp", {"command": resolved.build_command} - ) - self.logger.debug("Sphinx started: %s", response) - - src_uri = Uri.from_fs_path(response.src_dir) + src_uri = client.src_uri if src_uri is None: - self.logger.error("Invalid srcdir '%s'", response.src_dir) + self.logger.error("No src uri!") await client.stop() return None From 9f98a393ad80d4368ecd833599461c24117cda28 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Mon, 19 Jun 2023 19:33:15 +0100 Subject: [PATCH 051/141] lsp: Ensure `LanguageFeature` is available --- lib/esbonio/esbonio/server/server.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/esbonio/esbonio/server/server.py b/lib/esbonio/esbonio/server/server.py index fafa991b1..84fd7549e 100644 --- a/lib/esbonio/esbonio/server/server.py +++ b/lib/esbonio/esbonio/server/server.py @@ -287,6 +287,8 @@ def _get_setup_arguments( args[name] = server continue + from .feature import LanguageFeature + if issubclass(type_, LanguageFeature): # Try and obtain an instance of the requested language feature. feature = server.get_feature(type_) From f4b0a354ce1ec6fd42e3af836f2856c076477e8a Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Mon, 19 Jun 2023 19:33:51 +0100 Subject: [PATCH 052/141] lsp: Proof of concept `PreviewManager` feature Rather than spin up the http server in a separate process (like `SphinxLanguageServer` does), it looks like we can get away with pushing it into the server's `ThreadPoolExecutor` which should make communication a little easier. The idea here is that the client calls the `esbonio.server.previewFile` command with the uri it wishes to preview. The `PreviewManager` then spins up the http server and otherwise configures it to serve the relevant Sphinx project. It then replies to the client with the full uri required to view the relevant HTML file - removing the need for each client to figure it out themselves. While multi-project support is possible - it's only one at a time at the moment --- lib/esbonio/esbonio/server/cli.py | 6 +- .../features/preview_manager/__init__.py | 101 ++++++++++++++++++ 2 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 lib/esbonio/esbonio/server/features/preview_manager/__init__.py diff --git a/lib/esbonio/esbonio/server/cli.py b/lib/esbonio/esbonio/server/cli.py index 51e78e68f..924fd00f1 100644 --- a/lib/esbonio/esbonio/server/cli.py +++ b/lib/esbonio/esbonio/server/cli.py @@ -67,7 +67,11 @@ def main(argv: Optional[Sequence[str]] = None): cli = build_parser() args = cli.parse_args(argv) - modules = ["esbonio.server.features.sphinx_manager"] + # Order matters! + modules = [ + "esbonio.server.features.sphinx_manager", + "esbonio.server.features.preview_manager", + ] for mod in args.included_modules: modules.append(mod) diff --git a/lib/esbonio/esbonio/server/features/preview_manager/__init__.py b/lib/esbonio/esbonio/server/features/preview_manager/__init__.py new file mode 100644 index 000000000..fe2e547f3 --- /dev/null +++ b/lib/esbonio/esbonio/server/features/preview_manager/__init__.py @@ -0,0 +1,101 @@ +import asyncio +import logging +from http.server import HTTPServer +from http.server import SimpleHTTPRequestHandler +from typing import Any + +import pygls.uris as Uri + +from esbonio.server import EsbonioLanguageServer +from esbonio.server.feature import LanguageFeature +from esbonio.server.features.sphinx_manager import SphinxManager + + +class RequestHandler(SimpleHTTPRequestHandler): + def __init__(self, *args, logger: logging.Logger, directory: str, **kwargs) -> None: + self.logger = logger + super().__init__(*args, directory=directory, **kwargs) + + def translate_path(self, path: str) -> str: + result = super().translate_path(path) + self.logger.debug("Translate: '%s' -> '%s'", path, result) + return result + + def log_message(self, format: str, *args: Any) -> None: + self.logger.debug(format, *args) + + +class RequestHandlerFactory: + """Class for dynamically producing request handlers. + + ``HTTPServer`` works by taking a "request handler" class and creating an instance of + it for every request it receives. By making this class callable, we can dynamically + produce a request handler based on the current situation. + """ + + def __init__(self, logger: logging.Logger, build_dir: str): + self.logger = logger + self.build_dir = build_dir + + def __call__(self, *args, **kwargs): + return RequestHandler( + *args, logger=self.logger, directory=self.build_dir, **kwargs + ) + + +class PreviewManager(LanguageFeature): + """Language feature for managing previews.""" + + def __init__(self, server: EsbonioLanguageServer, sphinx: SphinxManager): + super().__init__(server) + self.sphinx = sphinx + + logger = server.logger.getChild("PreviewServer") + self._request_handler_factory = RequestHandlerFactory(logger, "") + self._http_server = None + self._http_future = None + + def get_http_server(self): + if self._http_server is not None: + return self._http_server + + self._http_server = HTTPServer(("localhost", 0), self._request_handler_factory) + + loop = asyncio.get_running_loop() + self._http_future = loop.run_in_executor( + self.server.thread_pool_executor, + self._http_server.serve_forever, + ) + + return self._http_server + + async def preview_file(self, params): + src_uri = params["uri"] + self.logger.debug("Preview file called %s", src_uri) + + client = await self.sphinx.get_client(src_uri) + if client is None or client.src_dir is None or client.build_dir is None: + return None + + src_path = Uri.to_fs_path(src_uri) + if src_path is None: + return None + + rst_path = src_path.replace(client.src_dir, "") + html_path = rst_path.replace(".rst", ".html") + self.logger.debug("'%s' -> '%s' -> '%s'", src_path, rst_path, html_path) + + server = self.get_http_server() + self._request_handler_factory.build_dir = client.build_dir + self.logger.debug("Preview running on port: %s", server.server_port) + + return {"uri": f"http://localhost:{server.server_port}{html_path}"} + + +def esbonio_setup(server: EsbonioLanguageServer, sphinx: SphinxManager): + manager = PreviewManager(server, sphinx) + server.add_feature(manager) + + @server.command("esbonio.server.previewFile") + async def preview_file(ls: EsbonioLanguageServer, *args): + return await manager.preview_file(args[0][0]) From bdf27ef5ee0b45176fb99ff12dc64a485bf2b806 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Jun 2023 15:01:55 +0000 Subject: [PATCH 053/141] build(deps-dev): bump webpack from 5.86.0 to 5.87.0 in /code Bumps [webpack](https://github.com/webpack/webpack) from 5.86.0 to 5.87.0. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.86.0...v5.87.0) --- updated-dependencies: - dependency-name: webpack dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- code/package-lock.json | 46 +++++++++++++++++++++--------------------- code/package.json | 2 +- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/code/package-lock.json b/code/package-lock.json index 64fa64f1f..f9d414385 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -23,7 +23,7 @@ "path-browserify": "^1.0.1", "ts-loader": "^9.4.3", "typescript": "^5.1.3", - "webpack": "^5.86.0", + "webpack": "^5.87.0", "webpack-cli": "^5.1.4" }, "engines": { @@ -1156,9 +1156,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.14.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.1.tgz", - "integrity": "sha512-Vklwq2vDKtl0y/vtwjSesgJ5MYS7Etuk5txS8VdKL4AOS1aUlD96zqIfsOSLQsdv3xgMRbtkWM8eG9XDfKUPow==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", "dev": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -2819,9 +2819,9 @@ "dev": true }, "node_modules/schema-utils": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", - "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.8", @@ -3454,9 +3454,9 @@ } }, "node_modules/webpack": { - "version": "5.86.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.86.0.tgz", - "integrity": "sha512-3BOvworZ8SO/D4GVP+GoRC3fVeg5MO4vzmq8TJJEkdmopxyazGDxN8ClqN12uzrZW9Tv8EED8v5VSb6Sqyi0pg==", + "version": "5.87.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.87.0.tgz", + "integrity": "sha512-GOu1tNbQ7p1bDEoFRs2YPcfyGs8xq52yyPBZ3m2VGnXGtV9MxjrkABHm4V9Ia280OefsSLzvbVoXcfLxjKY/Iw==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", @@ -3468,7 +3468,7 @@ "acorn-import-assertions": "^1.9.0", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.14.1", + "enhanced-resolve": "^5.15.0", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -3478,7 +3478,7 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.1.2", + "schema-utils": "^3.2.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.3.7", "watchpack": "^2.4.0", @@ -4770,9 +4770,9 @@ } }, "enhanced-resolve": { - "version": "5.14.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.1.tgz", - "integrity": "sha512-Vklwq2vDKtl0y/vtwjSesgJ5MYS7Etuk5txS8VdKL4AOS1aUlD96zqIfsOSLQsdv3xgMRbtkWM8eG9XDfKUPow==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", "dev": true, "requires": { "graceful-fs": "^4.2.4", @@ -6027,9 +6027,9 @@ "dev": true }, "schema-utils": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", - "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, "requires": { "@types/json-schema": "^7.0.8", @@ -6502,9 +6502,9 @@ } }, "webpack": { - "version": "5.86.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.86.0.tgz", - "integrity": "sha512-3BOvworZ8SO/D4GVP+GoRC3fVeg5MO4vzmq8TJJEkdmopxyazGDxN8ClqN12uzrZW9Tv8EED8v5VSb6Sqyi0pg==", + "version": "5.87.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.87.0.tgz", + "integrity": "sha512-GOu1tNbQ7p1bDEoFRs2YPcfyGs8xq52yyPBZ3m2VGnXGtV9MxjrkABHm4V9Ia280OefsSLzvbVoXcfLxjKY/Iw==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.3", @@ -6516,7 +6516,7 @@ "acorn-import-assertions": "^1.9.0", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.14.1", + "enhanced-resolve": "^5.15.0", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -6526,7 +6526,7 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.1.2", + "schema-utils": "^3.2.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.3.7", "watchpack": "^2.4.0", diff --git a/code/package.json b/code/package.json index 2ab7aa3a2..6751e2305 100644 --- a/code/package.json +++ b/code/package.json @@ -45,7 +45,7 @@ "path-browserify": "^1.0.1", "ts-loader": "^9.4.3", "typescript": "^5.1.3", - "webpack": "^5.86.0", + "webpack": "^5.87.0", "webpack-cli": "^5.1.4" }, "engines": { From dc4de8accff71dee7cd4e3171e53b8b6bbf98d81 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Fri, 23 Jun 2023 20:28:13 +0100 Subject: [PATCH 054/141] lsp: Add `lsp_devtools` support If the `sphinx.enableDevTools` flag is set and the `lsp_devtools` module is available, the `SphinxManager` will launch a wrapped version of the sphinx agent, enabling the use of devtools. --- .../server/features/sphinx_manager/client.py | 15 ++++++-- .../server/features/sphinx_manager/config.py | 37 ++++++++++++++++--- 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/lib/esbonio/esbonio/server/features/sphinx_manager/client.py b/lib/esbonio/esbonio/server/features/sphinx_manager/client.py index 31896859b..75572f2cd 100644 --- a/lib/esbonio/esbonio/server/features/sphinx_manager/client.py +++ b/lib/esbonio/esbonio/server/features/sphinx_manager/client.py @@ -1,6 +1,8 @@ from __future__ import annotations import asyncio +import json +import sys import typing from typing import Optional @@ -77,12 +79,17 @@ def build_uri(self) -> Optional[str]: async def start(self, config: SphinxConfig): """Start the sphinx agent.""" - command = [*config.python_command, "-m", "sphinx_agent"] + command = [] + if config.enable_dev_tools: + command.extend([sys.executable, "-m", "lsp_devtools", "agent", "--"]) + + command.extend([*config.python_command, "-m", "sphinx_agent"]) + env = {"PYTHONPATH": ":".join([str(p) for p in config.python_path])} + + self.logger.debug("Sphinx agent env: %s", json.dumps(env, indent=2)) self.logger.debug("Starting sphinx agent: %s", " ".join(command)) - await self.start_io( - *command, env={"PYTHONPATH": config.python_path}, cwd=config.cwd - ) + await self.start_io(*command, env=env, cwd=config.cwd) async def server_exit(self, server: asyncio.subprocess.Process): """Called when the sphinx agent process exits.""" diff --git a/lib/esbonio/esbonio/server/features/sphinx_manager/config.py b/lib/esbonio/esbonio/server/features/sphinx_manager/config.py index e6d9db42b..445953fec 100644 --- a/lib/esbonio/esbonio/server/features/sphinx_manager/config.py +++ b/lib/esbonio/esbonio/server/features/sphinx_manager/config.py @@ -11,8 +11,8 @@ from pygls.workspace import Workspace -def get_python_path() -> Optional[pathlib.Path]: - spec = importlib.util.find_spec("esbonio.sphinx_agent") +def get_python_path(module: str) -> Optional[pathlib.Path]: + spec = importlib.util.find_spec(module) if spec is None: return None @@ -28,6 +28,9 @@ def get_python_path() -> Optional[pathlib.Path]: class SphinxConfig: """Configuration for the sphinx application instance.""" + enable_dev_tools: bool = attrs.field(default=False) + """Flag to enable dev tools.""" + python_command: List[str] = attrs.field(factory=list) """The command to use when launching the python interpreter.""" @@ -37,7 +40,7 @@ class SphinxConfig: cwd: str = attrs.field(default="") """The working directory to use.""" - python_path: Optional[pathlib.Path] = attrs.field(default=get_python_path()) + python_path: List[pathlib.Path] = attrs.field(factory=list) """The value of ``PYTHONPATH`` to use when injecting the sphinx agent into the target environment""" @@ -49,9 +52,11 @@ def resolve( ) -> "Optional[SphinxConfig]": """Resolve the configuration based on user provided values.""" - if self.python_path is None: - logger.error("Unable to locate the sphinx agent") - return None + if len(self.python_path) == 0: + if (python_path := self._resolve_python_path(logger)) is None: + return None + + self.python_path = python_path cwd = self._resolve_cwd(uri, workspace, logger) if cwd is None: @@ -62,6 +67,7 @@ def resolve( build_command = self._guess_build_command(uri, logger) return SphinxConfig( + enable_dev_tools=self.enable_dev_tools, cwd=cwd, python_command=self.python_command, build_command=build_command, @@ -83,6 +89,25 @@ def _resolve_cwd(self, uri: str, workspace: Workspace, logger: logging.Logger): logger.debug("Cwd: %s", cwd) return cwd + def _resolve_python_path( + self, logger: logging.Logger + ) -> Optional[List[pathlib.Path]]: + if (sphinx_agent := get_python_path("esbonio.sphinx_agent")) is None: + logger.error("Unable to locate the sphinx agent") + return None + + python_path = [sphinx_agent] + if self.enable_dev_tools: + if (lsp_devtools := get_python_path("lsp_devtools")) is None: + logger.warning( + "Unable to locate module 'lsp_devtools', dev tools will not " + "be availble." + ) + else: + python_path.append(lsp_devtools) + + return python_path + def _guess_build_command(self, uri: str, logger: logging.Logger) -> List[str]: """Try and guess something a sensible build command given the uri.""" From 3e08daab3d2fbdeb312180a7786125cdd71c3af9 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Sat, 24 Jun 2023 21:23:08 +0100 Subject: [PATCH 055/141] sphinx_agent: Move contents of __init__.py to server.py This allows the main language server to share the type definitions in types.py without requiring sphinx to be importable. --- lib/esbonio/esbonio/sphinx_agent/__init__.py | 102 ------------------- lib/esbonio/esbonio/sphinx_agent/__main__.py | 2 +- lib/esbonio/esbonio/sphinx_agent/server.py | 102 +++++++++++++++++++ 3 files changed, 103 insertions(+), 103 deletions(-) create mode 100644 lib/esbonio/esbonio/sphinx_agent/server.py diff --git a/lib/esbonio/esbonio/sphinx_agent/__init__.py b/lib/esbonio/esbonio/sphinx_agent/__init__.py index ce61620e8..33576e65f 100644 --- a/lib/esbonio/esbonio/sphinx_agent/__init__.py +++ b/lib/esbonio/esbonio/sphinx_agent/__init__.py @@ -15,105 +15,3 @@ Unfortunately, this does mean re-inventing some wheels, but hopefully what we gain in portability makes it worth the trade off. """ -import asyncio -import dataclasses -import json -import logging -import re -import sys -import threading -import traceback -from concurrent.futures import ThreadPoolExecutor -from typing import Dict -from typing import Type -from typing import TypeVar - -from .handlers import HANDLERS -from .util import send_error - -logger = logging.getLogger(__name__) - - -T = TypeVar("T") - - -def parse_message(obj: Dict, cls: Type[T]) -> T: - """Convert a raw dict into the given type""" - - if dataclasses.is_dataclass(cls): - kwargs = {} - fields = {f.name: f for f in dataclasses.fields(cls)} - - for key, value in obj.items(): - kwargs[key] = parse_message(value, fields[key].type) - - return cls(**kwargs) - - return obj - - -def handle_message(data: bytes): - message = json.loads(data.decode("utf8")) - - method = message.get("method", None) - if not method: - raise TypeError("Invalid message") - - type_, handler = HANDLERS.get(method, (None, None)) - if type_ is None or handler is None: - raise TypeError(f"Unknown method: '{method}'") - - obj = parse_message(message, type_) - try: - handler(obj) - except Exception as e: - msg_id = message.get("id", None) - if msg_id is not None: - send_error( - id=msg_id, - code=-32602, - message=f"{e}", - data=dict(traceback=traceback.format_exc()), - ) - - -async def main_loop(loop, executor, stop_event, rfile, proxy): - """Originally taken from ``pygls``""" - - CONTENT_LENGTH_PATTERN = re.compile(rb"^Content-Length: (\d+)\r\n$") - - # Initialize message buffer - content_length = 0 - - while not stop_event.is_set() and not rfile.closed: - # Read a header line - header = await loop.run_in_executor(executor, rfile.readline) - if not header: - break - - # Extract content length if possible - if not content_length: - match = CONTENT_LENGTH_PATTERN.fullmatch(header) - if match: - content_length = int(match.group(1)) - logger.debug("Content length: %s", content_length) - - # Check if all headers have been read (as indicated by an empty line \r\n) - if content_length and not header.strip(): - # Read body - body = await loop.run_in_executor(executor, rfile.read, content_length) - if not body: - break - - proxy(body) - - # Reset the buffer - content_length = 0 - - -async def main(): - loop = asyncio.get_running_loop() - event = threading.Event() - executor = ThreadPoolExecutor(max_workers=2) - - await main_loop(loop, executor, event, sys.stdin.buffer, handle_message) diff --git a/lib/esbonio/esbonio/sphinx_agent/__main__.py b/lib/esbonio/esbonio/sphinx_agent/__main__.py index 266ee281b..96b75d1b1 100644 --- a/lib/esbonio/esbonio/sphinx_agent/__main__.py +++ b/lib/esbonio/esbonio/sphinx_agent/__main__.py @@ -1,5 +1,5 @@ import asyncio -from esbonio.sphinx_agent import main +from esbonio.sphinx_agent.server import main asyncio.run(main()) diff --git a/lib/esbonio/esbonio/sphinx_agent/server.py b/lib/esbonio/esbonio/sphinx_agent/server.py new file mode 100644 index 000000000..66dc8bba1 --- /dev/null +++ b/lib/esbonio/esbonio/sphinx_agent/server.py @@ -0,0 +1,102 @@ +import asyncio +import dataclasses +import json +import logging +import re +import sys +import threading +import traceback +from concurrent.futures import ThreadPoolExecutor +from typing import Dict +from typing import Type +from typing import TypeVar + +from .handlers import HANDLERS +from .util import send_error + +logger = logging.getLogger(__name__) + + +T = TypeVar("T") + + +def parse_message(obj: Dict, cls: Type[T]) -> T: + """Convert a raw dict into the given type""" + + if dataclasses.is_dataclass(cls): + kwargs = {} + fields = {f.name: f for f in dataclasses.fields(cls)} + + for key, value in obj.items(): + kwargs[key] = parse_message(value, fields[key].type) + + return cls(**kwargs) + + return obj + + +def handle_message(data: bytes): + message = json.loads(data.decode("utf8")) + + method = message.get("method", None) + if not method: + raise TypeError("Invalid message") + + type_, handler = HANDLERS.get(method, (None, None)) + if type_ is None or handler is None: + raise TypeError(f"Unknown method: '{method}'") + + obj = parse_message(message, type_) + try: + handler(obj) + except Exception as e: + msg_id = message.get("id", None) + if msg_id is not None: + send_error( + id=msg_id, + code=-32602, + message=f"{e}", + data=dict(traceback=traceback.format_exc()), + ) + + +async def main_loop(loop, executor, stop_event, rfile, proxy): + """Originally taken from ``pygls``""" + + CONTENT_LENGTH_PATTERN = re.compile(rb"^Content-Length: (\d+)\r\n$") + + # Initialize message buffer + content_length = 0 + + while not stop_event.is_set() and not rfile.closed: + # Read a header line + header = await loop.run_in_executor(executor, rfile.readline) + if not header: + break + + # Extract content length if possible + if not content_length: + match = CONTENT_LENGTH_PATTERN.fullmatch(header) + if match: + content_length = int(match.group(1)) + logger.debug("Content length: %s", content_length) + + # Check if all headers have been read (as indicated by an empty line \r\n) + if content_length and not header.strip(): + # Read body + body = await loop.run_in_executor(executor, rfile.read, content_length) + if not body: + break + + proxy(body) + + # Reset the buffer + content_length = 0 + + +async def main(): + loop = asyncio.get_running_loop() + event = threading.Event() + executor = ThreadPoolExecutor(max_workers=2) + + await main_loop(loop, executor, event, sys.stdin.buffer, handle_message) From be68d1eff44dbbf118dcf9684601a122873829c3 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Sat, 24 Jun 2023 21:26:25 +0100 Subject: [PATCH 056/141] sphinx_agent: Inject `webview.js` into html builds. When the `enable_sync_scrolling` flag is set, the sphinx agent will now inject an additional `webview.js` script into pages built with sphinx. This file implements a miniature JSON-RPC client over websockets that will allow the main language server to connect to the webview and control it. Currently only a `view/reload` notification from the server is supported, which, as the name suggests will allow the server to ask the page to reload itself. Taking this approach not only allows us to support fancy preview features in editors that do not come with a native webview component (like Neovim) but we get to work around a long standing bug (#440). This is because the page is reloading itself, we don't encounter the hard reload required when reloading externally when crossing the `