From bb97358e898a64b2166a6143aad0f4858c4fd191 Mon Sep 17 00:00:00 2001 From: Vipin Nair Date: Wed, 20 Sep 2023 13:02:08 -0700 Subject: [PATCH 01/70] Update Documentation View - Update existing documentation links to point to `lean-lang.org` - Add new doc links: - Functional Programming in Lean - The Mechanics of Proof --- vscode-lean4/package-lock.json | 4 ++-- vscode-lean4/src/docview.ts | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/vscode-lean4/package-lock.json b/vscode-lean4/package-lock.json index 1b9a6f658..a0305afbe 100644 --- a/vscode-lean4/package-lock.json +++ b/vscode-lean4/package-lock.json @@ -1,12 +1,12 @@ { "name": "lean4", - "version": "0.0.110", + "version": "0.0.111", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "lean4", - "version": "0.0.110", + "version": "0.0.111", "license": "Apache-2.0", "dependencies": { "axios": "~0.24.0", diff --git a/vscode-lean4/src/docview.ts b/vscode-lean4/src/docview.ts index a288ec34f..da133322c 100644 --- a/vscode-lean4/src/docview.ts +++ b/vscode-lean4/src/docview.ts @@ -224,9 +224,11 @@ export class DocViewProvider implements Disposable { } const books : any = { - 'Theorem Proving in Lean': mkCommandUri('lean4.docView.open', 'https://leanprover.github.io/theorem_proving_in_lean4/introduction.html'), + 'Theorem Proving in Lean': mkCommandUri('lean4.docView.open', 'https://lean-lang.org/theorem_proving_in_lean4/introduction.html'), + 'Functional Programming in Lean': mkCommandUri('lean4.docView.open', 'https://lean-lang.org/functional_programming_in_lean/'), 'Mathematics in Lean': mkCommandUri('lean4.docView.open', 'https://leanprover-community.github.io/mathematics_in_lean/'), - 'Reference Manual': mkCommandUri('lean4.docView.open', 'https://leanprover.github.io/lean4/doc/'), + 'The Mechanics of Proof': mkCommandUri('lean4.docView.open', 'https://hrmacbeth.github.io/math2001/'), + 'Reference Manual': mkCommandUri('lean4.docView.open', 'https://lean-lang.org/lean4/doc/'), 'Abbreviations Cheatsheet': mkCommandUri('lean4.docView.showAllAbbreviations'), 'Example': mkCommandUri('lean4.openExample', 'https://github.com/leanprover/lean4-samples/raw/main/HelloWorld/Main.lean'), From 2a5f6cc1a311ae56ef736dea95ba257009516f70 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Thu, 12 Oct 2023 15:33:05 +0200 Subject: [PATCH 02/70] feat: send --no-build on didOpen --- vscode-lean4/package.json | 5 +++++ vscode-lean4/src/config.ts | 4 ++++ vscode-lean4/src/leanclient.ts | 5 +++-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index 8db53dca2..aead283b7 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -64,6 +64,11 @@ "default": true, "markdownDescription": "Enable eager replacement of abbreviations that uniquely identify a symbol." }, + "lean4.automaticallyBuildDependencies": { + "type": "boolean", + "default": false, + "markdownDescription": "Enable automatically building dependencies when opening a file." + }, "lean4.serverEnv": { "type": "object", "default": {}, diff --git a/vscode-lean4/src/config.ts b/vscode-lean4/src/config.ts index 670dd8cbf..dd3e498fe 100644 --- a/vscode-lean4/src/config.ts +++ b/vscode-lean4/src/config.ts @@ -146,6 +146,10 @@ export function serverEnv(): object { return workspace.getConfiguration('lean4').get('serverEnv', {}) } +export function automaticallyBuildDependencies(): boolean { + return workspace.getConfiguration('lean4').get('automaticallyBuildDependencies', false) +} + export function serverEnvPaths(): string[] { return workspace.getConfiguration('lean4').get('serverEnvPaths', []) } diff --git a/vscode-lean4/src/leanclient.ts b/vscode-lean4/src/leanclient.ts index ed2f963cb..79736591c 100644 --- a/vscode-lean4/src/leanclient.ts +++ b/vscode-lean4/src/leanclient.ts @@ -17,7 +17,7 @@ import { } from 'vscode-languageclient/node' import * as ls from 'vscode-languageserver-protocol' -import { toolchainPath, lakePath, addServerEnvPaths, serverArgs, serverLoggingEnabled, serverLoggingPath, shouldAutofocusOutput, getElaborationDelay, lakeEnabled } from './config' +import { toolchainPath, lakePath, addServerEnvPaths, serverArgs, serverLoggingEnabled, serverLoggingPath, shouldAutofocusOutput, getElaborationDelay, lakeEnabled, automaticallyBuildDependencies } from './config' import { assert } from './utils/assert' import { LeanFileProgressParams, LeanFileProgressProcessingInfo, ServerStoppedReason } from '@leanprover/infoview-api'; import { batchExecute } from './utils/batch' @@ -408,13 +408,14 @@ export class LeanClient implements Disposable { } notifyDidOpen(doc: TextDocument) { - void this.client?.sendNotification(DidOpenTextDocumentNotification.type, { + void this.client?.sendNotification('textDocument/didOpen', { textDocument: { uri: doc.uri.toString(), languageId: doc.languageId, version: 1, text: doc.getText(), }, + extraPrintPathsFlags: automaticallyBuildDependencies() ? [] : ['--no-build'] }); } From 926dad029342d7717ac84d869a8f8d36180fd32b Mon Sep 17 00:00:00 2001 From: mhuisi Date: Thu, 12 Oct 2023 17:59:33 +0200 Subject: [PATCH 03/70] fix: correctly handle file worker restarts --- vscode-lean4/src/leanclient.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/vscode-lean4/src/leanclient.ts b/vscode-lean4/src/leanclient.ts index 79736591c..162982004 100644 --- a/vscode-lean4/src/leanclient.ts +++ b/vscode-lean4/src/leanclient.ts @@ -415,7 +415,7 @@ export class LeanClient implements Disposable { version: 1, text: doc.getText(), }, - extraPrintPathsFlags: automaticallyBuildDependencies() ? [] : ['--no-build'] + dependencyBuildMode: automaticallyBuildDependencies() ? 'always' : 'never' }); } @@ -505,12 +505,13 @@ export class LeanClient implements Disposable { } }) void this.client?.sendNotification('textDocument/didOpen', { - 'textDocument': { + textDocument: { uri, - 'languageId': 'lean4', - 'version': 1, - 'text': doc.getText() - } + languageId: 'lean4', + version: 1, + text: doc.getText() + }, + dependencyBuildMode: automaticallyBuildDependencies() ? 'always' : 'once' }) this.restartedWorkerEmitter.fire(uri) } From cdd056699fb234d7b3bee433788b2b6e12190be5 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Fri, 13 Oct 2023 13:59:33 +0200 Subject: [PATCH 04/70] chore: make version that setting is used in explicit --- vscode-lean4/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index aead283b7..d5881e610 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -67,7 +67,7 @@ "lean4.automaticallyBuildDependencies": { "type": "boolean", "default": false, - "markdownDescription": "Enable automatically building dependencies when opening a file." + "markdownDescription": "Enable automatically building dependencies when opening a file. This is the default for Lean 4 versions before 4.2.0." }, "lean4.serverEnv": { "type": "object", From 6385f19a6f8639eb6d9712835193275c428a880f Mon Sep 17 00:00:00 2001 From: mhuisi Date: Fri, 13 Oct 2023 14:08:04 +0200 Subject: [PATCH 05/70] chore: better config message --- vscode-lean4/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index d5881e610..2e20f3276 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -67,7 +67,7 @@ "lean4.automaticallyBuildDependencies": { "type": "boolean", "default": false, - "markdownDescription": "Enable automatically building dependencies when opening a file. This is the default for Lean 4 versions before 4.2.0." + "markdownDescription": "Enable automatically building dependencies when opening a file. In Lean versions pre-4.2.0, dependencies are always built automatically regardless of this setting." }, "lean4.serverEnv": { "type": "object", From 24c7ccdb43e64737b79b33e07507cfd7606ebdaf Mon Sep 17 00:00:00 2001 From: mhuisi Date: Fri, 13 Oct 2023 14:11:39 +0200 Subject: [PATCH 06/70] Release 0.0.112 --- vscode-lean4/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index 2e20f3276..92c3f58da 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -2,7 +2,7 @@ "name": "lean4", "displayName": "lean4", "description": "Lean 4 language support for VS Code", - "version": "0.0.111", + "version": "0.0.112", "publisher": "leanprover", "engines": { "vscode": "^1.70.0" From 5f461eb39e8dc85186363bdad28c5bab4c209162 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Tue, 17 Oct 2023 10:54:47 +0200 Subject: [PATCH 07/70] feat: notification for imports-out-of-date error --- vscode-lean4/src/leanclient.ts | 37 +++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/vscode-lean4/src/leanclient.ts b/vscode-lean4/src/leanclient.ts index 162982004..c144481a5 100644 --- a/vscode-lean4/src/leanclient.ts +++ b/vscode-lean4/src/leanclient.ts @@ -1,8 +1,9 @@ import { TextDocument, EventEmitter, Diagnostic, DocumentHighlight, Range, DocumentHighlightKind, workspace, Disposable, Uri, ConfigurationChangeEvent, OutputChannel, DiagnosticCollection, - WorkspaceFolder, window } from 'vscode' + WorkspaceFolder, window, commands } from 'vscode' import { + DiagnosticSeverity, DidChangeTextDocumentParams, DidCloseTextDocumentParams, DidOpenTextDocumentNotification, @@ -30,6 +31,7 @@ import { logger } from './utils/logger' import { SemVer } from 'semver'; import { fileExists, isFileInFolder } from './utils/fsHelper'; import { c2pConverter, p2cConverter, patchConverters } from './utils/converters' +import path = require('path') const escapeRegExp = (s: string) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); @@ -98,6 +100,39 @@ export class LeanClient implements Disposable { this.elanDefaultToolchain = elanDefaultToolchain; if (!this.toolchainPath) this.toolchainPath = toolchainPath(); this.subscriptions.push(workspace.onDidChangeConfiguration((e) => this.configChanged(e))); + + this.subscriptions.push(this.diagnostics(params => this.checkForImportsOutdatedError(params))) + } + + private async checkForImportsOutdatedError(params: PublishDiagnosticsParams) { + const fileUri = Uri.parse(params.uri) + const fileName = path.basename(fileUri.fsPath) + const isImportsOutdatedError = params.diagnostics.some(d => + d.severity === DiagnosticSeverity.Error + && d.message.includes('Imports are out of date and must be rebuilt') + && d.range.start.line === 0 + && d.range.start.character === 0 + && d.range.end.line === 0 + && d.range.end.character === 0) + if (!isImportsOutdatedError) { + return + } + + const message = `Imports of '${fileName}' are out of date and must be rebuilt.` + const input = 'Rebuild Imports' + const choice = await window.showInformationMessage(message, input) + if (choice !== input) { + return + } + + const fileUriString = fileUri.toString() + const document = workspace.textDocuments.find(doc => doc.uri.toString() === fileUriString) + if (!document || document.isClosed) { + void window.showErrorMessage(`'${fileName}' was closed in the meantime. Imports will not be rebuilt.`) + return + } + + await this.restartFile(document) } dispose(): void { From c93f2cf9563debf5e8ab459687d7816c7bb6d4b0 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Tue, 17 Oct 2023 16:15:20 +0200 Subject: [PATCH 08/70] Release 0.0.113 --- vscode-lean4/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index 92c3f58da..81bc86f30 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -2,7 +2,7 @@ "name": "lean4", "displayName": "lean4", "description": "Lean 4 language support for VS Code", - "version": "0.0.112", + "version": "0.0.113", "publisher": "leanprover", "engines": { "vscode": "^1.70.0" From eb9d8c61177017ba5553e494ae43ed0246766217 Mon Sep 17 00:00:00 2001 From: Marc Huisinga Date: Wed, 18 Oct 2023 13:40:49 +0200 Subject: [PATCH 09/70] Add project commands, command menu and walkthrough (#334) --- .github/workflows/on-push.yml | 21 +- .vscode/settings.json | 5 +- prerelease.sh | 13 + vscode-lean4/media/guide-documentation.md | 26 + vscode-lean4/media/guide-help.md | 8 + vscode-lean4/media/guide-installDeps-linux.md | 18 + vscode-lean4/media/guide-installDeps-mac.md | 16 + .../media/guide-installDeps-windows.md | 9 + vscode-lean4/media/guide-installElan-unix.md | 4 + .../media/guide-installElan-windows.md | 4 + vscode-lean4/media/guide-setupProject.md | 15 + vscode-lean4/media/lean-mini-dark.svg | 259 ++++++++++ vscode-lean4/media/lean-mini-light.svg | 259 ++++++++++ vscode-lean4/media/open-setup-guide.png | Bin 0 -> 17901 bytes vscode-lean4/package-lock.json | 17 +- vscode-lean4/package.json | 488 +++++++++++++++++- vscode-lean4/src/config.ts | 4 + vscode-lean4/src/docview.ts | 31 +- vscode-lean4/src/exports.ts | 16 +- vscode-lean4/src/extension.ts | 230 ++++++--- vscode-lean4/src/infoview.ts | 8 +- vscode-lean4/src/leanclient.ts | 455 ++++++++-------- vscode-lean4/src/projectinit.ts | 208 ++++++++ vscode-lean4/src/projectoperations.ts | 341 ++++++++++++ vscode-lean4/src/utils/batch.ts | 199 ++++++- vscode-lean4/src/utils/clientProvider.ts | 99 +++- vscode-lean4/src/utils/elan.ts | 6 + vscode-lean4/src/utils/errors.ts | 9 + vscode-lean4/src/utils/lake.ts | 90 ++++ vscode-lean4/src/utils/leanInstaller.ts | 213 +++----- vscode-lean4/src/utils/leanpkg.ts | 84 +-- vscode-lean4/src/utils/manifest.ts | 89 ++++ vscode-lean4/src/utils/projectInfo.ts | 96 ++-- 33 files changed, 2776 insertions(+), 564 deletions(-) create mode 100755 prerelease.sh create mode 100644 vscode-lean4/media/guide-documentation.md create mode 100644 vscode-lean4/media/guide-help.md create mode 100644 vscode-lean4/media/guide-installDeps-linux.md create mode 100644 vscode-lean4/media/guide-installDeps-mac.md create mode 100644 vscode-lean4/media/guide-installDeps-windows.md create mode 100644 vscode-lean4/media/guide-installElan-unix.md create mode 100644 vscode-lean4/media/guide-installElan-windows.md create mode 100644 vscode-lean4/media/guide-setupProject.md create mode 100644 vscode-lean4/media/lean-mini-dark.svg create mode 100644 vscode-lean4/media/lean-mini-light.svg create mode 100644 vscode-lean4/media/open-setup-guide.png create mode 100644 vscode-lean4/src/projectinit.ts create mode 100644 vscode-lean4/src/projectoperations.ts create mode 100644 vscode-lean4/src/utils/elan.ts create mode 100644 vscode-lean4/src/utils/errors.ts create mode 100644 vscode-lean4/src/utils/lake.ts create mode 100644 vscode-lean4/src/utils/manifest.ts diff --git a/.github/workflows/on-push.yml b/.github/workflows/on-push.yml index feab98fe4..975998d5f 100644 --- a/.github/workflows/on-push.yml +++ b/.github/workflows/on-push.yml @@ -43,7 +43,14 @@ jobs: npm ci npx lerna bootstrap --ci npm run build - npx lerna run --scope=lean4 package + + - name: Package + run: npx lerna run --scope=lean4 package + if: ${{ !startsWith(github.ref, 'refs/tags/v') || !endsWith(github.ref, '-pre') }} + + - name: Package pre-release + run: npx lerna run --scope=lean4 packagePreRelease + if: ${{ startsWith(github.ref, 'refs/tags/v') && endsWith(github.ref, '-pre') }} - name: Upload artifact uses: actions/upload-artifact@v2 @@ -53,7 +60,7 @@ jobs: path: 'vscode-lean4/lean4-*.vsix' - name: Publish packaged extension - if: startsWith(github.ref, 'refs/tags/v') && matrix.os == 'ubuntu-latest' + if: ${{ startsWith(github.ref, 'refs/tags/v') && !endsWith(github.ref, '-pre') && matrix.os == 'ubuntu-latest' }} run: | cd vscode-lean4 npx vsce publish -i lean4-*.vsix @@ -62,6 +69,16 @@ jobs: OVSX_PAT: ${{ secrets.OVSX_PAT }} VSCE_PAT: ${{ secrets.VSCE_PAT }} + - name: Publish packaged pre-release extension + if: ${{ startsWith(github.ref, 'refs/tags/v') && endsWith(github.ref, '-pre') && matrix.os == 'ubuntu-latest' }} + run: | + cd vscode-lean4 + npx vsce publish --pre-release -i lean4-*.vsix + npx ovsx publish --pre-release lean4-*.vsix + env: + OVSX_PAT: ${{ secrets.OVSX_PAT }} + VSCE_PAT: ${{ secrets.VSCE_PAT }} + - name: Upload extension as release if: startsWith(github.ref, 'refs/tags/v') && matrix.os == 'ubuntu-latest' uses: softprops/action-gh-release@v1 diff --git a/.vscode/settings.json b/.vscode/settings.json index 512315c94..5e457541a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,5 +8,8 @@ }, "typescript.tsdk": "./node_modules/typescript/lib", // we want to use the TS server from our node_modules folder to control its version "files.insertFinalNewline": true, - "files.trimTrailingWhitespace": true + "files.trimTrailingWhitespace": true, + "[markdown]": { + "files.trimTrailingWhitespace": false + } } diff --git a/prerelease.sh b/prerelease.sh new file mode 100755 index 000000000..38e994444 --- /dev/null +++ b/prerelease.sh @@ -0,0 +1,13 @@ +#!/bin/sh +if [ $# != 1 ]; then + echo Usage: ./prerelease.sh 1.2.3 + exit 1 +fi + +new_version="$1" +sed -i 's/"version": ".*"/"version": "'$new_version'"/' vscode-lean4/package.json +git commit -am "Release $new_version (pre-release)" +git tag -a v$new_version-pre -m "vscode-lean4 $new_version (pre-release)" + +git push +git push --tags diff --git a/vscode-lean4/media/guide-documentation.md b/vscode-lean4/media/guide-documentation.md new file mode 100644 index 000000000..690c16cc6 --- /dev/null +++ b/vscode-lean4/media/guide-documentation.md @@ -0,0 +1,26 @@ +## Books +If you want to learn Lean 4, choose one of the following introductory books based on your background. If you are getting stuck or have any questions, click on the 'Questions and Troubleshooting' step at the bottom on the left side. + +- [Functional Programming in Lean](https://lean-lang.org/functional_programming_in_lean/) + The standard introduction for using Lean 4 as a general-purpose programming language. +- [The Mechanics of Proof](https://hrmacbeth.github.io/math2001/) + An introduction to Lean 4 as an interactive theorem prover for anyone who also wants to learn how to write rigorous mathematical proofs. +- [Mathematics in Lean](https://leanprover-community.github.io/mathematics_in_lean/) + The standard introduction to Lean 4 as an interactive theorem prover for users with a mathematics background. +- [Theorem Proving in Lean 4](https://lean-lang.org/theorem_proving_in_lean4/) + The standard reference for using Lean 4 as an interactive theorem prover. Suited as an introduction for users with a computer science background, advanced users and for general use as a reference manual. + +Once you have completed one of these books and its exercises, you are ready to use Lean 4 for your own projects. If you want to use Lean 4 both as a general-purpose programming language and an interactive theorem prover, it is recommended to read both [Functional Programming in Lean](https://lean-lang.org/functional_programming_in_lean/) and [Theorem Proving in Lean 4](https://lean-lang.org/theorem_proving_in_lean4/). + +## Hands-On Tutorial +If you want to dive right into using Lean 4 to prove elementary theorems about natural numbers, you can play the [Natural Number Game](https://adam.math.hhu.de/#/g/hhu-adam/NNG4). It can be played online using your browser without a local installation. + +## Additional Resources +**Website** +[Lean's website](https://lean-lang.org/) links to learning resources, publications, talks and articles about Lean. + +**Lean Community** +The [Lean Community website](https://leanprover-community.github.io/index.html) links to several other helpful learning resources not listed here and provides an introduction to [mathlib](https://github.com/leanprover-community/mathlib4), Lean's math library. + +**Manual** +The [Lean Manual](https://lean-lang.org/lean4/doc/) documents several features of Lean 4 and can be consulted for some of the more technical details concerning Lean. diff --git a/vscode-lean4/media/guide-help.md b/vscode-lean4/media/guide-help.md new file mode 100644 index 000000000..39212f0e8 --- /dev/null +++ b/vscode-lean4/media/guide-help.md @@ -0,0 +1,8 @@ +## Asking Questions on the Lean Zulip Chat + +To post your question on the [Lean Zulip chat](https://leanprover.zulipchat.com/), you can follow these steps: +1. [Create a new Lean Zulip chat account](https://leanprover.zulipchat.com/register/). +2. [Visit the #new-members stream](https://leanprover.zulipchat.com/#narrow/stream/113489-new-members). +3. Click the 'New topic' button at the bottom of the page, enter a topic title, describe your question or issue in the message text box and click 'Send'. + +When posting code on the Lean Zulip chat, please reduce the code to a [minimal working example](https://leanprover-community.github.io/mwe.html) that includes all imports and declarations needed for others to copy and paste the code into their own development environment. Please also make sure to delimit the code by [three backticks](https://github.com/leanprover-community/mathlib/wiki/Code-in-backticks) so that the code is highlighted and formatted correctly. diff --git a/vscode-lean4/media/guide-installDeps-linux.md b/vscode-lean4/media/guide-installDeps-linux.md new file mode 100644 index 000000000..8ece155d0 --- /dev/null +++ b/vscode-lean4/media/guide-installDeps-linux.md @@ -0,0 +1,18 @@ +## Installing Required Dependencies +1. [Open a new terminal](command:workbench.action.terminal.new). +2. Depending on your Linux distribution, do one of the following to install Git and curl using your package manager: + * On Ubuntu and Debian, type in `sudo apt install git curl` and press Enter. + * On Fedora, type in `sudo dnf install git curl` and press Enter. + * If you are not sure which Linux distribution you are using, you can try both. +3. When prompted, type in your login credentials. +4. Wait until the installation has completed. + +## Dependencies Needed by Lean 4 +[Git](https://git-scm.com/) is a commonly used [Version Control System](https://en.wikipedia.org/wiki/Version_control) that is used by Lean to help manage different versions of Lean formalization packages and software packages. + +[curl](https://curl.se/) is a small tool to transfer data that is used by Lean to download files when managing Lean formalization packages and software packages. + +## Restricted Environments +If you are in an environment where you cannot install Git or curl, for example a restricted university computer, you can check if you already have them installed by [opening a new terminal](command:workbench.action.terminal.new), typing in `which git curl` and pressing Enter. If the terminal output displays two file paths and no error, you already have them installed. + +If your machine does not already have Git and curl installed and you cannot install them, there is currently no option to try Lean 4 with a local installation. If you want to try out Lean 4 regardless, you can read [Mathematics in Lean](https://leanprover-community.github.io/mathematics_in_lean/) and do the exercises with [an online instance of Lean 4 hosted using Gitpod](https://gitpod.io/#/https://github.com/leanprover-community/mathematics_in_lean). Doing so requires creating a GitHub account. diff --git a/vscode-lean4/media/guide-installDeps-mac.md b/vscode-lean4/media/guide-installDeps-mac.md new file mode 100644 index 000000000..9617e2a24 --- /dev/null +++ b/vscode-lean4/media/guide-installDeps-mac.md @@ -0,0 +1,16 @@ +## Installing Required Dependencies +1. [Open a new terminal](command:workbench.action.terminal.new). +2. Type in `/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"` and press Enter to install [Homebrew](https://brew.sh/), a package manager for macOS. +3. Follow the instructions in the terminal. +4. Type in `brew install curl git` and press Enter. +5. Wait until the installation has completed. + +## Dependencies Needed by Lean 4 +[Git](https://git-scm.com/) is a commonly used [Version Control System](https://en.wikipedia.org/wiki/Version_control) that is used by Lean to help manage different versions of Lean formalization packages and software packages. + +[curl](https://curl.se/) is a small tool to transfer data that is used by Lean to download files when managing Lean formalization packages and software packages. + +## Restricted Environments +If you are in an environment where you cannot install Homebrew, Git or curl, for example a restricted university computer, you can check if you already have them installed by [opening a new terminal](command:workbench.action.terminal.new), typing in `which git curl` and pressing Enter. If the terminal output displays two file paths and no error, you already have them installed. + +If your machine does not already have Homebrew, Git and curl installed and you cannot install them, there is currently no option to try Lean 4 with a local installation. If you want to try out Lean 4 regardless, you can read [Mathematics in Lean](https://leanprover-community.github.io/mathematics_in_lean/) and do the exercises with [an online instance of Lean 4 hosted using Gitpod](https://gitpod.io/#/https://github.com/leanprover-community/mathematics_in_lean). Doing so requires creating a GitHub account. diff --git a/vscode-lean4/media/guide-installDeps-windows.md b/vscode-lean4/media/guide-installDeps-windows.md new file mode 100644 index 000000000..324bead4f --- /dev/null +++ b/vscode-lean4/media/guide-installDeps-windows.md @@ -0,0 +1,9 @@ +## Installing Required Dependencies +1. Install [Git](https://git-scm.com/download/win). You can keep all settings in the installer at their default values. +2. Wait until the installation has completed. +3. Restart VS Code and re-open this guide. + +[Git](https://git-scm.com/) is a commonly used [Version Control System](https://en.wikipedia.org/wiki/Version_control) that is used by Lean to help manage different versions of Lean formalization packages and software packages. + +## Restricted Environments +If you are in an environment where you cannot install Git and it is not already installed, for example on a restricted university computer, there is currently no option to try Lean 4 with a local installation. If you want to try out Lean 4 regardless, you can read [Mathematics in Lean](https://leanprover-community.github.io/mathematics_in_lean/) and do the exercises with [an online instance of Lean 4 hosted using Gitpod](https://gitpod.io/#/https://github.com/leanprover-community/mathematics_in_lean). Doing so requires creating a GitHub account. diff --git a/vscode-lean4/media/guide-installElan-unix.md b/vscode-lean4/media/guide-installElan-unix.md new file mode 100644 index 000000000..1acdaceac --- /dev/null +++ b/vscode-lean4/media/guide-installElan-unix.md @@ -0,0 +1,4 @@ +## Elan +[Elan](https://github.com/leanprover/elan) automatically manages all the different versions of Lean and ensures that the correct version is used when opening a project. + +Clicking [this link](command:lean4.setup.installElan) will download the [Elan setup script](https://github.com/leanprover/elan/blob/master/elan-init.sh) and execute it. diff --git a/vscode-lean4/media/guide-installElan-windows.md b/vscode-lean4/media/guide-installElan-windows.md new file mode 100644 index 000000000..c56099c17 --- /dev/null +++ b/vscode-lean4/media/guide-installElan-windows.md @@ -0,0 +1,4 @@ +## Elan +[Elan](https://github.com/leanprover/elan) automatically manages all the different versions of Lean and ensures that the correct version is used when opening a project. + +Clicking [this link](command:lean4.setup.installElan) will download the [Elan setup script](https://github.com/leanprover/elan/blob/master/elan-init.ps1) and execute it. diff --git a/vscode-lean4/media/guide-setupProject.md b/vscode-lean4/media/guide-setupProject.md new file mode 100644 index 000000000..53648a304 --- /dev/null +++ b/vscode-lean4/media/guide-setupProject.md @@ -0,0 +1,15 @@ +## Project Creation +If you want to create a new project, click on one of the following: +- [Create a new standalone project](command:lean4.project.createStandaloneProject) + Standalone projects do not depend on any other Lean 4 projects. Dependencies can be added by modifying 'lakefile.lean' in the newly created project as described [here](https://github.com/leanprover/lean4/blob/master/src/lake/README.md#adding-dependencies). +- [Create a new mathlib project](command:lean4.project.createMathlibProject) + Mathlib projects depend on [mathlib](https://github.com/leanprover-community/mathlib4), the math library of Lean 4. + +If you want to open an existing project, click on one of the following: +- [Download an existing project](command:lean4.project.clone) +- [Open an existing local project](command:lean4.project.open) + +After creating or downloading a project, you can open it in the future by clicking the ∀-symbol in the top right, choosing 'Open Project…' > 'Open Local Project…' and selecting the project you created. + +## Complex Project Setups +Using its build system and package manager Lake, Lean 4 supports more complex project setups than the ones described above. You can find out more about Lake in the [Lean 4 GitHub repository](https://github.com/leanprover/lean4/blob/master/src/lake/README.md). diff --git a/vscode-lean4/media/lean-mini-dark.svg b/vscode-lean4/media/lean-mini-dark.svg new file mode 100644 index 000000000..5ba4d929f --- /dev/null +++ b/vscode-lean4/media/lean-mini-dark.svg @@ -0,0 +1,259 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vscode-lean4/media/lean-mini-light.svg b/vscode-lean4/media/lean-mini-light.svg new file mode 100644 index 000000000..691cdc68c --- /dev/null +++ b/vscode-lean4/media/lean-mini-light.svg @@ -0,0 +1,259 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vscode-lean4/media/open-setup-guide.png b/vscode-lean4/media/open-setup-guide.png new file mode 100644 index 0000000000000000000000000000000000000000..c86e984642be2d425451e6f6543bc1fc6eab1456 GIT binary patch literal 17901 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 literal 0 HcmV?d00001 diff --git a/vscode-lean4/package-lock.json b/vscode-lean4/package-lock.json index a0305afbe..66132b397 100644 --- a/vscode-lean4/package-lock.json +++ b/vscode-lean4/package-lock.json @@ -1,19 +1,20 @@ { "name": "lean4", - "version": "0.0.111", + "version": "0.0.113", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "lean4", - "version": "0.0.111", + "version": "0.0.113", "license": "Apache-2.0", "dependencies": { "axios": "~0.24.0", "cheerio": "^1.0.0-rc.10", "mobx": "5.15.7", "semver": "=7.3.5", - "vscode-languageclient": "=8.0.2" + "vscode-languageclient": "=8.0.2", + "zod": "^3.22.4" }, "devDependencies": { "@types/cheerio": "~0.22.30", @@ -37,7 +38,7 @@ "webpack-cli": "^4.10.0" }, "engines": { - "vscode": "^1.70.0" + "vscode": "^1.75.0" } }, "node_modules/@babel/runtime": { @@ -4661,6 +4662,14 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index 81bc86f30..411f62449 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -5,7 +5,7 @@ "version": "0.0.113", "publisher": "leanprover", "engines": { - "vscode": "^1.70.0" + "vscode": "^1.75.0" }, "categories": [ "Programming Languages" @@ -25,7 +25,7 @@ "lean4.toolchainPath": { "type": "string", "default": "", - "markdownDescription": "Path to your Lean toolchain. Leave this blank to get the default location from your PATH environment or from the default elan install location.", + "markdownDescription": "**DO NOT CHANGE** unless you know what you are doing. Path to your Lean toolchain. Leave this blank to get the default location from your PATH environment or from the default elan install location.", "scope": "machine-overridable" }, "lean4.input.enabled": { @@ -179,6 +179,16 @@ "type": "number", "default": 200, "description": "Time (in milliseconds) which must pass since latest edit until elaboration begins. Lower values may make editing feel faster at the cost of higher CPU usage." + }, + "lean4.showInvalidProjectWarnings": { + "type": "boolean", + "default": true, + "markdownDescription": "Show warnings whenever a .lean-file is opened in a folder that does not contain a 'lean-toolchain' file." + }, + "lean4.alwaysShowTitleBarMenu": { + "type": "boolean", + "default": true, + "markdownDescription": "Always display the Lean extension title bar menu in the top right. This helps beginners create and open Lean projects after launching an empty instance of VS Code, but may not be desirable for anyone who uses VS Code for things other than Lean." } } }, @@ -186,25 +196,25 @@ { "command": "lean4.restartServer", "category": "Lean 4", - "title": "Restart Server", + "title": "Server: Restart Server", "description": "Restart the Lean server (for all files)." }, { "command": "lean4.stopServer", "category": "Lean 4", - "title": "Stop Server", + "title": "Server: Stop Server", "description": "Stop the Lean server (for all files)." }, { "command": "lean4.restartFile", "category": "Lean 4", - "title": "Restart File", + "title": "Server: Restart File", "description": "Restarts the Lean server for the file that is currently focused, refreshing the dependencies." }, { "command": "lean4.refreshFileDependencies", "category": "Lean 4", - "title": "Refresh File Dependencies", + "title": "Server: Refresh File Dependencies", "description": "Restarts the Lean server for the file that is currently focused to refresh the dependencies." }, { @@ -226,7 +236,7 @@ { "command": "lean4.toggleInfoview", "category": "Lean 4", - "title": "Infoview: Toggle", + "title": "Infoview: Toggle Infoview", "description": "Toggle whether the infoview is displayed." }, { @@ -266,14 +276,92 @@ { "command": "lean4.docView.showAllAbbreviations", "category": "Lean 4", - "title": "Show all abbreviations", + "title": "Docview: Show All Abbreviations", "description": "Show help page containing all abbreviations and the Unicode characters they map to." }, { "command": "lean4.docView.open", "category": "Lean 4", - "title": "Open Documentation View", + "title": "Docview: Open Docview", "description": "Open documentation found in local 'html' folder in a separate web view panel." + }, + { + "command": "lean4.docView.back", + "category": "Lean 4", + "title": "Docview: Back", + "description": "Go to previous page in documentation view" + }, + { + "command": "lean4.docView.forward", + "category": "Lean 4", + "title": "Docview: Forward", + "description": "Go to next page in documentation view" + }, + { + "command": "lean4.troubleshooting.showOutput", + "category": "Lean 4", + "title": "Troubleshooting: Show Output", + "description": "Show output channel containing all progress updates and errors of commands" + }, + { + "command": "lean4.setup.showSetupGuide", + "category": "Lean 4", + "title": "Setup: Show Setup Guide", + "description": "Show 'Welcome' page containing a checklist of steps to install Lean 4" + }, + { + "command": "lean4.setup.installElan", + "category": "Lean 4", + "title": "Setup: Install Elan", + "description": "Install Lean's version manager 'Elan'" + }, + { + "command": "lean4.project.createStandaloneProject", + "category": "Lean 4", + "title": "Project: Create Standalone Project…", + "description": "Create a new Lean project that does not depend on any other projects" + }, + { + "command": "lean4.project.createMathlibProject", + "category": "Lean 4", + "title": "Project: Create Mathlib Project…", + "description": "Create a new Lean math formalization project using Mathlib" + }, + { + "command": "lean4.project.open", + "category": "Lean 4", + "title": "Project: Open Local Project…", + "description": "Opens a local Lean project" + }, + { + "command": "lean4.project.clone", + "category": "Lean 4", + "title": "Project: Download Project…", + "description": "Download an existing Lean project using `git clone`" + }, + { + "command": "lean4.project.build", + "category": "Lean 4", + "title": "Project: Build Project", + "description": "Build the current project" + }, + { + "command": "lean4.project.clean", + "category": "Lean 4", + "title": "Project: Clean Project", + "description": "Clean the current project, removing all build artifacts" + }, + { + "command": "lean4.project.updateDependency", + "category": "Lean 4", + "title": "Project: Update Dependency…", + "description": "Updates a dependency of the current project to the most recent version available for the branch pinned in 'lakefile.lean'." + }, + { + "command": "lean4.project.fetchCache", + "category": "Lean 4", + "title": "Project: Fetch Mathlib Build Cache", + "description": "Downloads cached Mathlib build artifacts to avoid full elaboration" } ], "languages": [ @@ -351,17 +439,37 @@ "menus": { "commandPalette": [ { - "command": "lean4.input.convert", - "when": "editorLangId == lean4 && lean4.input.isActive" + "command": "lean4.restartServer", + "when": "editorLangId == lean4" + }, + { + "command": "lean4.stopServer", + "when": "editorLangId == lean4" }, { "command": "lean4.restartFile", "when": "editorLangId == lean4" }, + { + "command": "lean4.refreshFileDependencies", + "when": "editorLangId == lean4" + }, + { + "command": "lean4.input.convert", + "when": "editorLangId == lean4 && lean4.input.isActive" + }, { "command": "lean4.displayGoal", "when": "editorLangId == lean4" }, + { + "command": "lean4.toggleInfoview", + "when": "editorLangId == lean4" + }, + { + "command": "lean4.displayList", + "when": "editorLangId == lean4" + }, { "command": "lean4.infoView.copyToComment", "when": "editorLangId == lean4" @@ -371,34 +479,226 @@ "when": "editorLangId == lean4" }, { - "command": "lean4.restartServer", + "command": "lean4.infoView.toggleUpdating", "when": "editorLangId == lean4" }, { - "command": "lean4.stopServer", + "command": "lean4.infoView.toggleExpectedType", "when": "editorLangId == lean4" }, { - "command": "lean4.restartFile", + "command": "lean4.docView.showAllAbbreviations", "when": "editorLangId == lean4" }, { - "command": "lean4.refreshFileDependencies", + "command": "lean4.docView.open" + }, + { + "command": "lean4.docView.back" + }, + { + "command": "lean4.docView.forward" + }, + { + "command": "lean4.troubleshooting.showOutput" + }, + { + "command": "lean4.setup.showSetupGuide" + }, + { + "command": "lean4.setup.installElan" + }, + { + "command": "lean4.project.createStandaloneProject" + }, + { + "command": "lean4.project.createMathlibProject" + }, + { + "command": "lean4.project.open" + }, + { + "command": "lean4.project.clone" + }, + { + "command": "lean4.project.build", "when": "editorLangId == lean4" }, { - "command": "lean4.docView.showAllAbbreviations", + "command": "lean4.project.clean", + "when": "editorLangId == lean4" + }, + { + "command": "lean4.project.updateDependency", + "when": "editorLangId == lean4" + }, + { + "command": "lean4.project.fetchCache", "when": "editorLangId == lean4" } ], "editor/title": [ { - "command": "lean4.displayGoal", + "submenu": "lean4.titlebar", + "when": "config.lean4.alwaysShowTitleBarMenu || lean4.isLeanFeatureSetActive", + "group": "navigation@0" + } + ], + "lean4.titlebar": [ + { + "submenu": "lean4.titlebar.newProject", + "when": "config.lean4.alwaysShowTitleBarMenu || lean4.isLeanFeatureSetActive", + "group": "1_setup@1" + }, + { + "submenu": "lean4.titlebar.openProject", + "when": "config.lean4.alwaysShowTitleBarMenu || lean4.isLeanFeatureSetActive", + "group": "1_setup@1" + }, + { + "command": "lean4.restartFile", + "when": "lean4.isLeanFeatureSetActive", + "group": "2_server@1" + }, + { + "command": "lean4.restartServer", + "when": "lean4.isLeanFeatureSetActive", + "group": "2_server@2" + }, + { + "command": "lean4.toggleInfoview", + "when": "lean4.isLeanFeatureSetActive", + "group": "3_infoview@1" + }, + { + "command": "lean4.troubleshooting.showOutput", + "when": "config.lean4.alwaysShowTitleBarMenu || lean4.isLeanFeatureSetActive", + "group": "4_troubleshooting" + }, + { + "submenu": "lean4.titlebar.versions", + "when": "config.lean4.alwaysShowTitleBarMenu || lean4.isLeanFeatureSetActive", + "group": "5_versions" + }, + { + "submenu": "lean4.titlebar.projectActions", + "when": "config.lean4.alwaysShowTitleBarMenu || lean4.isLeanFeatureSetActive", + "group": "6_projectActions@1" + }, + { + "submenu": "lean4.titlebar.documentation", + "when": "config.lean4.alwaysShowTitleBarMenu || lean4.isLeanFeatureSetActive", + "group": "7_documentation@1" + } + ], + "lean4.titlebar.newProject": [ + { + "command": "lean4.project.createStandaloneProject", + "when": "config.lean4.alwaysShowTitleBarMenu || lean4.isLeanFeatureSetActive", + "group": "1_newProject@1" + }, + { + "command": "lean4.project.createMathlibProject", + "when": "config.lean4.alwaysShowTitleBarMenu || lean4.isLeanFeatureSetActive", + "group": "1_newProject@2" + } + ], + "lean4.titlebar.openProject": [ + { + "command": "lean4.project.open", + "when": "config.lean4.alwaysShowTitleBarMenu || lean4.isLeanFeatureSetActive", + "group": "1_openProject@1" + }, + { + "command": "lean4.project.clone", + "when": "config.lean4.alwaysShowTitleBarMenu || lean4.isLeanFeatureSetActive", + "group": "1_openProject@2" + } + ], + "lean4.titlebar.versions": [ + { + "command": "lean4.setup.installElan", + "when": "config.lean4.alwaysShowTitleBarMenu || lean4.isLeanFeatureSetActive", + "group": "1_setup@1" + } + ], + "lean4.titlebar.projectActions": [ + { + "command": "lean4.project.build", + "when": "lean4.isLeanFeatureSetActive", + "group": "1_projectActions@1" + }, + { + "command": "lean4.project.clean", + "when": "lean4.isLeanFeatureSetActive", + "group": "1_projectActions@2" + }, + { + "command": "lean4.project.updateDependency", + "when": "lean4.isLeanFeatureSetActive", + "group": "1_projectActions@3" + }, + { + "command": "lean4.project.fetchCache", + "when": "lean4.isLeanFeatureSetActive", + "group": "2_mathlibActions@1" + } + ], + "lean4.titlebar.documentation": [ + { + "command": "lean4.setup.showSetupGuide", + "when": "config.lean4.alwaysShowTitleBarMenu || lean4.isLeanFeatureSetActive", + "group": "1_installation@1" + }, + { + "command": "lean4.docView.open", + "when": "config.lean4.alwaysShowTitleBarMenu || lean4.isLeanFeatureSetActive", + "group": "2_docview@1" + }, + { + "command": "lean4.docView.showAllAbbreviations", + "when": "config.lean4.alwaysShowTitleBarMenu || lean4.isLeanFeatureSetActive", + "group": "2_docview@2" + } + ], + "editor/context": [ + { + "command": "lean4.restartFile", "when": "editorLangId == lean4", - "group": "navigation@2" + "group": "z_commands" } ] }, + "submenus": [ + { + "id": "lean4.titlebar", + "label": "Lean 4", + "icon": { + "dark": "./media/lean-mini-dark.svg", + "light": "./media/lean-mini-light.svg" + } + }, + { + "id": "lean4.titlebar.newProject", + "label": "New Project…" + }, + { + "id": "lean4.titlebar.openProject", + "label": "Open Project…" + }, + { + "id": "lean4.titlebar.versions", + "label": "Version Management…" + }, + { + "id": "lean4.titlebar.projectActions", + "label": "Project Actions…" + }, + { + "id": "lean4.titlebar.documentation", + "label": "Documentation…" + } + ], "semanticTokenScopes": [ { "scopes": { @@ -414,16 +714,158 @@ "editor.tabSize": 2, "editor.wordSeparators": "`~@$%^&*()-=+[{]}⟨⟩⦃⦄⟦⟧⟮⟯‹›\\|;:\",.<>/" } - } + }, + "walkthroughs": [ + { + "id": "guide.linux", + "title": "Lean 4 Setup", + "description": "Getting started with Lean 4 on Linux\n", + "when": "isLinux", + "steps": [ + { + "id": "guide.linux.openSetupGuide", + "title": "Re-Open Setup Guide", + "description": "This guide can always be re-opened by opening an empty file, clicking on the ∀-symbol in the top right and selecting 'Documentation…' > 'Setup: Show Setup Guide'.", + "media": { + "image": "media/open-setup-guide.png", + "altText": "Click on the ∀-symbol in the top right and select 'Documentation…' > 'Setup: Show Setup Guide'." + } + }, + { + "id": "guide.linux.documentation", + "title": "Books and Documentation", + "description": "Learn using Lean 4 with the resources on the right.", + "media": { "markdown": "./media/guide-documentation.md" } + }, + { + "id": "guide.linux.installDeps", + "title": "Install Required Dependencies", + "description": "Install Git and curl using your package manager.", + "media": { "markdown": "./media/guide-installDeps-linux.md" } + }, + { + "id": "guide.linux.installElan", + "title": "Install Lean Version Manager", + "description": "Install Lean's version manager Elan.\n[Click to install](command:lean4.setup.installElan)", + "media": { "markdown": "./media/guide-installElan-unix.md" } + }, + { + "id": "guide.linux.setupProject", + "title": "Set Up Lean 4 Project", + "description": "Set up a Lean 4 project by clicking on one of the options on the right.", + "media": { "markdown": "./media/guide-setupProject.md" } + }, + { + "id": "guide.linux.help", + "title": "Questions and Troubleshooting", + "description": "If you have any questions or are having trouble with any of the previous steps, please visit us on the [Lean Zulip chat](https://leanprover.zulipchat.com/) so that we can help you.", + "media": { "markdown": "./media/guide-help.md" } + } + ] + }, + { + "id": "guide.mac", + "title": "Lean 4 Setup", + "description": "Getting started with Lean 4 on Mac\n", + "when": "isMac", + "steps": [ + { + "id": "guide.mac.openSetupGuide", + "title": "Re-Open Setup Guide", + "description": "This guide can always be re-opened by opening an empty file, clicking on the ∀-symbol in the top right and selecting 'Documentation…' > 'Setup: Show Setup Guide'.", + "media": { + "image": "media/open-setup-guide.png", + "altText": "Click on the ∀-symbol in the top right and select 'Documentation…' > 'Setup: Show Setup Guide'." + } + }, + { + "id": "guide.mac.documentation", + "title": "Books and Documentation", + "description": "Learn using Lean 4 with the resources on the right.", + "media": { "markdown": "./media/guide-documentation.md" } + }, + { + "id": "guide.mac.installDeps", + "title": "Install Required Dependencies", + "description": "Install Homebrew, Git and curl.", + "media": { "markdown": "./media/guide-installDeps-mac.md" } + }, + { + "id": "guide.mac.installElan", + "title": "Install Lean Version Manager", + "description": "Install Lean's version manager Elan.\n[Click to install](command:lean4.setup.installElan)", + "media": { "markdown": "./media/guide-installElan-unix.md" } + }, + { + "id": "guide.mac.setupProject", + "title": "Set Up Lean 4 Project", + "description": "Set up a Lean 4 project by clicking on one of the options on the right.", + "media": { "markdown": "./media/guide-setupProject.md" } + }, + { + "id": "guide.mac.help", + "title": "Questions and Troubleshooting", + "description": "If you have any questions or are having trouble with any of the previous steps, please visit us on the [Lean Zulip chat](https://leanprover.zulipchat.com/) so that we can help you.", + "media": { "markdown": "./media/guide-help.md" } + } + ] + }, + { + "id": "guide.windows", + "title": "Lean 4 Setup", + "description": "Getting started with Lean 4 on Windows\n", + "when": "isWindows", + "steps": [ + { + "id": "guide.windows.openSetupGuide", + "title": "Re-Open Setup Guide", + "description": "This guide can always be re-opened by opening an empty file, clicking on the ∀-symbol in the top right and selecting 'Documentation…' > 'Setup: Show Setup Guide'.", + "media": { + "image": "media/open-setup-guide.png", + "altText": "Click on the ∀-symbol in the top right and select 'Documentation…' > 'Setup: Show Setup Guide'." + } + }, + { + "id": "guide.windows.documentation", + "title": "Books and Documentation", + "description": "Learn using Lean 4 with the resources on the right.", + "media": { "markdown": "./media/guide-documentation.md" } + }, + { + "id": "guide.windows.installDeps", + "title": "Install Required Dependencies", + "description": "Install Git.", + "media": { "markdown": "./media/guide-installDeps-windows.md" } + }, + { + "id": "guide.windows.installElan", + "title": "Install Lean Version Manager", + "description": "Install Lean's version manager Elan.\n[Click to install](command:lean4.setup.installElan)", + "media": { "markdown": "./media/guide-installElan-windows.md" } + }, + { + "id": "guide.windows.setupProject", + "title": "Set Up Lean 4 Project", + "description": "Set up a Lean 4 project by clicking on one of the options on the right.", + "media": { "markdown": "./media/guide-setupProject.md" } + }, + { + "id": "guide.windows.help", + "title": "Questions and Troubleshooting", + "description": "If you have any questions or are having trouble with any of the previous steps, please visit us on the [Lean Zulip chat](https://leanprover.zulipchat.com/) so that we can help you.", + "media": { "markdown": "./media/guide-help.md" } + } + ] + } + ] }, "extensionKind": [ "workspace" ], "activationEvents": [ "onLanguage:lean", - "onLanguage:lean4", "onLanguage:markdown", - "onCommand:lean4.restartServer" + "onStartupFinished" ], "main": "./dist/extension", "scripts": { @@ -432,6 +874,7 @@ "watch": "webpack --env development --watch", "watchTest": "concurrently \"tsc -p . -w --outDir out\" \"npm run watch\"", "package": "vsce package", + "packagePreRelease": "vsce package --pre-release", "pretest": "tsc -p . --outDir out", "test": "node ./out/test/suite/runTest.js" }, @@ -442,7 +885,8 @@ "cheerio": "^1.0.0-rc.10", "mobx": "5.15.7", "semver": "=7.3.5", - "vscode-languageclient": "=8.0.2" + "vscode-languageclient": "=8.0.2", + "zod": "^3.22.4" }, "devDependencies": { "@types/cheerio": "~0.22.30", diff --git a/vscode-lean4/src/config.ts b/vscode-lean4/src/config.ts index dd3e498fe..339e327bf 100644 --- a/vscode-lean4/src/config.ts +++ b/vscode-lean4/src/config.ts @@ -223,6 +223,10 @@ export function getElaborationDelay(): number { return workspace.getConfiguration('lean4').get('elaborationDelay', 200); } +export function shouldShowInvalidProjectWarnings(): boolean { + return workspace.getConfiguration('lean4').get('showInvalidProjectWarnings', true) +} + export function getLeanExecutableName(): string { if (process.platform === 'win32') { return 'lean.exe' diff --git a/vscode-lean4/src/docview.ts b/vscode-lean4/src/docview.ts index da133322c..931c9bc3e 100644 --- a/vscode-lean4/src/docview.ts +++ b/vscode-lean4/src/docview.ts @@ -56,11 +56,12 @@ export class DocViewProvider implements Disposable { constructor(extensionUri: Uri) { this.extensionUri = extensionUri; this.subscriptions.push( - commands.registerCommand('lean4.docView.open', (url: string) => this.open(url)), + commands.registerCommand('lean4.docView.open', () => this.open()), + commands.registerCommand('lean4.docView.openUrl', (url: string) => this.open(url)), commands.registerCommand('lean4.docView.back', () => this.back()), commands.registerCommand('lean4.docView.forward', () => this.forward()), - commands.registerCommand('lean4.openTryIt', (code: string) => this.tryIt(code)), - commands.registerCommand('lean4.openExample', (file: string) => this.example(file)), + commands.registerCommand('lean4.docView.openTryIt', (code: string) => this.tryIt(code)), + commands.registerCommand('lean4.docView.openExample', (file: string) => this.example(file)), commands.registerCommand('lean4.docView.showAllAbbreviations', () => this.showAbbreviations()) ); this.subscriptions.push(workspace.onDidCloseTextDocument(doc => { @@ -224,17 +225,17 @@ export class DocViewProvider implements Disposable { } const books : any = { - 'Theorem Proving in Lean': mkCommandUri('lean4.docView.open', 'https://lean-lang.org/theorem_proving_in_lean4/introduction.html'), - 'Functional Programming in Lean': mkCommandUri('lean4.docView.open', 'https://lean-lang.org/functional_programming_in_lean/'), - 'Mathematics in Lean': mkCommandUri('lean4.docView.open', 'https://leanprover-community.github.io/mathematics_in_lean/'), - 'The Mechanics of Proof': mkCommandUri('lean4.docView.open', 'https://hrmacbeth.github.io/math2001/'), - 'Reference Manual': mkCommandUri('lean4.docView.open', 'https://lean-lang.org/lean4/doc/'), + 'Theorem Proving in Lean': mkCommandUri('lean4.docView.openUrl', 'https://lean-lang.org/theorem_proving_in_lean4/introduction.html'), + 'Functional Programming in Lean': mkCommandUri('lean4.docView.openUrl', 'https://lean-lang.org/functional_programming_in_lean/'), + 'Mathematics in Lean': mkCommandUri('lean4.docView.openUrl', 'https://leanprover-community.github.io/mathematics_in_lean/'), + 'The Mechanics of Proof': mkCommandUri('lean4.docView.openUrl', 'https://hrmacbeth.github.io/math2001/'), + 'Reference Manual': mkCommandUri('lean4.docView.openUrl', 'https://lean-lang.org/lean4/doc/'), 'Abbreviations Cheatsheet': mkCommandUri('lean4.docView.showAllAbbreviations'), - 'Example': mkCommandUri('lean4.openExample', 'https://github.com/leanprover/lean4-samples/raw/main/HelloWorld/Main.lean'), + 'Example': mkCommandUri('lean4.docView.openExample', 'https://github.com/leanprover/lean4-samples/raw/main/HelloWorld/Main.lean'), // These are handy for testing that the bad file logic is working. - //'Test bad file': mkCommandUri('lean4.docView.open', Uri.joinPath(this.extensionUri, 'media', 'webview.js')), - //'Test bad Uri': mkCommandUri('lean4.docView.open', 'https://leanprover.github.io/lean4/doc/images/code-success.png'), + //'Test bad file': mkCommandUri('lean4.docView.openUrl', Uri.joinPath(this.extensionUri, 'media', 'webview.js')), + //'Test bad Uri': mkCommandUri('lean4.docView.openUrl', 'https://leanprover.github.io/lean4/doc/images/code-success.png'), }; for (const book of Object.getOwnPropertyNames(books)) { @@ -319,17 +320,17 @@ var side_bar = false; // collapse the side bar menu by default. // here when the html is round tripped through the cheerio parser. } else if (link.attribs.tryitfile) { link.attribs.title = link.attribs.title || 'Open code block (in existing file)'; - link.attribs.href = mkCommandUri('lean4.openExample', new URL(link.attribs.tryitfile as string, url).toString()); + link.attribs.href = mkCommandUri('lean4.docView.openExample', new URL(link.attribs.tryitfile as string, url).toString()); } else if (tryItMatch) { const code = decodeURIComponent(tryItMatch[1] as string); link.attribs.title = link.attribs.title || 'Open code block in new editor'; - link.attribs.href = mkCommandUri('lean4.openTryIt', code); + link.attribs.href = mkCommandUri('lean4.docView.openTryIt', code); } else if (!link.attribs.href.startsWith('command:')) { const hrefUrl = new URL(link.attribs.href as string, url); const isExternal = !url || new URL(url).origin !== hrefUrl.origin; if (!isExternal || hrefUrl.protocol === 'file:') { link.attribs.title = link.attribs.title || link.attribs.href; - link.attribs.href = mkCommandUri('lean4.docView.open', hrefUrl.toString()); + link.attribs.href = mkCommandUri('lean4.docView.openUrl', hrefUrl.toString()); } } } @@ -380,7 +381,7 @@ var side_bar = false; // collapse the side bar menu by default. } /** Called by the user clicking a link. */ - async open(url?: string): Promise { + async open(url?: string | undefined): Promise { if (this.currentURL) { this.backStack.push(this.currentURL); this.forwardStack = []; diff --git a/vscode-lean4/src/exports.ts b/vscode-lean4/src/exports.ts index fe13010ba..807520c2f 100644 --- a/vscode-lean4/src/exports.ts +++ b/vscode-lean4/src/exports.ts @@ -2,12 +2,16 @@ import { InfoProvider } from './infoview' import { DocViewProvider } from './docview'; import { LeanInstaller } from './utils/leanInstaller' import { LeanClientProvider } from './utils/clientProvider'; +import { ProjectInitializationProvider } from './projectinit'; +import { ProjectOperationProvider } from './projectoperations'; export interface Exports { - isLean4Project: boolean; - version: string; - infoProvider: InfoProvider | undefined; - clientProvider: LeanClientProvider | undefined; - installer : LeanInstaller | undefined; - docView : DocViewProvider | undefined; + isLean4Project: boolean + version: string | undefined + infoProvider: InfoProvider | undefined + clientProvider: LeanClientProvider | undefined + projectOperationProvider: ProjectOperationProvider | undefined + installer: LeanInstaller | undefined + docView: DocViewProvider | undefined + projectInitializationProver: ProjectInitializationProvider | undefined } diff --git a/vscode-lean4/src/extension.ts b/vscode-lean4/src/extension.ts index fe69d5c10..e254000de 100644 --- a/vscode-lean4/src/extension.ts +++ b/vscode-lean4/src/extension.ts @@ -1,44 +1,61 @@ -import { window, Uri, workspace, ExtensionContext, TextDocument } from 'vscode' +import { window, ExtensionContext, TextDocument, tasks, commands, Disposable, workspace } from 'vscode' import { AbbreviationFeature } from './abbreviation' import { InfoProvider } from './infoview' -import { DocViewProvider } from './docview'; +import { DocViewProvider } from './docview' import { LeanTaskGutter } from './taskgutter' import { LeanInstaller } from './utils/leanInstaller' -import { LeanpkgService } from './utils/leanpkg'; -import { LeanClientProvider } from './utils/clientProvider'; -import { addDefaultElanPath, removeElanPath, addToolchainBinPath, isElanDisabled, getDefaultLeanVersion} from './config'; -import { findLeanPackageVersionInfo } from './utils/projectInfo'; +import { LeanpkgService } from './utils/leanpkg' +import { LeanClientProvider } from './utils/clientProvider' +import { addDefaultElanPath, removeElanPath, addToolchainBinPath, isElanDisabled, getDefaultLeanVersion, getDefaultElanPath} from './config' +import { findLeanPackageVersionInfo } from './utils/projectInfo' import { Exports } from './exports'; import { logger } from './utils/logger' +import { ProjectInitializationProvider } from './projectinit' +import { ProjectOperationProvider } from './projectoperations' +import { LeanClient } from './leanclient' + +interface AlwaysEnabledFeatures { + docView: DocViewProvider + projectInitializationProvider: ProjectInitializationProvider + installer: LeanInstaller +} + +interface Lean4EnabledFeatures { + clientProvider: LeanClientProvider + infoProvider: InfoProvider + projectOperationProvider: ProjectOperationProvider +} + +async function setLeanFeatureSetActive(isActive: boolean) { + await commands.executeCommand('setContext', 'lean4.isLeanFeatureSetActive', isActive) +} function isLean(languageId : string) : boolean { return languageId === 'lean' || languageId === 'lean4'; } - -function getLeanDocument() : TextDocument | undefined { - let document : TextDocument | undefined; - if (window.activeTextEditor && isLean(window.activeTextEditor.document.languageId)) - { - document = window.activeTextEditor.document +function findOpenLeanDocument() : TextDocument | undefined { + const activeEditor = window.activeTextEditor + if (activeEditor && isLean(activeEditor.document.languageId)) { + return activeEditor.document } - else { - // This happens if vscode starts with a lean file open - // but the "Getting Started" page is active. - for (const editor of window.visibleTextEditors) { - const lang = editor.document.languageId; - if (isLean(lang)) { - document = editor.document; - break; - } + + // This happens if vscode starts with a lean file open + // but the "Getting Started" page is active. + for (const editor of window.visibleTextEditors) { + if (isLean(editor.document.languageId)) { + return editor.document } } - return document; -} -export async function activate(context: ExtensionContext): Promise { + return undefined; +} - // for unit test that tests behavior when there is no elan installed. +/** + * Activates all extension features that are *always* enabled, even when no Lean 4 document is currently open. + */ +function activateAlwaysEnabledFeatures(context: ExtensionContext): AlwaysEnabledFeatures { + // For unit test that tests behavior when there is no elan installed. if (isElanDisabled()) { const elanRoot = removeElanPath(); if (elanRoot){ @@ -48,60 +65,149 @@ export async function activate(context: ExtensionContext): Promise { addDefaultElanPath(); } - const defaultToolchain = getDefaultLeanVersion(); - - // note: workspace.rootPath can be undefined in the untitled or adhoc case - // where the user ran "code lean_filename". - const doc = getLeanDocument(); - let packageUri = null; - let toolchainVersion = null; - if (doc) { - [packageUri, toolchainVersion] = await findLeanPackageVersionInfo(doc.uri); - if (toolchainVersion && toolchainVersion.indexOf('lean:3') > 0) { - logger.log(`Lean4 skipping lean 3 project: ${toolchainVersion}`); - return { isLean4Project: false, version: toolchainVersion, - infoProvider: undefined, clientProvider: undefined, installer: undefined, docView: undefined }; + context.subscriptions.push(commands.registerCommand('lean4.setup.showSetupGuide', async () => { + if (process.platform === 'win32') { + await commands.executeCommand('workbench.action.openWalkthrough', 'leanprover.lean4#guide.windows', false) + } else if (process.platform === 'darwin') { + await commands.executeCommand('workbench.action.openWalkthrough', 'leanprover.lean4#guide.mac', false) + } else if (process.platform === 'linux') { + await commands.executeCommand('workbench.action.openWalkthrough', 'leanprover.lean4#guide.linux', false) + } else { + await commands.executeCommand('workbench.action.openWalkthrough', 'leanprover.lean4#guide.linux', false) } - } + })) + + const docView = new DocViewProvider(context.extensionUri); + context.subscriptions.push(docView); const outputChannel = window.createOutputChannel('Lean: Editor'); + context.subscriptions.push(commands.registerCommand('lean4.troubleshooting.showOutput', () => outputChannel.show(true))) + const projectInitializationProvider = new ProjectInitializationProvider(outputChannel) + context.subscriptions.push(projectInitializationProvider) + + const defaultToolchain = getDefaultLeanVersion(); const installer = new LeanInstaller(outputChannel, defaultToolchain) - context.subscriptions.push(installer); - const versionInfo = await installer.checkLeanVersion(packageUri, toolchainVersion??defaultToolchain) - // Check whether rootPath is a Lean 3 project (the Lean 3 extension also uses the deprecated rootPath) + context.subscriptions.push(commands.registerCommand('lean4.setup.installElan', async () => { + await installer.installElan(); + if (isElanDisabled()) { + addToolchainBinPath(getDefaultElanPath()); + } else { + addDefaultElanPath(); + } + })) + + return { docView, projectInitializationProvider, installer } +} + +async function isLean3Project(installer: LeanInstaller): Promise { + const doc = findOpenLeanDocument(); + + const [packageUri, toolchainVersion] = doc + ? await findLeanPackageVersionInfo(doc.uri) + : [null, null] + + if (toolchainVersion && toolchainVersion.indexOf('lean:3') > 0) { + logger.log(`Lean4 skipping lean 3 project: ${toolchainVersion}`); + return true + } + + const versionInfo = await installer.checkLeanVersion(packageUri, toolchainVersion ?? installer.getDefaultToolchain()) if (versionInfo.version === '3') { - context.subscriptions.pop()?.dispose(); // stop installer - // We need to terminate before registering the LeanClientProvider, - // because that class changes the document id to `lean4`. - return { isLean4Project: false, version: '3', - infoProvider: undefined, clientProvider: undefined, installer: undefined, docView: undefined }; + return true } + return false +} + +function activateAbbreviationFeature(context: ExtensionContext, docView: DocViewProvider): AbbreviationFeature { + const abbrev = new AbbreviationFeature(); + // Pass the abbreviations through to the docView so it can show them on demand. + docView.setAbbreviations(abbrev.abbreviations.symbolsByAbbreviation); + context.subscriptions.push(abbrev); + return abbrev +} + +async function activateLean4Features(context: ExtensionContext, installer: LeanInstaller): Promise { + const clientProvider = new LeanClientProvider(installer, installer.getOutputChannel()); + context.subscriptions.push(clientProvider) + const pkgService = new LeanpkgService() + pkgService.versionChanged(async uri => { + const client: LeanClient | undefined = clientProvider.getClientForFolder(uri) + if (client && !client.isRunning()) { + // This can naturally happen when we update the Lean version using the "Update Dependency" command + // because the Lean server is stopped while doing so. We want to avoid triggering the "Version changed" + // message in this case. + return + } + await installer.handleVersionChanged(uri) + }); + pkgService.lakeFileChanged((uri) => installer.handleLakeFileChanged(uri)); context.subscriptions.push(pkgService); - const leanClientProvider = new LeanClientProvider(installer, pkgService, outputChannel); - context.subscriptions.push(leanClientProvider) + const infoProvider = new InfoProvider(clientProvider, {language: 'lean4'}, context); + context.subscriptions.push(infoProvider) - const info = new InfoProvider(leanClientProvider, {language: 'lean4'}, context); - context.subscriptions.push(info) + context.subscriptions.push(new LeanTaskGutter(clientProvider, context)) - const abbrev = new AbbreviationFeature(); - context.subscriptions.push(abbrev); + const projectOperationProvider: ProjectOperationProvider = new ProjectOperationProvider(installer.getOutputChannel(), clientProvider) - const docView = new DocViewProvider(context.extensionUri); - context.subscriptions.push(docView); + await setLeanFeatureSetActive(true) - // pass the abbreviations through to the docView so it can show them on demand. - docView.setAbbreviations(abbrev.abbreviations.symbolsByAbbreviation); + return { clientProvider, infoProvider, projectOperationProvider } +} - context.subscriptions.push(new LeanTaskGutter(leanClientProvider, context)) +export async function activate(context: ExtensionContext): Promise { + await setLeanFeatureSetActive(false) + const alwaysEnabledFeatures: AlwaysEnabledFeatures = activateAlwaysEnabledFeatures(context) + + if (await isLean3Project(alwaysEnabledFeatures.installer)) { + return { + isLean4Project: false, + version: '3', + infoProvider: undefined, + clientProvider: undefined, + projectOperationProvider: undefined, + installer: alwaysEnabledFeatures.installer, + docView: alwaysEnabledFeatures.docView, + projectInitializationProver: alwaysEnabledFeatures.projectInitializationProvider + } + } - pkgService.versionChanged((uri) => installer.handleVersionChanged(uri)); - pkgService.lakeFileChanged((uri) => installer.handleLakeFileChanged(uri)); + activateAbbreviationFeature(context, alwaysEnabledFeatures.docView) + + if (findOpenLeanDocument()) { + const lean4EnabledFeatures: Lean4EnabledFeatures = await activateLean4Features(context, alwaysEnabledFeatures.installer) + return { + isLean4Project: true, + version: '4', + infoProvider: lean4EnabledFeatures.infoProvider, + clientProvider: lean4EnabledFeatures.clientProvider, + projectOperationProvider: lean4EnabledFeatures.projectOperationProvider, + installer: alwaysEnabledFeatures.installer, + docView: alwaysEnabledFeatures.docView, + projectInitializationProver: alwaysEnabledFeatures.projectInitializationProvider + } + } - return { isLean4Project: true, version: '4', - infoProvider: info, clientProvider: leanClientProvider, installer, docView}; + // No Lean 4 document yet => Load remaining features when one is open + const disposeActivationListener: Disposable = workspace.onDidOpenTextDocument(async doc => { + if (isLean(doc.languageId)) { + await activateLean4Features(context, alwaysEnabledFeatures.installer) + disposeActivationListener.dispose() + } + }, context.subscriptions) + + return { + isLean4Project: true, + version: '4', + infoProvider: undefined, + clientProvider: undefined, + projectOperationProvider: undefined, + installer: alwaysEnabledFeatures.installer, + docView: alwaysEnabledFeatures.docView, + projectInitializationProver: alwaysEnabledFeatures.projectInitializationProvider + } } diff --git a/vscode-lean4/src/infoview.ts b/vscode-lean4/src/infoview.ts index 0fbe22fdf..4d7bf1ff9 100644 --- a/vscode-lean4/src/infoview.ts +++ b/vscode-lean4/src/infoview.ts @@ -281,7 +281,7 @@ export class InfoProvider implements Disposable { await this.sendPosition(); }), commands.registerTextEditorCommand('lean4.displayGoal', (editor) => this.openPreview(editor)), - commands.registerTextEditorCommand('lean4.toggleInfoview', (editor) => this.toggleInfoview(editor)), + commands.registerCommand('lean4.toggleInfoview', () => this.toggleInfoview()), commands.registerTextEditorCommand('lean4.displayList', async (editor) => { await this.openPreview(editor); await this.webviewPanel?.api.requestedAction({kind: 'toggleAllMessages'}); @@ -491,12 +491,14 @@ export class InfoProvider implements Disposable { this.rpcSessions = remaining } - private async toggleInfoview(editor: TextEditor) { + private async toggleInfoview() { if (this.webviewPanel) { this.webviewPanel.dispose(); // the onDispose handler sets this.webviewPanel = undefined + } else if (window.activeTextEditor && window.activeTextEditor.document.languageId === 'lean4') { + await this.openPreview(window.activeTextEditor); } else { - return this.openPreview(editor); + void window.showErrorMessage('No active Lean editor tab. Make sure to focus the Lean editor tab for which you want to open the infoview.') } } diff --git a/vscode-lean4/src/leanclient.ts b/vscode-lean4/src/leanclient.ts index c144481a5..90915c566 100644 --- a/vscode-lean4/src/leanclient.ts +++ b/vscode-lean4/src/leanclient.ts @@ -1,12 +1,11 @@ import { TextDocument, EventEmitter, Diagnostic, DocumentHighlight, Range, DocumentHighlightKind, workspace, Disposable, Uri, ConfigurationChangeEvent, OutputChannel, DiagnosticCollection, - WorkspaceFolder, window, commands } from 'vscode' + WorkspaceFolder, window, ProgressLocation, ProgressOptions, Progress } from 'vscode' import { DiagnosticSeverity, DidChangeTextDocumentParams, DidCloseTextDocumentParams, - DidOpenTextDocumentNotification, DocumentFilter, InitializeResult, LanguageClient, @@ -21,7 +20,7 @@ import * as ls from 'vscode-languageserver-protocol' import { toolchainPath, lakePath, addServerEnvPaths, serverArgs, serverLoggingEnabled, serverLoggingPath, shouldAutofocusOutput, getElaborationDelay, lakeEnabled, automaticallyBuildDependencies } from './config' import { assert } from './utils/assert' import { LeanFileProgressParams, LeanFileProgressProcessingInfo, ServerStoppedReason } from '@leanprover/infoview-api'; -import { batchExecute } from './utils/batch' +import { ExecutionExitCode, ExecutionResult, batchExecute } from './utils/batch' import { readLeanVersion } from './utils/projectInfo'; import * as fs from 'fs'; import { URL } from 'url'; @@ -31,6 +30,7 @@ import { logger } from './utils/logger' import { SemVer } from 'semver'; import { fileExists, isFileInFolder } from './utils/fsHelper'; import { c2pConverter, p2cConverter, patchConverters } from './utils/converters' +import { displayErrorWithOutput } from './utils/errors' import path = require('path') const escapeRegExp = (s: string) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); @@ -47,11 +47,12 @@ export class LeanClient implements Disposable { private toolchainPath: string private outputChannel: OutputChannel; private workspaceFolder: WorkspaceFolder | undefined; - private folderUri: Uri; + folderUri: Uri; private subscriptions: Disposable[] = [] private noPrompt : boolean = false; private showingRestartMessage : boolean = false; private elanDefaultToolchain: string; + private isRestarting: boolean = false private didChangeEmitter = new EventEmitter() didChange = this.didChangeEmitter.event @@ -141,211 +142,67 @@ export class LeanClient implements Disposable { } async showRestartMessage(restartFile: boolean = false): Promise { - if (!this.showingRestartMessage) { - this.showingRestartMessage = true; - let restartItem :string; - let messageTitle :string; - if (!restartFile) { - restartItem = 'Restart Lean Server'; - messageTitle = 'Lean Server has stopped unexpectedly.' + if (this.showingRestartMessage) { + return + } + this.showingRestartMessage = true; + let restartItem: string; + let messageTitle: string; + if (!restartFile) { + restartItem = 'Restart Lean Server'; + messageTitle = 'Lean Server has stopped unexpectedly.' + } else { + restartItem = 'Restart Lean Server on this file'; + messageTitle = 'The Lean Server has stopped processing this file.' + } + const item = await window.showErrorMessage(messageTitle, restartItem) + this.showingRestartMessage = false; + if (item === restartItem) { + if (restartFile && window.activeTextEditor) { + await this.restartFile(window.activeTextEditor.document); } else { - restartItem = 'Restart Lean Server on this file'; - messageTitle = 'The Lean Server has stopped processing this file.' - } - const item = await window.showErrorMessage(messageTitle, restartItem) - this.showingRestartMessage = false; - if (item === restartItem) { - if (restartFile && window.activeTextEditor){ - await this.restartFile(window.activeTextEditor.document); - } else { - void this.start(); - } + void this.start(); } } } async restart(): Promise { - const startTime = Date.now() - - logger.log('[LeanClient] Restarting Lean Server') - if (this.isStarted()) { - await this.stop() - } - - this.restartingEmitter.fire(undefined) - this.toolchainPath = toolchainPath(); - let version: string | null = null; - const env = addServerEnvPaths(process.env); - if (serverLoggingEnabled()) { - env.LEAN_SERVER_LOG_DIR = serverLoggingPath() - } - - let executable = lakePath() || - (this.toolchainPath ? join(this.toolchainPath, 'bin', 'lake') : 'lake'); - - // check if the lake process will start (skip it on scheme: 'untitled' files) - let useLake = lakeEnabled() && this.folderUri && this.folderUri.scheme === 'file'; - if (useLake) { - let knownDate = false; - const lakefile = Uri.joinPath(this.folderUri, 'lakefile.lean') - if (!await fileExists(new URL(lakefile.toString()))) { - useLake = false; - } - else { - // see if we can avoid the more expensive checkLakeVersion call. - const date = await this.checkToolchainVersion(this.folderUri); - if (date){ - // Feb 16 2022 is when the 3.1.0.pre was released. - useLake = date >= new Date(2022, 1, 16); - knownDate = true; - } - if (useLake && !knownDate){ - useLake = await this.checkLakeVersion(executable, version); - } - } - } - - if (!useLake) { - executable = (this.toolchainPath) ? join(this.toolchainPath, 'bin', 'lean') : 'lean'; - } - - const cwd = this.folderUri?.fsPath - if (!cwd && !version){ - // Fixes issue #227, for adhoc files it would pick up the cwd from the open folder - // which is not what we want. For adhoc files we want the (default) toolchain instead. - version = this.elanDefaultToolchain; - } - - let options = version ? ['+' + version] :[] - if (useLake) { - options = options.concat(['serve', '--']) - } else{ - options = options.concat(['--server']) - } - - // Add folder name to command-line so that it shows up in `ps aux`. - if (cwd) { - options.push('' + cwd) - } else { - options.push('untitled') + if (this.isRestarting) { + await window.showErrorMessage('Client is already being started.') + return } - - const serverOptions: ServerOptions = { - command: executable, - args: options.concat(serverArgs()), - options: { - cwd, - env + this.isRestarting = true + try { + logger.log('[LeanClient] Restarting Lean Server') + if (this.isStarted()) { + await this.stop() } - } - const documentSelector: DocumentFilter = { - language: 'lean4' - } + this.restartingEmitter.fire(undefined) + this.toolchainPath = toolchainPath(); - if (this.folderUri){ - documentSelector.scheme = this.folderUri.scheme - if (this.folderUri.scheme !== 'untitled') { - documentSelector.pattern = `${this.folderUri.fsPath}/**/*` + const progressOptions: ProgressOptions = { + location: ProgressLocation.Notification, + title: 'Starting Lean language client', + cancellable: false } + await window.withProgress(progressOptions, async progress => + await this.startClient(progress)) + } finally { + this.isRestarting = false } + } - const clientOptions: LanguageClientOptions = { - outputChannel: this.outputChannel, - revealOutputChannelOn: RevealOutputChannelOn.Never, // contrary to the name, this disables the message boxes - documentSelector: [documentSelector], - workspaceFolder: this.workspaceFolder, - initializationOptions: { - editDelay: getElaborationDelay(), hasWidgets: true, - }, - connectionOptions: { - maxRestartCount: 0, - cancellationStrategy: undefined as any, - }, - middleware: { - handleDiagnostics: (uri, diagnostics, next) => { - next(uri, diagnostics); - if (!this.client) return; - const uri_ = c2pConverter.asUri(uri); - const diagnostics_ = []; - for (const d of diagnostics) { - const d_: ls.Diagnostic = { - ...c2pConverter.asDiagnostic(d), - }; - diagnostics_.push(d_); - } - this.diagnosticsEmitter.fire({uri: uri_, diagnostics: diagnostics_}); - }, - - didOpen: async () => { - // Note: as per the LSP spec: An open notification must not be sent more than once - // without a corresponding close notification send before. This means open and close - // notification must be balanced and the max open count for a particular textDocument - // is one. So this even does nothing the notification is handled by the - // openLean4Document method below after the 'lean4' languageId is established and - // it has weeded out documents opened to invisible editors (like 'git:' schemes and - // invisible editors created for Ctrl+Hover events. A side effect of unbalanced - // open/close notification is leaking 'lean --worker' processes. - // See https://github.com/microsoft/vscode/issues/78453). - return; - }, - - didChange: async (data, next) => { - await next(data); - if (!this.running || !this.client) return; // there was a problem starting lean server. - const params = c2pConverter.asChangeTextDocumentParams(data); - this.didChangeEmitter.fire(params); - }, - - didClose: async (doc, next) => { - if (!this.isOpen.delete(doc.uri.toString())) { - return; - } - await next(doc); - if (!this.running || !this.client) return; // there was a problem starting lean server. - const params = c2pConverter.asCloseTextDocumentParams(doc); - this.didCloseEmitter.fire(params); - }, - - provideDocumentHighlights: async (doc, pos, ctok, next) => { - const leanHighlights = await next(doc, pos, ctok); - if (leanHighlights?.length) return leanHighlights; - - // vscode doesn't fall back to textual highlights, - // so we need to do that manually - await new Promise((res) => setTimeout(res, 250)); - if (ctok.isCancellationRequested) return; - - const wordRange = doc.getWordRangeAtPosition(pos); - if (!wordRange) return; - const word = doc.getText(wordRange); + private async startClient(progress: Progress<{ message?: string; increment?: number }>) { + // Should only be called from `restart` - const highlights: DocumentHighlight[] = []; - const text = doc.getText(); - const nonWordPattern = '[`~@$%^&*()-=+\\[{\\]}⟨⟩⦃⦄⟦⟧⟮⟯‹›\\\\|;:\",./\\s]|^|$' - const regexp = new RegExp(`(?<=${nonWordPattern})${escapeRegExp(word)}(?=${nonWordPattern})`, 'g') - for (const match of text.matchAll(regexp)) { - const start = doc.positionAt(match.index ?? 0) - highlights.push({ - range: new Range(start, start.translate(0, match[0].length)), - kind: DocumentHighlightKind.Text, - }) - } + const startTime = Date.now() + progress.report({ increment: 0 }) + this.client = await this.setupClient() - return highlights; - } - }, - } - this.client = new LanguageClient( - 'lean4', - 'Lean 4', - serverOptions, - clientOptions - ) let insideRestart = true; - patchConverters(this.client.protocol2CodeConverter, this.client.code2ProtocolConverter) try { - this.client.onDidChangeState(async (s) => { + this.client.onDidChangeState(async s => { // see https://github.com/microsoft/vscode-languageserver-node/issues/825 if (s.newState === State.Starting) { logger.log('[LeanClient] starting'); @@ -359,7 +216,7 @@ export class LeanClient implements Disposable { } else if (s.newState === State.Stopped) { this.running = false; logger.log('[LeanClient] has stopped or it failed to start'); - if (!this.noPrompt){ + if (!this.noPrompt) { // only raise this event and show the message if we are not the ones // who called the stop() method. this.stoppedEmitter.fire({message:'Lean server has stopped.', reason:''}); @@ -367,6 +224,7 @@ export class LeanClient implements Disposable { } } }) + progress.report({ increment: 80 }) await this.client.start() // tell the new client about the documents that are already open! for (const key of this.isOpen.keys()) { @@ -406,16 +264,12 @@ export class LeanClient implements Disposable { // Reveal the standard error output channel when the server prints something to stderr. // The vscode-languageclient library already takes care of writing it to the output channel. let stderrMsgBoxVisible = false; - (this.client as any)._serverProcess.stderr.on('data', async (chunk : Buffer) => { + (this.client as any)._serverProcess.stderr.on('data', async (chunk: Buffer) => { if (shouldAutofocusOutput()) { this.client?.outputChannel.show(true); } else if (!stderrMsgBoxVisible) { stderrMsgBoxVisible = true; - const outputItem = 'Show stderr output'; - const outPrompt = `Lean server printed an error:\n${chunk.toString()}`; - if (await window.showErrorMessage(outPrompt, outputItem) === outputItem) { - this.outputChannel.show(false); - } + await displayErrorWithOutput(`Lean server printed an error:\n${chunk.toString()}`) stderrMsgBoxVisible = false; } }); @@ -424,6 +278,24 @@ export class LeanClient implements Disposable { insideRestart = false; } + async withStoppedClient(action: () => Promise): Promise<'Success' | 'IsRestarting'> { + if (this.isRestarting) { + return 'IsRestarting' + } + this.isRestarting = true // Ensure that client cannot be restarted in the mean-time + + if (this.isStarted()) { + await this.stop() + } + + await action() + + this.isRestarting = false + await this.restart() + + return 'Success' + } + async openLean4Document(doc: TextDocument) { if (this.isOpen.has(doc.uri.toString())) return; if (!await this.isSameWorkspace(doc.uri)){ @@ -469,7 +341,6 @@ export class LeanClient implements Disposable { else { return uri.scheme === 'untitled' } - return false; } getWorkspaceFolder() : string { @@ -602,8 +473,12 @@ export class LeanClient implements Disposable { // Check that the Lake version is high enough to support "lake serve" option. const versionOptions = version ? ['+' + version, '--version'] : ['--version'] const start = Date.now() - const lakeVersion = await batchExecute(executable, versionOptions, this.folderUri?.fsPath, undefined); + const result: ExecutionResult = await batchExecute(executable, versionOptions, this.folderUri?.fsPath); + if (result.exitCode !== ExecutionExitCode.Success) { + return false + } logger.log(`[LeanClient] Ran '${executable} ${versionOptions.join(' ')}' in ${Date.now() - start} ms`); + const lakeVersion = result.stdout const actual = this.extractVersion(lakeVersion) if (actual.compare('3.0.0') > 0) { return true; @@ -623,4 +498,182 @@ export class LeanClient implements Disposable { return new SemVer('0.0.0'); } } + + private async determineServerOptions(): Promise { + const env = addServerEnvPaths(process.env) + if (serverLoggingEnabled()) { + env.LEAN_SERVER_LOG_DIR = serverLoggingPath() + } + + const [serverExecutable, options] = await this.determineExecutable() + + const cwd = this.folderUri?.fsPath + if (cwd) { + // Add folder name to command-line so that it shows up in `ps aux`. + options.push(cwd) + } else { + // Fixes issue #227, for adhoc files it would pick up the cwd from the open folder + // which is not what we want. For adhoc files we want the (default) toolchain instead. + options.unshift('+' + this.elanDefaultToolchain) + options.push('untitled') + } + + return { + command: serverExecutable, + args: options.concat(serverArgs()), + options: { + cwd, + env + } + } + } + + private async determineExecutable(): Promise<[string, string[]]> { + const lakeExecutable = lakePath() || + (this.toolchainPath ? join(this.toolchainPath, 'bin', 'lake') : 'lake') + const leanExecutable = + (this.toolchainPath) ? join(this.toolchainPath, 'bin', 'lean') : 'lean' + + if (await this.shouldUseLake(lakeExecutable)) { + return [lakeExecutable, ['serve', '--']] + } else{ + return [leanExecutable, ['--server']] + } + } + + private async shouldUseLake(lakeExecutable: string): Promise { + // check if the lake process will start (skip it on scheme: 'untitled' files) + if (!lakeEnabled() || !this.folderUri || this.folderUri.scheme !== 'file') { + return false + } + + const lakefile = Uri.joinPath(this.folderUri, 'lakefile.lean') + if (!await fileExists(new URL(lakefile.toString()))) { + return false + } + + // see if we can avoid the more expensive checkLakeVersion call. + const date = await this.checkToolchainVersion(this.folderUri); + if (date) { + // Feb 16 2022 is when the 3.1.0.pre was released. + return date >= new Date(2022, 1, 16); + } + + return await this.checkLakeVersion(lakeExecutable, null); + } + + private obtainClientOptions(): LanguageClientOptions { + const documentSelector: DocumentFilter = { + language: 'lean4' + } + + if (this.folderUri){ + documentSelector.scheme = this.folderUri.scheme + if (this.folderUri.scheme !== 'untitled') { + documentSelector.pattern = `${this.folderUri.fsPath}/**/*` + } + } + + return { + outputChannel: this.outputChannel, + revealOutputChannelOn: RevealOutputChannelOn.Never, // contrary to the name, this disables the message boxes + documentSelector: [documentSelector], + workspaceFolder: this.workspaceFolder, + initializationOptions: { + editDelay: getElaborationDelay(), hasWidgets: true, + }, + connectionOptions: { + maxRestartCount: 0, + cancellationStrategy: undefined as any, + }, + middleware: { + handleDiagnostics: (uri, diagnostics, next) => { + next(uri, diagnostics); + if (!this.client) return; + const uri_ = c2pConverter.asUri(uri); + const diagnostics_ = []; + for (const d of diagnostics) { + const d_: ls.Diagnostic = { + ...c2pConverter.asDiagnostic(d), + }; + diagnostics_.push(d_); + } + this.diagnosticsEmitter.fire({uri: uri_, diagnostics: diagnostics_}); + }, + + didOpen: async () => { + // Note: as per the LSP spec: An open notification must not be sent more than once + // without a corresponding close notification send before. This means open and close + // notification must be balanced and the max open count for a particular textDocument + // is one. So this even does nothing the notification is handled by the + // openLean4Document method below after the 'lean4' languageId is established and + // it has weeded out documents opened to invisible editors (like 'git:' schemes and + // invisible editors created for Ctrl+Hover events. A side effect of unbalanced + // open/close notification is leaking 'lean --worker' processes. + // See https://github.com/microsoft/vscode/issues/78453). + return; + }, + + didChange: async (data, next) => { + await next(data); + if (!this.running || !this.client) return; // there was a problem starting lean server. + const params = c2pConverter.asChangeTextDocumentParams(data); + this.didChangeEmitter.fire(params); + }, + + didClose: async (doc, next) => { + if (!this.isOpen.delete(doc.uri.toString())) { + return; + } + await next(doc); + if (!this.running || !this.client) return; // there was a problem starting lean server. + const params = c2pConverter.asCloseTextDocumentParams(doc); + this.didCloseEmitter.fire(params); + }, + + provideDocumentHighlights: async (doc, pos, ctok, next) => { + const leanHighlights = await next(doc, pos, ctok); + if (leanHighlights?.length) return leanHighlights; + + // vscode doesn't fall back to textual highlights, + // so we need to do that manually + await new Promise((res) => setTimeout(res, 250)); + if (ctok.isCancellationRequested) return; + + const wordRange = doc.getWordRangeAtPosition(pos); + if (!wordRange) return; + const word = doc.getText(wordRange); + + const highlights: DocumentHighlight[] = []; + const text = doc.getText(); + const nonWordPattern = '[`~@$%^&*()-=+\\[{\\]}⟨⟩⦃⦄⟦⟧⟮⟯‹›\\\\|;:\",./\\s]|^|$' + const regexp = new RegExp(`(?<=${nonWordPattern})${escapeRegExp(word)}(?=${nonWordPattern})`, 'g') + for (const match of text.matchAll(regexp)) { + const start = doc.positionAt(match.index ?? 0) + highlights.push({ + range: new Range(start, start.translate(0, match[0].length)), + kind: DocumentHighlightKind.Text, + }) + } + + return highlights; + } + }, + } + } + + private async setupClient(): Promise { + const serverOptions: ServerOptions = await this.determineServerOptions() + const clientOptions: LanguageClientOptions = this.obtainClientOptions() + + const client = new LanguageClient( + 'lean4', + 'Lean 4', + serverOptions, + clientOptions + ) + + patchConverters(client.protocol2CodeConverter, client.code2ProtocolConverter) + return client + } } diff --git a/vscode-lean4/src/projectinit.ts b/vscode-lean4/src/projectinit.ts new file mode 100644 index 000000000..c7c95d580 --- /dev/null +++ b/vscode-lean4/src/projectinit.ts @@ -0,0 +1,208 @@ +import { Disposable, Uri, commands, window, workspace, SaveDialogOptions, OutputChannel } from 'vscode'; +import path = require('path'); +import { checkParentFoldersForLeanProject, isValidLeanProject } from './utils/projectInfo'; +import { elanSelfUpdate } from './utils/elan'; +import { lake } from './utils/lake'; +import { ExecutionExitCode, ExecutionResult, batchExecuteWithProgress, displayError } from './utils/batch'; + +export class ProjectInitializationProvider implements Disposable { + + private subscriptions: Disposable[] = []; + + constructor(private channel: OutputChannel) { + this.subscriptions.push( + commands.registerCommand('lean4.project.createStandaloneProject', () => this.createStandaloneProject()), + commands.registerCommand('lean4.project.createMathlibProject', () => this.createMathlibProject()), + commands.registerCommand('lean4.project.open', () => this.openProject()), + commands.registerCommand('lean4.project.clone', () => this.cloneProject()) + ) + } + + private async createStandaloneProject() { + const projectFolder: Uri | 'DidNotComplete' = await this.createProject() + + if (projectFolder !== 'DidNotComplete') { + await ProjectInitializationProvider.openNewFolder(projectFolder) + } + } + + private async createMathlibProject() { + const mathlibToolchain = 'leanprover-community/mathlib4:lean-toolchain' + const projectFolder: Uri | 'DidNotComplete' = await this.createProject('math', mathlibToolchain) + if (projectFolder === 'DidNotComplete') { + return + } + + const cacheGetResult: ExecutionResult = await lake(this.channel, projectFolder, mathlibToolchain).fetchMathlibCache() + if (cacheGetResult.exitCode === ExecutionExitCode.Cancelled) { + return + } + if (cacheGetResult.exitCode !== ExecutionExitCode.Success) { + await displayError(cacheGetResult, 'Cannot fetch Mathlib build artifact cache.') + return + } + + await ProjectInitializationProvider.openNewFolder(projectFolder) + } + + private async createProject( + kind?: string | undefined, + toolchain: string = 'leanprover/lean4:stable'): Promise { + + const projectFolder: Uri | undefined = await ProjectInitializationProvider.askForNewProjectFolderLocation({ + saveLabel: 'Create project folder', + title: 'Create a new project folder' + }) + if (projectFolder === undefined) { + return 'DidNotComplete' + } + + await workspace.fs.createDirectory(projectFolder) + + // This can fail silently in setups without Elan. + await elanSelfUpdate(this.channel) + + const projectName: string = path.basename(projectFolder.fsPath) + const result: ExecutionResult = await lake(this.channel, projectFolder, toolchain).initProject(projectName, kind) + if (result.exitCode !== ExecutionExitCode.Success) { + await displayError(result, 'Cannot initialize project.') + return 'DidNotComplete' + } + + const updateResult: ExecutionResult = await lake(this.channel, projectFolder, toolchain).updateDependencies() + if (updateResult.exitCode === ExecutionExitCode.Cancelled) { + return 'DidNotComplete' + } + if (updateResult.exitCode !== ExecutionExitCode.Success) { + await displayError(updateResult, 'Cannot update dependencies.') + return 'DidNotComplete' + } + + return projectFolder + } + + private async openProject() { + const projectFolders: Uri[] | undefined = await window.showOpenDialog({ + title: 'Open Lean 4 project folder containing a \'lean-toolchain\' file', + openLabel: 'Open project folder', + canSelectFiles: false, + canSelectFolders: true, + canSelectMany: false + }) + if (projectFolders === undefined || projectFolders.length !== 1) { + return + } + + let projectFolder = projectFolders[0] + if (!await ProjectInitializationProvider.checkIsFileUriOrShowError(projectFolder)) { + return + } + + if (!await isValidLeanProject(projectFolder)) { + const parentProjectFolder: Uri | undefined = await ProjectInitializationProvider.attemptFindingLeanProjectInParentFolder(projectFolder) + if (parentProjectFolder === undefined) { + return + } + projectFolder = parentProjectFolder + } + + // This kills the extension host, so it has to be the last command + await commands.executeCommand('vscode.openFolder', projectFolder) + } + + private static async attemptFindingLeanProjectInParentFolder(projectFolder: Uri): Promise { + const parentProjectFolder: Uri | undefined = await checkParentFoldersForLeanProject(projectFolder) + if (parentProjectFolder === undefined) { + void window.showErrorMessage('The selected folder is not a valid Lean 4 project folder. Please make sure to select a folder containing a \'lean-toolchain\' file.') + return undefined + } + + const message = `The selected folder is not a valid Lean 4 project folder because it does not contain a 'lean-toolchain' file. +However, a valid Lean 4 project folder was found in one of the parent directories at '${parentProjectFolder.fsPath}'. +Open this project instead?` + const input = 'Open parent directory project' + const choice: string | undefined = await window.showInformationMessage(message, { modal: true }, input) + if (choice !== input) { + return undefined + } + + return parentProjectFolder + } + + private async cloneProject() { + const unparsedProjectUri: string | undefined = await window.showInputBox({ + title: 'URL Input', + value: 'https://github.com/leanprover-community/mathlib4', + prompt: 'URL of Git repository for existing Lean 4 project', + validateInput: value => { + try { + Uri.parse(value, true) + return undefined // Valid URI + } catch (e) { + return 'Invalid URL' + } + } + }) + if (unparsedProjectUri === undefined) { + return + } + const existingProjectUri = Uri.parse(unparsedProjectUri) + + const projectFolder: Uri | undefined = await ProjectInitializationProvider.askForNewProjectFolderLocation({ + saveLabel: 'Create project folder', + title: 'Create a new project folder to clone existing Lean 4 project into' + }) + if (projectFolder === undefined) { + return + } + + const result: ExecutionResult = await batchExecuteWithProgress('git', ['clone', existingProjectUri.toString(), projectFolder.fsPath], 'Cloning project', { channel: this.channel, allowCancellation: true }) + if (result.exitCode === ExecutionExitCode.Cancelled) { + return + } + if (result.exitCode !== ExecutionExitCode.Success) { + await displayError(result, 'Cannot download project.') + return + } + + // Try it. If this is not a mathlib project, it will fail silently. Otherwise, it will grab the cache. + const fetchResult: ExecutionResult = await lake(this.channel, projectFolder).fetchMathlibCache(true) + if (fetchResult.exitCode === ExecutionExitCode.Cancelled) { + return + } + + await ProjectInitializationProvider.openNewFolder(projectFolder) + } + + private static async askForNewProjectFolderLocation(options: SaveDialogOptions): Promise { + const projectFolder: Uri | undefined = await window.showSaveDialog(options) + if (projectFolder === undefined || !await this.checkIsFileUriOrShowError(projectFolder)) { + return undefined + } + return projectFolder + } + + private static async checkIsFileUriOrShowError(projectFolder: Uri): Promise { + if (projectFolder.scheme === 'file') { + return true + } else { + void window.showErrorMessage('Project folder must be created in a file system.') + return false + } + } + + private static async openNewFolder(projectFolder: Uri) { + const message = `Project initialized. Open new project folder '${path.basename(projectFolder.fsPath)}'?` + const input = 'Open project folder' + const choice: string | undefined = await window.showInformationMessage(message, { modal: true }, input) + if (choice === input) { + // This kills the extension host, so it has to be the last command + await commands.executeCommand('vscode.openFolder', projectFolder) + } + } + + dispose() { + for (const s of this.subscriptions) { s.dispose(); } + } + +} diff --git a/vscode-lean4/src/projectoperations.ts b/vscode-lean4/src/projectoperations.ts new file mode 100644 index 000000000..f46a078aa --- /dev/null +++ b/vscode-lean4/src/projectoperations.ts @@ -0,0 +1,341 @@ +import { Disposable, commands, window, OutputChannel, QuickPickItem, Uri } from 'vscode'; +import { LakeRunner, cacheNotFoundError, lake } from './utils/lake'; +import { ExecutionExitCode, ExecutionResult, batchExecute, displayError } from './utils/batch'; +import { LeanClientProvider } from './utils/clientProvider'; +import { LeanClient } from './leanclient'; +import { join } from 'path'; +import * as fs from 'fs' +import { DirectGitDependency, Manifest, ManifestReadError, parseAsManifest, parseManifestInFolder } from './utils/manifest'; + +export class ProjectOperationProvider implements Disposable { + + private subscriptions: Disposable[] = [] + private isRunningOperation: boolean = false // Used to synchronize project operations + + constructor(private channel: OutputChannel, private clientProvider: LeanClientProvider) { + this.subscriptions.push( + commands.registerCommand('lean4.project.build', () => this.buildProject()), + commands.registerCommand('lean4.project.clean', () => this.cleanProject()), + commands.registerCommand('lean4.project.updateDependency', () => this.updateDependency()), + commands.registerCommand('lean4.project.fetchCache', () => this.fetchMathlibCache()) + ) + } + + private async buildProject() { + await this.runOperation(async lakeRunner => { + const fetchResult: 'Success' | 'CacheNotAvailable' | 'Cancelled' = await this.tryFetchingCache(lakeRunner) + if (fetchResult === 'Cancelled') { + return + } + + const result: ExecutionResult = await lakeRunner.build() + if (result.exitCode === ExecutionExitCode.Cancelled) { + return + } + if (result.exitCode !== ExecutionExitCode.Success) { + void displayError(result, 'Cannot build project.') + return + } + + void window.showInformationMessage('Project built successfully.') + return + }) + } + + private async cleanProject() { + const deleteInput = 'Proceed' + const deleteChoice: string | undefined = await window.showInformationMessage('Delete all build artifacts?', { modal: true }, deleteInput) + if (deleteChoice !== deleteInput) { + return + } + + await this.runOperation(async lakeRunner => { + const cleanResult: ExecutionResult = await lakeRunner.clean() + if (cleanResult.exitCode === ExecutionExitCode.Cancelled) { + return + } + if (cleanResult.exitCode !== ExecutionExitCode.Success) { + void displayError(cleanResult, 'Cannot delete build artifacts.') + return + } + + const checkResult: 'Yes' | 'No' | 'Cancelled' = await lakeRunner.isMathlibCacheGetAvailable() + if (checkResult === 'Cancelled') { + return + } + if (checkResult === 'No') { + void window.showInformationMessage('Project cleaned successfully.') + return + } + + const fetchMessage = 'Project cleaned successfully. Do you want to fetch Mathlib\'s build artifact cache?' + const fetchInput = 'Fetch Cache' + const fetchChoice: string | undefined = await window.showInformationMessage(fetchMessage, { modal: true }, fetchInput) + if (fetchChoice !== fetchInput) { + return + } + + const fetchResult: ExecutionResult = await lakeRunner.fetchMathlibCache() + if (fetchResult.exitCode === ExecutionExitCode.Cancelled) { + return + } + if (fetchResult.exitCode !== ExecutionExitCode.Success) { + void displayError(fetchResult, 'Cannot fetch Mathlib build artifact cache.') + return + } + void window.showInformationMessage('Mathlib build artifact cache fetched successfully.') + }) + } + + private async fetchMathlibCache() { + await this.runOperation(async lakeRunner => { + const result: ExecutionResult = await lakeRunner.fetchMathlibCache() + if (result.exitCode === ExecutionExitCode.Cancelled) { + return + } + if (result.exitCode !== ExecutionExitCode.Success) { + if (result.stderr.includes(cacheNotFoundError)) { + void window.showErrorMessage('This command cannot be used in non-Mathlib projects.') + return + } + void displayError(result, 'Cannot fetch Mathlib build artifact cache.') + return + } + + void window.showInformationMessage('Mathlib build artifact cache fetched successfully.') + }) + } + + private async updateDependency() { + if (!window.activeTextEditor) { + return + } + + const activeClient: LeanClient | undefined = this.clientProvider.getActiveClient() + if (!activeClient) { + void window.showErrorMessage('No active client.') + this.isRunningOperation = false + return + } + + const manifestResult: Manifest | ManifestReadError = await parseManifestInFolder(activeClient.folderUri) + if (typeof manifestResult === 'string') { + void window.showErrorMessage(manifestResult) + return + } + + const dependencies: (DirectGitDependency & { remoteRevision?: string | undefined })[] = + await this.findUpdateableDependencies(manifestResult.directGitDependencies) + if (dependencies.length === 0) { + void window.showInformationMessage('Nothing to update - all dependencies are up-to-date.') + return + } + + const items: GitDependencyQuickPickItem[] = dependencies.map(gitDep => { + const shortLocalRevision: string = gitDep.revision.substring(0, 7) + const shortRemoteRevision: string | undefined = gitDep.remoteRevision?.substring(0, 7) + + const detail: string = shortRemoteRevision + ? `Current: ${shortLocalRevision} ⟹ New: ${shortRemoteRevision}` + : `Current: ${shortLocalRevision}` + + return { + label: `${gitDep.name} @ ${gitDep.inputRevision}`, + description: gitDep.uri.toString(), + detail, + ...gitDep + } + }) + + const dependencyChoice: GitDependencyQuickPickItem | undefined = await window.showQuickPick(items, { + title: 'Choose a dependency to update', + canPickMany: false + }) + if (!dependencyChoice) { + return + } + + const localToolchainPath: string = join(activeClient.folderUri.fsPath, 'lean-toolchain') + const dependencyToolchainResult: string | 'DoNotUpdate' | 'Cancelled' = await this.determineDependencyToolchain(localToolchainPath, dependencyChoice) + if (dependencyToolchainResult === 'Cancelled') { + return + } + + await this.runOperation(async lakeRunner => { + if (dependencyToolchainResult !== 'DoNotUpdate') { + try { + fs.writeFileSync(localToolchainPath, dependencyToolchainResult) + } catch { + void window.showErrorMessage('Cannot update Lean version.') + return + } + } + + const result: ExecutionResult = await lakeRunner.updateDependency(dependencyChoice.name) + if (result.exitCode === ExecutionExitCode.Cancelled) { + return + } + if (result.exitCode !== ExecutionExitCode.Success) { + void displayError(result, 'Cannot update dependency.') + return + } + + await this.tryFetchingCache(lakeRunner) + }) + } + + private async findUpdateableDependencies(dependencies: DirectGitDependency[]) { + const augmented: (DirectGitDependency & { remoteRevision?: string | undefined })[] = [] + + for (const dependency of dependencies) { + const result: ExecutionResult = await batchExecute('git', ['ls-remote', dependency.uri.toString(), dependency.inputRevision]) + if (result.exitCode !== ExecutionExitCode.Success) { + augmented.push(dependency) + continue + } + + const matches: RegExpMatchArray | null = result.stdout.match(/^[a-z0-9]+/) + if (!matches) { + augmented.push(dependency) + continue + } + + const remoteRevision: string = matches[0] + if (dependency.revision === remoteRevision) { + // Cannot be updated - filter it + continue + } + + augmented.push({ remoteRevision, ...dependency }) + } + + return augmented + } + + private async determineDependencyToolchain(localToolchainPath: string, dependency: DirectGitDependency): Promise { + const dependencyToolchainUri: Uri | undefined = this.determineDependencyToolchainUri(dependency.uri, dependency.inputRevision) + if (!dependencyToolchainUri) { + const message = `Could not determine Lean version of ${dependency.name} at ${dependency.uri}, as doing so is currently only supported for GitHub projects. Do you want to update ${dependency.name} without updating the Lean version of the open project to that of ${dependency.name} regardless?` + const input = 'Proceed' + const choice: string | undefined = await window.showInformationMessage(message, { modal: true}, input) + return choice === 'input' ? 'DoNotUpdate' : 'Cancelled' + } + + const toolchainResult = await this.fetchToolchains(localToolchainPath, dependencyToolchainUri) + if (!(toolchainResult instanceof Array)) { + const errorFlavor = toolchainResult === 'CannotReadLocalToolchain' + ? `Could not read Lean version of open project at '${localToolchainPath}'` + : `Could not fetch Lean version of ${dependency.name} at ${dependency.uri}` + const message = `${errorFlavor}. Do you want to update ${dependency.name} without updating the Lean version of the open project to that of ${dependency.name} regardless?` + const input = 'Proceed' + const choice: string | undefined = await window.showInformationMessage(message, { modal: true}, input) + return choice === 'input' ? 'DoNotUpdate' : 'Cancelled' + } + const [localToolchain, dependencyToolchain]: [string, string] = toolchainResult + + if (localToolchain === dependencyToolchain) { + return 'DoNotUpdate' + } + + const message = `The Lean version '${localToolchain}' of the open project differs from the Lean version '${dependencyToolchain}' of ${dependency.name}. Do you want to update the Lean version of the open project to the Lean version of ${dependency.name}?` + const input1 = 'Update Lean Version' + const input2 = 'Keep Lean Version' + const choice = await window.showInformationMessage(message, { modal: true }, input1, input2) + if (choice === undefined) { + return 'Cancelled' + } + if (choice !== input1) { + return 'DoNotUpdate' + } + + return dependencyToolchain + } + + private determineDependencyToolchainUri(dependencyUri: Uri, inputRevision: string): Uri | undefined { + // Example: + // Input: https://github.com/leanprover-community/mathlib4 + // Output: https://raw.githubusercontent.com/leanprover-community/mathlib4/master/lean-toolchain + + if (!dependencyUri.authority.includes('github.com')) { + return undefined + } + const match = dependencyUri.path.match(/\/([^\\]+\/[^\\\.]+)(\.git)?\/?/) + if (!match) { + return undefined + } + const repoPath: string = match[1] + + return Uri.from({ + scheme: 'https', + authority: 'raw.githubusercontent.com', + path: join(repoPath, inputRevision, 'lean-toolchain') + }) + } + + private async fetchToolchains(localToolchainPath: string, dependencyToolchainUri: Uri): Promise<[string, string] | 'CannotReadLocalToolchain' | 'CannotReadDependencyToolchain'> { + let localToolchain: string + try { + localToolchain = fs.readFileSync(localToolchainPath, 'utf8').trim() + } catch (e) { + return 'CannotReadLocalToolchain' + } + + const curlResult: ExecutionResult = await batchExecute('curl', ['-f', '-L', dependencyToolchainUri.toString()]) + if (curlResult.exitCode !== ExecutionExitCode.Success) { + return 'CannotReadDependencyToolchain' + } + const dependencyToolchain: string = curlResult.stdout.trim() + + return [localToolchain, dependencyToolchain] + } + + private async tryFetchingCache(lakeRunner: LakeRunner): Promise<'Success' | 'CacheNotAvailable' | 'Cancelled'> { + const fetchResult: ExecutionResult = await lakeRunner.fetchMathlibCache(true) + switch (fetchResult.exitCode) { + case ExecutionExitCode.Success: + return 'Success' + case ExecutionExitCode.Cancelled: + return 'Cancelled' + default: + return 'CacheNotAvailable' + } + } + + private async runOperation(command: (lakeRunner: LakeRunner) => Promise) { + if (this.isRunningOperation) { + void window.showErrorMessage('Another project action is already being executed. Please wait for its completion.') + return + } + this.isRunningOperation = true + + if (!this.clientProvider) { + void window.showErrorMessage('Lean client has not loaded yet.') + this.isRunningOperation = false + return + } + + const activeClient: LeanClient | undefined = this.clientProvider.getActiveClient() + if (!activeClient) { + void window.showErrorMessage('No active client.') + this.isRunningOperation = false + return + } + + const lakeRunner: LakeRunner = lake(this.channel, activeClient.folderUri) + + const result: 'Success' | 'IsRestarting' = await activeClient.withStoppedClient(() => command(lakeRunner)) + if (result === 'IsRestarting') { + void window.showErrorMessage('Cannot run project action while restarting the server.') + } + + this.isRunningOperation = false + } + + dispose() { + for (const s of this.subscriptions) { s.dispose(); } + } + +} + +interface GitDependencyQuickPickItem extends QuickPickItem, DirectGitDependency { +} diff --git a/vscode-lean4/src/utils/batch.ts b/vscode-lean4/src/utils/batch.ts index 3f962ad76..f1559b653 100644 --- a/vscode-lean4/src/utils/batch.ts +++ b/vscode-lean4/src/utils/batch.ts @@ -1,61 +1,218 @@ -import { OutputChannel } from 'vscode' +import { CancellationToken, Disposable, OutputChannel, ProgressLocation, ProgressOptions, window } from 'vscode' import { spawn } from 'child_process'; import { findProgramInPath, isRunningTest } from '../config' import { logger } from './logger' +import { displayErrorWithOutput } from './errors'; + +export interface ExecutionChannel { + combined?: OutputChannel | undefined + stdout?: OutputChannel | undefined + stderr?: OutputChannel | undefined +} + +export enum ExecutionExitCode { + Success, + CannotLaunch, + ExecutionError, + Cancelled +} + +export interface ExecutionResult { + exitCode: ExecutionExitCode + stdout: string + stderr: string +} + +function createCannotLaunchExecutionResult(message: string): ExecutionResult { + return { + exitCode: ExecutionExitCode.CannotLaunch, + stdout: '', + stderr: message + } +} export async function batchExecute( executablePath: string, - args: any[], - workingDirectory: string | null, - channel: OutputChannel | undefined): Promise { + args: string[], + workingDirectory?: string | undefined, + channel?: ExecutionChannel | undefined, + token?: CancellationToken | undefined): Promise { - return new Promise(function(resolve, reject){ - let output : string = ''; + return new Promise(function(resolve, reject) { + let stdout: string = '' + let stderr: string = '' let options = {} if (workingDirectory !== undefined) { options = { cwd: workingDirectory }; } try { - if (isRunningTest()) - { + if (isRunningTest()) { // The mocha test framework listens to process.on('uncaughtException') // which is raised if spawn cannot find the command and the test automatically // fails with "Uncaught Error: spawn elan ENOENT". Therefore we manually // check if the command exists so as not to trigger that exception. const fullPath = findProgramInPath(executablePath); if (!fullPath) { - resolve(undefined); + resolve(createCannotLaunchExecutionResult('')); return; } } + if (channel?.combined) { + const formattedCwd = workingDirectory ? `${workingDirectory}` : '' + const formattedArgs = args.map(arg => arg.includes(' ') ? `"${arg}"` : arg).join(' ') + channel.combined.appendLine(`${formattedCwd}> ${executablePath} ${formattedArgs}`) + } const proc = spawn(executablePath, args, options); - if (proc.pid === undefined) { - resolve(undefined); - return; - } + const disposeKill: Disposable | undefined = token?.onCancellationRequested(_ => proc.kill()) + + proc.on('error', err => { + disposeKill?.dispose() + resolve(createCannotLaunchExecutionResult(err.message)) + }); proc.stdout.on('data', (line) => { const s: string = line.toString(); - if (channel) channel.appendLine(s); - output += s + '\n'; + if (channel?.combined) channel.combined.appendLine(s) + if (channel?.stdout) channel.stdout.appendLine(s) + stdout += s + '\n'; }); proc.stderr.on('data', (line) => { const s: string = line.toString(); - if (channel) channel.appendLine(s); - output += s + '\n'; + if (channel?.combined) channel.combined.appendLine(s) + if (channel?.stderr) channel.stderr.appendLine(s) + stderr += s + '\n'; }); - proc.on('close', (code) => { + proc.on('close', (code, signal) => { + disposeKill?.dispose() logger.log(`child process exited with code ${code}`); - resolve(output) + if (signal === 'SIGTERM') { + if (channel?.combined) { + channel.combined.appendLine('=> Operation cancelled by user.') + } + resolve({ + exitCode: ExecutionExitCode.Cancelled, + stdout, + stderr + }) + return + } + if (code !== 0) { + if (channel?.combined) { + const formattedCode = code ? `Exit code: ${code}.` : '' + const formattedSignal = signal ? `Signal: ${signal}.` : '' + channel.combined.appendLine(`=> Operation failed. ${formattedCode} ${formattedSignal}`.trim()) + } + resolve({ + exitCode: ExecutionExitCode.ExecutionError, + stdout, + stderr + }) + return + } + resolve({ + exitCode: ExecutionExitCode.Success, + stdout, + stderr + }) }); - } catch (e){ + } catch (e) { logger.log(`error running ${executablePath} : ${e}`); - resolve(undefined); + resolve(createCannotLaunchExecutionResult('')); } }); } + +interface ProgressExecutionOptions { + cwd?: string | undefined + channel?: OutputChannel | undefined + translator?: ((line: string) => string | undefined) | undefined + allowCancellation?: boolean +} + +export async function batchExecuteWithProgress( + executablePath: string, + args: string[], + title: string, + options: ProgressExecutionOptions = {}): Promise { + + const titleSuffix = options.channel ? ' [(Details)](command:lean4.troubleshooting.showOutput)' : '' + + const progressOptions: ProgressOptions = { + location: ProgressLocation.Notification, + title: title + titleSuffix, + cancellable: options.allowCancellation === true + } + let inc = 0 + + const result: ExecutionResult = await window.withProgress(progressOptions, (progress, token) => { + const progressChannel: OutputChannel = { + name : 'ProgressChannel', + append(value: string) { + if (options.translator) { + const translatedValue: string | undefined = options.translator(value) + if (translatedValue === undefined) { + return + } + value = translatedValue + } + if (options.channel) { + options.channel.appendLine(value.trimEnd()) + } + if (inc < 90) { + inc += 2 + } + progress.report({ increment: inc, message: value }) + }, + appendLine(value: string) { + this.append(value + '\n') + }, + replace(_: string) { /* empty */ }, + clear() { /* empty */ }, + show() { /* empty */ }, + hide() { /* empty */ }, + dispose() { /* empty */ } + } + progress.report({ increment: 0 }) + return batchExecute(executablePath, args, options.cwd, { combined: progressChannel }, token); + }); + return result; +} + +type ExecutionHandler = () => Promise + +export interface BatchExecution { + execute: ExecutionHandler + optional?: boolean | undefined // `false` by default +} + +export async function executeAll(executions: BatchExecution[]): Promise { + const results: ExecutionResult[] = [] + for (const execution of executions) { + const result: ExecutionResult = await execution.execute() + results.push(result) + if (execution.optional !== true && result.exitCode !== ExecutionExitCode.Success) { + break + } + } + return results +} + +export async function displayError(result: ExecutionResult, message: string) { + if (result.exitCode === ExecutionExitCode.Success) { + throw Error() + } + const errorMessage: string = formatErrorMessage(result, message) + await displayErrorWithOutput(errorMessage) +} + +function formatErrorMessage(error: ExecutionResult, message: string): string { + if (error.stderr === '') { + return `${message}` + } + return `${message} Command error output: ${error.stderr}` +} diff --git a/vscode-lean4/src/utils/clientProvider.ts b/vscode-lean4/src/utils/clientProvider.ts index b3272aa55..e24f81c14 100644 --- a/vscode-lean4/src/utils/clientProvider.ts +++ b/vscode-lean4/src/utils/clientProvider.ts @@ -1,20 +1,19 @@ -import { Disposable, OutputChannel, workspace, TextDocument, commands, window, EventEmitter, Uri, languages, TextEditor } from 'vscode'; +import { Disposable, OutputChannel, workspace, TextDocument, commands, window, EventEmitter, Uri, languages, TextEditor, WorkspaceFolder } from 'vscode'; import { LeanInstaller, LeanVersion } from './leanInstaller' import { LeanpkgService } from './leanpkg'; import { LeanClient } from '../leanclient' import { LeanFileProgressProcessingInfo, ServerStoppedReason } from '@leanprover/infoview-api'; import * as path from 'path'; -import { findLeanPackageRoot } from './projectInfo'; +import { checkParentFoldersForLeanProject, findLeanPackageRoot, isValidLeanProject } from './projectInfo'; import { isFileInFolder } from './fsHelper'; import { logger } from './logger' -import { addDefaultElanPath, getDefaultElanPath, addToolchainBinPath, isElanDisabled, isRunningTest } from '../config' +import { addDefaultElanPath, getDefaultElanPath, addToolchainBinPath, isElanDisabled, isRunningTest, shouldShowInvalidProjectWarnings } from '../config' // This class ensures we have one LeanClient per workspace folder. export class LeanClientProvider implements Disposable { private subscriptions: Disposable[] = []; private outputChannel: OutputChannel; private installer : LeanInstaller; - private pkgService : LeanpkgService; private versions: Map = new Map(); private clients: Map = new Map(); private pending: Map = new Map(); @@ -34,18 +33,17 @@ export class LeanClientProvider implements Disposable { private clientStoppedEmitter = new EventEmitter<[LeanClient, boolean, ServerStoppedReason]>() clientStopped = this.clientStoppedEmitter.event - constructor(installer : LeanInstaller, pkgService : LeanpkgService, outputChannel : OutputChannel) { + constructor(installer: LeanInstaller, outputChannel: OutputChannel) { this.outputChannel = outputChannel; this.installer = installer; - this.pkgService = pkgService; // we must setup the installChanged event handler first before any didOpenEditor calls. installer.installChanged(async (uri: Uri) => await this.onInstallChanged(uri)); // Only change the document language for *visible* documents, // because this closes and then reopens the document. - window.visibleTextEditors.forEach((e) => this.didOpenEditor(e.document)); - this.subscriptions.push(window.onDidChangeVisibleTextEditors((es) => - es.forEach((e) => this.didOpenEditor(e.document)))); + window.visibleTextEditors.forEach(e => this.didOpenEditor(e.document)); + this.subscriptions.push(window.onDidChangeVisibleTextEditors(es => + es.forEach(e => this.didOpenEditor(e.document)))); this.subscriptions.push( commands.registerCommand('lean4.restartFile', () => this.restartFile()), @@ -54,7 +52,7 @@ export class LeanClientProvider implements Disposable { commands.registerCommand('lean4.stopServer', () => this.stopActiveClient()) ); - workspace.onDidOpenTextDocument((document) => this.didOpenEditor(document)); + workspace.onDidOpenTextDocument(document => this.didOpenEditor(document)); workspace.onDidChangeWorkspaceFolders((event) => { for (const folder of event.removed) { @@ -89,10 +87,10 @@ export class LeanClientProvider implements Disposable { { try { const uri = this.pendingInstallChanged.pop(); - if (uri){ + if (uri) { // have to check again here in case elan install had --default-toolchain none. const [workspaceFolder, folder, packageFileUri] = await findLeanPackageRoot(uri); - const packageUri = folder ? folder : Uri.from({scheme: 'untitled'}); + const packageUri = folder ?? Uri.from({scheme: 'untitled'}); logger.log('[ClientProvider] testLeanVersion'); const version = await this.installer.testLeanVersion(packageUri); if (version.version === '4') { @@ -115,14 +113,16 @@ export class LeanClientProvider implements Disposable { private async autoInstall() : Promise { // no prompt, just do it! - const version = this.installer.getDefaultToolchain(); - logger.log(`[ClientProvider] Installing ${version} via Elan during testing`); await this.installer.installElan(); if (isElanDisabled()) { addToolchainBinPath(getDefaultElanPath()); } else { addDefaultElanPath(); } + + for (const [_, client] of this.clients) { + await this.onInstallChanged(client.folderUri) + } } private getVisibleEditor(uri: Uri) : TextEditor | null { @@ -136,17 +136,33 @@ export class LeanClientProvider implements Disposable { } private restartFile() { - if (window.activeTextEditor && this.activeClient && window.activeTextEditor.document.languageId ==='lean4') { - void this.activeClient.restartFile(window.activeTextEditor.document); + if (!this.activeClient || !this.activeClient.isRunning()) { + void window.showErrorMessage('No active client.') + return + } + + if (!window.activeTextEditor || window.activeTextEditor.document.languageId !== 'lean4') { + void window.showErrorMessage('No active Lean editor tab. Make sure to focus the Lean editor tab for which you want to issue a restart.') + return } + + void this.activeClient.restartFile(window.activeTextEditor.document); } private stopActiveClient() { - void this.activeClient?.stop(); + if (this.activeClient && this.activeClient.isStarted()) { + void this.activeClient?.stop(); + } } - private restartActiveClient() { - void this.activeClient?.restart(); + private async restartActiveClient() { + const result: string | undefined = await window.showInformationMessage( + 'Restart Lean 4 server to re-elaborate all open files?', + { modal: true }, + 'Restart server') + if (result === 'Restart server') { + void this.activeClient?.restart(); + } } clientIsStarted() { @@ -154,8 +170,6 @@ export class LeanClientProvider implements Disposable { } async didOpenEditor(document: TextDocument) { - this.pkgService.didOpen(document.uri); - // bail as quickly as possible on non-lean files. if (document.languageId !== 'lean' && document.languageId !== 'lean4') { return; @@ -186,9 +200,13 @@ export class LeanClientProvider implements Disposable { try { const [cached, client] = await this.ensureClient(document.uri, undefined); - if (client) { - await client.openLean4Document(document) + if (!client) { + return } + + await this.checkIsValidProjectFolder(client.folderUri) + + await client.openLean4Document(document) } catch (e) { logger.log(`[ClientProvider] ### Error opening document: ${e}`); } @@ -223,7 +241,7 @@ export class LeanClientProvider implements Disposable { } getClientForFolder(folder: Uri) : LeanClient | undefined { - let client: LeanClient | undefined; + let client: LeanClient | undefined; const key = this.getKeyFromUri(folder); const cachedClient = this.clients.has(key); if (cachedClient) { @@ -275,7 +293,7 @@ export class LeanClientProvider implements Disposable { // Returns a null client if it turns out the new workspace is a lean3 workspace. async ensureClient(uri : Uri, versionInfo: LeanVersion | undefined) : Promise<[boolean,LeanClient | undefined]> { const [workspaceFolder, folder, packageFileUri] = await findLeanPackageRoot(uri); - const folderUri = folder ? folder : Uri.from({scheme: 'untitled'}); + const folderUri = folder ?? Uri.from({scheme: 'untitled'}); let client = this.getClientForFolder(folderUri); const key = this.getKeyFromUri(folder); const cachedClient = (client !== undefined); @@ -356,6 +374,37 @@ export class LeanClientProvider implements Disposable { return [cachedClient, client]; } + private async checkIsValidProjectFolder(folderUri: Uri) { + if (!shouldShowInvalidProjectWarnings()) { + return + } + + if (folderUri.scheme !== 'file') { + void window.showWarningMessage('Lean 4 server operating in restricted single file mode. Please open a valid Lean 4 project containing a \'lean-toolchain\' file for full functionality.') + return + } + + if (await isValidLeanProject(folderUri)) { + return + } + + const parentProjectFolder: Uri | undefined = await checkParentFoldersForLeanProject(folderUri) + if (parentProjectFolder === undefined) { + void window.showWarningMessage('Opened folder is not a valid Lean 4 project. Please open a valid Lean 4 project containing a \'lean-toolchain\' file for full functionality.') + return + } + + const message = `Opened folder is not a valid Lean 4 project folder because it does not contain a 'lean-toolchain' file. +However, a valid Lean 4 project folder was found in one of the parent directories at '${parentProjectFolder.fsPath}'. +Open this project instead?` + const input = 'Open parent directory project' + const choice: string | undefined = await window.showWarningMessage(message, input) + if (choice === input) { + // this kills the extension host + await commands.executeCommand('vscode.openFolder', parentProjectFolder) + } + } + dispose(): void { for (const s of this.subscriptions) { s.dispose(); } } diff --git a/vscode-lean4/src/utils/elan.ts b/vscode-lean4/src/utils/elan.ts new file mode 100644 index 000000000..d707686c1 --- /dev/null +++ b/vscode-lean4/src/utils/elan.ts @@ -0,0 +1,6 @@ +import { OutputChannel } from 'vscode'; +import { ExecutionResult, batchExecuteWithProgress } from './batch'; + +export async function elanSelfUpdate(channel: OutputChannel): Promise { + return await batchExecuteWithProgress('elan', ['self', 'update'], 'Updating Elan', { channel }) +} diff --git a/vscode-lean4/src/utils/errors.ts b/vscode-lean4/src/utils/errors.ts new file mode 100644 index 000000000..5910c4619 --- /dev/null +++ b/vscode-lean4/src/utils/errors.ts @@ -0,0 +1,9 @@ +import { commands, window } from 'vscode'; + +export async function displayErrorWithOutput(message: string) { + const input = 'Show Output' + const choice = await window.showErrorMessage(message, input) + if (choice === input) { + await commands.executeCommand('lean4.troubleshooting.showOutput') + } +} diff --git a/vscode-lean4/src/utils/lake.ts b/vscode-lean4/src/utils/lake.ts new file mode 100644 index 000000000..bc7b91c53 --- /dev/null +++ b/vscode-lean4/src/utils/lake.ts @@ -0,0 +1,90 @@ +import { OutputChannel, Uri } from 'vscode'; +import { ExecutionExitCode, ExecutionResult, batchExecute, batchExecuteWithProgress } from './batch'; + +export const cacheNotFoundError = 'unknown executable `cache`' +export const cacheNotFoundExitError = '=> Operation failed. Exit Code: 1.' + +export class LakeRunner { + channel: OutputChannel + cwdUri: Uri | undefined + toolchain: string | undefined + + constructor(channel: OutputChannel, cwdUri: Uri | undefined, toolchain?: string | undefined) { + this.channel = channel + this.cwdUri = cwdUri + this.toolchain = toolchain + } + + async initProject(name: string, kind?: string | undefined): Promise { + const args = kind ? [name, kind] : [name] + return this.runLakeCommandWithProgress('init', args, 'Initializing project') + } + + async updateDependencies(): Promise { + return this.runLakeCommandWithProgress('update', [], 'Updating dependencies') + } + + async updateDependency(dependencyName: string): Promise { + return this.runLakeCommandWithProgress('update', [dependencyName], `Updating '${dependencyName}' dependency`) + } + + async build(): Promise { + return this.runLakeCommandWithProgress('build', [], 'Building Lean project') + } + + async clean(): Promise { + return this.runLakeCommandWithProgress('clean', [], 'Cleaning Lean project') + } + + async fetchMathlibCache(filterError: boolean = false): Promise { + const prompt = 'Checking Mathlib build artifact cache' + return this.runLakeCommandWithProgress('exe', ['cache', 'get'], prompt, line => { + if (filterError && line.includes(cacheNotFoundError)) { + return undefined + } + return line + }) + } + + async isMathlibCacheGetAvailable(): Promise<'Yes' | 'No' | 'Cancelled'> { + const result: ExecutionResult = await this.runLakeCommandWithProgress('exe', ['cache'], 'Checking whether this is a Mathlib project') + if (result.exitCode === ExecutionExitCode.Cancelled) { + return 'Cancelled' + } + if (result.exitCode === ExecutionExitCode.Success) { + return 'Yes' + } + return 'No' + } + + private async runLakeCommandSilently(subCommand: string, args: string[]): Promise { + args = args.slice() + args.unshift(subCommand) + if (this.toolchain) { + args.unshift(`+${this.toolchain}`) + } + return await batchExecute('lake', args, this.cwdUri?.fsPath) + } + + private async runLakeCommandWithProgress( + subCommand: string, + args: string[], + waitingPrompt: string, + translator?: ((line: string) => string | undefined) | undefined): Promise { + args = args.slice() + args.unshift(subCommand) + if (this.toolchain) { + args.unshift(`+${this.toolchain}`) + } + return await batchExecuteWithProgress('lake', args, waitingPrompt, { + cwd: this.cwdUri?.fsPath, + channel: this.channel, + translator, + allowCancellation: true + }) + } +} + +export function lake(channel: OutputChannel, cwdUri: Uri | undefined, toolchain?: string | undefined): LakeRunner { + return new LakeRunner(channel, cwdUri, toolchain) +} diff --git a/vscode-lean4/src/utils/leanInstaller.ts b/vscode-lean4/src/utils/leanInstaller.ts index e851832d8..b052105ae 100644 --- a/vscode-lean4/src/utils/leanInstaller.ts +++ b/vscode-lean4/src/utils/leanInstaller.ts @@ -1,6 +1,6 @@ import { window, TerminalOptions, OutputChannel, Disposable, EventEmitter, ProgressLocation, Uri } from 'vscode' import { toolchainPath, addServerEnvPaths, getPowerShellPath, shouldAutofocusOutput, isRunningTest } from '../config' -import { batchExecute } from './batch' +import { ExecutionExitCode, ExecutionResult, batchExecute, batchExecuteWithProgress } from './batch' import { readLeanVersion, isCoreLean4Directory } from './projectInfo'; import { join } from 'path'; import { logger } from './logger' @@ -10,12 +10,11 @@ export class LeanVersion { error: string | undefined; } -export class LeanInstaller implements Disposable { +export class LeanInstaller { private leanInstallerLinux = 'https://raw.githubusercontent.com/leanprover/elan/master/elan-init.sh' private leanInstallerWindows = 'https://raw.githubusercontent.com/leanprover/elan/master/elan-init.ps1' private outputChannel: OutputChannel; - private subscriptions: Disposable[] = []; private prompting : boolean = false; private defaultToolchain : string; // the default to use if there is no elan installed private elanDefaultToolchain : string = ''; // the default toolchain according to elan (toolchain marked with '(default)') @@ -44,6 +43,10 @@ export class LeanInstaller implements Disposable { return this.promptUser; } + getOutputChannel(): OutputChannel { + return this.outputChannel + } + async testLeanVersion(packageUri: Uri) : Promise { // see if there is a lean-toolchain file and use that version info. @@ -82,23 +85,25 @@ export class LeanInstaller implements Disposable { } async handleVersionChanged(packageUri : Uri) : Promise { - if (packageUri && packageUri.scheme === 'file'){ + if (packageUri && packageUri.scheme === 'file') { const key = packageUri.fsPath; if (this.versionCache.has(key)) { this.versionCache.delete(key); } } - if (this.promptUser){ - if (this.prompting) { - return; - } - const restartItem = 'Restart Lean'; - const item = await this.showPrompt('Lean version changed', restartItem); - if (item === restartItem) { - await this.checkAndFire(packageUri); - } - } else { + if (!this.promptUser) { + await this.checkAndFire(packageUri); + return + } + + if (this.prompting) { + return; + } + + const restartItem = 'Restart Lean'; + const item = await this.showPrompt('Lean version changed', restartItem); + if (item === restartItem) { await this.checkAndFire(packageUri); } } @@ -123,16 +128,18 @@ export class LeanInstaller implements Disposable { } async handleLakeFileChanged(uri: Uri) : Promise { - if (this.promptUser){ - if (this.prompting) { - return; - } - const restartItem = 'Restart Lean'; - const item = await this.showPrompt('Lake file configuration changed', restartItem); - if (item === restartItem) { - this.installChangedEmitter.fire(uri); - } - } else { + if (!this.promptUser) { + this.installChangedEmitter.fire(uri); + return + } + + if (this.prompting) { + return; + } + + const restartItem = 'Restart Lean'; + const item = await this.showPrompt('Lake file configuration changed', restartItem); + if (item === restartItem) { this.installChangedEmitter.fire(uri); } } @@ -159,7 +166,7 @@ export class LeanInstaller implements Disposable { const item = await this.showPrompt(prompt, installItem) if (item === installItem) { try { - const result = await this.installElan(); + await this.installElan(); this.installChangedEmitter.fire(uri); } catch (err) { const msg = '' + err; @@ -206,7 +213,7 @@ export class LeanInstaller implements Disposable { } } - const env = addServerEnvPaths(process.env); + addServerEnvPaths(process.env); let options = ['--version'] if (version) { @@ -221,18 +228,16 @@ export class LeanInstaller implements Disposable { // looks for a global (default) installation of Lean. This way, we can support // single file editing. logger.log(`executeWithProgress ${cmd} ${options}`) - const stdout = await this.executeWithProgress('Checking Lean setup...', cmd, options, folderPath) - if (!stdout) { + const checkingResult: ExecutionResult = await batchExecute(cmd, options, folderPath, { combined: this.outputChannel }) + if (checkingResult.exitCode === ExecutionExitCode.CannotLaunch) { result.error = 'lean not found' - } - else if (stdout.indexOf('no default toolchain') > 0) { + } else if (checkingResult.stderr.indexOf('no default toolchain') > 0) { result.error = 'no default toolchain' - } - else { + } else { const filterVersion = /version (\d+)\.\d+\..+/ - const match = filterVersion.exec(stdout) + const match = filterVersion.exec(checkingResult.stdout) if (!match) { - return { version: '', error: `lean4: '${cmd} ${options}' returned incorrect version string '${stdout}'.` } + return { version: '', error: `lean4: '${cmd} ${options}' returned incorrect version string '${checkingResult.stdout}'.` } } const major = match[1]; result.version = major @@ -247,47 +252,6 @@ export class LeanInstaller implements Disposable { return result } - private async executeWithProgress(prompt: string, cmd: string, options: string[], workingDirectory: string | null): Promise{ - let inc = 0; - let stdout = '' - /* eslint-disable @typescript-eslint/no-this-alias */ - const realThis = this; - await window.withProgress({ - location: ProgressLocation.Notification, - title: '', - cancellable: false - }, (progress) => { - const progressChannel : OutputChannel = { - name : 'ProgressChannel', - append(value: string) - { - stdout += value; - if (realThis.outputChannel){ - // add the output here in case user wants to go look for it. - const msg = value.trim(); - logger.log(`[LeanInstaller] ${cmd} returned: ${msg}`); - realThis.outputChannel.appendLine(msg); - } - if (inc < 100) { - inc += 10; - } - progress.report({ increment: inc, message: value }); - }, - appendLine(value: string) { - this.append(value + '\n'); - }, - replace(value: string) { /* empty */ }, - clear() { /* empty */ }, - show() { /* empty */ }, - hide() { /* empty */ }, - dispose() { /* empty */ } - } - progress.report({increment:0, message: prompt}); - return batchExecute(cmd, options, workingDirectory, progressChannel); - }); - return stdout; - } - getDefaultToolchain() : string { return this.defaultToolchain; } @@ -319,7 +283,7 @@ export class LeanInstaller implements Disposable { try { const cmd = 'elan'; const options = ['toolchain', 'list']; - const stdout = await batchExecute(cmd, options, folderPath, undefined); + const stdout = (await batchExecute(cmd, options, folderPath)).stdout if (!stdout){ throw new Error('elan toolchain list returned no output.'); } @@ -337,77 +301,66 @@ export class LeanInstaller implements Disposable { } async hasElan() : Promise { - let elanInstalled = false; - // See if we have elan already. try { const options = ['--version'] - const stdout = await this.executeWithProgress('Checking Elan setup...', 'elan', options, null) + const result = await batchExecute('elan', options) const filterVersion = /elan (\d+)\.\d+\..+/ - const match = filterVersion.exec(stdout) - if (match) { - elanInstalled = true; - } + const match = filterVersion.exec(result.stdout) + return match !== null } catch (err) { - elanInstalled = false; + return false } - return elanInstalled; } async installElan() : Promise { - if (toolchainPath()) { void window.showErrorMessage('It looks like you\'ve modified the `lean.toolchainPath` user setting.' + 'Please clear this setting before installing elan.'); return false; - } else { - const terminalName = 'Lean installation via elan'; - - let terminalOptions: TerminalOptions = { name: terminalName }; - if (process.platform === 'win32') { - terminalOptions = { name: terminalName, shellPath: getPowerShellPath() }; - } - const terminal = window.createTerminal(terminalOptions); - terminal.show(); - - // We register a listener, to restart the Lean extension once elan has finished. - const result = new Promise(function(resolve, reject) { - window.onDidCloseTerminal(async (t) => { - if (t === terminal) { - resolve(true); - } else { - logger.log('[LeanInstaller] ignoring terminal closed: ' + t.name + ', waiting for: ' + terminalName); - }}); - }); + } - if (process.platform === 'win32') { - terminal.sendText( - `Start-BitsTransfer -Source "${this.leanInstallerWindows}" -Destination "elan-init.ps1"\r\n` + - 'Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope Process\r\n' + - `$rc = .\\elan-init.ps1 -NoPrompt 1 -DefaultToolchain ${this.defaultToolchain}\r\n` + - 'Write-Host "elan-init returned [$rc]"\r\n' + - 'del .\\elan-init.ps1\r\n' + - 'if ($rc -ne 0) {\r\n' + - ' Read-Host -Prompt "Press ENTER to continue"\r\n' + - '}\r\n' + - 'exit\r\n' - ); - } - else { - const elanArgs = `-y --default-toolchain ${this.defaultToolchain}`; - const prompt = '(echo && read -n 1 -s -r -p "Install failed, press ENTER to continue...")'; + const terminalName = 'Lean installation via elan'; - terminal.sendText(`bash -c 'curl ${this.leanInstallerLinux} -sSf | sh -s -- ${elanArgs} || ${prompt}' && exit `); - } + let terminalOptions: TerminalOptions = { name: terminalName }; + if (process.platform === 'win32') { + terminalOptions = { name: terminalName, shellPath: getPowerShellPath() }; + } + const terminal = window.createTerminal(terminalOptions); + terminal.show(); + + // We register a listener, to restart the Lean extension once elan has finished. + const result = new Promise(function(resolve, reject) { + window.onDidCloseTerminal(async (t) => { + if (t === terminal) { + resolve(true); + } else { + logger.log('[LeanInstaller] ignoring terminal closed: ' + t.name + ', waiting for: ' + terminalName); + }}); + }); - // clear any previous lean version errors. - this.versionCache.clear(); - this.elanDefaultToolchain = this.defaultToolchain; + if (process.platform === 'win32') { + terminal.sendText( + `Start-BitsTransfer -Source "${this.leanInstallerWindows}" -Destination "elan-init.ps1"\r\n` + + 'Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope Process\r\n' + + `$rc = .\\elan-init.ps1 -NoPrompt 1 -DefaultToolchain ${this.defaultToolchain}\r\n` + + 'Write-Host "elan-init returned [$rc]"\r\n' + + 'del .\\elan-init.ps1\r\n' + + 'if ($rc -ne 0) {\r\n' + + ' Read-Host -Prompt "Press ENTER to continue"\r\n' + + '}\r\n' + + 'exit\r\n' + ); + } else { + const elanArgs = `-y --default-toolchain ${this.defaultToolchain}`; + const prompt = '(echo && read -n 1 -s -r -p "Install failed, press ENTER to continue...")'; - return result; + terminal.sendText(`bash -c 'curl ${this.leanInstallerLinux} -sSf | sh -s -- ${elanArgs} || ${prompt}' && exit `); } - } - dispose(): void { - for (const s of this.subscriptions) { s.dispose(); } + // clear any previous lean version errors. + this.versionCache.clear(); + this.elanDefaultToolchain = this.defaultToolchain; + + return result; } } diff --git a/vscode-lean4/src/utils/leanpkg.ts b/vscode-lean4/src/utils/leanpkg.ts index 3f4020654..91c10ee1c 100644 --- a/vscode-lean4/src/utils/leanpkg.ts +++ b/vscode-lean4/src/utils/leanpkg.ts @@ -24,7 +24,6 @@ export class LeanpkgService implements Disposable { lakeFileChanged = this.lakeFileChangedEmitter.event constructor() { - // track changes in the version of lean specified in the lean-toolchain file // or the leanpkg.toml. While this is looking for all files with these names // it ignores files that are not in the package root. @@ -41,6 +40,11 @@ export class LeanpkgService implements Disposable { watcher2.onDidDelete((u) => this.handleLakeFileChanged(u, true)); this.subscriptions.push(watcher); }); + + window.visibleTextEditors.forEach(e => this.didOpen(e.document.uri)); + this.subscriptions.push(window.onDidChangeVisibleTextEditors(es => + es.forEach(e => this.didOpen(e.document.uri)))); + workspace.onDidOpenTextDocument(document => this.didOpen(document.uri)); } dispose(): void { @@ -49,7 +53,7 @@ export class LeanpkgService implements Disposable { // Must be called when every file is opened so it can track the current contents // of the files we care about. - didOpen(uri: Uri){ + private didOpen(uri: Uri){ const fileName = path.basename(uri.fsPath); if (fileName === this.lakeFileName){ void this.handleLakeFileChanged(uri, false); @@ -66,51 +70,61 @@ export class LeanpkgService implements Disposable { // Note: just opening the file fires this event sometimes which is annoying, so // we compare the contents just to be sure and normalize whitespace so that // just adding a new line doesn't trigger the prompt. - const [workspaceFolder, packageUri, packageFileUri] = await findLeanPackageRoot(uri); - if (packageUri) { - const fileUri = await this.findLakeFile(packageUri); - if (fileUri) { - const contents = await this.readWhitespaceNormalized(fileUri); - let existing : string | undefined; - const key = packageUri.toString(); - if (this.normalizedLakeFileContents.get(key)){ - existing = this.normalizedLakeFileContents.get(key); - } - if (contents !== existing) { - this.normalizedLakeFileContents.set(key, contents); - if (raiseEvent) { - // raise an event so the extension triggers handleLakeFileChanged. - this.lakeFileChangedEmitter.fire(packageUri); - } - } - } + const [_1, packageUri, _2] = await findLeanPackageRoot(uri) + if (!packageUri) { + return + } + + const fileUri = await this.findLakeFile(packageUri) + if (!fileUri) { + return + } + + const contents = await this.readWhitespaceNormalized(fileUri) + let existing : string | undefined + const key = packageUri.toString() + if (this.normalizedLakeFileContents.get(key)) { + existing = this.normalizedLakeFileContents.get(key) + } + if (contents === existing) { + return + } + + this.normalizedLakeFileContents.set(key, contents) + if (raiseEvent) { + // raise an event so the extension triggers handleLakeFileChanged. + this.lakeFileChangedEmitter.fire(packageUri) } } private async handleFileChanged(uri: Uri, raiseEvent : boolean) { // note: apply the same rules here with findLeanPkgVersionInfo no matter // if a file is added or removed so we always match the elan behavior. - const [packageUri, version] = await findLeanPackageVersionInfo(uri); - if (packageUri && version) { - let existing : string | undefined; - const key = packageUri.toString(); - if (this.currentVersion.has(key)){ - existing = this.currentVersion.get(key); - } - if (existing !== version){ - this.currentVersion.set(key, version); - if (raiseEvent) { - // raise an event so the extension triggers handleVersionChanged. - this.versionChangedEmitter.fire(packageUri); - } - } + const [packageUri, version] = await findLeanPackageVersionInfo(uri) + if (!packageUri || !version) { + return + } + + let existing: string | undefined + const key = packageUri.toString() + if (this.currentVersion.has(key)){ + existing = this.currentVersion.get(key) + } + if (existing === version) { + return + } + + this.currentVersion.set(key, version) + if (raiseEvent) { + // raise an event so the extension triggers handleVersionChanged. + this.versionChangedEmitter.fire(packageUri) } } private async findLakeFile(packageUri: Uri) : Promise { const fullPath = Uri.joinPath(packageUri, this.lakeFileName); const url = fullPath.fsPath; - if(await fileExists(url)) { + if (await fileExists(url)) { return fullPath; } return null; diff --git a/vscode-lean4/src/utils/manifest.ts b/vscode-lean4/src/utils/manifest.ts new file mode 100644 index 000000000..81fb1af46 --- /dev/null +++ b/vscode-lean4/src/utils/manifest.ts @@ -0,0 +1,89 @@ +import { join } from 'path' +import { Uri } from 'vscode' +import { z } from 'zod' +import * as fs from 'fs' + +export interface DirectGitDependency { + name: string + uri: Uri + revision: string + inputRevision: string +} + +export interface Manifest { + directGitDependencies: DirectGitDependency[] +} + +export function parseAsManifest(jsonString: string): Manifest | undefined { + let parsedJson: any + try { + parsedJson = JSON.parse(jsonString) + } catch (e) { + return undefined + } + + const schema = z.object({ + packages: z.array( + z.union([ + z.object({ + git: z.object({ + name: z.string(), + url: z.string().url(), + rev: z.string(), + inherited: z.boolean(), + 'inputRev?': z.optional(z.nullable(z.string())) + }) + }), + z.object({ + path: z.any() + }) + ]) + ) + }) + const result = schema.safeParse(parsedJson) + if (!result.success) { + return undefined + } + + const manifest: Manifest = { directGitDependencies: [] } + + for (const pkg of result.data.packages) { + if (!('git' in pkg)) { + continue + } + if (pkg.git.inherited) { + continue // Inherited Git packages are not direct dependencies + } + + const inputRev: string | null | undefined = pkg.git['inputRev?'] + + manifest.directGitDependencies.push({ + name: pkg.git.name, + uri: Uri.parse(pkg.git.url), + revision: pkg.git.rev, + inputRevision: inputRev ? inputRev : 'master' // Lake also always falls back to master + }) + } + + return manifest +} + +export type ManifestReadError = string + +export async function parseManifestInFolder(folderUri: Uri): Promise { + const manifestPath: string = join(folderUri.fsPath, 'lake-manifest.json') + + let jsonString: string + try { + jsonString = fs.readFileSync(manifestPath, 'utf8') + } catch (e) { + return `Cannot read 'lake-manifest.json' file at ${manifestPath} to determine dependencies.` + } + + const manifest: Manifest | undefined = parseAsManifest(jsonString) + if (!manifest) { + return `Cannot parse 'lake-manifest.json' file at ${manifestPath} to determine dependencies.` + } + + return manifest +} diff --git a/vscode-lean4/src/utils/projectInfo.ts b/vscode-lean4/src/utils/projectInfo.ts index c8102ef7d..91ae23b74 100644 --- a/vscode-lean4/src/utils/projectInfo.ts +++ b/vscode-lean4/src/utils/projectInfo.ts @@ -1,29 +1,33 @@ import * as fs from 'fs'; import { URL } from 'url'; -import { Uri, workspace, WorkspaceFolder } from 'vscode'; +import { FileType, Uri, workspace, WorkspaceFolder } from 'vscode'; import { fileExists } from './fsHelper'; import { logger } from './logger' +import path = require('path'); // Detect lean4 root directory (works for both lean4 repo and nightly distribution) export async function isCoreLean4Directory(path: Uri): Promise { - if (path.scheme === 'file'){ - return await fileExists(Uri.joinPath(path, 'LICENSE').fsPath) && await fileExists(Uri.joinPath(path, 'LICENSES').fsPath); + if (path.scheme !== 'file') { + return false } - return false; + + const licensePath = Uri.joinPath(path, 'LICENSE').fsPath + const licensesPath = Uri.joinPath(path, 'LICENSES').fsPath + const srcPath = Uri.joinPath(path, 'src').fsPath + return await fileExists(licensePath) + && await fileExists(licensesPath) + && await fileExists(srcPath) } // Find the root of a Lean project and return an optional WorkspaceFolder for it, // the Uri for the package root and the Uri for the 'leanpkg.toml' or 'lean-toolchain' file found there. export async function findLeanPackageRoot(uri: Uri) : Promise<[WorkspaceFolder | undefined, Uri | null, Uri | null]> { - if (!uri) return [undefined, null, null]; + if (!uri || uri.scheme !== 'file') return [undefined, null, null]; const toolchainFileName = 'lean-toolchain'; const tomlFileName = 'leanpkg.toml'; - if (uri.scheme === 'untitled'){ - // then return a Uri representing all untitled files. - return [undefined, Uri.from({scheme: 'untitled'}), null]; - } + let path = uri; let wsFolder = workspace.getWorkspaceFolder(uri); if (!wsFolder && workspace.workspaceFolders) { @@ -37,7 +41,7 @@ export async function findLeanPackageRoot(uri: Uri) : Promise<[WorkspaceFolder | if (wsFolder){ // jump to the real workspace folder if we have a Workspace for this file. path = wsFolder.uri; - } else if (path.scheme === 'file') { + } else { // then start searching from the directory containing this document. // The given uri may already be a folder Uri in some cases. if (fs.lstatSync(path.fsPath).isFile()) { @@ -47,34 +51,28 @@ export async function findLeanPackageRoot(uri: Uri) : Promise<[WorkspaceFolder | } const startFolder = path; - if (path.scheme === 'file') { - // search parent folders for a leanpkg.toml file, or a Lake lean-toolchain file. - while (true) { - // give preference to 'lean-toolchain' files if any. - const leanToolchain = Uri.joinPath(path, toolchainFileName); - if (await fileExists(leanToolchain.fsPath)) { - return [wsFolder, path, leanToolchain]; - } - else { - const leanPkg = Uri.joinPath(path, tomlFileName); - if (await fileExists(leanPkg.fsPath)) { - return [wsFolder, path, leanPkg]; - } - else if (await isCoreLean4Directory(path)) { - return [wsFolder, path, null]; - } - else if (searchUpwards) { - const parent = Uri.joinPath(path, '..'); - if (parent === path) { - // no project file found. - break; - } - path = parent; - } - else { - // don't search above a WorkspaceFolder barrier. + // search parent folders for a leanpkg.toml file, or a Lake lean-toolchain file. + while (true) { + // give preference to 'lean-toolchain' files if any. + const leanToolchain = Uri.joinPath(path, toolchainFileName); + if (await fileExists(leanToolchain.fsPath)) { + return [wsFolder, path, leanToolchain]; + } else { + const leanPkg = Uri.joinPath(path, tomlFileName); + if (await fileExists(leanPkg.fsPath)) { + return [wsFolder, path, leanPkg]; + } else if (await isCoreLean4Directory(path)) { + return [wsFolder, path, null]; + } else if (searchUpwards) { + const parent = Uri.joinPath(path, '..'); + if (parent === path) { + // no project file found. break; } + path = parent; + } else { + // don't search above a WorkspaceFolder barrier. + break; } } } @@ -88,7 +86,7 @@ export async function findLeanPackageRoot(uri: Uri) : Promise<[WorkspaceFolder | export async function findLeanPackageVersionInfo(uri: Uri) : Promise<[Uri | null, string | null]> { const [_, packageUri, packageFileUri] = await findLeanPackageRoot(uri); - if (!packageUri || packageUri.scheme === 'untitled') return [null, null]; + if (!packageUri) return [null, null]; let version : string | null = null; if (packageFileUri) { @@ -144,3 +142,27 @@ async function readLeanVersionFile(packageFileUri : Uri) : Promise { return ''; } + +export async function isValidLeanProject(projectFolder: Uri): Promise { + try { + const leanToolchainPath = Uri.joinPath(projectFolder, 'lean-toolchain').fsPath + + const isLeanProject: boolean = await fileExists(leanToolchainPath) + const isLeanItself: boolean = await isCoreLean4Directory(projectFolder) + return isLeanProject || isLeanItself + } catch { + return false + } +} + +export async function checkParentFoldersForLeanProject(folder: Uri): Promise { + let childFolder: Uri + do { + childFolder = folder + folder = Uri.file(path.dirname(folder.fsPath)) + if (await isValidLeanProject(folder)) { + return folder + } + } while (childFolder.fsPath !== folder.fsPath) + return undefined +} From bdbb2224af139585392637336229bacb885a7ffd Mon Sep 17 00:00:00 2001 From: mhuisi Date: Wed, 18 Oct 2023 13:46:55 +0200 Subject: [PATCH 10/70] Release 0.0.114 (pre-release) --- vscode-lean4/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index 411f62449..adfb93333 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -2,7 +2,7 @@ "name": "lean4", "displayName": "lean4", "description": "Lean 4 language support for VS Code", - "version": "0.0.113", + "version": "0.0.114", "publisher": "leanprover", "engines": { "vscode": "^1.75.0" From 8f65c1c527f4717b0f03b03ccb2267b4d8ae356f Mon Sep 17 00:00:00 2001 From: mhuisi Date: Wed, 18 Oct 2023 14:06:36 +0200 Subject: [PATCH 11/70] fix: use correct version of vsce, not outdated one --- .github/workflows/on-push.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/on-push.yml b/.github/workflows/on-push.yml index 975998d5f..3c4854730 100644 --- a/.github/workflows/on-push.yml +++ b/.github/workflows/on-push.yml @@ -63,7 +63,7 @@ jobs: if: ${{ startsWith(github.ref, 'refs/tags/v') && !endsWith(github.ref, '-pre') && matrix.os == 'ubuntu-latest' }} run: | cd vscode-lean4 - npx vsce publish -i lean4-*.vsix + npx @vscode/vsce publish -i lean4-*.vsix npx ovsx publish lean4-*.vsix env: OVSX_PAT: ${{ secrets.OVSX_PAT }} @@ -73,7 +73,7 @@ jobs: if: ${{ startsWith(github.ref, 'refs/tags/v') && endsWith(github.ref, '-pre') && matrix.os == 'ubuntu-latest' }} run: | cd vscode-lean4 - npx vsce publish --pre-release -i lean4-*.vsix + npx @vscode/vsce publish --pre-release -i lean4-*.vsix npx ovsx publish --pre-release lean4-*.vsix env: OVSX_PAT: ${{ secrets.OVSX_PAT }} From 71e67ad9cc07375ad34e6f6e42a850aff8d36ec1 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Wed, 18 Oct 2023 14:08:09 +0200 Subject: [PATCH 12/70] Release 0.0.115 (pre-release) --- vscode-lean4/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index adfb93333..4d82250df 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -2,7 +2,7 @@ "name": "lean4", "displayName": "lean4", "description": "Lean 4 language support for VS Code", - "version": "0.0.114", + "version": "0.0.115", "publisher": "leanprover", "engines": { "vscode": "^1.75.0" From 9d6c97bbcf73e02203e89674f1fd57a33b2fd6a6 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Wed, 18 Oct 2023 14:46:22 +0200 Subject: [PATCH 13/70] chore: update packaging tooling versions --- vscode-lean4/package-lock.json | 542 ++++++++++++--------------------- vscode-lean4/package.json | 4 +- 2 files changed, 203 insertions(+), 343 deletions(-) diff --git a/vscode-lean4/package-lock.json b/vscode-lean4/package-lock.json index 66132b397..1ae58c497 100644 --- a/vscode-lean4/package-lock.json +++ b/vscode-lean4/package-lock.json @@ -1,12 +1,12 @@ { "name": "lean4", - "version": "0.0.113", + "version": "0.0.115", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "lean4", - "version": "0.0.113", + "version": "0.0.115", "license": "Apache-2.0", "dependencies": { "axios": "~0.24.0", @@ -26,15 +26,15 @@ "@types/vscode": "^1.61.0", "@types/vscode-webview": "^1.57.0", "@vscode/test-electron": "^2.1.2", + "@vscode/vsce": "~2.21.1", "concurrently": "^7.0.0", "copy-webpack-plugin": "^10.2.4", "glob": "^7.1.6", "mocha": "^8.2.1", - "ovsx": "~0.2.1", + "ovsx": "~0.8.3", "source-map-loader": "^3.0.1", "ts-loader": "^9.2.6", "typescript": "^4.9.4", - "vsce": "~2.6.2", "webpack-cli": "^4.10.0" }, "engines": { @@ -302,6 +302,142 @@ "node": ">=10" } }, + "node_modules/@vscode/vsce": { + "version": "2.21.1", + "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-2.21.1.tgz", + "integrity": "sha512-f45/aT+HTubfCU2oC7IaWnH9NjOWp668ML002QiFObFRVUCoLtcwepp9mmql/ArFUy+HCHp54Xrq4koTcOD6TA==", + "dev": true, + "dependencies": { + "azure-devops-node-api": "^11.0.1", + "chalk": "^2.4.2", + "cheerio": "^1.0.0-rc.9", + "commander": "^6.2.1", + "glob": "^7.0.6", + "hosted-git-info": "^4.0.2", + "jsonc-parser": "^3.2.0", + "leven": "^3.1.0", + "markdown-it": "^12.3.2", + "mime": "^1.3.4", + "minimatch": "^3.0.3", + "parse-semver": "^1.1.1", + "read": "^1.0.7", + "semver": "^7.5.2", + "tmp": "^0.2.1", + "typed-rest-client": "^1.8.4", + "url-join": "^4.0.1", + "xml2js": "^0.5.0", + "yauzl": "^2.3.1", + "yazl": "^2.2.2" + }, + "bin": { + "vsce": "vsce" + }, + "engines": { + "node": ">= 14" + }, + "optionalDependencies": { + "keytar": "^7.7.0" + } + }, + "node_modules/@vscode/vsce/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@vscode/vsce/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@vscode/vsce/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@vscode/vsce/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@vscode/vsce/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@vscode/vsce/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@vscode/vsce/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@vscode/vsce/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@vscode/vsce/node_modules/xml2js": { + "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", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", @@ -704,7 +840,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "optional": true }, "node_modules/binary-extensions": { "version": "2.2.0", @@ -720,6 +857,7 @@ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, + "optional": true, "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -731,6 +869,7 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, + "optional": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -824,6 +963,7 @@ "url": "https://feross.org/support" } ], + "optional": true, "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -992,7 +1132,8 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true + "dev": true, + "optional": true }, "node_modules/chrome-trace-event": { "version": "1.0.3", @@ -1267,6 +1408,7 @@ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "dev": true, + "optional": true, "dependencies": { "mimic-response": "^3.1.0" }, @@ -1282,21 +1424,17 @@ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true, + "optional": true, "engines": { "node": ">=4.0.0" } }, - "node_modules/denodeify": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz", - "integrity": "sha512-KNTihKNmQENUZeKu5fzfpzRqR5S2VMp4gl9RFHiWzj9DfvYQPMJ6XHKNaQxaGCXwPk6y9yme3aUoaiAe+KX+vg==", - "dev": true - }, "node_modules/detect-libc": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", "dev": true, + "optional": true, "engines": { "node": ">=8" } @@ -1391,6 +1529,7 @@ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, + "optional": true, "dependencies": { "once": "^1.4.0" } @@ -1521,6 +1660,7 @@ "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", "dev": true, + "optional": true, "engines": { "node": ">=6" } @@ -1653,7 +1793,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true + "dev": true, + "optional": true }, "node_modules/fs.realpath": { "version": "1.0.0", @@ -1709,7 +1850,8 @@ "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "dev": true + "dev": true, + "optional": true }, "node_modules/glob": { "version": "7.2.3", @@ -1926,7 +2068,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "optional": true }, "node_modules/ignore": { "version": "5.2.4", @@ -1982,7 +2125,8 @@ "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true + "dev": true, + "optional": true }, "node_modules/interpret": { "version": "2.2.0", @@ -2150,6 +2294,12 @@ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, "node_modules/jszip": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", @@ -2168,6 +2318,7 @@ "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==", "dev": true, "hasInstallScript": true, + "optional": true, "dependencies": { "node-addon-api": "^4.3.0", "prebuild-install": "^7.0.1" @@ -2363,6 +2514,7 @@ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", "dev": true, + "optional": true, "engines": { "node": ">=10" }, @@ -2386,6 +2538,7 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, + "optional": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -2394,7 +2547,8 @@ "version": "0.5.3", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true + "dev": true, + "optional": true }, "node_modules/mobx": { "version": "5.15.7", @@ -2620,7 +2774,8 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "dev": true + "dev": true, + "optional": true }, "node_modules/neo-async": { "version": "2.6.2", @@ -2634,6 +2789,7 @@ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.45.0.tgz", "integrity": "sha512-iwXuFrMAcFVi/ZoZiqq8BzAdsLw9kxDfTC0HMyjXfSL/6CSDAGD5UmR7azrAgWV1zKYq7dUUMj4owusBWKLsiQ==", "dev": true, + "optional": true, "dependencies": { "semver": "^7.3.5" }, @@ -2645,7 +2801,8 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", - "dev": true + "dev": true, + "optional": true }, "node_modules/node-releases": { "version": "2.0.13", @@ -2692,213 +2849,40 @@ "wrappy": "1" } }, - "node_modules/os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "dev": true, - "dependencies": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, "node_modules/ovsx": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.2.1.tgz", - "integrity": "sha512-STCpZrGq5YW4TiR+IFRqnTeKm6SBAYewHbgD75NYh9Zzy0/G72Y3zScvLiCRMGkhu+4HfP41X8sB83RUBmO0XA==", + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.8.3.tgz", + "integrity": "sha512-LG7wTzy4eYV/KolFeO4AwWPzQSARvCONzd5oHQlNvYOlji2r/zjbdK8pyObZN84uZlk6rQBWrJrAdJfh/SX0Hg==", "dev": true, "dependencies": { + "@vscode/vsce": "^2.19.0", "commander": "^6.1.0", - "follow-redirects": "^1.13.2", + "follow-redirects": "^1.14.6", "is-ci": "^2.0.0", "leven": "^3.1.0", - "tmp": "^0.2.1", - "vsce": "~1.97.0" + "semver": "^7.5.2", + "tmp": "^0.2.1" }, "bin": { "ovsx": "lib/ovsx" }, "engines": { - "node": ">= 10" - } - }, - "node_modules/ovsx/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/ovsx/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/ovsx/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/ovsx/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/ovsx/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/ovsx/node_modules/entities": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", - "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", - "dev": true - }, - "node_modules/ovsx/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/ovsx/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/ovsx/node_modules/linkify-it": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", - "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", - "dev": true, - "dependencies": { - "uc.micro": "^1.0.1" - } - }, - "node_modules/ovsx/node_modules/markdown-it": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", - "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "entities": "~2.0.0", - "linkify-it": "^2.0.0", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - }, - "bin": { - "markdown-it": "bin/markdown-it.js" + "node": ">= 14" } }, "node_modules/ovsx/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/ovsx/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/ovsx/node_modules/url-join": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-1.1.0.tgz", - "integrity": "sha512-zz1wZk4Lb5PTVwZ3HWDmm8XnlPvmOof6/fjdDPA5yBrUcbtV64U6bV832Zf1BtU2WkBBWaUT46wCs+l0HP5nhg==", - "dev": true - }, - "node_modules/ovsx/node_modules/vsce": { - "version": "1.97.0", - "resolved": "https://registry.npmjs.org/vsce/-/vsce-1.97.0.tgz", - "integrity": "sha512-5Rxj6qO0dN4FnzVS9G94osstx8R3r1OQP39G7WYERpoO9X+OSodVVkRhFDapPNjekfUNo+d5Qn7W1EtNQVoLCg==", - "deprecated": "vsce has been renamed to @vscode/vsce. Install using @vscode/vsce instead.", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { - "azure-devops-node-api": "^11.0.1", - "chalk": "^2.4.2", - "cheerio": "^1.0.0-rc.9", - "commander": "^6.1.0", - "denodeify": "^1.2.1", - "glob": "^7.0.6", - "leven": "^3.1.0", - "lodash": "^4.17.15", - "markdown-it": "^10.0.0", - "mime": "^1.3.4", - "minimatch": "^3.0.3", - "osenv": "^0.1.3", - "parse-semver": "^1.1.1", - "read": "^1.0.7", - "semver": "^5.1.0", - "tmp": "^0.2.1", - "typed-rest-client": "^1.8.4", - "url-join": "^1.1.0", - "yauzl": "^2.3.1", - "yazl": "^2.2.2" + "lru-cache": "^6.0.0" }, "bin": { - "vsce": "out/vsce" + "semver": "bin/semver.js" }, "engines": { - "node": ">= 10" + "node": ">=10" } }, "node_modules/p-limit": { @@ -3123,6 +3107,7 @@ "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", "dev": true, + "optional": true, "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", @@ -3155,6 +3140,7 @@ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, + "optional": true, "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -3218,6 +3204,7 @@ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, + "optional": true, "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -3233,6 +3220,7 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "dev": true, + "optional": true, "engines": { "node": ">=0.10.0" } @@ -3547,7 +3535,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "optional": true }, "node_modules/simple-get": { "version": "4.0.1", @@ -3568,6 +3557,7 @@ "url": "https://feross.org/support" } ], + "optional": true, "dependencies": { "decompress-response": "^6.0.0", "once": "^1.3.1", @@ -3643,12 +3633,6 @@ "integrity": "sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==", "dev": true }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -3736,6 +3720,7 @@ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", "dev": true, + "optional": true, "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", @@ -3748,6 +3733,7 @@ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dev": true, + "optional": true, "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -3764,6 +3750,7 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, + "optional": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -3959,6 +3946,7 @@ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, + "optional": true, "dependencies": { "safe-buffer": "^5.0.1" }, @@ -4054,121 +4042,6 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, - "node_modules/vsce": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/vsce/-/vsce-2.6.7.tgz", - "integrity": "sha512-5dEtdi/yzWQbOU7JDUSOs8lmSzzkewBR5P122BUkmXE6A/DEdFsKNsg2773NGXJTwwF1MfsOgUR6QVF3cLLJNQ==", - "deprecated": "vsce has been renamed to @vscode/vsce. Install using @vscode/vsce instead.", - "dev": true, - "dependencies": { - "azure-devops-node-api": "^11.0.1", - "chalk": "^2.4.2", - "cheerio": "^1.0.0-rc.9", - "commander": "^6.1.0", - "glob": "^7.0.6", - "hosted-git-info": "^4.0.2", - "keytar": "^7.7.0", - "leven": "^3.1.0", - "markdown-it": "^12.3.2", - "mime": "^1.3.4", - "minimatch": "^3.0.3", - "parse-semver": "^1.1.1", - "read": "^1.0.7", - "semver": "^5.1.0", - "tmp": "^0.2.1", - "typed-rest-client": "^1.8.4", - "url-join": "^4.0.1", - "xml2js": "^0.4.23", - "yauzl": "^2.3.1", - "yazl": "^2.2.2" - }, - "bin": { - "vsce": "vsce" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/vsce/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/vsce/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/vsce/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/vsce/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/vsce/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/vsce/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/vsce/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/vsce/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/vscode-jsonrpc": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2.tgz", @@ -4501,19 +4374,6 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "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==", - "dev": true, - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/xmlbuilder": { "version": "11.0.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index 4d82250df..bdca8e23e 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -902,11 +902,11 @@ "copy-webpack-plugin": "^10.2.4", "glob": "^7.1.6", "mocha": "^8.2.1", - "ovsx": "~0.2.1", + "ovsx": "~0.8.3", "source-map-loader": "^3.0.1", "ts-loader": "^9.2.6", "typescript": "^4.9.4", - "vsce": "~2.6.2", + "@vscode/vsce": "~2.21.1", "webpack-cli": "^4.10.0" }, "icon": "images/lean_logo.png", From 0e98f2ee9121fbb8d1662379787ab96b8ef60df4 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Wed, 18 Oct 2023 14:50:31 +0200 Subject: [PATCH 14/70] Release 0.0.116 (pre-release) --- vscode-lean4/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index bdca8e23e..70bbe7a4c 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -2,7 +2,7 @@ "name": "lean4", "displayName": "lean4", "description": "Lean 4 language support for VS Code", - "version": "0.0.115", + "version": "0.0.116", "publisher": "leanprover", "engines": { "vscode": "^1.75.0" From 26ab05dd21425989066803271c0de2950c90191d Mon Sep 17 00:00:00 2001 From: mhuisi Date: Wed, 18 Oct 2023 15:37:22 +0200 Subject: [PATCH 15/70] chore: mark prereleases as such in github releases --- .github/workflows/on-push.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/on-push.yml b/.github/workflows/on-push.yml index 3c4854730..2af10e087 100644 --- a/.github/workflows/on-push.yml +++ b/.github/workflows/on-push.yml @@ -85,6 +85,7 @@ jobs: with: files: 'vscode-lean4/lean4-*.vsix' fail_on_unmatched_files: true + prerelease: ${{ endsWith(github.ref, '-pre') }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 58ccddae00a3440babad2eb2b895bde7dcb14d4e Mon Sep 17 00:00:00 2001 From: Marc Huisinga Date: Thu, 19 Oct 2023 15:52:20 +0200 Subject: [PATCH 16/70] Assorted test fixes (#340) --- vscode-lean4/package-lock.json | 4 +-- vscode-lean4/src/extension.ts | 16 +++++++--- vscode-lean4/src/utils/clientProvider.ts | 9 ++++-- .../test/suite/restarts/restarts.test.ts | 10 +++++++ .../test/suite/toolchains/toolchain.test.ts | 1 + vscode-lean4/test/suite/utils/helpers.ts | 29 +++++++++++++++---- 6 files changed, 55 insertions(+), 14 deletions(-) diff --git a/vscode-lean4/package-lock.json b/vscode-lean4/package-lock.json index 1ae58c497..ff47451eb 100644 --- a/vscode-lean4/package-lock.json +++ b/vscode-lean4/package-lock.json @@ -1,12 +1,12 @@ { "name": "lean4", - "version": "0.0.115", + "version": "0.0.116", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "lean4", - "version": "0.0.115", + "version": "0.0.116", "license": "Apache-2.0", "dependencies": { "axios": "~0.24.0", diff --git a/vscode-lean4/src/extension.ts b/vscode-lean4/src/extension.ts index e254000de..07f06ab2c 100644 --- a/vscode-lean4/src/extension.ts +++ b/vscode-lean4/src/extension.ts @@ -159,12 +159,14 @@ async function activateLean4Features(context: ExtensionContext, installer: LeanI return { clientProvider, infoProvider, projectOperationProvider } } +let extensionExports: Exports + export async function activate(context: ExtensionContext): Promise { await setLeanFeatureSetActive(false) const alwaysEnabledFeatures: AlwaysEnabledFeatures = activateAlwaysEnabledFeatures(context) if (await isLean3Project(alwaysEnabledFeatures.installer)) { - return { + extensionExports = { isLean4Project: false, version: '3', infoProvider: undefined, @@ -174,13 +176,14 @@ export async function activate(context: ExtensionContext): Promise { docView: alwaysEnabledFeatures.docView, projectInitializationProver: alwaysEnabledFeatures.projectInitializationProvider } + return extensionExports } activateAbbreviationFeature(context, alwaysEnabledFeatures.docView) if (findOpenLeanDocument()) { const lean4EnabledFeatures: Lean4EnabledFeatures = await activateLean4Features(context, alwaysEnabledFeatures.installer) - return { + extensionExports = { isLean4Project: true, version: '4', infoProvider: lean4EnabledFeatures.infoProvider, @@ -190,17 +193,21 @@ export async function activate(context: ExtensionContext): Promise { docView: alwaysEnabledFeatures.docView, projectInitializationProver: alwaysEnabledFeatures.projectInitializationProvider } + return extensionExports } // No Lean 4 document yet => Load remaining features when one is open const disposeActivationListener: Disposable = workspace.onDidOpenTextDocument(async doc => { if (isLean(doc.languageId)) { - await activateLean4Features(context, alwaysEnabledFeatures.installer) + const lean4EnabledFeatures: Lean4EnabledFeatures = await activateLean4Features(context, alwaysEnabledFeatures.installer) + extensionExports.infoProvider = lean4EnabledFeatures.infoProvider + extensionExports.clientProvider = lean4EnabledFeatures.clientProvider + extensionExports.projectOperationProvider = lean4EnabledFeatures.projectOperationProvider disposeActivationListener.dispose() } }, context.subscriptions) - return { + extensionExports = { isLean4Project: true, version: '4', infoProvider: undefined, @@ -210,4 +217,5 @@ export async function activate(context: ExtensionContext): Promise { docView: alwaysEnabledFeatures.docView, projectInitializationProver: alwaysEnabledFeatures.projectInitializationProvider } + return extensionExports } diff --git a/vscode-lean4/src/utils/clientProvider.ts b/vscode-lean4/src/utils/clientProvider.ts index e24f81c14..f2d443e25 100644 --- a/vscode-lean4/src/utils/clientProvider.ts +++ b/vscode-lean4/src/utils/clientProvider.ts @@ -48,7 +48,7 @@ export class LeanClientProvider implements Disposable { this.subscriptions.push( commands.registerCommand('lean4.restartFile', () => this.restartFile()), commands.registerCommand('lean4.refreshFileDependencies', () => this.restartFile()), - commands.registerCommand('lean4.restartServer', () => this.restartActiveClient()), + commands.registerCommand('lean4.restartServer', showDialog => this.restartActiveClient(showDialog ?? true)), commands.registerCommand('lean4.stopServer', () => this.stopActiveClient()) ); @@ -155,7 +155,12 @@ export class LeanClientProvider implements Disposable { } } - private async restartActiveClient() { + private async restartActiveClient(showDialog: boolean = true) { + if (!showDialog) { + void this.activeClient?.restart(); + return + } + const result: string | undefined = await window.showInformationMessage( 'Restart Lean 4 server to re-elaborate all open files?', { modal: true }, diff --git a/vscode-lean4/test/suite/restarts/restarts.test.ts b/vscode-lean4/test/suite/restarts/restarts.test.ts index 4e031ab86..da361da20 100644 --- a/vscode-lean4/test/suite/restarts/restarts.test.ts +++ b/vscode-lean4/test/suite/restarts/restarts.test.ts @@ -113,6 +113,16 @@ suite('Lean Server Restart Test Suite', () => { const info = lean.exports.infoProvider; assert(info, 'No InfoProvider export'); + + const activeEditor = vscode.window.activeTextEditor + assert(activeEditor, 'No active text editor') + const evalLine = '#eval main' + const startOffset = activeEditor.document.getText().indexOf(evalLine) + assert(startOffset !== -1, 'Cannot find #eval in Main.lean') + const endOffset = startOffset + evalLine.length + const endPos = activeEditor.document.positionAt(endOffset) + activeEditor.selection = new vscode.Selection(endPos, endPos) + const expectedVersion = 'Hello:'; const html = await waitForInfoviewHtml(info, expectedVersion); const versionString = extractPhrase(html, 'Hello:', '<').trim(); diff --git a/vscode-lean4/test/suite/toolchains/toolchain.test.ts b/vscode-lean4/test/suite/toolchains/toolchain.test.ts index 64f5c424b..94228a75b 100644 --- a/vscode-lean4/test/suite/toolchains/toolchain.test.ts +++ b/vscode-lean4/test/suite/toolchains/toolchain.test.ts @@ -13,6 +13,7 @@ suite('Toolchain Test Suite', () => { test('Edit lean-toolchain version', async () => { logger.log('=================== Edit lean-toolchain version ==================='); + void vscode.window.showInformationMessage('Running tests: ' + __dirname); const testsRoot = path.join(__dirname, '..', '..', '..', '..', 'test', 'test-fixtures', 'simple'); diff --git a/vscode-lean4/test/suite/utils/helpers.ts b/vscode-lean4/test/suite/utils/helpers.ts index 46083a91b..b70f8b190 100644 --- a/vscode-lean4/test/suite/utils/helpers.ts +++ b/vscode-lean4/test/suite/utils/helpers.ts @@ -38,17 +38,17 @@ export async function initLean4(fileName: string) : Promise { + logger.log('Waiting for info view provider to be loaded...'); + + let count = 0; + while (!exports.infoProvider) { + count += 1; + if (count >= retries){ + logger.log('Info view provider did not load.') + return false; + } + await sleep(delay); + } + + logger.log('Info view provider loaded.') + return true +} + export async function waitForInfoViewOpen(infoView: InfoProvider, retries=60, delay=1000) : Promise { let count = 0; let opened = false; @@ -374,7 +391,7 @@ export async function restartLeanServer(client: LeanClient, retries=60, delay=10 client.restarted(() => { stateChanges.push('restarted'); }); client.serverFailed(() => { stateChanges.push('failed'); }); - await vscode.commands.executeCommand('lean4.restartServer'); + await vscode.commands.executeCommand('lean4.restartServer', false); while (count < retries){ const index = stateChanges.indexOf('restarted'); From 013f52d6e5723a1dd2a89a0d36d98099039e4589 Mon Sep 17 00:00:00 2001 From: Marc Huisinga Date: Thu, 19 Oct 2023 16:59:50 +0200 Subject: [PATCH 17/70] feat: change whitespace default settings (#341) --- vscode-lean4/package.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index 70bbe7a4c..a9e18f1eb 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -712,7 +712,13 @@ "[lean4]": { "editor.unicodeHighlight.ambiguousCharacters": false, "editor.tabSize": 2, - "editor.wordSeparators": "`~@$%^&*()-=+[{]}⟨⟩⦃⦄⟦⟧⟮⟯‹›\\|;:\",.<>/" + "editor.insertSpaces": true, + "editor.wordSeparators": "`~@$%^&*()-=+[{]}⟨⟩⦃⦄⟦⟧⟮⟯‹›\\|;:\",.<>/", + "files.encoding": "utf8", + "files.eol": "\n", + "files.insertFinalNewline": true, + "files.trimFinalNewlines": true, + "files.trimTrailingWhitespace": true } }, "walkthroughs": [ From a79d9b401353259071ccccd674523f70ba3491a7 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Mon, 23 Oct 2023 18:05:12 +0200 Subject: [PATCH 18/70] Release 0.0.117 --- vscode-lean4/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index a9e18f1eb..0ce4e83a5 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -2,7 +2,7 @@ "name": "lean4", "displayName": "lean4", "description": "Lean 4 language support for VS Code", - "version": "0.0.116", + "version": "0.0.117", "publisher": "leanprover", "engines": { "vscode": "^1.75.0" From 9589c3128026c39af9ab5a5edeb4ae24e23cf085 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Mon, 30 Oct 2023 13:36:31 +0100 Subject: [PATCH 19/70] feat: remove server restart prompt --- vscode-lean4/src/utils/clientProvider.ts | 17 +++-------------- vscode-lean4/test/suite/utils/helpers.ts | 2 +- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/vscode-lean4/src/utils/clientProvider.ts b/vscode-lean4/src/utils/clientProvider.ts index f2d443e25..242b3ebf8 100644 --- a/vscode-lean4/src/utils/clientProvider.ts +++ b/vscode-lean4/src/utils/clientProvider.ts @@ -48,7 +48,7 @@ export class LeanClientProvider implements Disposable { this.subscriptions.push( commands.registerCommand('lean4.restartFile', () => this.restartFile()), commands.registerCommand('lean4.refreshFileDependencies', () => this.restartFile()), - commands.registerCommand('lean4.restartServer', showDialog => this.restartActiveClient(showDialog ?? true)), + commands.registerCommand('lean4.restartServer', () => this.restartActiveClient()), commands.registerCommand('lean4.stopServer', () => this.stopActiveClient()) ); @@ -155,19 +155,8 @@ export class LeanClientProvider implements Disposable { } } - private async restartActiveClient(showDialog: boolean = true) { - if (!showDialog) { - void this.activeClient?.restart(); - return - } - - const result: string | undefined = await window.showInformationMessage( - 'Restart Lean 4 server to re-elaborate all open files?', - { modal: true }, - 'Restart server') - if (result === 'Restart server') { - void this.activeClient?.restart(); - } + private async restartActiveClient() { + void this.activeClient?.restart(); } clientIsStarted() { diff --git a/vscode-lean4/test/suite/utils/helpers.ts b/vscode-lean4/test/suite/utils/helpers.ts index b70f8b190..c3cd2a789 100644 --- a/vscode-lean4/test/suite/utils/helpers.ts +++ b/vscode-lean4/test/suite/utils/helpers.ts @@ -391,7 +391,7 @@ export async function restartLeanServer(client: LeanClient, retries=60, delay=10 client.restarted(() => { stateChanges.push('restarted'); }); client.serverFailed(() => { stateChanges.push('failed'); }); - await vscode.commands.executeCommand('lean4.restartServer', false); + await vscode.commands.executeCommand('lean4.restartServer'); while (count < retries){ const index = stateChanges.indexOf('restarted'); From b023be480bf4c51f339d02a37ff47aceecebc3a7 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Mon, 30 Oct 2023 13:46:04 +0100 Subject: [PATCH 20/70] chore: change name of 'create mathlib project' command --- vscode-lean4/media/guide-setupProject.md | 4 ++-- vscode-lean4/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vscode-lean4/media/guide-setupProject.md b/vscode-lean4/media/guide-setupProject.md index 53648a304..386db8421 100644 --- a/vscode-lean4/media/guide-setupProject.md +++ b/vscode-lean4/media/guide-setupProject.md @@ -2,8 +2,8 @@ If you want to create a new project, click on one of the following: - [Create a new standalone project](command:lean4.project.createStandaloneProject) Standalone projects do not depend on any other Lean 4 projects. Dependencies can be added by modifying 'lakefile.lean' in the newly created project as described [here](https://github.com/leanprover/lean4/blob/master/src/lake/README.md#adding-dependencies). -- [Create a new mathlib project](command:lean4.project.createMathlibProject) - Mathlib projects depend on [mathlib](https://github.com/leanprover-community/mathlib4), the math library of Lean 4. +- [Create a new project using Mathlib](command:lean4.project.createMathlibProject) + The created project will depend on [Mathlib](https://github.com/leanprover-community/mathlib4), the math library of Lean 4. If you want to open an existing project, click on one of the following: - [Download an existing project](command:lean4.project.clone) diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index 0ce4e83a5..c524039c8 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -324,7 +324,7 @@ { "command": "lean4.project.createMathlibProject", "category": "Lean 4", - "title": "Project: Create Mathlib Project…", + "title": "Project: Create Project Using Mathlib…", "description": "Create a new Lean math formalization project using Mathlib" }, { From 4282b22208cf1814516a6f92cb82aa90ef81f7d6 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Tue, 31 Oct 2023 09:52:40 +0100 Subject: [PATCH 21/70] fix: focus independent command activation --- vscode-lean4/package.json | 40 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index c524039c8..8fe9b1289 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -421,74 +421,74 @@ "command": "lean4.restartFile", "key": "ctrl+shift+x", "mac": "cmd+shift+x", - "when": "editorTextFocus && editorLangId == lean4" + "when": "lean4.isLeanFeatureSetActive" }, { "command": "lean4.toggleInfoview", "key": "ctrl+shift+enter", "mac": "cmd+shift+enter", - "when": "editorTextFocus && editorLangId == lean4" + "when": "lean4.isLeanFeatureSetActive" }, { "command": "lean4.displayList", "key": "ctrl+shift+alt+enter", "mac": "cmd+shift+alt+enter", - "when": "editorTextFocus && editorLangId == lean4" + "when": "lean4.isLeanFeatureSetActive" } ], "menus": { "commandPalette": [ { "command": "lean4.restartServer", - "when": "editorLangId == lean4" + "when": "lean4.isLeanFeatureSetActive" }, { "command": "lean4.stopServer", - "when": "editorLangId == lean4" + "when": "lean4.isLeanFeatureSetActive" }, { "command": "lean4.restartFile", - "when": "editorLangId == lean4" + "when": "lean4.isLeanFeatureSetActive" }, { "command": "lean4.refreshFileDependencies", - "when": "editorLangId == lean4" + "when": "lean4.isLeanFeatureSetActive" }, { "command": "lean4.input.convert", - "when": "editorLangId == lean4 && lean4.input.isActive" + "when": "lean4.isLeanFeatureSetActive && lean4.input.isActive" }, { "command": "lean4.displayGoal", - "when": "editorLangId == lean4" + "when": "lean4.isLeanFeatureSetActive" }, { "command": "lean4.toggleInfoview", - "when": "editorLangId == lean4" + "when": "lean4.isLeanFeatureSetActive" }, { "command": "lean4.displayList", - "when": "editorLangId == lean4" + "when": "lean4.isLeanFeatureSetActive" }, { "command": "lean4.infoView.copyToComment", - "when": "editorLangId == lean4" + "when": "lean4.isLeanFeatureSetActive" }, { "command": "lean4.infoView.toggleStickyPosition", - "when": "editorLangId == lean4" + "when": "lean4.isLeanFeatureSetActive" }, { "command": "lean4.infoView.toggleUpdating", - "when": "editorLangId == lean4" + "when": "lean4.isLeanFeatureSetActive" }, { "command": "lean4.infoView.toggleExpectedType", - "when": "editorLangId == lean4" + "when": "lean4.isLeanFeatureSetActive" }, { "command": "lean4.docView.showAllAbbreviations", - "when": "editorLangId == lean4" + "when": "lean4.isLeanFeatureSetActive" }, { "command": "lean4.docView.open" @@ -522,19 +522,19 @@ }, { "command": "lean4.project.build", - "when": "editorLangId == lean4" + "when": "lean4.isLeanFeatureSetActive" }, { "command": "lean4.project.clean", - "when": "editorLangId == lean4" + "when": "lean4.isLeanFeatureSetActive" }, { "command": "lean4.project.updateDependency", - "when": "editorLangId == lean4" + "when": "lean4.isLeanFeatureSetActive" }, { "command": "lean4.project.fetchCache", - "when": "editorLangId == lean4" + "when": "lean4.isLeanFeatureSetActive" } ], "editor/title": [ From 76ccd1da5bb341250bb39a6161c1d52ad43da759 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Tue, 31 Oct 2023 15:55:28 +0100 Subject: [PATCH 22/70] fix: bad error message + crash without default toolchain --- vscode-lean4/src/utils/clientProvider.ts | 2 ++ vscode-lean4/src/utils/leanInstaller.ts | 41 ++++++++++-------------- 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/vscode-lean4/src/utils/clientProvider.ts b/vscode-lean4/src/utils/clientProvider.ts index 242b3ebf8..af46a518a 100644 --- a/vscode-lean4/src/utils/clientProvider.ts +++ b/vscode-lean4/src/utils/clientProvider.ts @@ -8,6 +8,7 @@ import { checkParentFoldersForLeanProject, findLeanPackageRoot, isValidLeanProje import { isFileInFolder } from './fsHelper'; import { logger } from './logger' import { addDefaultElanPath, getDefaultElanPath, addToolchainBinPath, isElanDisabled, isRunningTest, shouldShowInvalidProjectWarnings } from '../config' +import { displayErrorWithOutput } from './errors'; // This class ensures we have one LeanClient per workspace folder. export class LeanClientProvider implements Disposable { @@ -357,6 +358,7 @@ export class LeanClientProvider implements Disposable { // as a result of UI options shown by testLeanVersion. await client.start(); } else { + void displayErrorWithOutput('Cannot determine Lean version: ' + versionInfo.error) logger.log(`[ClientProvider] skipping client.start because of versionInfo error: ${versionInfo?.error}`); } } diff --git a/vscode-lean4/src/utils/leanInstaller.ts b/vscode-lean4/src/utils/leanInstaller.ts index b052105ae..446194472 100644 --- a/vscode-lean4/src/utils/leanInstaller.ts +++ b/vscode-lean4/src/utils/leanInstaller.ts @@ -58,28 +58,22 @@ export class LeanInstaller { // Ah, there is no elan, but what if Lean is in the PATH due to custom install? const found = await this.checkLeanVersion(packageUri, leanVersion); if (found.error) { - return { version: '4', error: 'no elan installed' } + return { version: '', error: 'no elan installed' } } } else if (! await isCoreLean4Directory(packageUri)) { const defaultVersion = await this.getElanDefaultToolchain(packageUri); if (!defaultVersion) { - void this.showToolchainOptions(packageUri); - } else { - leanVersion = defaultVersion; + return { version: '', error: 'no default toolchain' } } + leanVersion = defaultVersion; } } const found = await this.checkLeanVersion(packageUri, leanVersion); - if (found.error) { - if (leanVersion){ - // if we have a lean-toolchain version or a workspace override then - // use that version during the installElan process. - this.defaultToolchain = leanVersion; - } - if (found.error === 'no default toolchain') { - await this.showToolchainOptions(packageUri) - } + if (found.error && leanVersion) { + // if we have a lean-toolchain version or a workspace override then + // use that version during the installElan process. + this.defaultToolchain = leanVersion; } return found; } @@ -187,16 +181,7 @@ export class LeanInstaller { return s.trim(); } - async showToolchainOptions(uri: Uri) : Promise { - if (!this.promptUser){ - // no need to prompt when there is no user. - return; - } - await window.showErrorMessage('You have no default "lean-toolchain" in this folder or any parent folder.') - } - async checkLeanVersion(packageUri: Uri | null, version: string | null): Promise { - let cmd = toolchainPath(); if (!cmd) { cmd = 'lean' @@ -206,7 +191,7 @@ export class LeanInstaller { const folderUri = packageUri ?? Uri.from({scheme: 'untitled'}); const folderPath: string = folderUri.scheme === 'file' ? folderUri.fsPath : ''; const cacheKey = folderUri.toString(); - if (this.versionCache.has(cacheKey)) { + if (!version && this.versionCache.has(cacheKey)) { const result = this.versionCache.get(cacheKey); if (result){ return result; @@ -231,6 +216,12 @@ export class LeanInstaller { const checkingResult: ExecutionResult = await batchExecute(cmd, options, folderPath, { combined: this.outputChannel }) if (checkingResult.exitCode === ExecutionExitCode.CannotLaunch) { result.error = 'lean not found' + } else if (checkingResult.exitCode === ExecutionExitCode.ExecutionError) { + if (checkingResult.stderr.match(/error: toolchain '.*' is not installed/)) { + result.error = 'selected elan default toolchain not installed - please set a new default toolchain' + } else { + result.error = 'lean version not found' + } } else if (checkingResult.stderr.indexOf('no default toolchain') > 0) { result.error = 'no default toolchain' } else { @@ -248,7 +239,9 @@ export class LeanInstaller { if (this.outputChannel) this.outputChannel.appendLine(msg); result.error = err } - this.versionCache.set(cacheKey, result); + if (!version) { + this.versionCache.set(cacheKey, result); + } return result } From 4b91e2550d156352cfdfbf340062886e255ee4bb Mon Sep 17 00:00:00 2001 From: mhuisi Date: Tue, 31 Oct 2023 18:15:12 +0100 Subject: [PATCH 23/70] fix: bootstrap error message --- vscode-lean4/src/utils/clientProvider.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vscode-lean4/src/utils/clientProvider.ts b/vscode-lean4/src/utils/clientProvider.ts index af46a518a..cea8611b9 100644 --- a/vscode-lean4/src/utils/clientProvider.ts +++ b/vscode-lean4/src/utils/clientProvider.ts @@ -1,13 +1,12 @@ -import { Disposable, OutputChannel, workspace, TextDocument, commands, window, EventEmitter, Uri, languages, TextEditor, WorkspaceFolder } from 'vscode'; +import { Disposable, OutputChannel, workspace, TextDocument, commands, window, EventEmitter, Uri, languages, TextEditor } from 'vscode'; import { LeanInstaller, LeanVersion } from './leanInstaller' -import { LeanpkgService } from './leanpkg'; import { LeanClient } from '../leanclient' import { LeanFileProgressProcessingInfo, ServerStoppedReason } from '@leanprover/infoview-api'; import * as path from 'path'; import { checkParentFoldersForLeanProject, findLeanPackageRoot, isValidLeanProject } from './projectInfo'; import { isFileInFolder } from './fsHelper'; import { logger } from './logger' -import { addDefaultElanPath, getDefaultElanPath, addToolchainBinPath, isElanDisabled, isRunningTest, shouldShowInvalidProjectWarnings } from '../config' +import { addDefaultElanPath, getDefaultElanPath, addToolchainBinPath, isElanDisabled, shouldShowInvalidProjectWarnings } from '../config' import { displayErrorWithOutput } from './errors'; // This class ensures we have one LeanClient per workspace folder. @@ -279,6 +278,8 @@ export class LeanClientProvider implements Disposable { // but does not wait for the install to complete. await this.installer.showInstallOptions(uri); } + } else { + void displayErrorWithOutput('Cannot determine Lean version: ' + versionInfo.error) } return versionInfo; } @@ -358,7 +359,6 @@ export class LeanClientProvider implements Disposable { // as a result of UI options shown by testLeanVersion. await client.start(); } else { - void displayErrorWithOutput('Cannot determine Lean version: ' + versionInfo.error) logger.log(`[ClientProvider] skipping client.start because of versionInfo error: ${versionInfo?.error}`); } } From 2f3f44ee882bc1b822c2f0ed74abe7301adb0358 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Tue, 31 Oct 2023 18:29:06 +0100 Subject: [PATCH 24/70] Release 0.0.118 --- vscode-lean4/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index 8fe9b1289..ff18f12cb 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -2,7 +2,7 @@ "name": "lean4", "displayName": "lean4", "description": "Lean 4 language support for VS Code", - "version": "0.0.117", + "version": "0.0.118", "publisher": "leanprover", "engines": { "vscode": "^1.75.0" From a5e1034ae1d922cb8b0192ec7a90a45d6f599a73 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Fri, 3 Nov 2023 12:03:18 +0100 Subject: [PATCH 25/70] fix: still start language client when project folder is invalid --- vscode-lean4/src/utils/clientProvider.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vscode-lean4/src/utils/clientProvider.ts b/vscode-lean4/src/utils/clientProvider.ts index cea8611b9..d6591a0a7 100644 --- a/vscode-lean4/src/utils/clientProvider.ts +++ b/vscode-lean4/src/utils/clientProvider.ts @@ -198,9 +198,9 @@ export class LeanClientProvider implements Disposable { return } - await this.checkIsValidProjectFolder(client.folderUri) - await client.openLean4Document(document) + + await this.checkIsValidProjectFolder(client.folderUri) } catch (e) { logger.log(`[ClientProvider] ### Error opening document: ${e}`); } From 4ca21b6a657d07f5143585b0ebe86383e988625e Mon Sep 17 00:00:00 2001 From: mhuisi Date: Fri, 10 Nov 2023 18:11:15 +0100 Subject: [PATCH 26/70] chore: rename "install elan" button --- README.md | 4 ++-- docs/bootstrapping.md | 2 +- vscode-lean4/media/install-elan.png | Bin 4806 -> 0 bytes vscode-lean4/media/install-lean.png | Bin 0 -> 9455 bytes vscode-lean4/src/utils/leanInstaller.ts | 2 +- 5 files changed, 4 insertions(+), 4 deletions(-) delete mode 100644 vscode-lean4/media/install-elan.png create mode 100644 vscode-lean4/media/install-lean.png diff --git a/README.md b/README.md index 8c9cb5e75..d4c7dc22e 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,9 @@ containing the following: 1. Open your file `hello.lean`. 1. If `Lean` is not yet installed on your system you will see a prompt like this: - ![prompt](vscode-lean4/media/install-elan.png) + ![prompt](vscode-lean4/media/install-lean.png) -1. Click the `Install Lean using Elan` option and enter any default options that appear in the terminal window. +1. Click the `Install Lean` option and enter any default options that appear in the terminal window. 1. After this succeeds the correct version of Lean will be installed by `elan` and you should see something like this in the `Lean: Editor` output panel: ``` diff --git a/docs/bootstrapping.md b/docs/bootstrapping.md index 8521aaad8..1c506dbbd 100644 --- a/docs/bootstrapping.md +++ b/docs/bootstrapping.md @@ -16,7 +16,7 @@ yet and in that case `getLeanVersion` calls `testLeanVersion` on the ![prompt](images/InstallPrompt.png) -If the user clicks `Install Lean using Elan` then this will happen +If the user clicks `Install Lean` then this will happen and elan will be installed in the default location and a stable build of Lean will also be installed. diff --git a/vscode-lean4/media/install-elan.png b/vscode-lean4/media/install-elan.png deleted file mode 100644 index 285b4910878b3638fdda0edb4b128cc188c0151a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4806 zcmcgwcQ71mw_iyRL5g0&ipc81s?kgIU90Sp=w)@XLXfBtArV2euxg?#tJmnf5rP$U zS9C&@2upNU*>B(P{`1Y;dGEb{-81vldFGjO=9J%WPK>dUF5?xhD*yn1QD5)ADF8s# zMcG?izCf8-8}n{Z7AikeT}?p6;LSD4;gYKcR09C0PM|+^pr)MZeDogr0RUIO{5`08 zP{l|9fXPb#z6SiMEitX;s6c;Vr+J-X|vlmdk5FXaniuf>w6^Mw*0^WV{< zipvwwq!VjqcVLU;zs2terw@v_=*z8~@tF(DI`e+}MFe%Jl-PqfP64^EqgA~iwBKfn z5kh_zihlHKeyj-n+p1wx#UE%lUlNccyNhyG99HYdF8r4!OV!G>E6H4Fei9s7RY9&�l~$zTbi=@2>jCj= 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%0D)Vc$X6}KRZG0UjSE(WQ!*1NZ&<(lv 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 L@V!FR(EtAcu$6yT literal 0 HcmV?d00001 diff --git a/vscode-lean4/src/utils/leanInstaller.ts b/vscode-lean4/src/utils/leanInstaller.ts index 446194472..2452efb5e 100644 --- a/vscode-lean4/src/utils/leanInstaller.ts +++ b/vscode-lean4/src/utils/leanInstaller.ts @@ -147,7 +147,7 @@ export class LeanInstaller { // note; we keep the LeanClient alive so that it can be restarted if the // user changes the Lean: Executable Path. - const installItem = 'Install Lean using Elan'; + const installItem = 'Install Lean'; let prompt = 'Failed to start \'lean\' language server' if (path){ prompt += ` from ${path}` From 0634d7fa426ae0e49f9a0cff17a048894912d46d Mon Sep 17 00:00:00 2001 From: mhuisi Date: Fri, 10 Nov 2023 17:52:19 +0100 Subject: [PATCH 27/70] fix: detect core src directory --- vscode-lean4/src/utils/leanInstaller.ts | 4 ++-- vscode-lean4/src/utils/projectInfo.ts | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/vscode-lean4/src/utils/leanInstaller.ts b/vscode-lean4/src/utils/leanInstaller.ts index 2452efb5e..2b132d6d7 100644 --- a/vscode-lean4/src/utils/leanInstaller.ts +++ b/vscode-lean4/src/utils/leanInstaller.ts @@ -1,6 +1,6 @@ -import { window, TerminalOptions, OutputChannel, Disposable, EventEmitter, ProgressLocation, Uri } from 'vscode' +import { window, TerminalOptions, OutputChannel, EventEmitter, Uri } from 'vscode' import { toolchainPath, addServerEnvPaths, getPowerShellPath, shouldAutofocusOutput, isRunningTest } from '../config' -import { ExecutionExitCode, ExecutionResult, batchExecute, batchExecuteWithProgress } from './batch' +import { ExecutionExitCode, ExecutionResult, batchExecute } from './batch' import { readLeanVersion, isCoreLean4Directory } from './projectInfo'; import { join } from 'path'; import { logger } from './logger' diff --git a/vscode-lean4/src/utils/projectInfo.ts b/vscode-lean4/src/utils/projectInfo.ts index 91ae23b74..fcc6a622c 100644 --- a/vscode-lean4/src/utils/projectInfo.ts +++ b/vscode-lean4/src/utils/projectInfo.ts @@ -15,9 +15,26 @@ export async function isCoreLean4Directory(path: Uri): Promise { const licensePath = Uri.joinPath(path, 'LICENSE').fsPath const licensesPath = Uri.joinPath(path, 'LICENSES').fsPath const srcPath = Uri.joinPath(path, 'src').fsPath - return await fileExists(licensePath) + + const isCoreLean4RootDirectory = + await fileExists(licensePath) && await fileExists(licensesPath) && await fileExists(srcPath) + if (isCoreLean4RootDirectory) { + return true + } + + const initPath = Uri.joinPath(path, 'Init').fsPath + const leanPath = Uri.joinPath(path, 'Lean').fsPath + const kernelPath = Uri.joinPath(path, 'kernel').fsPath + const runtimePath = Uri.joinPath(path, 'runtime').fsPath + + const isCoreLean4SrcDirectory = + await fileExists(initPath) + && await fileExists(leanPath) + && await fileExists(kernelPath) + && await fileExists(runtimePath) + return isCoreLean4SrcDirectory } // Find the root of a Lean project and return an optional WorkspaceFolder for it, From ddf645d70bac3a2ce9d6285e9d4e53cdc6952e22 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Fri, 10 Nov 2023 17:23:26 +0100 Subject: [PATCH 28/70] chore: update lean toolchain after `lake update` --- vscode-lean4/src/projectoperations.ts | 80 +++++++++------------------ 1 file changed, 27 insertions(+), 53 deletions(-) diff --git a/vscode-lean4/src/projectoperations.ts b/vscode-lean4/src/projectoperations.ts index f46a078aa..8ceb5f7e0 100644 --- a/vscode-lean4/src/projectoperations.ts +++ b/vscode-lean4/src/projectoperations.ts @@ -155,22 +155,7 @@ export class ProjectOperationProvider implements Disposable { return } - const localToolchainPath: string = join(activeClient.folderUri.fsPath, 'lean-toolchain') - const dependencyToolchainResult: string | 'DoNotUpdate' | 'Cancelled' = await this.determineDependencyToolchain(localToolchainPath, dependencyChoice) - if (dependencyToolchainResult === 'Cancelled') { - return - } - await this.runOperation(async lakeRunner => { - if (dependencyToolchainResult !== 'DoNotUpdate') { - try { - fs.writeFileSync(localToolchainPath, dependencyToolchainResult) - } catch { - void window.showErrorMessage('Cannot update Lean version.') - return - } - } - const result: ExecutionResult = await lakeRunner.updateDependency(dependencyChoice.name) if (result.exitCode === ExecutionExitCode.Cancelled) { return @@ -181,6 +166,22 @@ export class ProjectOperationProvider implements Disposable { } await this.tryFetchingCache(lakeRunner) + + const localToolchainPath: string = join(activeClient.folderUri.fsPath, 'lean-toolchain') + const dependencyToolchainPath: string = join(activeClient.folderUri.fsPath, 'lake-packages', dependencyChoice.name, 'lean-toolchain') + const dependencyToolchainResult: string | 'DoNotUpdate' | 'Cancelled' = await this.determineDependencyToolchain(localToolchainPath, dependencyToolchainPath, dependencyChoice.name) + if (dependencyToolchainResult === 'Cancelled') { + return + } + + if (dependencyToolchainResult !== 'DoNotUpdate') { + try { + fs.writeFileSync(localToolchainPath, dependencyToolchainResult) + } catch { + void window.showErrorMessage('Cannot update Lean version.') + return + } + } }) } @@ -212,23 +213,16 @@ export class ProjectOperationProvider implements Disposable { return augmented } - private async determineDependencyToolchain(localToolchainPath: string, dependency: DirectGitDependency): Promise { - const dependencyToolchainUri: Uri | undefined = this.determineDependencyToolchainUri(dependency.uri, dependency.inputRevision) - if (!dependencyToolchainUri) { - const message = `Could not determine Lean version of ${dependency.name} at ${dependency.uri}, as doing so is currently only supported for GitHub projects. Do you want to update ${dependency.name} without updating the Lean version of the open project to that of ${dependency.name} regardless?` - const input = 'Proceed' - const choice: string | undefined = await window.showInformationMessage(message, { modal: true}, input) - return choice === 'input' ? 'DoNotUpdate' : 'Cancelled' - } + private async determineDependencyToolchain(localToolchainPath: string, dependencyToolchainPath: string, dependencyName: string): Promise { - const toolchainResult = await this.fetchToolchains(localToolchainPath, dependencyToolchainUri) + const toolchainResult = await this.readToolchains(localToolchainPath, dependencyToolchainPath) if (!(toolchainResult instanceof Array)) { const errorFlavor = toolchainResult === 'CannotReadLocalToolchain' ? `Could not read Lean version of open project at '${localToolchainPath}'` - : `Could not fetch Lean version of ${dependency.name} at ${dependency.uri}` - const message = `${errorFlavor}. Do you want to update ${dependency.name} without updating the Lean version of the open project to that of ${dependency.name} regardless?` + : `Could not read Lean version of ${dependencyName} at ${dependencyToolchainPath}` + const message = `${errorFlavor}. Do you want to update ${dependencyName} without updating the Lean version of the open project to that of ${dependencyName} regardless?` const input = 'Proceed' - const choice: string | undefined = await window.showInformationMessage(message, { modal: true}, input) + const choice: string | undefined = await window.showInformationMessage(message, { modal: true }, input) return choice === 'input' ? 'DoNotUpdate' : 'Cancelled' } const [localToolchain, dependencyToolchain]: [string, string] = toolchainResult @@ -237,7 +231,7 @@ export class ProjectOperationProvider implements Disposable { return 'DoNotUpdate' } - const message = `The Lean version '${localToolchain}' of the open project differs from the Lean version '${dependencyToolchain}' of ${dependency.name}. Do you want to update the Lean version of the open project to the Lean version of ${dependency.name}?` + const message = `The Lean version '${localToolchain}' of the open project differs from the Lean version '${dependencyToolchain}' of ${dependencyName}. Do you want to update the Lean version of the open project to the Lean version of ${dependencyName}?` const input1 = 'Update Lean Version' const input2 = 'Keep Lean Version' const choice = await window.showInformationMessage(message, { modal: true }, input1, input2) @@ -251,28 +245,7 @@ export class ProjectOperationProvider implements Disposable { return dependencyToolchain } - private determineDependencyToolchainUri(dependencyUri: Uri, inputRevision: string): Uri | undefined { - // Example: - // Input: https://github.com/leanprover-community/mathlib4 - // Output: https://raw.githubusercontent.com/leanprover-community/mathlib4/master/lean-toolchain - - if (!dependencyUri.authority.includes('github.com')) { - return undefined - } - const match = dependencyUri.path.match(/\/([^\\]+\/[^\\\.]+)(\.git)?\/?/) - if (!match) { - return undefined - } - const repoPath: string = match[1] - - return Uri.from({ - scheme: 'https', - authority: 'raw.githubusercontent.com', - path: join(repoPath, inputRevision, 'lean-toolchain') - }) - } - - private async fetchToolchains(localToolchainPath: string, dependencyToolchainUri: Uri): Promise<[string, string] | 'CannotReadLocalToolchain' | 'CannotReadDependencyToolchain'> { + private async readToolchains(localToolchainPath: string, dependencyToolchainPath: string): Promise<[string, string] | 'CannotReadLocalToolchain' | 'CannotReadDependencyToolchain'> { let localToolchain: string try { localToolchain = fs.readFileSync(localToolchainPath, 'utf8').trim() @@ -280,11 +253,12 @@ export class ProjectOperationProvider implements Disposable { return 'CannotReadLocalToolchain' } - const curlResult: ExecutionResult = await batchExecute('curl', ['-f', '-L', dependencyToolchainUri.toString()]) - if (curlResult.exitCode !== ExecutionExitCode.Success) { + let dependencyToolchain: string + try { + dependencyToolchain = fs.readFileSync(dependencyToolchainPath, 'utf8').trim() + } catch (e) { return 'CannotReadDependencyToolchain' } - const dependencyToolchain: string = curlResult.stdout.trim() return [localToolchain, dependencyToolchain] } From ba5c660d578fc60dc17089293593d94df6bceb94 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Fri, 10 Nov 2023 21:28:43 +0100 Subject: [PATCH 29/70] fix: use manifest packagesDir entry instead of lake-packages --- vscode-lean4/src/projectoperations.ts | 2 +- vscode-lean4/src/utils/manifest.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/vscode-lean4/src/projectoperations.ts b/vscode-lean4/src/projectoperations.ts index 8ceb5f7e0..0af237276 100644 --- a/vscode-lean4/src/projectoperations.ts +++ b/vscode-lean4/src/projectoperations.ts @@ -168,7 +168,7 @@ export class ProjectOperationProvider implements Disposable { await this.tryFetchingCache(lakeRunner) const localToolchainPath: string = join(activeClient.folderUri.fsPath, 'lean-toolchain') - const dependencyToolchainPath: string = join(activeClient.folderUri.fsPath, 'lake-packages', dependencyChoice.name, 'lean-toolchain') + const dependencyToolchainPath: string = join(activeClient.folderUri.fsPath, manifestResult.packagesDir, dependencyChoice.name, 'lean-toolchain') const dependencyToolchainResult: string | 'DoNotUpdate' | 'Cancelled' = await this.determineDependencyToolchain(localToolchainPath, dependencyToolchainPath, dependencyChoice.name) if (dependencyToolchainResult === 'Cancelled') { return diff --git a/vscode-lean4/src/utils/manifest.ts b/vscode-lean4/src/utils/manifest.ts index 81fb1af46..dea9e8b72 100644 --- a/vscode-lean4/src/utils/manifest.ts +++ b/vscode-lean4/src/utils/manifest.ts @@ -11,6 +11,7 @@ export interface DirectGitDependency { } export interface Manifest { + packagesDir: string directGitDependencies: DirectGitDependency[] } @@ -23,6 +24,7 @@ export function parseAsManifest(jsonString: string): Manifest | undefined { } const schema = z.object({ + packagesDir: z.string(), packages: z.array( z.union([ z.object({ @@ -45,7 +47,7 @@ export function parseAsManifest(jsonString: string): Manifest | undefined { return undefined } - const manifest: Manifest = { directGitDependencies: [] } + const manifest: Manifest = { packagesDir: result.data.packagesDir, directGitDependencies: [] } for (const pkg of result.data.packages) { if (!('git' in pkg)) { From 3f62c2a45d2e1861cdb448673a271d03d915902a Mon Sep 17 00:00:00 2001 From: Jon Eugster Date: Tue, 14 Nov 2023 15:04:50 +0100 Subject: [PATCH 30/70] fix: update semver (#343) --- vscode-lean4/package-lock.json | 65 ++++++---------------------------- vscode-lean4/package.json | 4 +-- 2 files changed, 12 insertions(+), 57 deletions(-) diff --git a/vscode-lean4/package-lock.json b/vscode-lean4/package-lock.json index ff47451eb..c4046fe66 100644 --- a/vscode-lean4/package-lock.json +++ b/vscode-lean4/package-lock.json @@ -1,18 +1,18 @@ { "name": "lean4", - "version": "0.0.116", + "version": "0.0.117", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "lean4", - "version": "0.0.116", + "version": "0.0.117", "license": "Apache-2.0", "dependencies": { "axios": "~0.24.0", "cheerio": "^1.0.0-rc.10", "mobx": "5.15.7", - "semver": "=7.3.5", + "semver": "^7.5.4", "vscode-languageclient": "=8.0.2", "zod": "^3.22.4" }, @@ -22,7 +22,7 @@ "@types/mocha": "^8.2.0", "@types/node": "^18.11.9", "@types/ps-node": "~0.1.1", - "@types/semver": "^5.3.30", + "@types/semver": "^7.5.4", "@types/vscode": "^1.61.0", "@types/vscode-webview": "^1.57.0", "@vscode/test-electron": "^2.1.2", @@ -249,9 +249,9 @@ "dev": true }, "node_modules/@types/semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==", "dev": true }, "node_modules/@types/vscode": { @@ -287,21 +287,6 @@ "node": ">=16" } }, - "node_modules/@vscode/test-electron/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@vscode/vsce": { "version": "2.21.1", "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-2.21.1.tgz", @@ -398,21 +383,6 @@ "node": ">=4" } }, - "node_modules/@vscode/vsce/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@vscode/vsce/node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -2870,21 +2840,6 @@ "node": ">= 14" } }, - "node_modules/ovsx/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -3433,9 +3388,9 @@ } }, "node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index ff18f12cb..3afe61229 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -890,7 +890,7 @@ "axios": "~0.24.0", "cheerio": "^1.0.0-rc.10", "mobx": "5.15.7", - "semver": "=7.3.5", + "semver": "^7.5.4", "vscode-languageclient": "=8.0.2", "zod": "^3.22.4" }, @@ -900,7 +900,7 @@ "@types/mocha": "^8.2.0", "@types/node": "^18.11.9", "@types/ps-node": "~0.1.1", - "@types/semver": "^5.3.30", + "@types/semver": "^7.5.4", "@types/vscode": "^1.61.0", "@types/vscode-webview": "^1.57.0", "@vscode/test-electron": "^2.1.2", From a7ecccfb1b251b759f8edc00f55fc8d88fcd72ef Mon Sep 17 00:00:00 2001 From: Jon Eugster Date: Fri, 17 Nov 2023 15:49:05 +0100 Subject: [PATCH 31/70] fix: update npm packages (#358) --- vscode-lean4/package-lock.json | 303 ++++++++++++++++----------------- vscode-lean4/package.json | 16 +- 2 files changed, 154 insertions(+), 165 deletions(-) diff --git a/vscode-lean4/package-lock.json b/vscode-lean4/package-lock.json index c4046fe66..61afc0e16 100644 --- a/vscode-lean4/package-lock.json +++ b/vscode-lean4/package-lock.json @@ -1,15 +1,15 @@ { "name": "lean4", - "version": "0.0.117", + "version": "0.0.118", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "lean4", - "version": "0.0.117", + "version": "0.0.118", "license": "Apache-2.0", "dependencies": { - "axios": "~0.24.0", + "axios": "^1.6.2", "cheerio": "^1.0.0-rc.10", "mobx": "5.15.7", "semver": "^7.5.4", @@ -30,7 +30,7 @@ "concurrently": "^7.0.0", "copy-webpack-plugin": "^10.2.4", "glob": "^7.1.6", - "mocha": "^8.2.1", + "mocha": "^10.2.0", "ovsx": "~0.8.3", "source-map-loader": "^3.0.1", "ts-loader": "^9.2.6", @@ -266,12 +266,6 @@ "integrity": "sha512-ghW5SfuDmsGDS2A4xkvGsLwDRNc3Vj5rS6rPOyPm/IryZuf3wceZKxgYaUoW+k9f0f/CB7y2c1rRsdOWZWn0PQ==", "dev": true }, - "node_modules/@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", - "dev": true - }, "node_modules/@vscode/test-electron": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.3.3.tgz", @@ -714,15 +708,6 @@ "node": ">=6" } }, - "node_modules/ansi-regex": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", - "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -769,12 +754,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "node_modules/axios": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz", - "integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", + "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", "dependencies": { - "follow-redirects": "^1.14.4" + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" } }, "node_modules/azure-devops-node-api": { @@ -1066,24 +1058,30 @@ } }, "node_modules/chokidar": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", - "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], "dependencies": { - "anymatch": "~3.1.1", + "anymatch": "~3.1.2", "braces": "~3.0.2", - "glob-parent": "~5.1.0", + "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" + "readdirp": "~3.6.0" }, "engines": { "node": ">= 8.10.0" }, "optionalDependencies": { - "fsevents": "~2.3.1" + "fsevents": "~2.3.2" } }, "node_modules/chokidar/node_modules/glob-parent": { @@ -1217,6 +1215,17 @@ "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "dev": true }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", @@ -1399,6 +1408,14 @@ "node": ">=4.0.0" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/detect-libc": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", @@ -1759,6 +1776,19 @@ } } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -1773,9 +1803,9 @@ "dev": true }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "optional": true, @@ -1888,15 +1918,6 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, - "node_modules/growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true, - "engines": { - "node": ">=4.x" - } - }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -2152,15 +2173,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -2203,6 +2215,18 @@ "node": ">=0.10.0" } }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -2240,9 +2264,9 @@ } }, "node_modules/js-yaml": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", - "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "dependencies": { "argparse": "^2.0.1" @@ -2362,15 +2386,19 @@ "dev": true }, "node_modules/log-symbols": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", - "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dev": true, "dependencies": { - "chalk": "^4.0.0" + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/lru-cache": { @@ -2460,8 +2488,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "peer": true, "engines": { "node": ">= 0.6" } @@ -2470,8 +2496,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "peer": true, "dependencies": { "mime-db": "1.52.0" }, @@ -2530,43 +2554,39 @@ } }, "node_modules/mocha": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz", - "integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", "dev": true, "dependencies": { - "@ungap/promise-all-settled": "1.1.2", "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", - "chokidar": "3.5.1", - "debug": "4.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", "diff": "5.0.0", "escape-string-regexp": "4.0.0", "find-up": "5.0.0", - "glob": "7.1.6", - "growl": "1.10.5", + "glob": "7.2.0", "he": "1.2.0", - "js-yaml": "4.0.0", - "log-symbols": "4.0.0", - "minimatch": "3.0.4", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", "ms": "2.1.3", - "nanoid": "3.1.20", - "serialize-javascript": "5.0.1", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", "strip-json-comments": "3.1.1", "supports-color": "8.1.1", - "which": "2.0.2", - "wide-align": "1.1.3", - "workerpool": "6.1.0", + "workerpool": "6.2.1", "yargs": "16.2.0", "yargs-parser": "20.2.4", "yargs-unparser": "2.0.0" }, "bin": { "_mocha": "bin/_mocha", - "mocha": "bin/mocha" + "mocha": "bin/mocha.js" }, "engines": { - "node": ">= 10.12.0" + "node": ">= 14.0.0" }, "funding": { "type": "opencollective", @@ -2593,33 +2613,10 @@ "wrap-ansi": "^7.0.0" } }, - "node_modules/mocha/node_modules/debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/mocha/node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/mocha/node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -2636,6 +2633,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/mocha/node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/mocha/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -2646,15 +2655,24 @@ } }, "node_modules/mocha/node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" } }, "node_modules/mocha/node_modules/ms": { @@ -2664,9 +2682,9 @@ "dev": true }, "node_modules/mocha/node_modules/serialize-javascript": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", - "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", "dev": true, "dependencies": { "randombytes": "^2.1.0" @@ -2729,9 +2747,9 @@ "dev": true }, "node_modules/nanoid": { - "version": "3.1.20", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz", - "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", "dev": true, "bin": { "nanoid": "bin/nanoid.cjs" @@ -3090,6 +3108,11 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -3208,9 +3231,9 @@ } }, "node_modules/readdirp": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", - "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, "dependencies": { "picomatch": "^2.2.1" @@ -3597,31 +3620,6 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", - "dev": true, - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -4241,15 +4239,6 @@ "node": ">= 8" } }, - "node_modules/wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dev": true, - "dependencies": { - "string-width": "^1.0.2 || 2" - } - }, "node_modules/wildcard": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", @@ -4257,9 +4246,9 @@ "dev": true }, "node_modules/workerpool": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz", - "integrity": "sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", "dev": true }, "node_modules/wrap-ansi": { diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index 3afe61229..4cc83191e 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -671,11 +671,11 @@ }, "submenus": [ { - "id": "lean4.titlebar", - "label": "Lean 4", - "icon": { - "dark": "./media/lean-mini-dark.svg", - "light": "./media/lean-mini-light.svg" + "id": "lean4.titlebar", + "label": "Lean 4", + "icon": { + "dark": "./media/lean-mini-dark.svg", + "light": "./media/lean-mini-light.svg" } }, { @@ -887,7 +887,7 @@ "dependencies": { "@leanprover/infoview": "~0.4.3", "@leanprover/infoview-api": "~0.2.1", - "axios": "~0.24.0", + "axios": "^1.6.2", "cheerio": "^1.0.0-rc.10", "mobx": "5.15.7", "semver": "^7.5.4", @@ -904,15 +904,15 @@ "@types/vscode": "^1.61.0", "@types/vscode-webview": "^1.57.0", "@vscode/test-electron": "^2.1.2", + "@vscode/vsce": "~2.21.1", "concurrently": "^7.0.0", "copy-webpack-plugin": "^10.2.4", "glob": "^7.1.6", - "mocha": "^8.2.1", + "mocha": "^10.2.0", "ovsx": "~0.8.3", "source-map-loader": "^3.0.1", "ts-loader": "^9.2.6", "typescript": "^4.9.4", - "@vscode/vsce": "~2.21.1", "webpack-cli": "^4.10.0" }, "icon": "images/lean_logo.png", From 7350dcd973d8aaa7b6c4d933b09974e35094e379 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Fri, 17 Nov 2023 17:26:49 +0100 Subject: [PATCH 32/70] fix: update lake manifest parsing for manifest version 7 --- vscode-lean4/src/utils/manifest.ts | 87 +++++++++++++++++++++++++----- 1 file changed, 74 insertions(+), 13 deletions(-) diff --git a/vscode-lean4/src/utils/manifest.ts b/vscode-lean4/src/utils/manifest.ts index dea9e8b72..a16dc31ef 100644 --- a/vscode-lean4/src/utils/manifest.ts +++ b/vscode-lean4/src/utils/manifest.ts @@ -15,15 +15,8 @@ export interface Manifest { directGitDependencies: DirectGitDependency[] } -export function parseAsManifest(jsonString: string): Manifest | undefined { - let parsedJson: any - try { - parsedJson = JSON.parse(jsonString) - } catch (e) { - return undefined - } - - const schema = z.object({ +function parseVersion1To6Manifest(parsedJson: any) { + const version1To6ManifestSchema = z.object({ packagesDir: z.string(), packages: z.array( z.union([ @@ -42,7 +35,8 @@ export function parseAsManifest(jsonString: string): Manifest | undefined { ]) ) }) - const result = schema.safeParse(parsedJson) + + const result = version1To6ManifestSchema.safeParse(parsedJson) if (!result.success) { return undefined } @@ -57,19 +51,86 @@ export function parseAsManifest(jsonString: string): Manifest | undefined { continue // Inherited Git packages are not direct dependencies } - const inputRev: string | null | undefined = pkg.git['inputRev?'] - manifest.directGitDependencies.push({ name: pkg.git.name, uri: Uri.parse(pkg.git.url), revision: pkg.git.rev, - inputRevision: inputRev ? inputRev : 'master' // Lake also always falls back to master + inputRevision: pkg.git['inputRev?'] ?? 'master' // Lake also always falls back to master }) } return manifest } +function parseVersion7ToNManifest(parsedJson: any) { + const version7ToNManifestSchema = z.object({ + packagesDir: z.string(), + packages: z.array( + z.union([ + z.object({ + type: z.literal('git'), + name: z.string(), + url: z.string().url(), + rev: z.string(), + inherited: z.boolean(), + inputRev: z.optional(z.nullable(z.string())) + }), + z.object({ + type: z.literal('path') + }) + ]) + + ) + }) + + const result = version7ToNManifestSchema.safeParse(parsedJson) + if (!result.success) { + return undefined + } + + const manifest: Manifest = { packagesDir: result.data.packagesDir, directGitDependencies: [] } + + for (const pkg of result.data.packages) { + if (pkg.type !== 'git') { + continue + } + if (pkg.inherited) { + continue // Inherited Git packages are not direct dependencies + } + + manifest.directGitDependencies.push({ + name: pkg.name, + uri: Uri.parse(pkg.url), + revision: pkg.rev, + inputRevision: pkg.inputRev ?? 'master' // Lake also always falls back to master + }) + } + + return manifest +} + +export function parseAsManifest(jsonString: string): Manifest | undefined { + let parsedJson: any + try { + parsedJson = JSON.parse(jsonString) + } catch (e) { + return undefined + } + + const versionSchema = z.object({ version: z.number().int().nonnegative() }) + const versionResult = versionSchema.safeParse(parsedJson) + if (!versionResult.success) { + return undefined + } + const version = versionResult.data.version + + if (version <= 6) { + return parseVersion1To6Manifest(parsedJson) + } else { + return parseVersion7ToNManifest(parsedJson) + } +} + export type ManifestReadError = string export async function parseManifestInFolder(folderUri: Uri): Promise { From 8d0cc34dcfa00da8b4a48394ba1fb3a600e3f985 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Fri, 17 Nov 2023 17:58:05 +0100 Subject: [PATCH 33/70] Release 0.0.119 --- vscode-lean4/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index 4cc83191e..e66d94478 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -2,7 +2,7 @@ "name": "lean4", "displayName": "lean4", "description": "Lean 4 language support for VS Code", - "version": "0.0.118", + "version": "0.0.119", "publisher": "leanprover", "engines": { "vscode": "^1.75.0" From 08d46f1a67e7858bdd04ed8a58940827bc639338 Mon Sep 17 00:00:00 2001 From: Marc Huisinga Date: Tue, 21 Nov 2023 13:44:25 +0100 Subject: [PATCH 34/70] chore: add rrbracket to abbreviations (#360) --- vscode-lean4/src/abbreviation/abbreviations.json | 1 + 1 file changed, 1 insertion(+) diff --git a/vscode-lean4/src/abbreviation/abbreviations.json b/vscode-lean4/src/abbreviation/abbreviations.json index 811e922aa..ca6cc1f64 100644 --- a/vscode-lean4/src/abbreviation/abbreviations.json +++ b/vscode-lean4/src/abbreviation/abbreviations.json @@ -1086,6 +1086,7 @@ "rbag": "⟆", "rat": "ℚ", "radioactive": "☢", + "rrbracket": "〛", "rangle": "⟩", "rq": "’", "rial": "﷼", From 2fd18c6a7417860f3917d02d97cfde2c4eaf9317 Mon Sep 17 00:00:00 2001 From: Marc Huisinga Date: Sun, 26 Nov 2023 11:07:38 +0100 Subject: [PATCH 35/70] feat: build lean project after initialization (#363) --- vscode-lean4/src/projectinit.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/vscode-lean4/src/projectinit.ts b/vscode-lean4/src/projectinit.ts index c7c95d580..2d83896f0 100644 --- a/vscode-lean4/src/projectinit.ts +++ b/vscode-lean4/src/projectinit.ts @@ -19,11 +19,22 @@ export class ProjectInitializationProvider implements Disposable { } private async createStandaloneProject() { - const projectFolder: Uri | 'DidNotComplete' = await this.createProject() + const toolchain = 'leanprover/lean4:stable' + const projectFolder: Uri | 'DidNotComplete' = await this.createProject(undefined, toolchain) + if (projectFolder === 'DidNotComplete') { + return + } - if (projectFolder !== 'DidNotComplete') { - await ProjectInitializationProvider.openNewFolder(projectFolder) + const buildResult: ExecutionResult = await lake(this.channel, projectFolder, toolchain).build() + if (buildResult.exitCode === ExecutionExitCode.Cancelled) { + return } + if (buildResult.exitCode !== ExecutionExitCode.Success) { + await displayError(buildResult, 'Cannot build Lean project.') + return + } + + await ProjectInitializationProvider.openNewFolder(projectFolder) } private async createMathlibProject() { From 207c0f168c7fd3546f33ffce2d14c41dde136157 Mon Sep 17 00:00:00 2001 From: Marc Huisinga Date: Sun, 26 Nov 2023 11:08:29 +0100 Subject: [PATCH 36/70] chore: use lean4 scope for lean-markdown (#361) --- vscode-lean4/package.json | 10 +++++----- .../{lean-markdown.json => lean4-markdown.json} | 2 +- vscode-lean4/syntaxes/lean4.json | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) rename vscode-lean4/syntaxes/{lean-markdown.json => lean4-markdown.json} (99%) diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index e66d94478..368e93181 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -380,10 +380,10 @@ "configuration": "./language-configuration.json" }, { - "id": "leanmarkdown", + "id": "lean4markdown", "aliases": [], "extensions": [ - ".leanmarkdown" + ".lean4markdown" ], "configuration": "./language-configuration.json" } @@ -395,9 +395,9 @@ "path": "./syntaxes/lean4.json" }, { - "language": "leanmarkdown", - "scopeName": "source.lean.markdown", - "path": "./syntaxes/lean-markdown.json" + "language": "lean4markdown", + "scopeName": "source.lean4.markdown", + "path": "./syntaxes/lean4-markdown.json" }, { "scopeName": "markdown.lean4.codeblock", diff --git a/vscode-lean4/syntaxes/lean-markdown.json b/vscode-lean4/syntaxes/lean4-markdown.json similarity index 99% rename from vscode-lean4/syntaxes/lean-markdown.json rename to vscode-lean4/syntaxes/lean4-markdown.json index b06bd7f93..691d98f76 100644 --- a/vscode-lean4/syntaxes/lean-markdown.json +++ b/vscode-lean4/syntaxes/lean4-markdown.json @@ -5,7 +5,7 @@ ], "version": "https://github.com/microsoft/vscode/blob/df3ae4adefbb780f5f686e58ac6a8d305a8c86dc/extensions/markdown-basics/syntaxes/markdown.tmLanguage.json", "name": "Markdown", - "scopeName": "source.lean.markdown", + "scopeName": "source.lean4.markdown", "patterns": [ { "include": "#frontMatter" diff --git a/vscode-lean4/syntaxes/lean4.json b/vscode-lean4/syntaxes/lean4.json index 9db919821..cff18ecb3 100644 --- a/vscode-lean4/syntaxes/lean4.json +++ b/vscode-lean4/syntaxes/lean4.json @@ -62,27 +62,27 @@ "begin": "--", "end": "$", "name": "comment.line.double-dash.lean4", "patterns": [ - { "include": "source.lean.markdown" } + { "include": "source.lean4.markdown" } ] }, "docComment": { "begin": "/--", "end": "-/", "name": "comment.block.documentation.lean4", "patterns": [ - { "include": "source.lean.markdown" }, + { "include": "source.lean4.markdown" }, { "include": "#blockComment" } ] }, "modDocComment": { "begin": "/-!", "end": "-/", "name": "comment.block.documentation.lean4", "patterns": [ - { "include": "source.lean.markdown" }, + { "include": "source.lean4.markdown" }, { "include": "#blockComment" } ] }, "blockComment": { "begin": "/-", "end": "-/", "name": "comment.block.lean4", "patterns": [ - { "include": "source.lean.markdown" }, + { "include": "source.lean4.markdown" }, { "include": "#blockComment" } ] }, From ddef96eeb3adb25eb38d1ab0f898f41860afdf82 Mon Sep 17 00:00:00 2001 From: Marc Huisinga Date: Mon, 27 Nov 2023 11:48:05 +0100 Subject: [PATCH 37/70] doc: add more information to walkthrough (#362) --- vscode-lean4/media/context-menu.png | Bin 0 -> 30139 bytes vscode-lean4/media/guide-documentation.md | 8 ++- vscode-lean4/media/guide-help.md | 8 ++- vscode-lean4/media/guide-installDeps-linux.md | 2 +- vscode-lean4/media/guide-installDeps-mac.md | 2 +- .../media/guide-installDeps-windows.md | 2 +- vscode-lean4/media/guide-installElan-unix.md | 2 + .../media/guide-installElan-windows.md | 2 + vscode-lean4/media/guide-setupProject.md | 21 ++++-- vscode-lean4/media/guide-vscode.md | 30 +++++++++ vscode-lean4/media/new-project-structure.png | Bin 0 -> 11649 bytes .../open-local-project_show-setup_buttons.png | Bin 0 -> 25513 bytes vscode-lean4/media/restart-file.png | Bin 0 -> 8971 bytes vscode-lean4/media/show-output.png | Bin 0 -> 21713 bytes vscode-lean4/media/symbol-search.png | Bin 0 -> 25900 bytes vscode-lean4/media/unicode-hover.png | Bin 0 -> 3852 bytes vscode-lean4/package.json | 60 ++++++++++++------ vscode-lean4/src/extension.ts | 8 +-- 18 files changed, 108 insertions(+), 37 deletions(-) create mode 100644 vscode-lean4/media/context-menu.png create mode 100644 vscode-lean4/media/guide-vscode.md create mode 100644 vscode-lean4/media/new-project-structure.png create mode 100644 vscode-lean4/media/open-local-project_show-setup_buttons.png create mode 100644 vscode-lean4/media/restart-file.png create mode 100644 vscode-lean4/media/show-output.png create mode 100644 vscode-lean4/media/symbol-search.png create mode 100644 vscode-lean4/media/unicode-hover.png diff --git a/vscode-lean4/media/context-menu.png b/vscode-lean4/media/context-menu.png new file mode 100644 index 0000000000000000000000000000000000000000..3bb99b90e131401eb5145a2632514952c8075051 GIT binary patch literal 30139 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 VpaHKSKEji-S5 'Open Local Project…' and selecting the project you created. +Completing the project creation process and choosing to open the new project will close this guide. You can re-open it later by clicking the ∀-symbol in the top right and selecting 'Documentation…' > 'Setup: Show Setup Guide'. + + ![∀-symbol buttons](open-local-project_show-setup_buttons.png) + If you want to create a new project, click on one of the following: - [Create a new standalone project](command:lean4.project.createStandaloneProject) - Standalone projects do not depend on any other Lean 4 projects. Dependencies can be added by modifying 'lakefile.lean' in the newly created project as described [here](https://github.com/leanprover/lean4/blob/master/src/lake/README.md#adding-dependencies). + Standalone projects do not depend on any other Lean 4 projects. This option is suitable if you want to use Lean 4 as a general-purpose programming language or for program verification. + Dependencies can be added by modifying 'lakefile.lean' in the newly created project as described [here](https://github.com/leanprover/lean4/blob/master/src/lake/README.md#adding-dependencies). You may want to add [Lean's standard library](https://github.com/leanprover/std4) to the list of dependencies. - [Create a new project using Mathlib](command:lean4.project.createMathlibProject) - The created project will depend on [Mathlib](https://github.com/leanprover-community/mathlib4), the math library of Lean 4. + The created project will depend on [Mathlib](https://github.com/leanprover-community/mathlib4), the math library of Lean 4. This option is suitable if you want to use Lean 4 for a math formalization project. + To update Mathlib after creating the project, you can click the ∀-symbol in the top right and choose 'Project Actions…' > 'Project: Update Dependency…'. If you want to open an existing project, click on one of the following: -- [Download an existing project](command:lean4.project.clone) -- [Open an existing local project](command:lean4.project.open) - -After creating or downloading a project, you can open it in the future by clicking the ∀-symbol in the top right, choosing 'Open Project…' > 'Open Local Project…' and selecting the project you created. +- [Download an existing project](command:lean4.project.clone) + This option is suitable if you want to contribute to another Lean 4 project, like [Mathlib](https://github.com/leanprover-community/mathlib4). +- [Open an existing local project](command:lean4.project.open) + This option is suitable if you have been provided with a local Lean 4 project by someone else, like an instructor. ## Complex Project Setups Using its build system and package manager Lake, Lean 4 supports more complex project setups than the ones described above. You can find out more about Lake in the [Lean 4 GitHub repository](https://github.com/leanprover/lean4/blob/master/src/lake/README.md). diff --git a/vscode-lean4/media/guide-vscode.md b/vscode-lean4/media/guide-vscode.md new file mode 100644 index 000000000..52b021deb --- /dev/null +++ b/vscode-lean4/media/guide-vscode.md @@ -0,0 +1,30 @@ +## Using Lean 4 in VS Code + +**Working with multiple files** +When working on a Lean 4 file `A.lean` that imports another Lean 4 file `B.lean`, you will notice that changes to `B.lean` do not automatically appear in `A.lean`. +To make them appear, select the tab for `A.lean`, click on the ∀-symbol in the top right and select 'Server: Restart File' (Ctrl+Shift+X). +This manual interaction helps to prevent accidental and potentially expensive rebuilds of the project. + + ![Restart File](restart-file.png) + +**Inputting Unicode Symbols** +You can input Unicode symbols in Lean 4 files by typing a backslash (`\`) character followed by the name of the Unicode symbol. +For example, `\all` becomes `∀` and `\Nat` becomes `ℕ`. + +If you encounter a Unicode symbol in Lean 4 code and want to learn how to type it, you can hover over the symbol with your mouse and it will display the name of the Unicode symbol. + + ![Unicode Hover](unicode-hover.png) + +A full list of all Unicode symbol names can be found by clicking on the ∀-symbol in the top right and selecting 'Documentation…' > 'Docview: Show All Abbreviations'. + +**Navigating Lean 4 Code** +Right-clicking on any identifer will bring up the following context menu: + + ![Context Menu](context-menu.png) + +The two most important entries in this list are 'Go to Definition' and 'Find All References'. +'Go to Definition' will take you to the file that defines the identifier, whereas 'Find All References' will display all locations where the identifier is used. + +If you know the name of an identifier but are not sure where to find it, you can open the symbol search by hitting 'Ctrl+P' and typing in `#` followed by the name of the identifier. The search will bring up all identifiers containing the given name and clicking on any of the results will take you to the file where it is defined. + + ![Symbol Search](symbol-search.png) diff --git a/vscode-lean4/media/new-project-structure.png b/vscode-lean4/media/new-project-structure.png new file mode 100644 index 0000000000000000000000000000000000000000..17a3fae8195dee8a97d98c8e85405f662b4153b1 GIT binary patch literal 11649 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 literal 0 HcmV?d00001 diff --git a/vscode-lean4/media/open-local-project_show-setup_buttons.png b/vscode-lean4/media/open-local-project_show-setup_buttons.png new file mode 100644 index 0000000000000000000000000000000000000000..c79e0f536eb2a5cd3ae2cb5860a8bfcad41edfaa GIT binary patch literal 25513 zcmZsC1yoht_bm#Fgn)D-BHi5}ARyh{Af1=)5Re9u?vj%3?(PN&>F(}$o9}zS@&56K z!wcMd&pG?-z4lsj%{fnythDG`cwBfWD5$q$Up~u2LA^u*zhAt04PH4Q9{o^IFZ@h} zgk;5pgx=fOS{s>K7(zi&M0!N>e(Csx-=(7k-Q-<(4a{09hIMYh7xR) zL`%Au(9hLXidszkd(}d&T8_QlWvVydh~5{|Ne9!(uRi@048cYYzdJcxTstIqKRF;- z!KLq=GjBxo4vTqKsca9U3A-KYGt5^b9J`;4RsKCfak zOC~w{IvY)}aU7uqsL3e@jRcWP*1ta?nZbxy;=t0xbT;}UnY$U((W##i7Q<#FtU!`V z7M_6@>l6Iq1DmB67$fbCzK7cZFT@|?h#m)*ZLBopP`;@O2@4A9J(SpI0Y&Gz{l6}n7)npAC&*ZI1BP`fD6ceIqd!YQ z1fUCG$C&afdzp$fW#tAd(BSkJg|1{>cKU`W@~sbf!S`@eJeSEne6cJDvsC>MevOrGJN05=ik08zkmK4 z4*&U;*vI$z_3)+9&sX4Q=TL@xeraiC=j8cZ@q~oLTTL1&!Q2V4e-2qdm^9;#-rRhf zI5Vl})35F?Zz>`!eMnHHHLmo0;ssr*nBQ#zLWbgYc8XLnFi7BppAC%kOw~4yl#A50 zChlWeyf(@|+B{zoH=+NErP9=n=*0+(=EOaC9nBf?n2II+XFy}UDO?Ue3k%QA&rg5P zT)AEB_uZT&By%~OhA$BQGxESBi>0)8=bqact{yYFPS%g1fsF<=!Y^ULNLI-t#Kg!* zNPM-MT&HfDw3`Um7wYVO{rV{J?|lqB-ZOt&Y;v2qNeLj_mHPboGxYE#l_Fa|6%nQ7 zzN`}G0Cj1YG8LI?0-8`Q&jbhm)K8Y$bq* z&7>}0l!P;nLuNeNhs+^2D1__FW*Pc929Y7zK6!cm&+D_9nz#QfVqY;jm^Q2AoNy`g z6t=Iu2)};)vRQ8RTr+NRyUH;P!7RMF*}~o8Omle*pJm(m{XEH58NGr0F4q|YS6uP& z6wY~9LQdyV=%^fTz$Df5B~%!5dfX!N@oltq2sL?dxSYZ~-PgvBCi9ta@V8sLHb>!fP zty0G2JCv3fA@8XYAp!<)2nYogGQh>)zs87%A1>K^mNQzMlrT2 zXlNP@s-@KN{Y*Xz_`SvC_1jN4>GX6Wxf4_7|3ttAJoez= zplrc`Y`$WAf>;JY;2Vlv)@8PB@GHXQa%y(ps&)&*HyI*4u%>H;d46CK^L)!etS)f8~O96 zeB~VeaLPcs8gma-QBX~ThCG<0!}j!y!a~HVIiw=CfXvJfefY$<`QRt`?xb0RnS=N9 zbeO}xSERyt_3Gv)u^@{r_?f5pd!CR1?7>bgLZ0}91hFeWlq+v=32-xq@#MK+cdXLE zp&v#Uyd~~z(jto2YNU9`5?rv1@rMCh%#BW)roFSX^O|Eb%$a85@86WOtq}tT>|G*` z-eMHNVg^4HClwD}eSQ7=C)aIzE?YZ0O4=f?np}IO=S3F;2~4uOK8_2EkYVdSr3c$EbJ5-1UA4-L)N-ye|MaFa2+d_ZGQj%!wmY1l zRH`S0SDAc$4Rd;i$EF)Ap1tai^}Tl( z>jD)6qpPIFYV%?y*TB?tcDs5+u}HavxE6l>5^AV z=-}X4GM@)7Gc$86-9z}ne2s!;A$xI&+tneM$8dtXr1o|}aS4f?u`JjIrz5iW@4css zG|tweWR7*gzl|GHHC3rfVYh_M!ORnbP_B`RiL-%x04mnVFdsl$3SF z8>TF{Ow7z-5eAESqD%+-`@JJ0Eje^3rVtcC&8X9;dnRq?6@T12$ldvl(AF?AgJHko zqU#=Qs_QQ0T$Q<~yZcLUL$K*~Tf@JyvsZRzUwPjhHbhibvYehFm=))t!zZVtY|q!w zgI(M`lIFqY-ST)F0&XXn+bR4ViHNMGd!$$t8Ca@{?U@pKUbo9aCtN8hsRYI~hs(pi zJ@JeN3H(n6;}a8VwKl}+MX`NRvoyA(*IP6xMS#xy%1VQKIWN2sS zXCxxN&L6}hDoKY25AQW87icXcuZVAT?>r zC@W*OJX9BTyP=s$7&JH@P|(sE&R1J*U%1LED3qA$;uBL3MKb~g>@@0r&CNS zsb+E99`zxUN}Mbubb(RUG#@?YN@BBIU2YQ!v%33LAoylX7sPh=s*ne8Q_AMViJy^}j=sLE!fqy$w!;{N_NU6#Ve-Xd5$8{i5(bMp}OB9RPPT`MbT zn`38u0s^1Y9+AHb3sBA{U06GR%6#$huSzKua!Os!F!l9ux1=hcs~0Y)LZR6baeCI) z*7p`$!zuV&_JPQJ&S{1Nu}omc@9)#SLJ~EdEhh~?iedko%H;sh&CQL9x@!H!wfX50 zmWGyAt&t^h>_qI|AY9c5oyrPPMcXDzvEkYAqz+}J352n_@Rj)J= zP*>-wt8+nRc{2u;o&Eas^i)hjLKLi{k&&{23z}eH1CvdjX2$INd{jz`6a-SXUXL=9 zUt1dwa_Dn$l+k>~n)Va*RK-5q z?aKD57gg&+WfoGgi($skM`f82Z-@tq$WI^DVFpON@RQFk9OsqOUHSCAs6o+6P_s*z z*__GZFJ-As-tA47KB%m}VRqsMV#JxG|2?WTBWD`c8=o4BQ{1oiwF)(}p`qcrI;VsP z+*t3xE$=&yNlZ03;^LM;MM9L_%=}7lo2mn@SxESFO8T~0u_!gZ(cHwHT9_adKRP}m zYOs&?t*l)}ugi@N@FYzrVF$z3c_DN`)~@<4%rozJ0!SvT54k?N{wSyQgFy--Hes+9 z?M);a6^(vcw@etQ-f4D@XV+D8Iib<0kI}+;D;XjM@MrDxQA3W|Jv8~dCbsCtCjK8a zhA-TVZ`X?I{9U%V0=F%ru#Fs&c25Nq!tSJ6xT8C>qnr!k>IDY4s<}fWJY|06`Iw$; z?}d0V=TlHs*k6&ZpVcMLosc{j+Br?-pedt%)hB;ZE#J#E$gZ84O# zdmRzq<#@U7`u@PFOu%YXdCXQoSl9FuZK_T|*V9nGA5Y=Wa@xDhBy7Pr);6!OPXRc#=b#|DB_FZvZyTtQt578 z619cyaPyb16{wJ2N;!E=7a|hdX;2t9gAWVFomY=;_f0N~-;!Eip$^j!^sgZ!8BKhZ zS#THmQA_D(NuoJ={&sWlyBK0cT{-5d{%#c2wAUr69f`si=H6IpsNUrrf7xEMr{qC4 z41NMCSKNkA$82>qPm$;*a{JME`5*xfn;~Y9hG5?UOI&Gdcr?3m^vKmvV1|VTn&4tM zY4VLD$BP+f)}kH0KvsUgA9V(B3FeFM*BN`vCQcpciS0l{K}rIfmy(26bAsI;zM?F$ z&6Kv^D^5S*cQA&LSW%U_JF^6xJ;1&3^kwFbExjTYWpL8_bI$%{q1><0lK8XNvbCn@ z)ZveTI}SUIH)BLR!B^SJF-EC_H(%)z8seVA$~@InW_e#s65?dopG%yq#+(Rs*07@5 zQYY|v#u#?li!F48*zHeRMlJ<^)PtS`PP6n#X`DMGOP|PtFS>>=ejve8qIaGl#QJru zBA2uo9e>_nNK-1-L`q=8`qm7)#<$BW0ys zJS_qp$u2^8hQ~J6Fi4wJJg&Urx=y44PjQ-y7M8p1rDIxO-XusB#Hpan>M>BioGMJ> zd^_(sf!#b4$@xSWdKE*CKrOR5a^7S6mq+~~t@})lHva53t2W`A;Z<89_WU=kCl|Dy z#|dYPL!?W5)q&$FN)wW}H9i}rhqzq%=orEEC;2Zet5iLwkB;^vLB|vxQ*dgKeXin+ zdFVJQGOU+`W6VwqFcxW#eizk`?r4+mBwE*QbOr0lm|d=6@O%8_&L>Sa?sxQ~EEPZAn5+r+?u+WJfuZ3^Y>mhtC*TiiTxq2m)zQLSJ)&*jZ^BRK zM(d0bEaG&x>Y@>hJ-9SjKa@z)Ce<$3@PU_Ky&g9WDI7l}cum!Gin1qjRm{mU zKt|Z5Y=11tN=_%12myilB#A2-ZrC9%P2%k4-kS070VE2!4}V3F_2V~h`!DIvxWebD ztLbg}vA=Kljh*Gg*+0@?JnabKU~Y1=z3=4UaoTV@c_R#qNS&X-)INElrdfrGPGmt7=7e8gK{k#{^!$upm@?9E z!|?HHg`IVMR~b}^Z@aS#+y{w~jO3tepT@Ms^@Hl5L1$~)JNlGDy6&@` z+{jL&ol#6~)Z;*e$d>O)7AjO3)Fc$Am+eQv=_TewGRa7m^h-Tm`F>VX-9-W9guCG| z=cDE4^Sqs#dt*7-HZ&5yn|C+*aKqrs?S2zw2&)sQ$G{I|^Na)<&Q2=^k47~zC#Q`s z9G@vp%X!kh>MNsZuy+@J5MCF4Yq?)iVxiCj(Wtt2AWaX5O;Z;6sfoBF=Y^8G7T%Kk zd(luMkm|+7W*6epPCL8x-Rfju^+2KAQPsF)tdv^_B=Q!Qq+P)@q1)(-aTx0y&A~>0 zI!n~KyIpcIPtUCRD2LP6q3?@vGPWPH%Cc{nij_QHsNFh){N` z`$LQrqsdHSR2Hz zq*6&9BrcLC?boWHcVn#HSrZBU+6EBUw_Y`}Uai=SoW=Akn*rIvfdtW}>{;Ic{;Y9^d2 zQJ~Rz7` z@6-OV@v(POdhoMdoL{&0-aP5y3RP>n2&J!G7*D*SRj*29+f=M1qkxpFWJ*oRM`sBY zD6f4@R_6Q5&k>)`X6`~`g4_ci1LKa;KF@ysHC9Ny`DZbbcskDrP0EysJ?B*YxADqX zAD@~Nhl#qC{_^AMl#eY>B7VuwxDbNx&Gt>}eKKTfi6gffP!KD&zjr&|4V>uX4{VIy zGGiUiiH>`x@Ya&WwbF%)qOj=R+i*T9dcQt=zJEh7Nyt$TwL-LM#27~<`T%K01ppEp z7C(0$?4db&oHEu5Im<*uC?#S?QN*3UcZ}Il@Uknsl|-I5kV2U}S78NvhMzXnM2nu& z7-5vU+1>LKuim=qKZR!HecWtG3L83QtXVd2;h`l56Dk3Klos3dIyBe20vtX7A@QOTaT z9Zy~V?Y#3aD67{EN};}BK!YD&^TbZYmo4>}Bs`RG$2R~Y9gU%GcxW_uyM?N zr7Ln@w|E6LTB>auDydb(4caJ8q*lPWLv&hFZt+^R*-eO{MAG(Q3;b&yk-> zJuz)SFNyf3JDT|7oGHxL0JL*U9^uxqsgMNs(K7eBL(-3)JSZ(jZ#mR7Tuz5#N!JhZ zt`qh`4E6AtjRLYfcBO{*Rof%k7lIIP!bhZE&V4azY#~TZRgOGtyPn@ueHw5acPEdm zwWS-gu3WSE+W*%2khj{EG77mKwOk+01#f8`qni1{$DFyQ55f?07f%S4Oe1H+;9rT} zd%k!$tpN=y!KX8Vy#v?^c6T@z^Bks&7o_OqW#?O;=OmLwH*<8q&*mL(?}tZdboH%y zI=LUt=mw!~RUaJhEC=S4VMSN+hQ`+?b`<+wy9}Y8Ru64#5#zRRdGxP)#HiOvciR)vE-~Kt`+8gysr1FmsqxXqenTfEs_U+6uDCVQdt4r5VeKMsEf9H z)^?heou^k!%ije}F>&$s&d)wUL2#5(ZazUT8D5~}U2nyfKLc6;PDFgICT_w0>RK$5 z#QZU%^@Zbd&+~0L(0hmSd!IagHyg`*1*rMx*y)y1@em;oD#5KBjx13(xzp9d%*?O~ zR$-SeTZJUhbXg_ry~RDWN9C9l>npty?7hE~d$ZJb>)sdH@cmBr(h6ZE38{|;UgqaL zihQ+ytpK1x0vme&jsjhymeWwHp6XdEfy~rd`uGZq`K&jiu-6W%MsI)2@~egIzvac@ z$U`vHbRxF0Pbj07j0#0vC8XG^nXts;9KY4a9D43F=@QijB0qd4P$AlFS1hF0esB@k zTSfR0_qjL*0V_tn*w3WU@F5iupY9d1lk00ZNKILDyuZ}Rt3J>uOA)h+!vA0P77XOS z2{;gThA0}8)x+s>LkV>FSMdI;-y^8V{ZLRjSiA)@-hW(2$dU0%$;|A2sQ;C~yhO(1 zP91+K&lThBspzb#-;( z%Qn>Rw>#u4){DvG^}E~J@1 z2?)G6Ie{zGZb}5ahDePU;F9B6c9i=2`$u=+#iaSV`eO>dh>6v08WQk0qhyz_1XSc2 zWBvRoEi3z;BoUtYa|+f(mjP*N_L#~X4Q=L+V#oj$D=20^HE#CQF7XC zTKGatHqBkdL6H|U3W+)%~;XMo5e>` zd0oJy{h6P)+f`)J@p@pz!NGwlRImEUXwWSWSjU0_>b34yV~s9$(rJ7{?fxOXKvC-b z4M;^EAgnwece*a-d9B9@zNKerDfQ*cn$W+g8$lAAfE(cuKrsi&zxR{v81eeq_ z&)Xot)Ey5p%bXq5NI;oM=4KfvJadqtIMz_dt0DBOfHjRGZ&8Nm;^$dST> zYHw#NGaSH#V!?fjMg}th=-S~_UI|;w?L(YjEU)|ajMJr^z^d9 zq$?uzDzm=rv5g`;F)=X?4i2CJ4c}hinJhK)B4E+Mq$?FDfBg7y@{TnJL@gp78+!V* z{cs{{(&kW-fq{XPr{@c;di%}Qt`H7x?#S3!>ATB=+4`#cbyH(w(Ihsj`=uwTwz;`P zAT*%9d)F6)M*h3dsWb2$I+o7Y@n3y^W@k@^xi@IvgOjgsY@Eznx17xAh?*=m;+$;` z8Gv{~M@L7&<_NaiVu}a!IpE-Lu3C&M?6!*4YeqUdVE}2F>V66*oysFDCI$xuh-RRF zo%BUq0`Dux z%L^(hqHAkwHv;-ItX$#?5C?yWEGaP>54+K5-4e95tv#!Bwi8RKyk0+|qdU7ouue`- zKag#{@9XQsMtt4g(E+isNe2Y0QtV8zmImT?`41mHJckpY((MlyaQp>*;#6dS@bu-& zmro@#Gp?vycAJPHnErqk-mQ8Ih*VXLxE81MYI`=2M$pKmZJr(uOviu085tP?`ZgZW z?0_0JnXjhp34gHE+ysh`NXbmrlo_Yzy)~Gb-$gb5lhO|Z8ZMp&MBiWyD1SiLuv=+= z1$a^hM#c=FCRi-gMuKeh9LSP`ZR#~c6BP*jkF~+C5HOe5*E_e;yp&0oHR|ngxKe;h zpkwSxb$03bqe!DBb7E)Itm?C<=-SRs5MX?bM^f+a&v4f&@9*97Ux5Uyj!&1wd$;tF zjBJ|YV1Jgmd+Ffdpl^7X?a`6}yLWh6-&mz;Nh8bjo3Af)2vz_t|HR&fDv&#s=Ober z)|TGs%9S3{{>KYoz2w)}*jSLm%*Xcv85tQ!?BRsG{gEW1$5%w3z&e5gr(|_MVOG_> zBq1Te2naQbKYvsW^z`I5+_300KNVF&r@NeO@?0(0ad5J-=L~?ji4pe)oaj%HA~rn# z_R4O{kdV6&@SQ0RT3Xs6Y)vg%UZtzZ@8BAz;}Y~Qbj{4VQ+XT8%FEja2lsRKNr?S^ zw5|}!-mC;CCu^=vAj&S1j{OSyj(}BOFc<|C2SENZ8x7`FgK_f!?t8j4wR}%}O9+`) z(%rpXX(HhV%1FfsQV!7Ko>NfE(_@l~PRf^D=@bwewK*(1_WnS7Nn|nAZ}jSDYg=?4 zPvLPv1zXEtEK@i-CgvULsc@G&m$+uPgC7p;6V3Kw_kY>6ID2jBQ31v((b*WP|(WQ5(Btsn5nJ0#W0{h@ zMSc|t8NK~F0Rb6JVtE9XNhAg)eQ*&0im#{$aJofXLMj>BnxcF?i1ux zw?oc)#|s$UR__-;8WMuyIqmHLm(_s}eGb<{2UAm18nsgbpa->2Psf5$9N%o|DBfwC zno;QTBUfsYKAOp%;bx>xc+eRRZv)1mQIVO``OS; zp+-&W`nrPs?qvRSW#ippOBgM-*Mox}z!xj`H)kqRx!NVMJoTOPhw7>|@Y>{$cxd~Z?IAv?Dmq(U$)H_N_PWtEj5fz<=ZY8g|T$A6t9;Nam` z_e!u7G&Kj=m)tvU&bDSt^+*i5LygY2KWTe7pdKC`^!8C6VL}`%E%!f|0ubrwXhz8( z80Z%J55RRMImk9TE-znNn6!^_?|*e=@I}T1!AT{tW&ir+x4Np|_k-K!2?`*uP$1U! z{YdHs!twI*$rRtr-bE-j<7w(J(2xlKmK!pInpkJL2T&P-k587#)Nc%~lyES&XBRU| z3#SK;_V()l3}q_hhJ)Du85N~gVH9?fT4+90gI9;#IYi>qp%h9;@a1T+Nv*}R!(nNi z!b-Y})#*_5tD#|;(a^|GV)n6AUbjCL#t|p|9$>fPbD%gVOgq%XRDrMz2lJ03qkh2) zVVeZ35YdZ(okJ<5R2 zZm!pE0D?AFl5Qs>BV#emB&MQD1YVKg;9w4?L(S~;flmP05V{`=fOk}@c11sskocUk zgY6{)2H!PZ)bb7k!yjZXiCFi686B?WaL|%?F3V^J2SJ>|`kx9E_xVhcA(iRwxXaf}Y?2GtFMrgeMXSZ!7TTYYRdQnhz zlp`GfhDbnQW65ndpIq!qpz-~+ZjMZv_Qu$P)!+Kl!-gY9y>@C~kvZAUig+0(YWM(F zBa{HIGealFwpgz}=D8C!1p!&x45#AiS zLsrO<>{@INI%#5YZA!hqb_Twff~xM%qCE_b`+snk^z1;NadNfP16&F`z|#W26{rZH zFskqI1x3iDgLwaR6IcYYsI#jhBON_0ZISpW)M#@PEF&Z1)U?;}vH&nE6xT=k>@ULYD;a=)?MF^JJ>C+SkX=4+f~y zC#Sn|C5ByHUACbA0&SI^Uefk>HnWkD65f|R+%8s-Qo+ouY;KAO2>6suLFsM{YXK7g zfO(wu+oh1n$$F89qNCpOs#yR?G4|})ikU%}f!rytuHN4rrq}Hf91`*z(@Nu>VkRaO z0270`!zYtT{pwzb-7lKh6nz8=7_bwKny}Q?)lJpQfKi2!-xX`|&XyY@08bw99{C{= z@R;qpmX(!}k(1ZVZMnGAfxOH`#9lIR_}8s>gg(8r^arg*`_6Px0eUg_AnnfYAIk!P z-ADVgUZE{Iob8mK939!Js~s=QSo?;Cm>;!ORr#*tQc|>Hd>VFfyDq@i$(o5f_IkR) zeU7cZpGTnvz3Qm}(*fqTubUoZ*^6I@q)CuVU1lGr#@C@RJ*Xr z%=@%91OZM9quohU(10*_-q(un6mmWQ_mtAOrieFDTy9R?=N+1VMpM~1_RjsQ905@EM#Rw4ZM3DwNXv8-+H?Oa+0ftiEc-{AX zKMMH82)!El%gQ!<>$_DD-XtV!g|XWzSKDn#C$gG%AFt3)RGKOP)O2!j0h(7L zX~P``3>Cje(+VbQNMK2uY&gi(Y!byj4p!*5|}Syo!QoS&PzzT6fcY?!k4cz47e z-a4NfaikPSY89?=sVEFQMbDk^YL`9^vOwV8FGVW3d_`a%%jwr;aDw-3YwaPTe@{UX z2r%}K$jCO(YzRn8yD*>Aw-g$#cB*WHItGZ9{rQ@be*dm|hdnq%{O1xyE|aQ%vf4E@ zEjL3^Ou*%Q+>OT!dMq!TxpKpS;{QHhpx$rB>3Hf*7dpvONP>#1Z?UREfet!r|KsB# zrIJhZ9Gg8T($TP#z=m{xInTxi&?QKoobJ~Q2?+@foAYhHunEjt zyuic}7{qC^@Ce+ft2;Y=-(C?#rKOEDdw8AxF&Hw}QubKlqrn~JuwfPnr?FZE=s7YfgT zmcyKHakLnh43s5DXL{ z;F#R%7keZ3bV>r)lh4cVW71LHl54pEBd*k8F)Hu?16cL^`lA)}N5J(Pnef#I#fhGs zU8N7^pU(nsLF*DJi6TgcYDM|4ZTP<*@~>U^**W?@xkuuEt=#|R>yQ%H(>`*S!@8}H zB>!9zQuEwYUoEs~Hk3GDTOzOy!|?*Ud)8U6>*BS^%INJ&b*frDE) z8{uy-zA^-@i%hx zSoGTK$1AFhO+;S@Vr`)6osOi%`%URIYrO$&24bYABMTbTIQOf+PWZgI$gS=EI%Otf zAIPMWzqq^egkX6M0g7rHWWAgm_-6}N2z~SW_wNDj!~i|i%V+kW@wgoYgfyoERRX|F ziJ_s0b2Zi@fYB7NvZ6!g+m?cy2rC!eMg|53;!b!je?mv*Jx4L0zPGsFj}#>&qoTsK zK7tKPyScexG#UK_^3%;$nxdefU~hka{qC(Q+_P>lWd=nEAU70~T<0p<{g)$C)DdesL`&V&*E zr*8`jng#=HqZ#z+^7(a;v}~pyI5XZ(^TO&$8|aFt;TztY83oR>M+j zcvu>sw2guiOeRMQ6i__$cPA;kcL2o&co{~|duPy9J=2Bg@WQmTNT%qRn5&0}NZ#`K zzkq|Uv%6dQW-)=;IG%aS)^1kY`|CoA{o#>0&#R&95(Oa{RIU|w445v>OudDBLO>a zIll<&4O%47d6Iwy2VLZF3b*J$EbY!>6E{eHtd26yE-vrT?0&4Te+2_ySy=(x=qRX$ zP`0+V06QUrQ)P*+QPR>1XN^t9TcM%7y1RTZ-7nsrF2XxGIYGz5Qn}FvId^t;77#X& z_1<^*1WCBLQ&r7#n`ft|`ryid+I(&!tXnLZ=}NR3s<9EX!4nYAJE;{5 zp%c66I+kboQ)YCUy~Pk5Tq!g_RH`;!pH4Mvm#|-kY;A60^V8F^f?B3RN>5j$ktMgb zwkCCT_&1ams0=vWM@Gix)U>(i3JUp`))?SU2;B<#@z^Y$^E%`xICLSRrG+23i9d_P z^1lGi_COF&x92l`BO@h{=JN7#DlZ~#$57A%<^qvKGKnn)^lB;zsZmiH8@sB2{Q8&Q z0}VSiqTx*RA;=X!5)*?XB9K82!RK{FXJ=<$I|uvlq!Uf%81!b(Obx(V^sb;)+4-t< zcDtJhiV9Yhy5)VbxS{1eFFSi&Wu-l^HOrOU|CR!Y?zz<&i1pAJutl7yavwWR*8`G( zpT8wYz8zs^^UtdWky>3{1=Iy8GS6rbG%ON!iFa03mdi<(o~o+qGdm1QNYNGkvknEM z5p0bQAas6vT($Z@pKp)-txbLb{TiSx0asU7--%}HB|ecbTw#0rn<4X<{3*w;U%&o{ zit+{fqRI8*_YBis;?ZaZAjzJvV`F2%`H#1=9zrL8aUblrPC(_s`@hVV7X$X_Vwa?T z>*Mnrtp>+#wAhM@Go`JG9s56XbD7Eoaun!*UPr^{Ar$R7rTYOWLTu;)EFJgAa02e$ zHZLiGjy;RH${=4@WY+qFC`?%5PF8?yK>AtP{!=Ng(mtL&fX!+9F$9wq<~=8;Kj_<( zxdnt=*gpd|G)ROXk9_S4j+r{-k&%!9-TqNLiz#Y#b#*cav} zG9Rt4kMbv{(>wYS!t=c=il>_quaC^QjCgoS>J9t2{X<2KZbQ#cxd)OJVlB=K$r& z%>4tPN@;&G{tINLQos!2FfaZHMF|W3f6vDJFNE{Y(`f%4=KyK-8A+{n=Ru(I=Co_5 zO7t*RFMr<`1K96fU~axvxkpf;4NU6z9GaPmRAn_aJ>A`}v*ju4NINZaX7>692G+pT zLn&$7KBJnjxTK`L6e5m4fBuYS3L^kMi+VBH@CPq>r=^kE?@!tCD~E@4wB7*FWp=ya zgZxFSUiqGuHf3Rf2M*V-Rwz0aw|8KGoR*dVC@=}L8-H|O!Vz~`BH#nW0W^u6+FDiH zFM-^$5D25czklA8qteUQaD)H}lG;2wzSGk`*@^~o$14{IgJ^Gk?^l~`*4QJEuQ>hZ zA4_#Okf(3NJ@K>Uu<+mrV37fM+Iig`T4lfco@5L(La@6~PB*=1E?y2(pR8>P@=kvo$;CUicUSPqt zsSRvqCo=nR}P-s?fP3%!*l~i11H+&H^!7ZK|+>lH7Cbc7SM;;j*XvJ$x zzv;ynH~5!7eThJPb$kq_x^Yg@>>k!-MbDKPEvMbhgkcOXHht+1+9heToc35b?GJA3 zYYAkcmkkA0;=we3Jrel6kc_Ko1&HJ#b11brv@E;FCELBUCAOdJC*5eJ`m+(h;mfu-z0g!E4nIIz%UVLC{0S`w6<^P!cdL6(fO|xi z_!p;7meJxAcr}YR%G%z2OyXW$+xep2tz=|A9YslBvsqEZh)>-lCU%D1S(Byp=IKg< z$MF|-ZuOx(^TXD(GU{7#U(~eR*NpoXJOfBzL$swWwP3@vlo)lkt0HZAM-_1M{Z`2%E~Fjh_unjR^cBcu3a8?|BMNELT&;R&~w7G!#e!NJs*Q#xtZO zh~3Q*%P>f^&Fk+fj11o-%nNd!9hkh-ib+5Dus+dt&3R>XGlzn@b-TL0Ke9-m09RSR z@PU!k9!^h&>V;^I->{*}vQ2dnaA=ECJiDq(^h5EbmUM?L;yX*Jy9diGiUp!#dh2}? zOwQ~$FtIvh0&J;RUG3km&%gS5s4BRbm_N9a&7{nrmG+j*Rp_SvA6s|>DoeAUWl~pk z@HF~B4_RcL6O!Em_2VV*diQ78vlbcS{!iz&iFdIO`N@z1-F2vE8Z+J|LrVkvQvxx5 z!ou($dA%Lx#LgI@6Sh~+UUP;ZP5}kZa#J{$dCXGFOyjq-Z_K{GdfRULzNQBs`xmytw4B_EkL1e&dVBRdx($`E zqoEHF1>u{2?B=X7)EgLDu~pG-t*0wvA3gb^DJupvc2BDZ4TnY@$GgV1w>dGZ}`e~bK+r5?k{1M}|Kh{jpS0?c&+aY+mJDl+tK4#NH$=@woOc9s%dXv47yYKWr zL{idS^Q6CwzP_*(PReO-P;uFqyLh1zjEefZGJP`Ub;Oo0+)m=)`U;v2K9pGSbzbHqoPb>jY01fl))nN}NQ5B<$I8L4L-jnDsOz}~|DL#|duwT| zjcPl!Zuk1l1gzTWa~?jBFY~d#ia4ZG`O5|g5DU^%2}W4dn$rFM8p2<2pmKO1cEH!1 z{!u_PVcnE4dP-1>z^FwT)#%x01jA~IRaneYWBxn>{wgJ?PWD6cjaP?gPPz>EWyoN9H}0 zRA^PIV()@myURtb-5+bPuO1B`PZW_>S+IIpS#U0XBDnDm9S6C6& z0YQeO?np2;UR1yxyLouc|D!_&Pr+oOi9|Zb%$>`G!~Hn;aa?_3Inawp1?dS_c@aMr zv!h&Sd19hUPlYi%zfcEH$d(a3WkF~=t?T;SwxpiM?yWQx!Oj*nm86|avl^QCX05|O~8Xl45={yGqrjFudE zm|vpb%P89XjXktlb4XtBR?<8;BA4B`R+>`c5BxT+`&*XspiUtkWTX?od+ zaQS*+R?o*7ZN20SEw!jISUQsqIqXe*+e9yV0ZiGJs>|t9+Rc3WNn2{+xEL3*FudSrDUt?%^ zao;w29i3}^WlTRrdGgE5Y&9(BQg-*SCiHS>J&YeKGYzweyMNn?#8EvFMj)MA!sBud z4Bt;4aEXb{7Fu%^4iSR9P)~uEQXoy96oT+nKAjQn#XS#q07ab=iW^^|teeaAF7UfG`a%~={ ziRLx4_+%FVixelLU6!O$+RN^z!b7m~3&~QP16s70^s+zdE+*2|^a8#pXgB!VLHdjS zBvD!df-&@*A6g@L)FI=m@pqOm^qvdhR-5x;1zDLA6PW1`iW2)^C`p26@AuHR%xD-S z?u+GF(ZaFLVp2AeC@oXyV*0SIF5(Q+d!@!gRrB_#I&riin@3zUPDT9{~x)y49Q z#^RMzW&A66f5=6u46&G;m8e=lP$S7%8&7|5$I6|cXOKTwknLpGi^ptCT?+Z%01_2h-;}5Nz{zPl`qv9dTMLA)dAF<+yM5QmEmKIZbgw+n8 zh`bmrI=DK#UuJ%zrhr|5^3lOfZB8&sv93*)W!{f?IZQs!@2h-SiWzI zxZm;SY>aa`lsxGJ-F z!_BDY&fi!l@R#=|Wd`m*!raERR3$VL!J8I0M2$2&xS%u?9hi%qosa4P<;Ts^c`r&z z`5ALZO#e?|XC6&u`}J{UtVEBLLL`}@j2SW&p%6(ZgdRhZxsZ%yOrcVQBxH^wGnFAz z=43oFiwtEZW8UxS`TgFt-f6x6WLX`@eeV0Z_VwL+f4*BjPb`(s%gQ%&>cRI9mTmd$ z9A8QpZuc_E+{fy}1yUbj6yv)6vy((;=tpgwm9a}?x^#@EgDw(r_+NJN+}Z4U3-E8DS6 zkUB-);PlW^dnFhDN$${NKg)uu=4+!9m3j@;ruw{ukIjqu4_(y#xpQ#DrO#ZeL)>4W zuVQYI!`f($!SyYbYV#N|!stP)xtz{x3*uZ))a}(9aYC|>yIdC9$n`ai{TFk%TIlGE z#F|e1Yza_uXr%#6Dl$E-9k}LpsHkz5XHnn%ADYYc6QwgvHwm-8duf#--_QKW-(kvI z*AP}yl=U)Rqg(o8OtQ~hM$++0oCiz?!H)14{^5Yjm~NodaCKt^s%}6bX7oZgm5{bwI51Lh^mD5f3Vvy!W2*BRAPgt&jHpKJk*UJ2}o)ENeLUd*s53j;B%PM}ntCrqGkltWC8c z6^-H6(CNd!Dmn`{6J%v_?d4ouc=t7py9(w7+A?ij7W~@orbnC-bQ>seK725R=`W{{ zlboI(-2T!^P-?vX-fiKqLWIv=+w`faui<%up_?8uM$-LeU%n^X)$8O=fJcaaSF^mf zrhVyB+eA?q+hDNS!-g$zLm8u{g~B|TakR>L4S03(J?h-DeY^KPX^oC z%F2`2*wAOswj=iplKEJsN_pu@VT{kSi&48Ip64e}RS!sa0D;S1Cl}b<)CFez zG(7xEkNcv8;u8an9Z2{)TfCT=yQR1NX{QugiEqlL>sL?aT$?Ypo>xm(8`Z1`OGI9+ zU>LsePk~^SntCm1{(^x*&uP6@s-Mx{UNR~4G}&y(AE0$r^zliW%C$bnVH=-*-6zwD z>w=a-Pm;|CSzoF`e_=X}og=p>(pXQlm~a+s>={yi>0vpcG2CW9GHDjW%>U{Hdx9bl zvvp$3b_eNPCv+NuzIfVl+Mn~`jA5=LSbgX6Ep&asT<2i>=1~wF^5OI=tRi-IpXH))h(^6ZF}YRCsLxZQn@bX7Y9_nhl51#$q+E22IKyGf)X{Oo z(D23V(o#Iokm~Ac1G|Tq4B~M_K;U#T>?-5;V`6%pJ{-u{H8gsj(QjhHYHohsAlS~5 z-ey(L$0s(HU@gUAy9J{nUdXzIqq3xGj^D9nKDL<`<{iENpta|QK+>7~SG#`pXm07R ztJ|JK?6Kl86^~B5=UYgrSn*7uvXR?ZhsJ>=Chn6Sqe72o`Jkhh8b%1Mt4PNf`_qg& z?HcN!-Kn>m`!MeM@8Qog^;rjH=@oiPI27)oXH@JDfd1!!!+-ua;nl&br)akAU_j-d z^!hbU4h5Q7x5v`|!1Z`F8fB!{;UWI}o7~Q4x~Z3n=FYWQ<+*Ro%t5|5pVUM!>va@eWyf(_y--+7yb9L?p3sDr_b8{8lmj?sd+S{-ET1iY!Hod{m zG>P9w5x_F=ZaVw+cwz*&$c2ga2eo0Q7(&3wB4JxRH4hYWtrwG!ruzggXZxb?Wm*L6@j zW69~T6l-3eI}0Y2)<2D<_#jB=^5*7HbU3Q#M9We6X?QN|^X=OPE_4uNw)GF%q;t`A zDOw3x+1W$Ov%_RyrbXSBtVsY<;9s1QZut*4*Geg|t@J%@C540@@w~kK0%!v1MxeCX z($?mile3#dBccpR%d!`yDd7Xs&I6BC!e^$vrni`U^xaljt-&KKyv-YRRw2vtG?bK- z?`Ny!rJR3A?%A^^qk~V}`9uIc`)E$H99*4`i;GWWXP5AZiBY(@9S0}`q<20*e*G?f z8toOuQqPUglQ&Z`GAIuM8dqVv{1J`3nYlS`QPJIDwWn|05-Tr1B{Ne-t{y2834Rk( z4pP&sKJOX<`1it?aDxL-Dcm!P^|4NEG%e>)dSD7w7&S- z&*-hnSv5SM=;)KR9$4yn747ZMqN1X1Oc3olO<7Si$55H_{(g3EAeSv&U1jSl4l;{v z{e_d6@(j$(+sn}5#%6|10=@fC65M+39G8rHR^of$H2?{|He8$gR(nyG`MK0h?&72`H9n?Fe^ zoIL40GAsM5rvh!ANIBVX&<7R`fs|!6H359u-1A@5>Pan3@U;(FrQ+My7#R9YyK}?6 z=RPYA6N;&afKD!qw`S8S2GEf@g)%GOv>Rfi=~Yyyt3$nJ6kbg>;6q%>89k7s89MT_ zpcCDUx`Fb+@Hr~lv1UxC`AU(TlEQoM-f#4CAKYG_ttpx=StDT?cRWJOqp2ttNqiv>5B^>xm!Mc7WLf1mf%O zKQ|a)keZQEWg>K5TU$|8^#}(C2dD-Ng1UM&?sZZ=9o^C9fVZGi)VX(~qK=N2yT`i= zm=ZMI_Z!&NRZ~+%idOht9|efpy%e}`zxX4jG`hrJ`#_J2!r>dN9Qq&MqNXLE-3yy_%Uo6tkeYX zrA+zt1LBLTH;c}O+c=JW=2%^vRM80OV|cOpYq|#1Ck-uaWnEp6oX1vduh-_V@<_K& zsk|M(bs{Z2-ND)UV_zSePq|5?u9nta<>4T3n3z)XG@?Lm7-a z!|r468yXsZrS)yI6l-g1Gh{sMIhB!;Dy6Bdy&HhHWghdPLm&4`+Iw?7G-N%0gx@Rk z0Rs4&44cd%qb)r>Jt-+E);a{d5)V#{xl?@6N<12E#)E@{K74$99FmfOJ6XhYBLj5P zxwyIg!7Ohzv9VEfoYP~Ke;E*}$%7zq>QuS=Ot~&*IE{5QhNA7h^ke0Mei95^_Jz*9 z#ZDFV^$+l9+d4Ypc(-GrKaGeWADGHac>n$$u0AR{y2UEbrnp{Po1S6sUjKOBi1n!W z%*@0dE;Y96PC}d4yT@8gXJ%&5H;M$CDs0zhxRso|wzg>Q@+_$jC1$ycN8^R%;`*yo zeretB+C!D^xSQ^ z&&nc*>h3yB(5PyylMRB-saI4=YQNGw# zxS5KH7cMtF+*n@+2*?|xaP=xjg})NWf`SDNPy}Ig2TtVjxglgDn%qlCkp`Oi5yR8) z+y({*%dy}D2rNP-WF;jfFlq?jxg{1E*^d+Hw0<`SoG&Eom`p=M(|GR_qM8d zrpL>^mLS$5Cn!`p^Jkc4rA`?8p2Aw7#2nAyVjBwQko^a``ZI5m=AV?|(f|3)E|MOF z_ALK{Xfd$bmZ_#+d}Fx6ZI!p0)X)#3o7eg<`_K4e3=H{~CI*K}37y63;Ua`8h^>9N zZ9Cm!p@$1@NEEyX2@Ev(z3vKOg7|?0oEEEui|@LGMb1ibQ@xqU+v}|s6O)r(olX;2 z)1ac0K*JycIRfG6^K@%Gm)Z~hV-WtRbV7- zyRX}mEl<4@_?JNvJ@vomzU@2V{Nqz~aCGL{`!8RY?v|KI_qumjWDl82viLV11t zd{SHbhYzwIs|)33B7+kXK~M!v=7w@zSEdJC-r{G{@API}t$;pxOA(OnfzK7_%*yI{ z!PuBI#*I+2%3L4*p)xtvQ&~xg5(rRbr8+n77(G6(+@?EItjE%RvZf{y-w?cod{x`n zxEbmKOt%2q_}u*bJG{%vPJ%J7#+iTSOc!bTUMhi5LnPh@3dFGMbHIcZCk{Bug9zy= z>>K=KySdd5%D4+TIP4(9ji#le3jrq_qi5tAIZ|)TBQM{dO$R`*u;@Ah>}d}VS!jJ= zXru8ysrS3O#%VF(adq_$qzmWq<9oaT;fOj-Fk;oInwxWN+qR8WHmdeZq8BHg4;tIB zV*!DXeT-w1s8@Gu|WcvL~{NS#o0qk61d zFx2T0etsA?WQoK(^$Soo@d@l@kOahQv2Sna9U_CjmqOZQ%513ezNHxRXj4o8fgmVq zQAt8IL4e+#%+Ntb5%!pKdSpB~Hvj3$LaW*e%)sNH<2aEGS`(jmD<=Rojl4D4vC|vx z_7svGo`kBIL6-#H?JzhB7?+Uvi%WgUV8%i`y>SgdTqJLe34v011wDvurW{<%l+f}C zIt+T|(W4nQgmv`2g>1UTpdCW<@`8R?%i6u4_5Y!R26djZY;_!5Fi>C6ky}XULvZlU zhFJC*ZOx6~cT=mJkU3=PF()XI(uiI=7Am_W2}ZiD?c&D@YU5ioJ2<(x@*3R%RH>UM z-o+E1!=%YCKU zXjykd4)zhNv@_sA3kG&}P3s@GaO`w+bRgGyPAE~esD2npaz%mPh=Y4@@}_{(UyO{W zVcOhSr8KDH=i|G+o0-g?cK=6`c>{*8eIjO`?7H_x@WbfJHnu3G9?Mog+Gubo%j8tL z!_Jr!uA(keGA~_6FHehq1Z!j6IZa$WDLwB?yfL%EWrH z1hxth`+mwn7e7Hv5GLnsfLBYsK4os_AdzwzT&2f`5vYuWii0ues&i5>j zHF07BDQ)htrt;as#B{CxuGiQ6pE!bDU8UZ+c%3pcJAC9>(C5$R<<{-_^YZebcCD9#&T?>t?z?Kw%;O@)D2~R3BV_uY3=D5FHv25MZvaqqAoXs?%g#kN}Phb#eX zikWyfhbp&$sF<0ZElRSnPZYs+gMFghT09IhT=7v6|FYFJRaN7QiXw3}Po6xf^WL&? zwDn2YFL2PB5Y`x)iSsT0>0%X=@h&V52vLAta1&m>BOk)nXf3K-WhUaVV95>jig~a{ zjvRsgrgUi4?|-WExp*7%!%|Yj?2La@BA%{4DZ1DXoJ0*le*L_F8zUGHLT@M?NTrK< zdc!|{_#*65`IL)f#K&(9uHHjUO^y4>D@d?h>_g5EZ7`1UpF!~^V$6KUY(Ly|`A^lo zQb+dxt8TB~+4Y&c+mSpBgKHfGF>eZJ6sxq0A@EoSQv1BTs*QE+%w6}QWuU)&!UdkHhU-p-tTJ}P)A_)}I^hwh00nY8!{&hgr zd_B7$F)eL-2Br;Ki|HCOQt%_wHgh#JT=yBV%jnpNnT5K95Ida!P~oqW*uLR{FoE$t z))zRaew*-COc;eo)~|j7_8cv|%tB8naEukmUo|W$EClx|Q16~<;{>Ku_s#7v`At_= zm?lkztAi1=`P}x9$}!Q2a2W%ne2jJ2-F<>lsl2f}>q0({D}?|l&k6&1{RH`^zX6MQY0Hu?7H@$EZzj3lK? z7QD;Tj`$?1{T`aRcshfobcX>I*XxX(9AVE6$lb`3#$^d$OT;d#U~ zHO_TGyw%mIs%@-y=WqSg*f>)3{Ur~q5O9=ZPJ%i!3yXR4A>TrC8L_J}csd2n_V&)s zq;a|=|L61PW>Vzx$g@a(P1rOF3k!wZm+cY!9wI1!ImScFb{JO1+O@a0AAod(p=zd} zRMrnd(vQi=T2wHs_K!nMXplqPwgkU0%NR5swIAf>9|BCZ($t@i3s4 ze~}i(u?#9z)ES!L{W<|SAQp-)*vuO3Q9`YyE?31jiqS)%D!5mjQI2T@m~VQzgM}wKZ}S6 z(9f{w%Hl;(F~$4{JQ0%j2gOxZxfe~Kqt9w;s%SkGpYF62Lyl%59*sfFF6jh5hz6Vu zJG>Kl26^CAg>Uo;QVdH=%Y(4};X(6v1Sco+1P2FS)YYAls3Ec^4g9Xb;1}jzwJUh@b$MLQh z((4cAP|L_j1MwI`;@j_TkPu-WxHrD+F~%5XF!O;}&~hG8{{B?;caI={1jPRwdZ+#r zucYMj%E}JCBPkaIoe_L7y+lhNPlk<#xZ$}~!Fud0Ns_wc{H*35<+20&%O*Pa02_WKd2j67ZUTZq0+ zW*-f_y{wNv32}w=Hv$quGi5$&CAX4tCmcMf>FK1w9i?j@P9edt$obO`@x1i!+{M@O zJEjwW_p3&Toue;IdwW2EX7FE0%cA6&(m(Uy|66hUzf`)R=$VRw{*{Hq0V=*hL9L{f zl^?FoaoWwoCZl+0XBB?4KSe-P6f?4_-e3G64bMPmd2s=o+8dc=ntG0sT>^L z9QbogsnhWn8_3QoX`IefFuC_1*wdZv literal 0 HcmV?d00001 diff --git a/vscode-lean4/media/restart-file.png b/vscode-lean4/media/restart-file.png new file mode 100644 index 0000000000000000000000000000000000000000..f2849164e47dc70bff42c474b85063e36ba3e00d GIT binary patch literal 8971 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 literal 0 HcmV?d00001 diff --git a/vscode-lean4/media/show-output.png b/vscode-lean4/media/show-output.png new file mode 100644 index 0000000000000000000000000000000000000000..070cbe83950bf66c1abf186235cb9d0e306769d7 GIT binary patch literal 21713 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 literal 0 HcmV?d00001 diff --git a/vscode-lean4/media/symbol-search.png b/vscode-lean4/media/symbol-search.png new file mode 100644 index 0000000000000000000000000000000000000000..54aa8af7f60e4d0feac89efd34df963acaa1ad6c GIT binary patch literal 25900 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 z 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 BOR@j} literal 0 HcmV?d00001 diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index 368e93181..f1febabfe 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -723,13 +723,13 @@ }, "walkthroughs": [ { - "id": "guide.linux", + "id": "lean4.welcome.linux", "title": "Lean 4 Setup", "description": "Getting started with Lean 4 on Linux\n", "when": "isLinux", "steps": [ { - "id": "guide.linux.openSetupGuide", + "id": "lean4.welcome.linux.openSetupGuide", "title": "Re-Open Setup Guide", "description": "This guide can always be re-opened by opening an empty file, clicking on the ∀-symbol in the top right and selecting 'Documentation…' > 'Setup: Show Setup Guide'.", "media": { @@ -738,31 +738,37 @@ } }, { - "id": "guide.linux.documentation", + "id": "lean4.welcome.linux.documentation", "title": "Books and Documentation", "description": "Learn using Lean 4 with the resources on the right.", "media": { "markdown": "./media/guide-documentation.md" } }, { - "id": "guide.linux.installDeps", + "id": "lean4.welcome.linux.installDeps", "title": "Install Required Dependencies", "description": "Install Git and curl using your package manager.", "media": { "markdown": "./media/guide-installDeps-linux.md" } }, { - "id": "guide.linux.installElan", + "id": "lean4.welcome.linux.installElan", "title": "Install Lean Version Manager", "description": "Install Lean's version manager Elan.\n[Click to install](command:lean4.setup.installElan)", "media": { "markdown": "./media/guide-installElan-unix.md" } }, { - "id": "guide.linux.setupProject", + "id": "lean4.welcome.linux.setupProject", "title": "Set Up Lean 4 Project", "description": "Set up a Lean 4 project by clicking on one of the options on the right.", "media": { "markdown": "./media/guide-setupProject.md" } }, { - "id": "guide.linux.help", + "id": "lean4.welcome.linux.vscode", + "title": "Using Lean 4 in VS Code", + "description": "Learn how to use Lean 4 together with its VS Code extension.", + "media": { "markdown": "./media/guide-vscode.md" } + }, + { + "id": "lean4.welcome.linux.help", "title": "Questions and Troubleshooting", "description": "If you have any questions or are having trouble with any of the previous steps, please visit us on the [Lean Zulip chat](https://leanprover.zulipchat.com/) so that we can help you.", "media": { "markdown": "./media/guide-help.md" } @@ -770,13 +776,13 @@ ] }, { - "id": "guide.mac", + "id": "lean4.welcome.mac", "title": "Lean 4 Setup", "description": "Getting started with Lean 4 on Mac\n", "when": "isMac", "steps": [ { - "id": "guide.mac.openSetupGuide", + "id": "lean4.welcome.mac.openSetupGuide", "title": "Re-Open Setup Guide", "description": "This guide can always be re-opened by opening an empty file, clicking on the ∀-symbol in the top right and selecting 'Documentation…' > 'Setup: Show Setup Guide'.", "media": { @@ -785,31 +791,37 @@ } }, { - "id": "guide.mac.documentation", + "id": "lean4.welcome.mac.documentation", "title": "Books and Documentation", "description": "Learn using Lean 4 with the resources on the right.", "media": { "markdown": "./media/guide-documentation.md" } }, { - "id": "guide.mac.installDeps", + "id": "lean4.welcome.mac.installDeps", "title": "Install Required Dependencies", "description": "Install Homebrew, Git and curl.", "media": { "markdown": "./media/guide-installDeps-mac.md" } }, { - "id": "guide.mac.installElan", + "id": "lean4.welcome.mac.installElan", "title": "Install Lean Version Manager", "description": "Install Lean's version manager Elan.\n[Click to install](command:lean4.setup.installElan)", "media": { "markdown": "./media/guide-installElan-unix.md" } }, { - "id": "guide.mac.setupProject", + "id": "lean4.welcome.mac.setupProject", "title": "Set Up Lean 4 Project", "description": "Set up a Lean 4 project by clicking on one of the options on the right.", "media": { "markdown": "./media/guide-setupProject.md" } }, { - "id": "guide.mac.help", + "id": "lean4.welcome.mac.vscode", + "title": "Using Lean 4 in VS Code", + "description": "Learn how to use Lean 4 together with its VS Code extension.", + "media": { "markdown": "./media/guide-vscode.md" } + }, + { + "id": "lean4.welcome.mac.help", "title": "Questions and Troubleshooting", "description": "If you have any questions or are having trouble with any of the previous steps, please visit us on the [Lean Zulip chat](https://leanprover.zulipchat.com/) so that we can help you.", "media": { "markdown": "./media/guide-help.md" } @@ -817,13 +829,13 @@ ] }, { - "id": "guide.windows", + "id": "lean4.welcome.windows", "title": "Lean 4 Setup", "description": "Getting started with Lean 4 on Windows\n", "when": "isWindows", "steps": [ { - "id": "guide.windows.openSetupGuide", + "id": "lean4.welcome.windows.openSetupGuide", "title": "Re-Open Setup Guide", "description": "This guide can always be re-opened by opening an empty file, clicking on the ∀-symbol in the top right and selecting 'Documentation…' > 'Setup: Show Setup Guide'.", "media": { @@ -832,31 +844,37 @@ } }, { - "id": "guide.windows.documentation", + "id": "lean4.welcome.windows.documentation", "title": "Books and Documentation", "description": "Learn using Lean 4 with the resources on the right.", "media": { "markdown": "./media/guide-documentation.md" } }, { - "id": "guide.windows.installDeps", + "id": "lean4.welcome.windows.installDeps", "title": "Install Required Dependencies", "description": "Install Git.", "media": { "markdown": "./media/guide-installDeps-windows.md" } }, { - "id": "guide.windows.installElan", + "id": "lean4.welcome.windows.installElan", "title": "Install Lean Version Manager", "description": "Install Lean's version manager Elan.\n[Click to install](command:lean4.setup.installElan)", "media": { "markdown": "./media/guide-installElan-windows.md" } }, { - "id": "guide.windows.setupProject", + "id": "lean4.welcome.windows.setupProject", "title": "Set Up Lean 4 Project", "description": "Set up a Lean 4 project by clicking on one of the options on the right.", "media": { "markdown": "./media/guide-setupProject.md" } }, { - "id": "guide.windows.help", + "id": "lean4.welcome.windows.vscode", + "title": "Using Lean 4 in VS Code", + "description": "Learn how to use Lean 4 together with its VS Code extension.", + "media": { "markdown": "./media/guide-vscode.md" } + }, + { + "id": "lean4.welcome.windows.help", "title": "Questions and Troubleshooting", "description": "If you have any questions or are having trouble with any of the previous steps, please visit us on the [Lean Zulip chat](https://leanprover.zulipchat.com/) so that we can help you.", "media": { "markdown": "./media/guide-help.md" } diff --git a/vscode-lean4/src/extension.ts b/vscode-lean4/src/extension.ts index 07f06ab2c..c37988e45 100644 --- a/vscode-lean4/src/extension.ts +++ b/vscode-lean4/src/extension.ts @@ -67,13 +67,13 @@ function activateAlwaysEnabledFeatures(context: ExtensionContext): AlwaysEnabled context.subscriptions.push(commands.registerCommand('lean4.setup.showSetupGuide', async () => { if (process.platform === 'win32') { - await commands.executeCommand('workbench.action.openWalkthrough', 'leanprover.lean4#guide.windows', false) + await commands.executeCommand('workbench.action.openWalkthrough', 'leanprover.lean4#lean4.welcome.windows', false) } else if (process.platform === 'darwin') { - await commands.executeCommand('workbench.action.openWalkthrough', 'leanprover.lean4#guide.mac', false) + await commands.executeCommand('workbench.action.openWalkthrough', 'leanprover.lean4#lean4.welcome.mac', false) } else if (process.platform === 'linux') { - await commands.executeCommand('workbench.action.openWalkthrough', 'leanprover.lean4#guide.linux', false) + await commands.executeCommand('workbench.action.openWalkthrough', 'leanprover.lean4#lean4.welcome.linux', false) } else { - await commands.executeCommand('workbench.action.openWalkthrough', 'leanprover.lean4#guide.linux', false) + await commands.executeCommand('workbench.action.openWalkthrough', 'leanprover.lean4#lean4.welcome.linux', false) } })) From 61b60a54c17d7176dc94d40f462eee008d1c8b6e Mon Sep 17 00:00:00 2001 From: mhuisi Date: Mon, 27 Nov 2023 11:55:34 +0100 Subject: [PATCH 38/70] Release 0.0.120 --- vscode-lean4/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index f1febabfe..ee0b5ae7d 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -2,7 +2,7 @@ "name": "lean4", "displayName": "lean4", "description": "Lean 4 language support for VS Code", - "version": "0.0.119", + "version": "0.0.120", "publisher": "leanprover", "engines": { "vscode": "^1.75.0" From ccb1e34c040bbdb589d3bbb665a0b8c4d477c3c2 Mon Sep 17 00:00:00 2001 From: Marc Huisinga Date: Mon, 27 Nov 2023 14:43:31 +0100 Subject: [PATCH 39/70] fix: open setup guide after installation (#365) --- vscode-lean4/package.json | 134 +++++++--------------------------- vscode-lean4/src/extension.ts | 13 +--- 2 files changed, 27 insertions(+), 120 deletions(-) diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index ee0b5ae7d..62eb127c5 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -723,13 +723,12 @@ }, "walkthroughs": [ { - "id": "lean4.welcome.linux", + "id": "lean4.welcome", "title": "Lean 4 Setup", - "description": "Getting started with Lean 4 on Linux\n", - "when": "isLinux", + "description": "Getting started with Lean 4\n", "steps": [ { - "id": "lean4.welcome.linux.openSetupGuide", + "id": "lean4.welcome.openSetupGuide", "title": "Re-Open Setup Guide", "description": "This guide can always be re-opened by opening an empty file, clicking on the ∀-symbol in the top right and selecting 'Documentation…' > 'Setup: Show Setup Guide'.", "media": { @@ -738,143 +737,60 @@ } }, { - "id": "lean4.welcome.linux.documentation", + "id": "lean4.welcome.documentation", "title": "Books and Documentation", "description": "Learn using Lean 4 with the resources on the right.", "media": { "markdown": "./media/guide-documentation.md" } }, { - "id": "lean4.welcome.linux.installDeps", + "id": "lean4.welcome.installDeps.linux", "title": "Install Required Dependencies", "description": "Install Git and curl using your package manager.", - "media": { "markdown": "./media/guide-installDeps-linux.md" } + "media": { "markdown": "./media/guide-installDeps-linux.md" }, + "when": "isLinux" }, { - "id": "lean4.welcome.linux.installElan", - "title": "Install Lean Version Manager", - "description": "Install Lean's version manager Elan.\n[Click to install](command:lean4.setup.installElan)", - "media": { "markdown": "./media/guide-installElan-unix.md" } - }, - { - "id": "lean4.welcome.linux.setupProject", - "title": "Set Up Lean 4 Project", - "description": "Set up a Lean 4 project by clicking on one of the options on the right.", - "media": { "markdown": "./media/guide-setupProject.md" } - }, - { - "id": "lean4.welcome.linux.vscode", - "title": "Using Lean 4 in VS Code", - "description": "Learn how to use Lean 4 together with its VS Code extension.", - "media": { "markdown": "./media/guide-vscode.md" } - }, - { - "id": "lean4.welcome.linux.help", - "title": "Questions and Troubleshooting", - "description": "If you have any questions or are having trouble with any of the previous steps, please visit us on the [Lean Zulip chat](https://leanprover.zulipchat.com/) so that we can help you.", - "media": { "markdown": "./media/guide-help.md" } - } - ] - }, - { - "id": "lean4.welcome.mac", - "title": "Lean 4 Setup", - "description": "Getting started with Lean 4 on Mac\n", - "when": "isMac", - "steps": [ - { - "id": "lean4.welcome.mac.openSetupGuide", - "title": "Re-Open Setup Guide", - "description": "This guide can always be re-opened by opening an empty file, clicking on the ∀-symbol in the top right and selecting 'Documentation…' > 'Setup: Show Setup Guide'.", - "media": { - "image": "media/open-setup-guide.png", - "altText": "Click on the ∀-symbol in the top right and select 'Documentation…' > 'Setup: Show Setup Guide'." - } - }, - { - "id": "lean4.welcome.mac.documentation", - "title": "Books and Documentation", - "description": "Learn using Lean 4 with the resources on the right.", - "media": { "markdown": "./media/guide-documentation.md" } + "id": "lean4.welcome.installDeps.mac", + "title": "Install Required Dependencies", + "description": "Install Homebrew, Git and curl.", + "media": { "markdown": "./media/guide-installDeps-mac.md" }, + "when": "isMac" }, { - "id": "lean4.welcome.mac.installDeps", + "id": "lean4.welcome.installDeps.windows", "title": "Install Required Dependencies", - "description": "Install Homebrew, Git and curl.", - "media": { "markdown": "./media/guide-installDeps-mac.md" } + "description": "Install Git.", + "media": { "markdown": "./media/guide-installDeps-windows.md" }, + "when": "isWindows" }, { - "id": "lean4.welcome.mac.installElan", + "id": "lean4.welcome.installElan.unix", "title": "Install Lean Version Manager", "description": "Install Lean's version manager Elan.\n[Click to install](command:lean4.setup.installElan)", - "media": { "markdown": "./media/guide-installElan-unix.md" } - }, - { - "id": "lean4.welcome.mac.setupProject", - "title": "Set Up Lean 4 Project", - "description": "Set up a Lean 4 project by clicking on one of the options on the right.", - "media": { "markdown": "./media/guide-setupProject.md" } - }, - { - "id": "lean4.welcome.mac.vscode", - "title": "Using Lean 4 in VS Code", - "description": "Learn how to use Lean 4 together with its VS Code extension.", - "media": { "markdown": "./media/guide-vscode.md" } - }, - { - "id": "lean4.welcome.mac.help", - "title": "Questions and Troubleshooting", - "description": "If you have any questions or are having trouble with any of the previous steps, please visit us on the [Lean Zulip chat](https://leanprover.zulipchat.com/) so that we can help you.", - "media": { "markdown": "./media/guide-help.md" } - } - ] - }, - { - "id": "lean4.welcome.windows", - "title": "Lean 4 Setup", - "description": "Getting started with Lean 4 on Windows\n", - "when": "isWindows", - "steps": [ - { - "id": "lean4.welcome.windows.openSetupGuide", - "title": "Re-Open Setup Guide", - "description": "This guide can always be re-opened by opening an empty file, clicking on the ∀-symbol in the top right and selecting 'Documentation…' > 'Setup: Show Setup Guide'.", - "media": { - "image": "media/open-setup-guide.png", - "altText": "Click on the ∀-symbol in the top right and select 'Documentation…' > 'Setup: Show Setup Guide'." - } - }, - { - "id": "lean4.welcome.windows.documentation", - "title": "Books and Documentation", - "description": "Learn using Lean 4 with the resources on the right.", - "media": { "markdown": "./media/guide-documentation.md" } - }, - { - "id": "lean4.welcome.windows.installDeps", - "title": "Install Required Dependencies", - "description": "Install Git.", - "media": { "markdown": "./media/guide-installDeps-windows.md" } + "media": { "markdown": "./media/guide-installElan-unix.md" }, + "when": "isLinux || isMac" }, { - "id": "lean4.welcome.windows.installElan", + "id": "lean4.welcome.installElan.windows", "title": "Install Lean Version Manager", "description": "Install Lean's version manager Elan.\n[Click to install](command:lean4.setup.installElan)", - "media": { "markdown": "./media/guide-installElan-windows.md" } + "media": { "markdown": "./media/guide-installElan-windows.md" }, + "when": "isWindows" }, { - "id": "lean4.welcome.windows.setupProject", + "id": "lean4.welcome.setupProject", "title": "Set Up Lean 4 Project", "description": "Set up a Lean 4 project by clicking on one of the options on the right.", "media": { "markdown": "./media/guide-setupProject.md" } }, { - "id": "lean4.welcome.windows.vscode", + "id": "lean4.welcome.vscode", "title": "Using Lean 4 in VS Code", "description": "Learn how to use Lean 4 together with its VS Code extension.", "media": { "markdown": "./media/guide-vscode.md" } }, { - "id": "lean4.welcome.windows.help", + "id": "lean4.welcome.help", "title": "Questions and Troubleshooting", "description": "If you have any questions or are having trouble with any of the previous steps, please visit us on the [Lean Zulip chat](https://leanprover.zulipchat.com/) so that we can help you.", "media": { "markdown": "./media/guide-help.md" } diff --git a/vscode-lean4/src/extension.ts b/vscode-lean4/src/extension.ts index c37988e45..f4d98abb8 100644 --- a/vscode-lean4/src/extension.ts +++ b/vscode-lean4/src/extension.ts @@ -65,17 +65,8 @@ function activateAlwaysEnabledFeatures(context: ExtensionContext): AlwaysEnabled addDefaultElanPath(); } - context.subscriptions.push(commands.registerCommand('lean4.setup.showSetupGuide', async () => { - if (process.platform === 'win32') { - await commands.executeCommand('workbench.action.openWalkthrough', 'leanprover.lean4#lean4.welcome.windows', false) - } else if (process.platform === 'darwin') { - await commands.executeCommand('workbench.action.openWalkthrough', 'leanprover.lean4#lean4.welcome.mac', false) - } else if (process.platform === 'linux') { - await commands.executeCommand('workbench.action.openWalkthrough', 'leanprover.lean4#lean4.welcome.linux', false) - } else { - await commands.executeCommand('workbench.action.openWalkthrough', 'leanprover.lean4#lean4.welcome.linux', false) - } - })) + context.subscriptions.push(commands.registerCommand('lean4.setup.showSetupGuide', async () => + commands.executeCommand('workbench.action.openWalkthrough', 'leanprover.lean4#lean4.welcome', false))) const docView = new DocViewProvider(context.extensionUri); context.subscriptions.push(docView); From 063edd173bf63dafb5340bc8dc2ac49b56977c99 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Mon, 27 Nov 2023 14:44:15 +0100 Subject: [PATCH 40/70] Release 0.0.121 --- vscode-lean4/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index 62eb127c5..09d18dfd2 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -2,7 +2,7 @@ "name": "lean4", "displayName": "lean4", "description": "Lean 4 language support for VS Code", - "version": "0.0.120", + "version": "0.0.121", "publisher": "leanprover", "engines": { "vscode": "^1.75.0" From 940658e27d273371918f8c5e82b9cf7ae740971d Mon Sep 17 00:00:00 2001 From: Wojciech Nawrocki Date: Thu, 7 Dec 2023 11:26:50 -0500 Subject: [PATCH 41/70] chore: bump @leanprover/infoview (#372) --- lean4-infoview/package-lock.json | 4 ++-- lean4-infoview/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lean4-infoview/package-lock.json b/lean4-infoview/package-lock.json index 439677801..c73aec8a1 100644 --- a/lean4-infoview/package-lock.json +++ b/lean4-infoview/package-lock.json @@ -1,12 +1,12 @@ { "name": "@leanprover/infoview", - "version": "0.4.3", + "version": "0.4.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@leanprover/infoview", - "version": "0.4.3", + "version": "0.4.4", "license": "Apache-2.0", "dependencies": { "@vscode/codicons": "^0.0.32", diff --git a/lean4-infoview/package.json b/lean4-infoview/package.json index ce8ac00db..afb03848b 100644 --- a/lean4-infoview/package.json +++ b/lean4-infoview/package.json @@ -1,6 +1,6 @@ { "name": "@leanprover/infoview", - "version": "0.4.3", + "version": "0.4.4", "description": "An interactive display for the Lean 4 theorem prover.", "scripts": { "watch": "rollup --config --environment NODE_ENV:development --watch", From 9a70ded67215a5c27186b13db1889ce4f6677711 Mon Sep 17 00:00:00 2001 From: Hunter Monroe Date: Thu, 7 Dec 2023 11:32:45 -0500 Subject: [PATCH 42/70] doc: clarify which folder to run npm in (#367) * Update dev.md lerna commands are outdated (and still not working) * Update docs/dev.md --------- Co-authored-by: Wojciech Nawrocki --- docs/dev.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/dev.md b/docs/dev.md index 44c08cddb..b6efd1f06 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -14,7 +14,7 @@ See the following design topics: ### Building - Make sure you have an up to date installation of `npm` and `node.js`. For example `npm` version 8.1.3 and `node.js` version v16.13.0. -- Run `npm install` in this folder. This installs the Lerna package manager. +- Run `npm install` in your workspace root folder. This installs the Lerna package manager. - Run `npx lerna bootstrap`. This sets up the project's dependencies. - Run `npx lerna run build`. This compiles the extension (which is necessary for go-to-definition in VS Code). From 23c9571ea6e1893bf64617900f9f987818021203 Mon Sep 17 00:00:00 2001 From: Wojciech Nawrocki Date: Wed, 20 Dec 2023 10:09:10 +0100 Subject: [PATCH 43/70] Support snippet edits in code actions and workspace edits (#375) * feat: support extended WorkspaceEdit * chore: lint * chore: comment --- .eslintrc.js | 2 +- lean4-infoview/src/infoview/messages.tsx | 4 +- vscode-lean4/src/utils/converters.ts | 94 +++++++++++++++++++++--- 3 files changed, 87 insertions(+), 13 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 2b9c136c0..3d62910a3 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -61,7 +61,7 @@ module.exports = { "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-misused-new": "error", "@typescript-eslint/no-unused-vars": "off", - "@typescript-eslint/no-namespace": "error", + "@typescript-eslint/no-namespace": "off", "@typescript-eslint/no-parameter-properties": "off", "@typescript-eslint/no-inferrable-types": "off", "@typescript-eslint/no-use-before-define": "off", diff --git a/lean4-infoview/src/infoview/messages.tsx b/lean4-infoview/src/infoview/messages.tsx index 97fa034a2..398153302 100644 --- a/lean4-infoview/src/infoview/messages.tsx +++ b/lean4-infoview/src/infoview/messages.tsx @@ -175,8 +175,8 @@ function AllMessagesBody({uri, messages, setNumDiags}: AllMessagesBodyProps) { setNumDiags(msgs.length) } void fn() - }, [messages]) - React.useEffect(() => () => /* Called on unmount. */ setNumDiags(undefined), []) + }, [messages, setNumDiags]) + React.useEffect(() => () => /* Called on unmount. */ setNumDiags(undefined), [setNumDiags]) if (msgs === undefined) return <>Loading messages... else return } diff --git a/vscode-lean4/src/utils/converters.ts b/vscode-lean4/src/utils/converters.ts index 85a11d433..e6998cd4c 100644 --- a/vscode-lean4/src/utils/converters.ts +++ b/vscode-lean4/src/utils/converters.ts @@ -10,42 +10,116 @@ * @module */ -import { createConverter as createP2CConverter } from 'vscode-languageclient/lib/common/protocolConverter'; -import { createConverter as createC2PConverter } from 'vscode-languageclient/lib/common/codeConverter'; +import { createConverter as createP2CConverter } from 'vscode-languageclient/lib/common/protocolConverter' +import { createConverter as createC2PConverter } from 'vscode-languageclient/lib/common/codeConverter' +import * as async from 'vscode-languageclient/lib/common/utils/async' import * as ls from 'vscode-languageserver-protocol' import * as code from 'vscode' -import { Code2ProtocolConverter, Protocol2CodeConverter } from 'vscode-languageclient'; +import { Code2ProtocolConverter, Protocol2CodeConverter } from 'vscode-languageclient' interface Lean4Diagnostic extends ls.Diagnostic { fullRange: ls.Range; } +interface SnippetTextEdit extends ls.TextEdit { + leanExtSnippet: { value: string } +} + +namespace SnippetTextEdit { + export function is(value: any): value is SnippetTextEdit { + if (!ls.TextEdit.is(value)) return false + if (!('leanExtSnippet' in value)) return false + const snip = value.leanExtSnippet + if (snip === null || typeof snip !== 'object') return false + if (!('value' in snip)) return false + if (typeof snip.value !== 'string' && !(snip.value instanceof String)) return false + return true + } +} + export const p2cConverter = createP2CConverter(undefined, true, true) export const c2pConverter = createC2PConverter(undefined) export function patchConverters(p2cConverter: Protocol2CodeConverter, c2pConverter: Code2ProtocolConverter) { // eslint-disable-next-line @typescript-eslint/unbound-method - const oldAsDiagnostic = p2cConverter.asDiagnostic + const oldP2cAsDiagnostic = p2cConverter.asDiagnostic p2cConverter.asDiagnostic = function (protDiag: Lean4Diagnostic): code.Diagnostic { if (!protDiag.message) { // Fixes: Notification handler 'textDocument/publishDiagnostics' failed with message: message must be set protDiag.message = ' '; } - const diag = oldAsDiagnostic.apply(this, [protDiag]) + const diag = oldP2cAsDiagnostic.apply(this, [protDiag]) diag.fullRange = p2cConverter.asRange(protDiag.fullRange) return diag } - p2cConverter.asDiagnostics = async (diags) => diags.map(d => p2cConverter.asDiagnostic(d)) - + // The original definition refers to `asDiagnostic` as a local function + // rather than as a member of `Protocol2CodeConverter`, + // so we need to overwrite it, too. + p2cConverter.asDiagnostics = async (diags, token) => async.map(diags, d => p2cConverter.asDiagnostic(d), token) // eslint-disable-next-line @typescript-eslint/unbound-method - const c2pAsDiagnostic = c2pConverter.asDiagnostic + const oldC2pAsDiagnostic = c2pConverter.asDiagnostic c2pConverter.asDiagnostic = function (diag: code.Diagnostic & {fullRange: code.Range}): Lean4Diagnostic { - const protDiag = c2pAsDiagnostic.apply(this, [diag]) + const protDiag = oldC2pAsDiagnostic.apply(this, [diag]) protDiag.fullRange = c2pConverter.asRange(diag.fullRange) return protDiag } - c2pConverter.asDiagnostics = async (diags) => diags.map(d => c2pConverter.asDiagnostic(d)) + c2pConverter.asDiagnostics = async (diags, token) => async.map(diags, d => c2pConverter.asDiagnostic(d), token) + + // eslint-disable-next-line @typescript-eslint/unbound-method + const oldP2CAsWorkspaceEdit = p2cConverter.asWorkspaceEdit + p2cConverter.asWorkspaceEdit = async function (item: ls.WorkspaceEdit | null | undefined, token?: code.CancellationToken) { + if (item === undefined || item === null) return undefined + if (item.documentChanges) { + // 1. Preprocess `documentChanges` by filtering out snippet edits + // which we support as a Lean-specific extension. + // 2. Create a `WorkspaceEdit` using the default function + // which does not take snippet edits into account. + // 3. Append the snippet edits. + // Note that this may permute the relative ordering of snippet edits and text edits, + // so users cannot rely on it; + // but a mix of both doesn't seem to work in VSCode anyway as of 1.84.2. + const snippetChanges: [code.Uri, code.SnippetTextEdit[]][] = [] + const documentChanges = await async.map(item.documentChanges, change => { + if (!ls.TextDocumentEdit.is(change)) return true + const uri = code.Uri.parse(change.textDocument.uri) + const snippetEdits: code.SnippetTextEdit[] = [] + const edits = change.edits.filter(edit => { + if (!SnippetTextEdit.is(edit)) return true + const range = p2cConverter.asRange(edit.range) + snippetEdits.push( + new code.SnippetTextEdit( + range, + new code.SnippetString(edit.leanExtSnippet.value))) + return false + }) + snippetChanges.push([uri, snippetEdits]) + return { ...change, edits } + }, token) + const newItem = { ...item, documentChanges } + const result: code.WorkspaceEdit = await oldP2CAsWorkspaceEdit.apply(this, [newItem, token]) + for (const [uri, snippetEdits] of snippetChanges) + result.set(uri, snippetEdits) + return result + } + return oldP2CAsWorkspaceEdit.apply(this, [item, token]) + } + + // eslint-disable-next-line @typescript-eslint/unbound-method + const oldP2cAsCodeAction = p2cConverter.asCodeAction + p2cConverter.asCodeAction = async function (item: ls.CodeAction | null | undefined, token?: code.CancellationToken) { + if (item === undefined || item === null) return undefined + if (item.edit || item.diagnostics) { + const result: code.CodeAction = await oldP2cAsCodeAction.apply(this, [item, token]) + if (item.diagnostics !== undefined) result.diagnostics = await p2cConverter.asDiagnostics(item.diagnostics, token) + if (item.edit) result.edit = await p2cConverter.asWorkspaceEdit(item.edit, token) + } + return oldP2cAsCodeAction.apply(this, [item, token]) + } + + // Note: as of 2023-12-10, there is no c2pConverter.asWorkspaceEdit. + // This is possibly because code.WorkspaceEdit supports features + // that cannot be encoded in ls.WorkspaceEdit. } patchConverters(p2cConverter, c2pConverter) From a09d19a78fd3d1c9409505164b610cf36edff7e7 Mon Sep 17 00:00:00 2001 From: Wojciech Nawrocki Date: Thu, 21 Dec 2023 14:23:46 +0100 Subject: [PATCH 44/70] feat: optional user widget names (#376) * feat: optional user widget names * chore: fix doc --- lean4-infoview-api/src/rpcApi.ts | 5 +++-- lean4-infoview/src/infoview/info.tsx | 23 ++++++++++++++++------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/lean4-infoview-api/src/rpcApi.ts b/lean4-infoview-api/src/rpcApi.ts index 61f602a26..55835eb1c 100644 --- a/lean4-infoview-api/src/rpcApi.ts +++ b/lean4-infoview-api/src/rpcApi.ts @@ -153,8 +153,9 @@ export function getGoToLocation(rs: RpcSessionAtPos, kind: GoToKind, info: InfoW export interface UserWidget { id: string; - /** Pretty user name. */ - name: string; + /** Newer widget APIs do not send this. + * In previous versions, it used to be a user-readable name to show in a title bar. */ + name?: string; /** A hash (provided by Lean) of the widgetSource's sourcetext. * This is used to look up the WidgetSource object. */ diff --git a/lean4-infoview/src/infoview/info.tsx b/lean4-infoview/src/infoview/info.tsx index 1b577a5df..0c797e9d8 100644 --- a/lean4-infoview/src/infoview/info.tsx +++ b/lean4-infoview/src/infoview/info.tsx @@ -130,13 +130,22 @@ const InfoDisplayContent = React.memo((props: InfoDisplayContentProps) => { initiallyOpen={config.showExpectedType} displayCount={false} togglingAction='toggleExpectedType' /> - {userWidgets.map(widget => -
- {widget.name} - -
- )} + {userWidgets.map(widget => { + const inner = + + if (widget.name) + return
+ {widget.name} + {inner} +
+ else + return inner + })}
Messages ({messages.length}) From 00724db3dbed7c038a3448fda7da33856c1de776 Mon Sep 17 00:00:00 2001 From: Marc Huisinga Date: Fri, 22 Dec 2023 15:42:37 +0100 Subject: [PATCH 45/70] fix: windows tests (#380) --- vscode-lean4/package-lock.json | 14 +++++++------- vscode-lean4/package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/vscode-lean4/package-lock.json b/vscode-lean4/package-lock.json index 61afc0e16..372bf47f3 100644 --- a/vscode-lean4/package-lock.json +++ b/vscode-lean4/package-lock.json @@ -1,12 +1,12 @@ { "name": "lean4", - "version": "0.0.118", + "version": "0.0.121", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "lean4", - "version": "0.0.118", + "version": "0.0.121", "license": "Apache-2.0", "dependencies": { "axios": "^1.6.2", @@ -25,7 +25,7 @@ "@types/semver": "^7.5.4", "@types/vscode": "^1.61.0", "@types/vscode-webview": "^1.57.0", - "@vscode/test-electron": "^2.1.2", + "@vscode/test-electron": "^2.3.8", "@vscode/vsce": "~2.21.1", "concurrently": "^7.0.0", "copy-webpack-plugin": "^10.2.4", @@ -267,15 +267,15 @@ "dev": true }, "node_modules/@vscode/test-electron": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.3.3.tgz", - "integrity": "sha512-hgXCkDP0ibboF1K6seqQYyHAzCURgTwHS/6QU7slhwznDLwsRwg9bhfw1CZdyUEw8vvCmlrKWnd7BlQnI0BC4w==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.3.8.tgz", + "integrity": "sha512-b4aZZsBKtMGdDljAsOPObnAi7+VWIaYl3ylCz1jTs+oV6BZ4TNHcVNC3xUn0azPeszBmwSBDQYfFESIaUQnrOg==", "dev": true, "dependencies": { "http-proxy-agent": "^4.0.1", "https-proxy-agent": "^5.0.0", "jszip": "^3.10.1", - "semver": "^7.3.8" + "semver": "^7.5.2" }, "engines": { "node": ">=16" diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index 09d18dfd2..ac6ca766c 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -837,7 +837,7 @@ "@types/semver": "^7.5.4", "@types/vscode": "^1.61.0", "@types/vscode-webview": "^1.57.0", - "@vscode/test-electron": "^2.1.2", + "@vscode/test-electron": "^2.3.8", "@vscode/vsce": "~2.21.1", "concurrently": "^7.0.0", "copy-webpack-plugin": "^10.2.4", From 17116780cbd58313455dba4756fbbb6bc9b8dcb3 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Fri, 22 Dec 2023 16:29:38 +0100 Subject: [PATCH 46/70] Release 0.0.122 --- vscode-lean4/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index ac6ca766c..196414b9c 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -2,7 +2,7 @@ "name": "lean4", "displayName": "lean4", "description": "Lean 4 language support for VS Code", - "version": "0.0.121", + "version": "0.0.122", "publisher": "leanprover", "engines": { "vscode": "^1.75.0" From 8d8c17e41996a0108accfe6f0aebf288d45e9ce3 Mon Sep 17 00:00:00 2001 From: Marc Huisinga Date: Fri, 22 Dec 2023 17:16:26 +0100 Subject: [PATCH 47/70] chore: change name of 'rebuild imports' button (#381) --- vscode-lean4/src/leanclient.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vscode-lean4/src/leanclient.ts b/vscode-lean4/src/leanclient.ts index 90915c566..c5f72263c 100644 --- a/vscode-lean4/src/leanclient.ts +++ b/vscode-lean4/src/leanclient.ts @@ -119,8 +119,8 @@ export class LeanClient implements Disposable { return } - const message = `Imports of '${fileName}' are out of date and must be rebuilt.` - const input = 'Rebuild Imports' + const message = `Imports of '${fileName}' are out of date and must be rebuilt. Restarting the file will rebuild them.` + const input = 'Restart File' const choice = await window.showInformationMessage(message, input) if (choice !== input) { return From 918b6c70e46639bf72129e7fc74362d8a05efc97 Mon Sep 17 00:00:00 2001 From: Marc Huisinga Date: Fri, 22 Dec 2023 18:32:52 +0100 Subject: [PATCH 48/70] feat: display modal warning before updating project (#382) --- vscode-lean4/src/projectoperations.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/vscode-lean4/src/projectoperations.ts b/vscode-lean4/src/projectoperations.ts index 0af237276..b9e2c9b6b 100644 --- a/vscode-lean4/src/projectoperations.ts +++ b/vscode-lean4/src/projectoperations.ts @@ -114,7 +114,6 @@ export class ProjectOperationProvider implements Disposable { const activeClient: LeanClient | undefined = this.clientProvider.getActiveClient() if (!activeClient) { void window.showErrorMessage('No active client.') - this.isRunningOperation = false return } @@ -155,6 +154,13 @@ export class ProjectOperationProvider implements Disposable { return } + const warningMessage = `This command will update ${dependencyChoice.name} to its most recent version. It is only intended to be used by maintainers of this project. If the updated version of ${dependencyChoice.name} is incompatible with any other dependency or the code in this project, this project may not successfully build anymore. Are you sure you want to proceed?` + const warningInput = 'Proceed' + const warningChoice = await window.showWarningMessage(warningMessage, { modal: true }, warningInput) + if (warningChoice !== warningInput) { + return + } + await this.runOperation(async lakeRunner => { const result: ExecutionResult = await lakeRunner.updateDependency(dependencyChoice.name) if (result.exitCode === ExecutionExitCode.Cancelled) { From 9fcdd00b22baacb3f7457547f3153296636ec827 Mon Sep 17 00:00:00 2001 From: David Thrane Christiansen Date: Tue, 9 Jan 2024 09:42:38 +0100 Subject: [PATCH 49/70] feat: themeable infoview colors (#370) Adds support for user-modifiable colors in the infoview for proof states. These colors can also be set in VS Code themes. --- README.md | 12 ++++ lean4-infoview/src/infoview/index.css | 20 ++---- vscode-lean4/package.json | 88 ++++++++++++++++++++++++--- 3 files changed, 96 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index d4c7dc22e..36075c8de 100644 --- a/README.md +++ b/README.md @@ -209,6 +209,18 @@ name of the relative path to the store the logs. * `lean4.infoview.reverseTacticState`: show each goal above its local context by default. This can also be toggled by clicking a button (see the Infoview panel description above). The default is `false`. +#### Colors + +These colors are used to display proof states in the infoview: + +* `lean4.infoView.hypothesisName`: accessible hypothesis names +* `lean4.infoView.inaccessibleHypothesisName`: inaccessible hypothesis names +* `lean4.infoView.goalCount`: the number of goals +* `lean4.infoView.turnstile`: the turnstile (⊢) that separates the hypotheses from the goal +* `lean4.infoView.caseLabel`: case labels (e.g. `case zero`) + +They can be set in a color theme, or under `workbench.colorCustomizations` in the settings file. + ## Extension commands This extension also contributes the following commands, which can be bound to keys if desired using the [VS Code keyboard bindings](https://code.visualstudio.com/docs/getstarted/keybindings). diff --git a/lean4-infoview/src/infoview/index.css b/lean4-infoview/src/infoview/index.css index 14a5225d8..e6d3899e1 100644 --- a/lean4-infoview/src/infoview/index.css +++ b/lean4-infoview/src/infoview/index.css @@ -30,27 +30,17 @@ html,body { } /* These are syntax highlights for the string goal view. */ -.goal-goals { color: #569cd6; } -.goal-vdash { color: #569cd6; } -.goal-case { color: #a1df90; } -.goal-hyp { color: #ffcc00; } +.goal-goals { color: var(--vscode-lean4-infoView\.goalCount); } +.goal-vdash { color: var(--vscode-lean4-infoView\.turnstile); } +.goal-case { color: var(--vscode-lean4-infoView\.caseLabel); } +.goal-hyp { color: var(--vscode-lean4-infoView\.hypothesisName); } .goal-inaccessible { - color: var(--vscode-editor-foreground); + color: var(--vscode-lean4-infoView\.inaccessibleHypothesisName); opacity: 0.7; font-style: italic; font-weight: normal; } -.vscode-light .goal-goals { color: #367cb6; } -.vscode-light .goal-vdash { color: #367cb6; } -.vscode-light .goal-case { color: #1f7a1f; } -.vscode-light .goal-hyp { color: #cc7a00; } - -.vscode-high-contrast .goal-goals { color: var(--vscode-terminal-ansiBlue); } -.vscode-high-contrast .goal-vdash { color: var(--vscode-terminal-ansiBlue); } -.vscode-high-contrast .goal-case { color: var(--vscode-terminal-ansiGreen); } -.vscode-high-contrast .goal-hyp { color: var(--vscode-terminal-ansiYellow); } - /* Used to denote text highlighted by the pretty-print expression widget. */ .highlightable { border-radius: 2pt; diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index 196414b9c..60e6a99be 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -436,6 +436,58 @@ "when": "lean4.isLeanFeatureSetActive" } ], + "colors": [ + { + "id": "lean4.infoView.hypothesisName", + "description": "The color used to display hypothesis names in the infoview", + "defaults": { + "light": "#cc7a00", + "dark": "#ffcc00", + "highContrast": "foreground", + "highContrastLight": "foreground" + } + }, + { + "id": "lean4.infoView.inaccessibleHypothesisName", + "description": "The color used to display inaccessible hypothesis names in the infoview", + "defaults": { + "light": "editor.foreground", + "dark": "editor.foreground", + "highContrast": "editor.foreground", + "highContrastLight": "editor.foreground" + } + }, + { + "id": "lean4.infoView.goalCount", + "description": "The color used to display the goal count in the infoview (e.g. \"1 goal\")", + "defaults": { + "light": "#367cb6", + "dark": "#569cd6", + "highContrast": "terminal.ansiBlue", + "highContrastLight": "terminal.ansiBlue" + } + }, + { + "id": "lean4.infoView.turnstile", + "description": "The color used to display the turnstile (⊢) in the infoview", + "defaults": { + "light": "#367cb6", + "dark": "#569cd6", + "highContrast": "terminal.ansiBlue", + "highContrastLight": "terminal.ansiBlue" + } + }, + { + "id": "lean4.infoView.caseLabel", + "description": "The color used to display the names of individual proof cases in the infoview", + "defaults": { + "light": "#1f7a1f", + "dark": "#a1df90", + "highContrast": "terminal.ansiGreen", + "highContrastLight": "terminal.ansiGreen" + } + } + ], "menus": { "commandPalette": [ { @@ -740,60 +792,78 @@ "id": "lean4.welcome.documentation", "title": "Books and Documentation", "description": "Learn using Lean 4 with the resources on the right.", - "media": { "markdown": "./media/guide-documentation.md" } + "media": { + "markdown": "./media/guide-documentation.md" + } }, { "id": "lean4.welcome.installDeps.linux", "title": "Install Required Dependencies", "description": "Install Git and curl using your package manager.", - "media": { "markdown": "./media/guide-installDeps-linux.md" }, + "media": { + "markdown": "./media/guide-installDeps-linux.md" + }, "when": "isLinux" }, { "id": "lean4.welcome.installDeps.mac", "title": "Install Required Dependencies", "description": "Install Homebrew, Git and curl.", - "media": { "markdown": "./media/guide-installDeps-mac.md" }, + "media": { + "markdown": "./media/guide-installDeps-mac.md" + }, "when": "isMac" }, { "id": "lean4.welcome.installDeps.windows", "title": "Install Required Dependencies", "description": "Install Git.", - "media": { "markdown": "./media/guide-installDeps-windows.md" }, + "media": { + "markdown": "./media/guide-installDeps-windows.md" + }, "when": "isWindows" }, { "id": "lean4.welcome.installElan.unix", "title": "Install Lean Version Manager", "description": "Install Lean's version manager Elan.\n[Click to install](command:lean4.setup.installElan)", - "media": { "markdown": "./media/guide-installElan-unix.md" }, + "media": { + "markdown": "./media/guide-installElan-unix.md" + }, "when": "isLinux || isMac" }, { "id": "lean4.welcome.installElan.windows", "title": "Install Lean Version Manager", "description": "Install Lean's version manager Elan.\n[Click to install](command:lean4.setup.installElan)", - "media": { "markdown": "./media/guide-installElan-windows.md" }, + "media": { + "markdown": "./media/guide-installElan-windows.md" + }, "when": "isWindows" }, { "id": "lean4.welcome.setupProject", "title": "Set Up Lean 4 Project", "description": "Set up a Lean 4 project by clicking on one of the options on the right.", - "media": { "markdown": "./media/guide-setupProject.md" } + "media": { + "markdown": "./media/guide-setupProject.md" + } }, { "id": "lean4.welcome.vscode", "title": "Using Lean 4 in VS Code", "description": "Learn how to use Lean 4 together with its VS Code extension.", - "media": { "markdown": "./media/guide-vscode.md" } + "media": { + "markdown": "./media/guide-vscode.md" + } }, { "id": "lean4.welcome.help", "title": "Questions and Troubleshooting", "description": "If you have any questions or are having trouble with any of the previous steps, please visit us on the [Lean Zulip chat](https://leanprover.zulipchat.com/) so that we can help you.", - "media": { "markdown": "./media/guide-help.md" } + "media": { + "markdown": "./media/guide-help.md" + } } ] } From ceccfe7232234836e32488e074ed8273043b5c77 Mon Sep 17 00:00:00 2001 From: David Thrane Christiansen Date: Tue, 9 Jan 2024 10:01:37 +0100 Subject: [PATCH 50/70] feat: customizable occurrence highlighting (#377) Makes it possible to disable substring-based occurrence highlighting and use only Lean's compiler responses. --- README.md | 2 ++ vscode-lean4/package.json | 5 +++++ vscode-lean4/src/config.ts | 4 ++++ vscode-lean4/src/leanclient.ts | 10 +++++++--- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 36075c8de..1cd5f2df7 100644 --- a/README.md +++ b/README.md @@ -191,6 +191,8 @@ name of the relative path to the store the logs. * `lean4.typesInCompletionList`: controls whether the types of all items in the list of completions are displayed. By default, only the type of the highlighted item is shown. +* `lean4.fallBackToStringOccurrenceHighlighting`: controls whether the editor should fall back to string-based occurrence highlighting when there are no symbol occurrences found. + ### Infoview settings * `lean4.infoview.autoOpen`: controls whether the Infoview is automatically displayed when the Lean extension is activated for the first time in a given VS Code workspace(`true` by default). If you manually close the Infoview it will stay closed for that workspace until. You can then open it again using the Ctrl+Shift+P `Lean 4: Infoview: Display Goal` command. diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index 60e6a99be..073a3067f 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -64,6 +64,11 @@ "default": true, "markdownDescription": "Enable eager replacement of abbreviations that uniquely identify a symbol." }, + "lean4.fallBackToStringOccurrenceHighlighting": { + "type": "boolean", + "description": "Fall back to string-based occurrence highlighting when there are no semantic symbol occurrences from the Lean language server to highlight.", + "default": false + }, "lean4.automaticallyBuildDependencies": { "type": "boolean", "default": false, diff --git a/vscode-lean4/src/config.ts b/vscode-lean4/src/config.ts index 339e327bf..b457c3835 100644 --- a/vscode-lean4/src/config.ts +++ b/vscode-lean4/src/config.ts @@ -227,6 +227,10 @@ export function shouldShowInvalidProjectWarnings(): boolean { return workspace.getConfiguration('lean4').get('showInvalidProjectWarnings', true) } +export function getFallBackToStringOccurrenceHighlighting(): boolean { + return workspace.getConfiguration('lean4').get('fallBackToStringOccurrenceHighlighting', false) +} + export function getLeanExecutableName(): string { if (process.platform === 'win32') { return 'lean.exe' diff --git a/vscode-lean4/src/leanclient.ts b/vscode-lean4/src/leanclient.ts index c5f72263c..cb43e548f 100644 --- a/vscode-lean4/src/leanclient.ts +++ b/vscode-lean4/src/leanclient.ts @@ -17,7 +17,7 @@ import { } from 'vscode-languageclient/node' import * as ls from 'vscode-languageserver-protocol' -import { toolchainPath, lakePath, addServerEnvPaths, serverArgs, serverLoggingEnabled, serverLoggingPath, shouldAutofocusOutput, getElaborationDelay, lakeEnabled, automaticallyBuildDependencies } from './config' +import { toolchainPath, lakePath, addServerEnvPaths, serverArgs, serverLoggingEnabled, serverLoggingPath, shouldAutofocusOutput, getElaborationDelay, lakeEnabled, automaticallyBuildDependencies, getFallBackToStringOccurrenceHighlighting } from './config' import { assert } from './utils/assert' import { LeanFileProgressParams, LeanFileProgressProcessingInfo, ServerStoppedReason } from '@leanprover/infoview-api'; import { ExecutionExitCode, ExecutionResult, batchExecute } from './utils/batch' @@ -635,8 +635,12 @@ export class LeanClient implements Disposable { const leanHighlights = await next(doc, pos, ctok); if (leanHighlights?.length) return leanHighlights; - // vscode doesn't fall back to textual highlights, - // so we need to do that manually + // vscode doesn't fall back to textual highlights, so we + // need to do that manually if the user asked for it + if (!getFallBackToStringOccurrenceHighlighting()) { + return []; + } + await new Promise((res) => setTimeout(res, 250)); if (ctok.isCancellationRequested) return; From 3422d8eab27c1185d187a85559d181dfa64d42f5 Mon Sep 17 00:00:00 2001 From: Marc Huisinga Date: Tue, 9 Jan 2024 10:21:17 +0100 Subject: [PATCH 51/70] doc: remove unused changelog (#383) --- CHANGELOG.md | 104 -------------------------------------- vscode-lean4/CHANGELOG.md | 3 -- 2 files changed, 107 deletions(-) delete mode 100644 CHANGELOG.md delete mode 100644 vscode-lean4/CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 2fca12b98..000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,104 +0,0 @@ -# Changelog - -### 0.0.41 - -- Read "lean-toolchain" files and do not set --default-toolchain to something specific. -- elan should not install multiple toolchains. - -### 0.0.40 (Oct 21, 2021): c387eab150b988a47956192b0fc48e950f6c1fca - -- Improved error handling when Lean language server fails to start. -- Fix InfoView stops updating afer "Lean 4: Restart Server" command. -- Update project to npm version 8.1.0. - -### 0.0.39 (Oct 20, 2021): 6510b32473fe589f0a1c36d7fc12d77a6956ea05 - -- Fix LeanDiagnostic type. - -### 0.0.38 (Oct 20, 2021): ec38311418c92a95dfd8895bc28470140617a3c0 - -- Enable auto-install via elan. -- Report output from `lean --version` because that may result in a long running "downloading lean" session so this output helps explain to the user why the big delay and what if anything went wrong. -- Read Lean version from the leanpkg.toml file. -- addDefaultElanPath so PATH environment is not needed. -- Add support for pre-term goal Lean versions. -- Add info-on-hover widgets. -- Fix debugging of infoview source code. - -### 0.0.36 (Oct 5, 2021): b88795134ba938d285bd896c33225f366fa46eed - -- Remove begin / end from the brackets section of the language config. -- Add logging to abbreviation rewriter so we can catch any future flakiness... -- Infoview should not be so aggressive about reopening all the time, and should not open on markdown files. -- Fix data loss in RPC. -- Show language server errors in popup -- Infoview now stays closed if user closes it - -### 0.0.35 (Sep 29, 2021): 0ecaef8f7801928c217ceaabf22735bb57747aef - -- add 'Lean 4: Select Interpreter' so user can enter a path that is workspace specific. -- auto open of Infoview should only happen once per vscode session. -- auto open of Infoview should not happen on markdown files. - -### 0.0.33 (Jul 17, 2021): d5f1926be34e73af23d551be779a5b98e721e0ba - -- New Infoview package -- Fix bug in collapsing state -- Add copyToComment command - -### 0.0.31 (Jun 7, 2021): 0d834ab33bc8fb8a7627912519edf2f9ab9fc083 - -- map \. to cdot - -### 0.0.30 (Jun 4, 2021): 40a07756b9c35bd974566dc65961b57ce5e0e7fd - -- Fix duplicate timer events - -### 0.0.29 (Jun 4, 2021) -- Adds support for term mode goals. Discussion at [leanprover/lean4#504](https://github.com/leanprover/lean4/issues/504). - -### 0.0.26 - 0.0.28 (May 26, 2021) -- Adds an option `lean4.elaborationDelay` to configure the delay after which the Lean 4 server starts elaborating with all accumulated changes. - -### 0.0.10 - 0.0.25 (Apr 28, 2021) -- Adds the options `lean4.serverEnvPaths` and `lean4.serverEnv` for adding environment variables and PATH components to the Lean 4 server environment. - -### 0.0.7 - 0.0.9 (Mar 11, 2021) -- Ports the current [vscode-lean](https://github.com/leanprover/vscode-lean) infoview to vscode-lean4. Removes the `lean4.plainInfoView.toggleAutoUpdate` command and adds the following configuration options and commands: - - Configuration options: - - `lean4.infoViewAllErrorsOnLine` - - `lean4.infoViewAutoOpen` - - `lean4.infoViewAutoOpenShowGoal` - - `lean4.infoViewStyle` - - `lean4.infoViewFilterIndex` - - Commands: - - `lean4.displayGoal` (Ctrl+Shift+Enter) - - `lean4.displayList` (Ctrl+Shift+Alt+Enter) - - `lean4.infoView.copyToComment` - - `lean4.infoView.toggleStickyPosition` - - `lean4.infoView.toggleUpdating` - -### 0.0.3 - 0.0.6 (Feb 12, 2021) -- Implements a very basic infoview to display plaintext Lean 4 goals with basic highlighting. Includes a command `lean4.plainInfoView.toggleAutoUpdate` (Ctrl+Shift+T). - -### 0.0.2 (Jan 26, 2021) -- Ports the rewrite of the abbreviation feature from [vscode-lean](https://github.com/leanprover/vscode-lean) to vscode-lean4. A discussion can be found at [leanprover/vscode-lean#240](https://github.com/leanprover/vscode-lean/pull/240). - -### 0.0.1 (Jan 19, 2021) -- Ports previous barebones version of vscode-lean4 to start its history on top of [vscode-lean](https://github.com/leanprover/vscode-lean) for easier porting of PRs of vscode-lean to vscode-lean4. Includes the following features: - - An LSP client - - Support for Unicode abbreviations as taken from vscode-lean - - A Lean 4 syntax declaration - - A compatibility layer to enable users to install both vscode-lean and vscode-lean4 despite the file suffix conflict (see discussion in [leanprover/vscode-lean#253](https://github.com/leanprover/vscode-lean/pull/253)) - - The following configuration options: - - `lean4.executablePath` - - `lean4.input.enabled` - - `lean4.input.customTranslations` - - `lean4.input.languages` - - `lean4.input.leader` - - `lean4.serverLogging.enabled` - - `lean4.serverLogging.path` - - The following commands: - - `lean4.restartServer` - - `lean4.input.convert` (Tab) - - `lean4.refreshFileDependencies` (Ctrl+Shift+X) diff --git a/vscode-lean4/CHANGELOG.md b/vscode-lean4/CHANGELOG.md deleted file mode 100644 index 717e4c971..000000000 --- a/vscode-lean4/CHANGELOG.md +++ /dev/null @@ -1,3 +0,0 @@ -# Change Log - -Changes are listed in the [README](./README.md). From b3e8da84bc860ba4c2841f67cc29f5b0bfe94cba Mon Sep 17 00:00:00 2001 From: mhuisi Date: Tue, 9 Jan 2024 10:25:12 +0100 Subject: [PATCH 52/70] Release 0.0.123 --- vscode-lean4/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index 073a3067f..3288544d8 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -2,7 +2,7 @@ "name": "lean4", "displayName": "lean4", "description": "Lean 4 language support for VS Code", - "version": "0.0.122", + "version": "0.0.123", "publisher": "leanprover", "engines": { "vscode": "^1.75.0" From a4f66b50dc3145234e8b44e68935daf8506cefd7 Mon Sep 17 00:00:00 2001 From: Marc Huisinga Date: Mon, 15 Jan 2024 11:50:45 +0100 Subject: [PATCH 53/70] feat: more syntactic highlighting for sorry-like identifiers (#384) --- vscode-lean4/syntaxes/lean4.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-lean4/syntaxes/lean4.json b/vscode-lean4/syntaxes/lean4.json index cff18ecb3..ac982f24a 100644 --- a/vscode-lean4/syntaxes/lean4.json +++ b/vscode-lean4/syntaxes/lean4.json @@ -11,7 +11,7 @@ "match": "\\b(? Date: Mon, 15 Jan 2024 11:50:59 +0100 Subject: [PATCH 54/70] doc: move description of dependencies to the front (#385) --- vscode-lean4/media/guide-installDeps-linux.md | 10 +++++----- vscode-lean4/media/guide-installDeps-mac.md | 10 +++++----- vscode-lean4/media/guide-installDeps-windows.md | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/vscode-lean4/media/guide-installDeps-linux.md b/vscode-lean4/media/guide-installDeps-linux.md index ab4c7a3b0..8903b74b3 100644 --- a/vscode-lean4/media/guide-installDeps-linux.md +++ b/vscode-lean4/media/guide-installDeps-linux.md @@ -1,3 +1,8 @@ +## Dependencies Needed by Lean 4 +[Git](https://git-scm.com/) is a commonly used [Version Control System](https://en.wikipedia.org/wiki/Version_control) that is used by Lean to help manage different versions of Lean formalization packages and software packages. + +[curl](https://curl.se/) is a small tool to transfer data that is used by Lean to download files when managing Lean formalization packages and software packages. + ## Installing Required Dependencies 1. [Open a new terminal](command:workbench.action.terminal.new). 2. Depending on your Linux distribution, do one of the following to install Git and curl using your package manager: @@ -7,11 +12,6 @@ 3. When prompted, type in your login credentials. 4. Wait until the installation has completed. -## Dependencies Needed by Lean 4 -[Git](https://git-scm.com/) is a commonly used [Version Control System](https://en.wikipedia.org/wiki/Version_control) that is used by Lean to help manage different versions of Lean formalization packages and software packages. - -[curl](https://curl.se/) is a small tool to transfer data that is used by Lean to download files when managing Lean formalization packages and software packages. - ## Restricted Environments If you are in an environment where you cannot install Git or curl, for example a restricted university computer, you can check if you already have them installed by [opening a new terminal](command:workbench.action.terminal.new), typing in `which git curl` and pressing Enter. If the terminal output displays two file paths and no error, you already have them installed. diff --git a/vscode-lean4/media/guide-installDeps-mac.md b/vscode-lean4/media/guide-installDeps-mac.md index ced471a93..eb20fa902 100644 --- a/vscode-lean4/media/guide-installDeps-mac.md +++ b/vscode-lean4/media/guide-installDeps-mac.md @@ -1,3 +1,8 @@ +## Dependencies Needed by Lean 4 +[Git](https://git-scm.com/) is a commonly used [Version Control System](https://en.wikipedia.org/wiki/Version_control) that is used by Lean to help manage different versions of Lean formalization packages and software packages. + +[curl](https://curl.se/) is a small tool to transfer data that is used by Lean to download files when managing Lean formalization packages and software packages. + ## Installing Required Dependencies 1. [Open a new terminal](command:workbench.action.terminal.new). 2. Type in `/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"` and press Enter to install [Homebrew](https://brew.sh/), a package manager for macOS. @@ -5,11 +10,6 @@ 4. Type in `brew install curl git` and press Enter. 5. Wait until the installation has completed. -## Dependencies Needed by Lean 4 -[Git](https://git-scm.com/) is a commonly used [Version Control System](https://en.wikipedia.org/wiki/Version_control) that is used by Lean to help manage different versions of Lean formalization packages and software packages. - -[curl](https://curl.se/) is a small tool to transfer data that is used by Lean to download files when managing Lean formalization packages and software packages. - ## Restricted Environments If you are in an environment where you cannot install Homebrew, Git or curl, for example a restricted university computer, you can check if you already have them installed by [opening a new terminal](command:workbench.action.terminal.new), typing in `which git curl` and pressing Enter. If the terminal output displays two file paths and no error, you already have them installed. diff --git a/vscode-lean4/media/guide-installDeps-windows.md b/vscode-lean4/media/guide-installDeps-windows.md index a411f735a..4fafa6b10 100644 --- a/vscode-lean4/media/guide-installDeps-windows.md +++ b/vscode-lean4/media/guide-installDeps-windows.md @@ -1,9 +1,9 @@ ## Installing Required Dependencies +[Git](https://git-scm.com/) is a commonly used [Version Control System](https://en.wikipedia.org/wiki/Version_control) that is used by Lean to help manage different versions of Lean formalization packages and software packages. + 1. Install [Git](https://git-scm.com/download/win). You can keep all settings in the installer at their default values. 2. Wait until the installation has completed. 3. Restart VS Code and re-open this guide. -[Git](https://git-scm.com/) is a commonly used [Version Control System](https://en.wikipedia.org/wiki/Version_control) that is used by Lean to help manage different versions of Lean formalization packages and software packages. - ## Restricted Environments If you are in an environment where you cannot install Git and it is not already installed, for example on a restricted university computer, there is currently no option to try Lean 4 with a local installation. If you want to try out Lean 4 regardless, you can read [Mathematics in Lean](https://leanprover-community.github.io/mathematics_in_lean/) and do the exercises with [an online instance of Lean 4 hosted using Gitpod](https://gitpod.io/#/https://github.com/leanprover-community/mathematics_in_lean). Doing so requires creating a GitHub account. Alternatively, you can also [play the Natural Number Game](https://adam.math.hhu.de/#/g/hhu-adam/NNG4) or [try a single-file version of Lean 4 in your web browser](https://live.lean-lang.org/). From 72d70623ce9a2ff66a7b1d268f337aa131f05f5b Mon Sep 17 00:00:00 2001 From: Marc Huisinga Date: Mon, 15 Jan 2024 11:51:13 +0100 Subject: [PATCH 55/70] fix: allow downloading projects with ssh git links (#386) --- vscode-lean4/src/projectinit.ts | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/vscode-lean4/src/projectinit.ts b/vscode-lean4/src/projectinit.ts index 2d83896f0..55daedce3 100644 --- a/vscode-lean4/src/projectinit.ts +++ b/vscode-lean4/src/projectinit.ts @@ -141,23 +141,14 @@ Open this project instead?` } private async cloneProject() { - const unparsedProjectUri: string | undefined = await window.showInputBox({ + const projectUri: string | undefined = await window.showInputBox({ title: 'URL Input', value: 'https://github.com/leanprover-community/mathlib4', - prompt: 'URL of Git repository for existing Lean 4 project', - validateInput: value => { - try { - Uri.parse(value, true) - return undefined // Valid URI - } catch (e) { - return 'Invalid URL' - } - } + prompt: 'URL of Git repository for existing Lean 4 project' }) - if (unparsedProjectUri === undefined) { + if (projectUri === undefined) { return } - const existingProjectUri = Uri.parse(unparsedProjectUri) const projectFolder: Uri | undefined = await ProjectInitializationProvider.askForNewProjectFolderLocation({ saveLabel: 'Create project folder', @@ -167,7 +158,7 @@ Open this project instead?` return } - const result: ExecutionResult = await batchExecuteWithProgress('git', ['clone', existingProjectUri.toString(), projectFolder.fsPath], 'Cloning project', { channel: this.channel, allowCancellation: true }) + const result: ExecutionResult = await batchExecuteWithProgress('git', ['clone', projectUri, projectFolder.fsPath], 'Cloning project', { channel: this.channel, allowCancellation: true }) if (result.exitCode === ExecutionExitCode.Cancelled) { return } From a017ae54d1f0f5af5b9ed295de1814bb9e1bf12f Mon Sep 17 00:00:00 2001 From: Geoffrey Irving Date: Wed, 17 Jan 2024 10:41:23 +0000 Subject: [PATCH 56/70] =?UTF-8?q?feat:=20abbreviate=20`average:=20?= =?UTF-8?q?=E2=A8=8D,=20-int:=20=E2=A8=8D,=20oiint:=20=E2=88=AF,=20tint:?= =?UTF-8?q?=20=E2=88=AF,=20pd:=20=E2=88=82`=20(#387)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add `"average": "⨍"` to abbreviations [Zulip discussion](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/How.20to.20type.20.E2.A8.8D/near/412626263) * feat: more abbreviations: "-int": "⨍", "oiint": "∯", "tint": "∯" [Zulip discussion](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/How.20to.20type.20.E2.A8.8D/near/412626263) * feat: abbreviate "pd": "∂" [Zulip](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/How.20to.20type.20.E2.A8.8D/near/412641364) --- vscode-lean4/src/abbreviation/abbreviations.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vscode-lean4/src/abbreviation/abbreviations.json b/vscode-lean4/src/abbreviation/abbreviations.json index ca6cc1f64..b92b938b5 100644 --- a/vscode-lean4/src/abbreviation/abbreviations.json +++ b/vscode-lean4/src/abbreviation/abbreviations.json @@ -322,6 +322,8 @@ "austral": "₳", "afghani": "؋", "amalg": "∐", + "average": "⨍", + "-int": "⨍", "or=": "≚", "ordfeminine": "ª", "ordmasculine": "º", @@ -349,10 +351,13 @@ "ominus": "⊖", "odot": "⊙", "oint": "∮", + "oiint": "∯", "oslash": "⊘", "otimes": "⊗", + "pd": "∂", "*=": "≛", "t=": "≜", + "tint": "∯", "transport": "▹", "trans": "▹", "triangledown": "▿", From 2351c134b24c1b4a9b9f38608a899b1361832cc2 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Wed, 17 Jan 2024 11:59:07 +0100 Subject: [PATCH 57/70] Release 0.0.124 --- vscode-lean4/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index 3288544d8..8b0ef9f70 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -2,7 +2,7 @@ "name": "lean4", "displayName": "lean4", "description": "Lean 4 language support for VS Code", - "version": "0.0.123", + "version": "0.0.124", "publisher": "leanprover", "engines": { "vscode": "^1.75.0" From 3e33173185f830874a91bf91309f8a522290613d Mon Sep 17 00:00:00 2001 From: Marc Huisinga Date: Wed, 24 Jan 2024 09:10:02 +0100 Subject: [PATCH 58/70] fix: mitigate abbreviation race conditions (#389) --- .../rewriter/AbbreviationRewriter.ts | 182 ++++++++++++------ 1 file changed, 118 insertions(+), 64 deletions(-) diff --git a/vscode-lean4/src/abbreviation/rewriter/AbbreviationRewriter.ts b/vscode-lean4/src/abbreviation/rewriter/AbbreviationRewriter.ts index 2f8e0e11a..365b08272 100644 --- a/vscode-lean4/src/abbreviation/rewriter/AbbreviationRewriter.ts +++ b/vscode-lean4/src/abbreviation/rewriter/AbbreviationRewriter.ts @@ -61,7 +61,7 @@ export class AbbreviationRewriter { ); this.disposables.push( window.onDidChangeTextEditorSelection((e) => { - if (e.textEditor !== this.textEditor) { + if (e.textEditor.document !== this.textEditor.document) { return; } @@ -108,95 +108,153 @@ export class AbbreviationRewriter { this.trackedAbbreviations.delete(a); } - // Wait for VS Code to trigger `onDidChangeTextEditorSelection` - await waitForNextTick(); + const replacements = this.computeReplacements(abbreviations) + const replacingSuccessful = await this.replaceAbbreviations(replacements) + if (replacingSuccessful) { + this.moveSelections(replacements) + this.abbreviationProvider.onAbbreviationsCompleted(this.textEditor); + } else { + // If replacing the abbreviation did not succeed, keep it around so that we can re-try next time + // when the text document was changed, the cursor was moved around or the replacement was triggered + // manually. + for (const a of abbreviations) { + this.trackedAbbreviations.add(a); + } + } + + this.updateState(); + } + + private computeReplacements(abbreviations: TrackedAbbreviation[]): { + range: Range + newText: string + cursorOffset?: number | undefined + }[] { const cursorVar = '$CURSOR'; const replacements = new Array<{ - range: Range; - newText: string; - transformOffsetInRange: (offset: number) => number; + range: Range + newText: string + cursorOffset?: number | undefined }>(); + for (const abbr of abbreviations) { const symbol = abbr.matchingSymbol; if (symbol) { const newText = symbol.replace(cursorVar, ''); - let cursorOffset = symbol.indexOf(cursorVar); + let cursorOffset: number | undefined = symbol.indexOf(cursorVar); if (cursorOffset === -1) { - // position the cursor after the inserted symbol - cursorOffset = newText.length; + cursorOffset = undefined; } replacements.push({ range: abbr.range, newText, - transformOffsetInRange: (offset) => cursorOffset, + cursorOffset, }); } } - // Process replacements with highest offset first - replacements.sort((a, b) => b.range.offset - a.range.offset); - // We cannot rely on VS Code to update the selections - - // it becomes janky if symbols are inserted that are longer - // than their abbreviation. It also does not really work for \[[]]. - const newSelections = this.textEditor.selections - .map((s) => fromVsCodeRange(s, this.textEditor.document)) - .map((s) => { - // Apply the replacement of abbreviations to the selections. - let newSel = s; - for (const r of replacements) { - if ( - r.range.isBefore(newSel) && - !r.range.containsRange(newSel) - ) { - // don't do this on ` \abbr| ` - newSel = newSel.move(r.newText.length - r.range.length); - } else if ( - !r.range.isAfter(newSel) || - r.range.containsRange(newSel) - ) { - // do this on ` \abbr| ` or ` \ab|br ` - // newSel and r.range intersect - const offset = newSel.offset - r.range.offset; - const newOffset = r.transformOffsetInRange(offset); - newSel = newSel.move(newOffset - offset); - } - } - return newSel; - }); + return replacements + } + private async replaceAbbreviations(replacements: { + range: Range; + newText: string; + cursorOffset?: number | undefined; + }[]): Promise { // We don't want replaced symbols (e.g. "\") to trigger abbreviations. this.dontTrackNewAbbr = true; + let ok = false; + let retries = 0 try { - ok = await this.textEditor.edit((builder) => { - for (const r of replacements) { - builder.replace( - toVsCodeRange(r.range, this.textEditor.document), - r.newText - ); - } - }); + // The user may have changed the text document in-between `this.textEditor` being updated + // (when the call to the extension was started) and `this.textEditor.edit()` being executed. + // In this case, since the state of the editor that the extension sees and the state that + // the user sees are different, VS Code will reject the edit. + // This occurs especially often in setups with increased latency until the extension is triggered, + // e.g. an SSH setup. Since VS Code does not appear to support an atomic read -> write operation, + // unfortunately the only thing we can do here is to retry. + while (!ok && retries < 10) { + ok = await this.textEditor.edit((builder) => { + for (const r of replacements) { + builder.replace( + toVsCodeRange(r.range, this.textEditor.document), + r.newText + ); + } + }) + retries++ + } } catch (e) { - this.writeError('Error: while replacing abbreviation: ' + e); + this.writeError('Error while replacing abbreviation: ' + e); } + this.dontTrackNewAbbr = false; - if (ok) { - this.textEditor.selections = newSelections.map((s) => { - const vr = toVsCodeRange(s, this.textEditor.document); - return new Selection(vr.start, vr.end); - }); + return ok + } - this.abbreviationProvider.onAbbreviationsCompleted(this.textEditor); + private moveSelections(replacements: { + range: Range; + newText: string; + cursorOffset?: number | undefined; + }[]) { + // Only move the cursor if there were any abbreviations with $CURSOR. + // This is important because setting `this.textEditor.selections = this.textEditor.selections` + // may override changes to the cursor made between the `this.textEditor.edit` call and updating + // the selection. This is due to `this.textEditor.selections` being only updated on `await`. + if (!replacements.some(r => r.cursorOffset)) { + return } - else { - // Our edit did not succeed, do not update the selections. - // This can happen if `waitForNextTick` waits too long. - this.writeError('Error: Unable to replace abbreviation'); + + // Process replacements with lowest offset first + replacements.sort((a, b) => a.range.offset - b.range.offset); + + const afterEditReplacements = new Array<{ + range: Range + newText: string + cursorOffset?: number | undefined + }>(); + let totalOffsetShift = 0 + for (const r of replacements) { + // Re-adjust range to account for new length and changes in prior lengths. + const afterEditRange = new Range(r.range.offset + totalOffsetShift, r.newText.length) + afterEditReplacements.push({ + range: afterEditRange, + newText: r.newText, + cursorOffset: r.cursorOffset + }) + totalOffsetShift += r.newText.length - r.range.length } - this.updateState(); + const newSelections = this.textEditor.selections + .map(s => fromVsCodeRange(s, this.textEditor.document)) + .map(s => { + for (const r of afterEditReplacements) { + if (!r.cursorOffset) { + // Only move cursor if abbreviation contained $CURSOR + continue + } + + const isCursorAtEndOfAbbreviation = s.offset === r.range.offsetEnd + 1 + // Safety check: Prevents moving the cursor if e.g. the replacement triggered + // because the selection was moved away from the abbreviation. + if (isCursorAtEndOfAbbreviation) { + // Move cursor backwards to the position of $CURSOR + return s.move(r.cursorOffset - r.newText.length) + } + } + + // Cursor not at the end of any abbreviation that contained $CURSOR + // => Keep it where it is + return s + }) + + this.textEditor.selections = newSelections.map(s => { + const vr = toVsCodeRange(s, this.textEditor.document); + return new Selection(vr.start, vr.end) + }); } private updateState() { @@ -271,7 +329,3 @@ function toVsCodeRange(range: Range, doc: TextDocument): LineColRange { const end = doc.positionAt(range.offsetEnd + 1); return new LineColRange(start, end); } - -function waitForNextTick(): Promise { - return new Promise((res) => setTimeout(res, 0)); -} From d2e3351ebebb85f42d0093f6ea950921933848f7 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Wed, 24 Jan 2024 09:10:33 +0100 Subject: [PATCH 59/70] Release 0.0.125 --- vscode-lean4/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index 8b0ef9f70..06430153d 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -2,7 +2,7 @@ "name": "lean4", "displayName": "lean4", "description": "Lean 4 language support for VS Code", - "version": "0.0.124", + "version": "0.0.125", "publisher": "leanprover", "engines": { "vscode": "^1.75.0" From 3adc6c7e7013a247f611b4304649ab407f32b03d Mon Sep 17 00:00:00 2001 From: Marc Huisinga Date: Tue, 30 Jan 2024 16:26:41 +0100 Subject: [PATCH 60/70] fix: use manual cursor manipulation when vim ext is installed (#391) --- .../rewriter/AbbreviationRewriter.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/vscode-lean4/src/abbreviation/rewriter/AbbreviationRewriter.ts b/vscode-lean4/src/abbreviation/rewriter/AbbreviationRewriter.ts index 365b08272..39cd5749d 100644 --- a/vscode-lean4/src/abbreviation/rewriter/AbbreviationRewriter.ts +++ b/vscode-lean4/src/abbreviation/rewriter/AbbreviationRewriter.ts @@ -1,5 +1,5 @@ import { Range as LineColRange } from 'vscode'; -import { commands, Disposable, TextEditor, window, workspace, Selection, OutputChannel, TextDocument } from 'vscode'; +import { commands, Disposable, TextEditor, window, workspace, Selection, OutputChannel, TextDocument, extensions } from 'vscode'; import { assert } from '../../utils/assert'; import { AbbreviationProvider } from '../AbbreviationProvider'; import { AbbreviationConfig } from '../config'; @@ -22,6 +22,11 @@ export class AbbreviationRewriter { private dontTrackNewAbbr = false; private stderrOutput: OutputChannel; private firstOutput = true; + private isVimExtensionInstalled = false; + + private checkIsVimExtensionInstalled() { + this.isVimExtensionInstalled = extensions.getExtension('vscodevim.vim') !== undefined + } constructor( private readonly config: AbbreviationConfig, @@ -87,6 +92,9 @@ export class AbbreviationRewriter { this.forceReplace([...this.trackedAbbreviations]) ) ); + + this.checkIsVimExtensionInstalled() + this.disposables.push(extensions.onDidChange(_ => this.checkIsVimExtensionInstalled())) } private writeError(e: string) { @@ -204,7 +212,14 @@ export class AbbreviationRewriter { // This is important because setting `this.textEditor.selections = this.textEditor.selections` // may override changes to the cursor made between the `this.textEditor.edit` call and updating // the selection. This is due to `this.textEditor.selections` being only updated on `await`. - if (!replacements.some(r => r.cursorOffset)) { + // + // When users have the Vim extension installed, the builtin selection manipulation of VS Code + // consistently moves the cursor to a wrong position, likely because the Vim extension manipulates + // the cursor itself or because edits sent by the VS Code extension conflict with that of the + // AbbreviationRewriter. In this case, we fall back to manually manipulating the cursor. This is + // subject to race conditions, but at least not consistently wrong, as would otherwise be the case + // with the Vim extension installed. + if (!replacements.some(r => r.cursorOffset) && !this.isVimExtensionInstalled) { return } From ca26dfb40e1a45acaabee16e5fe319825f3b29f5 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Tue, 30 Jan 2024 16:28:06 +0100 Subject: [PATCH 61/70] Release 0.0.126 --- vscode-lean4/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index 06430153d..269dfc03c 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -2,7 +2,7 @@ "name": "lean4", "displayName": "lean4", "description": "Lean 4 language support for VS Code", - "version": "0.0.125", + "version": "0.0.126", "publisher": "leanprover", "engines": { "vscode": "^1.75.0" From c2b1918778b84162536d4a6533a9a8e6735c0c88 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Wed, 31 Jan 2024 10:50:47 +0100 Subject: [PATCH 62/70] Release 0.0.127 --- vscode-lean4/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index 269dfc03c..40225b3f3 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -2,7 +2,7 @@ "name": "lean4", "displayName": "lean4", "description": "Lean 4 language support for VS Code", - "version": "0.0.126", + "version": "0.0.127", "publisher": "leanprover", "engines": { "vscode": "^1.75.0" From 82464991f7e221411248c18f49d08cc4fc13790f Mon Sep 17 00:00:00 2001 From: Newell Jensen Date: Fri, 9 Feb 2024 00:33:06 -0800 Subject: [PATCH 63/70] chore: update README.md (#394) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1cd5f2df7..9bb5130cb 100644 --- a/README.md +++ b/README.md @@ -136,8 +136,8 @@ You can also disable auto-opening behavior using the setting `lean4.infoViewAuto | Symbol | Description | |--------|-------------| | ![quotes](vscode-lean4/media/quotes.png) | Copy the contents of the widget to a comment in the active text editor. | - | ![pin](vscode-lean4/media/pin.png) | Split off a "pinned" tactic state widget, which tracks the tactic state at a fixed position, even if you move your cursor away. When pinned you will see the unpin and reveal file location icons appear. | - | ![unpin](vscode-lean4/media/unpin.png) | Remove a pinned widget from the Infoview. | + | ![pin](vscode-lean4/media/pin.png) | Remove a pinned widget from the Infoview. | + | ![unpin](vscode-lean4/media/unpin.png) | Split off a "pinned" tactic state widget, which tracks the tactic state at a fixed position, even if you move your cursor away. When pinned you will see the unpin and reveal file location icons appear. | | ![reveal](vscode-lean4/media/reveal-file-location.png) | Move the cursor in the editor to the pinned location in the file. | | ![pause](vscode-lean4/media/pause.png) | Prevent the tactic state widget from updating when the file is edited. When paused you will see the following addition icons show up. | ![continue](vscode-lean4/media/continue.png) | Once paused you can then click this icon to resume updates. | From cd0968f1bba1a5b0616fa9d1a2b23f83afffc6c4 Mon Sep 17 00:00:00 2001 From: Anand Rao <18333981+0art0@users.noreply.github.com> Date: Sat, 17 Feb 2024 19:16:13 +0000 Subject: [PATCH 64/70] Export `LocationsContext` in `@leanprover/infoview` (#379) The `LocationsContext` is exported in `infoview/goalLocation.tsx` but not in the `.index.tsx` file. --- lean4-infoview/src/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lean4-infoview/src/index.tsx b/lean4-infoview/src/index.tsx index 01361452a..f07198840 100644 --- a/lean4-infoview/src/index.tsx +++ b/lean4-infoview/src/index.tsx @@ -12,7 +12,7 @@ export { EditorContext, VersionContext } from './infoview/contexts'; export { EditorConnection } from './infoview/editorConnection'; export { RpcContext } from './infoview/rpcSessions'; export { ServerVersion } from './infoview/serverVersion'; -export { GoalLocation, GoalsLocation } from './infoview/goalLocation'; +export { LocationsContext, GoalLocation, GoalsLocation } from './infoview/goalLocation'; export { importWidgetModule, DynamicComponent, DynamicComponentProps, PanelWidgetProps } from './infoview/userWidget'; From 9434a061189b8b0f64906429c9c6f99e8ceda360 Mon Sep 17 00:00:00 2001 From: Wojciech Nawrocki Date: Sat, 17 Feb 2024 14:37:23 -0500 Subject: [PATCH 65/70] Release 0.0.128 --- lean4-infoview/package-lock.json | 4 +- lean4-infoview/package.json | 2 +- vscode-lean4/package-lock.json | 1244 +++++++++++++++++------------- vscode-lean4/package.json | 4 +- 4 files changed, 716 insertions(+), 538 deletions(-) diff --git a/lean4-infoview/package-lock.json b/lean4-infoview/package-lock.json index c73aec8a1..cedb7344a 100644 --- a/lean4-infoview/package-lock.json +++ b/lean4-infoview/package-lock.json @@ -1,12 +1,12 @@ { "name": "@leanprover/infoview", - "version": "0.4.4", + "version": "0.4.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@leanprover/infoview", - "version": "0.4.4", + "version": "0.4.5", "license": "Apache-2.0", "dependencies": { "@vscode/codicons": "^0.0.32", diff --git a/lean4-infoview/package.json b/lean4-infoview/package.json index afb03848b..8dcf76d31 100644 --- a/lean4-infoview/package.json +++ b/lean4-infoview/package.json @@ -1,6 +1,6 @@ { "name": "@leanprover/infoview", - "version": "0.4.4", + "version": "0.4.5", "description": "An interactive display for the Lean 4 theorem prover.", "scripts": { "watch": "rollup --config --environment NODE_ENV:development --watch", diff --git a/vscode-lean4/package-lock.json b/vscode-lean4/package-lock.json index 372bf47f3..c17a21c01 100644 --- a/vscode-lean4/package-lock.json +++ b/vscode-lean4/package-lock.json @@ -1,12 +1,12 @@ { "name": "lean4", - "version": "0.0.121", + "version": "0.0.128", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "lean4", - "version": "0.0.121", + "version": "0.0.128", "license": "Apache-2.0", "dependencies": { "axios": "^1.6.2", @@ -42,12 +42,12 @@ } }, "node_modules/@babel/runtime": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz", - "integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", + "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", "dev": true, "dependencies": { - "regenerator-runtime": "^0.13.11" + "regenerator-runtime": "^0.14.0" }, "engines": { "node": ">=6.9.0" @@ -78,9 +78,9 @@ } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "peer": true, "engines": { @@ -109,21 +109,21 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", "dev": true, "peer": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", + "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", "dev": true, "peer": true, "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@nodelib/fs.scandir": { @@ -171,18 +171,18 @@ } }, "node_modules/@types/cheerio": { - "version": "0.22.31", - "resolved": "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.31.tgz", - "integrity": "sha512-Kt7Cdjjdi2XWSfrZ53v4Of0wG3ZcmaegFXjMmz9tfNrZSkzzo36G0AL1YqSdcIA78Etjt6E609pt5h1xnQkPUw==", + "version": "0.22.35", + "resolved": "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.35.tgz", + "integrity": "sha512-yD57BchKRvTV+JD53UZ6PD8KWY5g5rvvMLRnZR3EQBCZXiDT/HR+pKpMzFGlWNhFrXlo7VPZXtKvIEwZkAWOIA==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/eslint": { - "version": "8.44.0", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.0.tgz", - "integrity": "sha512-gsF+c/0XOguWgaOgvFs+xnnRqt9GwgTvIks36WpE6ueeI4KCEHHd8K/CKHqhOqrJKsYH8m27kRzQEvWXAwXUTw==", + "version": "8.56.2", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.2.tgz", + "integrity": "sha512-uQDwm1wFHmbBbCZCqAlq6Do9LYwByNZHWzXppSnay9SuwJ+VRbjkbLABer54kcPnMSlG6Fdiy2yaFXm/z9Z5gw==", "dev": true, "peer": true, "dependencies": { @@ -191,9 +191,9 @@ } }, "node_modules/@types/eslint-scope": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", - "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", "dev": true, "peer": true, "dependencies": { @@ -202,9 +202,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", - "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true, "peer": true }, @@ -219,9 +219,9 @@ } }, "node_modules/@types/json-schema": { - "version": "7.0.12", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", - "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "node_modules/@types/minimatch": { @@ -237,39 +237,42 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.16.19", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.19.tgz", - "integrity": "sha512-IXl7o+R9iti9eBW4Wg2hx1xQDig183jj7YLn8F7udNceyfkbn1ZxmzZXuak20gR40D7pIkIY1kYGx5VIGbaHKA==", - "dev": true + "version": "18.19.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.17.tgz", + "integrity": "sha512-SzyGKgwPzuWp2SHhlpXKzCX0pIOfcI4V2eF37nNBJOhwlegQ83omtVQ1XxZpDE06V/d6AQvfQdPfnw0tRC//Ng==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } }, "node_modules/@types/ps-node": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@types/ps-node/-/ps-node-0.1.1.tgz", - "integrity": "sha512-t/8CsMBQ1ekBIb+Soqxce6w8M7yt0jRoXgsWHkS66VQ9OcMDQeoRLzz+gGpVeBc8pVskOTwRbCqHxDOGFwkgsg==", + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@types/ps-node/-/ps-node-0.1.3.tgz", + "integrity": "sha512-9lJ7dWmWsdZnh/QMwX11+T+Se8Q1dk4LJqUwAEMsl7riiYmvmSl/Hfr7FlfJawD2+eb12A1hYAmu1J89k2PVdQ==", "dev": true }, "node_modules/@types/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.7.tgz", + "integrity": "sha512-/wdoPq1QqkSj9/QOeKkFquEuPzQbHTWAMPH/PaUMB+JuR31lXhlWXRZ52IpfDYVlDOUBvX09uBrPwxGT1hjNBg==", "dev": true }, "node_modules/@types/vscode": { - "version": "1.80.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.80.0.tgz", - "integrity": "sha512-qK/CmOdS2o7ry3k6YqU4zD3R2AYlJfbwBoSbKpBoP+GpXNE+0NEgJOli4n0bm0diK5kfBnchgCEj4igQz/44Hg==", + "version": "1.86.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.86.0.tgz", + "integrity": "sha512-DnIXf2ftWv+9LWOB5OJeIeaLigLHF7fdXF6atfc7X5g2w/wVZBgk0amP7b+ub5xAuW1q7qP5YcFvOcit/DtyCQ==", "dev": true }, "node_modules/@types/vscode-webview": { - "version": "1.57.1", - "resolved": "https://registry.npmjs.org/@types/vscode-webview/-/vscode-webview-1.57.1.tgz", - "integrity": "sha512-ghW5SfuDmsGDS2A4xkvGsLwDRNc3Vj5rS6rPOyPm/IryZuf3wceZKxgYaUoW+k9f0f/CB7y2c1rRsdOWZWn0PQ==", + "version": "1.57.5", + "resolved": "https://registry.npmjs.org/@types/vscode-webview/-/vscode-webview-1.57.5.tgz", + "integrity": "sha512-iBAUYNYkz+uk1kdsq05fEcoh8gJmwT3lqqFPN7MGyjQ3HVloViMdo7ZJ8DFIP8WOK74PjOEilosqAyxV2iUFUw==", "dev": true }, "node_modules/@vscode/test-electron": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.3.8.tgz", - "integrity": "sha512-b4aZZsBKtMGdDljAsOPObnAi7+VWIaYl3ylCz1jTs+oV6BZ4TNHcVNC3xUn0azPeszBmwSBDQYfFESIaUQnrOg==", + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.3.9.tgz", + "integrity": "sha512-z3eiChaCQXMqBnk2aHHSEkobmC2VRalFQN0ApOAtydL172zXGxTwGrRtviT5HnUB+Q+G3vtEYFtuQkYqBzYgMA==", "dev": true, "dependencies": { "http-proxy-agent": "^4.0.1", @@ -318,90 +321,6 @@ "keytar": "^7.7.0" } }, - "node_modules/@vscode/vsce/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@vscode/vsce/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@vscode/vsce/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@vscode/vsce/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@vscode/vsce/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@vscode/vsce/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@vscode/vsce/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@vscode/vsce/node_modules/xml2js": { - "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", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/@webassemblyjs/ast": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", @@ -617,12 +536,13 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "deprecated": "Use your platform's native atob() and btoa() methods instead", "dev": true }, "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, "peer": true, "bin": { @@ -708,19 +628,25 @@ "node": ">=6" } }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "color-convert": "^1.9.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=4" } }, "node_modules/anymatch": { @@ -760,11 +686,11 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/axios": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", - "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz", + "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==", "dependencies": { - "follow-redirects": "^1.15.0", + "follow-redirects": "^1.15.4", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } @@ -874,9 +800,9 @@ "dev": true }, "node_modules/browserslist": { - "version": "4.21.9", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz", - "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", "dev": true, "funding": [ { @@ -894,10 +820,10 @@ ], "peer": true, "dependencies": { - "caniuse-lite": "^1.0.30001503", - "electron-to-chromium": "^1.4.431", - "node-releases": "^2.0.12", - "update-browserslist-db": "^1.0.11" + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" }, "bin": { "browserslist": "cli.js" @@ -948,13 +874,19 @@ "peer": true }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -973,9 +905,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001515", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001515.tgz", - "integrity": "sha512-eEFDwUOZbE24sb+Ecsx3+OvNETqjWIdabMy52oOkIgcUtAsQifjUG9q4U9dgTHJM2mfk4uEPxc0+xuFdJ629QA==", + "version": "1.0.30001587", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001587.tgz", + "integrity": "sha512-HMFNotUmLXn71BQxg8cijvqxnIAofforZOwGsxyXJ0qugTdspUF4sPSJ2vhgprHCB996tIDzEq1ubumPDV8ULA==", "dev": true, "funding": [ { @@ -994,31 +926,17 @@ "peer": true }, "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/cheerio": { @@ -1133,50 +1051,6 @@ "node": ">=12" } }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -1192,21 +1066,18 @@ } }, "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "color-name": "1.1.3" } }, "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, "node_modules/colorette": { @@ -1267,6 +1138,91 @@ "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" } }, + "node_modules/concurrently/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/concurrently/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/concurrently/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/concurrently/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/concurrently/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/copy-webpack-plugin": { "version": "10.2.4", "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-10.2.4.tgz", @@ -1408,6 +1364,23 @@ "node": ">=4.0.0" } }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -1417,9 +1390,9 @@ } }, "node_modules/detect-libc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", - "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", "dev": true, "optional": true, "engines": { @@ -1499,9 +1472,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.461", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.461.tgz", - "integrity": "sha512-1JkvV2sgEGTDXjdsaQCeSwYYuhLRphRpc+g6EHTFELJXEiznLt3/0pZ9JuAOQ5p2rI3YxKTbivtvajirIfhrEQ==", + "version": "1.4.673", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.673.tgz", + "integrity": "sha512-zjqzx4N7xGdl5468G+vcgzDhaHkaYgVcf9MqgexcTqsl2UHSCmOj/Bi3HAprg4BZCpC7HyD8a6nZl6QAZf72gw==", "dev": true, "peer": true }, @@ -1546,9 +1519,9 @@ } }, "node_modules/envinfo": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.10.0.tgz", - "integrity": "sha512-ZtUjZO6l5mwTHvc1L9+1q5p/R3wTopcfqMW8r5t8SJSKqeVI/LtajORwRFEKpEFuekjD0VBjwu1HMxL4UalIRw==", + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.1.tgz", + "integrity": "sha512-8PiZgZNIB4q/Lw4AhOvAfB/ityHAd2bli3lESSWmWSzSsl5dKpy5N1d1Rfkd2teq/g9xN90lc6o98DOjMeYHpg==", "dev": true, "bin": { "envinfo": "dist/cli.js" @@ -1557,32 +1530,50 @@ "node": ">=4" } }, - "node_modules/es-module-lexer": { + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", - "integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", + "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", "dev": true, "peer": true }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true, "engines": { "node": ">=6" } }, "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.8.0" } }, "node_modules/eslint-scope": { @@ -1659,9 +1650,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz", - "integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -1703,9 +1694,9 @@ } }, "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -1758,9 +1749,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", "funding": [ { "type": "individual", @@ -1817,10 +1808,13 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/get-caller-file": { "version": "2.0.5", @@ -1832,15 +1826,19 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1912,31 +1910,43 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, "engines": { - "node": ">= 0.4.0" + "node": ">=4" } }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, - "engines": { - "node": ">=8" + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-proto": { @@ -1963,6 +1973,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hasown": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", + "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -2063,9 +2085,9 @@ "optional": true }, "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "dev": true, "engines": { "node": ">= 4" @@ -2153,12 +2175,12 @@ } }, "node_modules/is-core-module": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", - "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dev": true, "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2173,6 +2195,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -2263,6 +2294,32 @@ "node": ">= 10.13.0" } }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -2289,9 +2346,9 @@ "dev": true }, "node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", "dev": true }, "node_modules/jszip": { @@ -2401,6 +2458,76 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -2554,9 +2681,9 @@ } }, "node_modules/mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.3.0.tgz", + "integrity": "sha512-uF2XJs+7xSLsrmIvn37i/wnc91nw7XjOQB8ccyx5aEgdnohr7n+rEiZP23WkCYHjilR6+EboEnbq/ZQDz4LSbg==", "dev": true, "dependencies": { "ansi-colors": "4.1.1", @@ -2566,13 +2693,12 @@ "diff": "5.0.0", "escape-string-regexp": "4.0.0", "find-up": "5.0.0", - "glob": "7.2.0", + "glob": "8.1.0", "he": "1.2.0", "js-yaml": "4.1.0", "log-symbols": "4.1.0", "minimatch": "5.0.1", "ms": "2.1.3", - "nanoid": "3.3.3", "serialize-javascript": "6.0.0", "strip-json-comments": "3.1.1", "supports-color": "8.1.1", @@ -2587,19 +2713,15 @@ }, "engines": { "node": ">= 14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" } }, - "node_modules/mocha/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/mocha/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, - "engines": { - "node": ">=8" + "dependencies": { + "balanced-match": "^1.0.0" } }, "node_modules/mocha/node_modules/cliui": { @@ -2613,42 +2735,41 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/mocha/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/mocha/node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^5.0.1", + "once": "^1.3.0" }, "engines": { - "node": "*" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/mocha/node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mocha/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/mocha/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "engines": { "node": ">=8" @@ -2666,15 +2787,6 @@ "node": ">=10" } }, - "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/mocha/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -2690,30 +2802,19 @@ "randombytes": "^2.1.0" } }, - "node_modules/mocha/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.1" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, "node_modules/mocha/node_modules/yargs": { @@ -2746,18 +2847,6 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, - "node_modules/nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/napi-build-utils": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", @@ -2773,9 +2862,9 @@ "peer": true }, "node_modules/node-abi": { - "version": "3.45.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.45.0.tgz", - "integrity": "sha512-iwXuFrMAcFVi/ZoZiqq8BzAdsLw9kxDfTC0HMyjXfSL/6CSDAGD5UmR7azrAgWV1zKYq7dUUMj4owusBWKLsiQ==", + "version": "3.54.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.54.0.tgz", + "integrity": "sha512-p7eGEiQil0YUV3ItH4/tBb781L5impVmmx2E9FRKF7d18XXzp4PGT2tdYMFY6wQqgxD0IwNZOiSJ0/K0fSi/OA==", "dev": true, "optional": true, "dependencies": { @@ -2793,9 +2882,9 @@ "optional": true }, "node_modules/node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", "dev": true, "peer": true }, @@ -2820,9 +2909,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3125,9 +3214,9 @@ } }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "engines": { "node": ">=6" @@ -3255,9 +3344,9 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", "dev": true }, "node_modules/require-directory": { @@ -3279,12 +3368,12 @@ } }, "node_modules/resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "dependencies": { - "is-core-module": "^2.11.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -3386,9 +3475,9 @@ "dev": true }, "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==", "dev": true }, "node_modules/schema-utils": { @@ -3411,9 +3500,9 @@ } }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -3425,14 +3514,31 @@ } }, "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==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "dependencies": { "randombytes": "^2.1.0" } }, + "node_modules/set-function-length": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz", + "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.2", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -3482,14 +3588,18 @@ } }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz", + "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3555,13 +3665,12 @@ } }, "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", "dev": true, - "peer": true, "engines": { - "node": ">=0.10.0" + "node": ">= 8" } }, "node_modules/source-map-js": { @@ -3605,6 +3714,16 @@ "source-map": "^0.6.0" } }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/spawn-command": { "version": "0.0.2-1", "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", @@ -3620,6 +3739,32 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -3633,18 +3778,15 @@ } }, "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "has-flag": "^3.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "node": ">=4" } }, "node_modules/supports-preserve-symlinks-flag": { @@ -3714,9 +3856,9 @@ } }, "node_modules/terser": { - "version": "5.19.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.0.tgz", - "integrity": "sha512-JpcpGOQLOXm2jsomozdMDpd5f8ZHh1rR48OFgWUH3QsyZcfPgv2qDCYbcDEAYNd4OZRj2bWYKpwdll/udZCk/Q==", + "version": "5.27.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.27.1.tgz", + "integrity": "sha512-29wAr6UU/oQpnTw5HoadwjUZnFQXGdOfj0LjZ4sVxzqwHh/QVkvr7m8y9WoR4iN3FRitVduTc6KdjcW38Npsug==", "dev": true, "peer": true, "dependencies": { @@ -3733,17 +3875,17 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.9", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", - "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", "dev": true, "peer": true, "dependencies": { - "@jridgewell/trace-mapping": "^0.3.17", + "@jridgewell/trace-mapping": "^0.3.20", "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", "serialize-javascript": "^6.0.1", - "terser": "^5.16.8" + "terser": "^5.26.0" }, "engines": { "node": ">= 10.13.0" @@ -3861,15 +4003,16 @@ } }, "node_modules/ts-loader": { - "version": "9.4.4", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.4.tgz", - "integrity": "sha512-MLukxDHBl8OJ5Dk3y69IsKVFRA/6MwzEqBgh+OXMPB/OD01KQuWPFd1WAQP8a5PeSCAxfnkhiuWqfmFJzJQt9w==", + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", + "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==", "dev": true, "dependencies": { "chalk": "^4.1.0", "enhanced-resolve": "^5.0.0", "micromatch": "^4.0.0", - "semver": "^7.3.4" + "semver": "^7.3.4", + "source-map": "^0.7.4" }, "engines": { "node": ">=12.0.0" @@ -3879,10 +4022,80 @@ "webpack": "^5.0.0" } }, + "node_modules/ts-loader/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ts-loader/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ts-loader/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ts-loader/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/ts-loader/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-loader/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/tslib": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", - "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", "dev": true }, "node_modules/tunnel": { @@ -3943,10 +4156,16 @@ "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", "dev": true }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, "node_modules/update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", "dev": true, "funding": [ { @@ -4045,20 +4264,20 @@ } }, "node_modules/webpack": { - "version": "5.88.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.1.tgz", - "integrity": "sha512-FROX3TxQnC/ox4N+3xQoWZzvGXSuscxR32rbzjpXgEzWudJFEJBpdlkkob2ylrv5yzzufD1zph1OoFsLtm6stQ==", + "version": "5.90.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.2.tgz", + "integrity": "sha512-ziXu8ABGr0InCMEYFnHrYweinHK2PWrMqnwdHk2oK3rRhv/1B+2FnfwYv5oD+RrknK/Pp/Hmyvu+eAsaMYhzCw==", "dev": true, "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.0", + "@types/estree": "^1.0.5", "@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.9.0", - "browserslist": "^4.14.5", + "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.15.0", "es-module-lexer": "^1.2.1", @@ -4072,7 +4291,7 @@ "neo-async": "^2.6.2", "schema-utils": "^3.2.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.7", + "terser-webpack-plugin": "^5.3.10", "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" }, @@ -4149,12 +4368,13 @@ } }, "node_modules/webpack-merge": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.9.0.tgz", - "integrity": "sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", "dev": true, "dependencies": { "clone-deep": "^4.0.1", + "flat": "^5.0.2", "wildcard": "^2.0.0" }, "engines": { @@ -4268,56 +4488,58 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "color-convert": "^2.0.1" }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.1" + "color-name": "~1.1.4" }, "engines": { - "node": ">=8" + "node": ">=7.0.0" } }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, + "node_modules/xml2js": { + "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", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/xmlbuilder": { "version": "11.0.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", @@ -4383,50 +4605,6 @@ "node": ">=10" } }, - "node_modules/yargs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/yargs/node_modules/yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index 40225b3f3..62c66c888 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -2,7 +2,7 @@ "name": "lean4", "displayName": "lean4", "description": "Lean 4 language support for VS Code", - "version": "0.0.127", + "version": "0.0.128", "publisher": "leanprover", "engines": { "vscode": "^1.75.0" @@ -894,7 +894,7 @@ "test": "node ./out/test/suite/runTest.js" }, "dependencies": { - "@leanprover/infoview": "~0.4.3", + "@leanprover/infoview": "~0.4.5", "@leanprover/infoview-api": "~0.2.1", "axios": "^1.6.2", "cheerio": "^1.0.0-rc.10", From 19afab22c4b8cef83f26bd3ba01a49fa3eb76f94 Mon Sep 17 00:00:00 2001 From: Richard Copley Date: Mon, 26 Feb 2024 09:56:28 +0000 Subject: [PATCH 66/70] feat: More arrows (#399) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add "⇰", and also "|->" as an alias for "mapsto" Co-authored-by: Phil Nguyen --- vscode-lean4/src/abbreviation/abbreviations.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vscode-lean4/src/abbreviation/abbreviations.json b/vscode-lean4/src/abbreviation/abbreviations.json index b92b938b5..ab448b9fd 100644 --- a/vscode-lean4/src/abbreviation/abbreviations.json +++ b/vscode-lean4/src/abbreviation/abbreviations.json @@ -910,6 +910,8 @@ "|-": "⊢", "|=n": "⊭", "|=": "⊨", + "|->" : "↦", + "|=>" : "⇰", "||-n": "⊮", "||-": "⊩", "||=n": "⊯", From 21c1ef09dd6831065da6a0e04f80e31982343990 Mon Sep 17 00:00:00 2001 From: mhuisi Date: Mon, 26 Feb 2024 13:30:43 +0100 Subject: [PATCH 67/70] Release 0.0.129 --- vscode-lean4/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vscode-lean4/package.json b/vscode-lean4/package.json index 62c66c888..bd36d29d1 100644 --- a/vscode-lean4/package.json +++ b/vscode-lean4/package.json @@ -2,7 +2,7 @@ "name": "lean4", "displayName": "lean4", "description": "Lean 4 language support for VS Code", - "version": "0.0.128", + "version": "0.0.129", "publisher": "leanprover", "engines": { "vscode": "^1.75.0" From 37d2d73fb87afa1cefc4a6b1a3d2826d22af8bd0 Mon Sep 17 00:00:00 2001 From: Marc Huisinga Date: Wed, 6 Mar 2024 09:31:51 +0100 Subject: [PATCH 68/70] fix: use fullRange diagnostic field when filtering diagnostics (#402) --- lean4-infoview/src/infoview/info.tsx | 4 ++-- vscode-lean4/package-lock.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lean4-infoview/src/infoview/info.tsx b/lean4-infoview/src/infoview/info.tsx index 0c797e9d8..85700245d 100644 --- a/lean4-infoview/src/infoview/info.tsx +++ b/lean4-infoview/src/infoview/info.tsx @@ -8,7 +8,7 @@ import { ConfigContext, EditorContext, LspDiagnosticsContext, ProgressContext } import { lspDiagToInteractive, MessagesList } from './messages'; import { getInteractiveGoals, getInteractiveTermGoal, InteractiveDiagnostic, InteractiveGoals, UserWidgetInstance, Widget_getWidgets, RpcSessionAtPos, isRpcError, - RpcErrorCode, getInteractiveDiagnostics, InteractiveTermGoal } from '@leanprover/infoview-api'; + RpcErrorCode, getInteractiveDiagnostics, InteractiveTermGoal, LeanDiagnostic } from '@leanprover/infoview-api'; import { PanelWidgetDisplay } from './userWidget' import { RpcContext, useRpcSessionAtPos } from './rpcSessions'; import { GoalsLocation, Locations, LocationsContext } from './goalLocation'; @@ -267,7 +267,7 @@ function InfoAux(props: InfoProps) { // Note: the curly braces are important. https://medium.com/geekculture/react-uncaught-typeerror-destroy-is-not-a-function-192738a6e79b setLspDiagsHere(diags0 => { const diagPred = (d: Diagnostic) => - RangeHelpers.contains(d.range, {line: pos.line, character: pos.character}, config.allErrorsOnLine) + RangeHelpers.contains((d as LeanDiagnostic).fullRange || d.range, {line: pos.line, character: pos.character}, config.allErrorsOnLine) const newDiags = (lspDiags.get(pos.uri) || []).filter(diagPred) if (newDiags.length === diags0.length && newDiags.every((d, i) => d === diags0[i])) return diags0 return newDiags diff --git a/vscode-lean4/package-lock.json b/vscode-lean4/package-lock.json index c17a21c01..ec8371eb8 100644 --- a/vscode-lean4/package-lock.json +++ b/vscode-lean4/package-lock.json @@ -1,12 +1,12 @@ { "name": "lean4", - "version": "0.0.128", + "version": "0.0.129", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "lean4", - "version": "0.0.128", + "version": "0.0.129", "license": "Apache-2.0", "dependencies": { "axios": "^1.6.2", From 212cbd41e6f69ec19b4a7e99f7c2be61030b3520 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Tue, 12 Mar 2024 12:09:28 -0400 Subject: [PATCH 69/70] feat: provide more bracket support (#330) * feat: support for modified standard brackets * feat: support for modified string literals * feat: support for markdown enclosers on select * change: remove `$[`, `]` as a bracket pair * docs: create `language-configuration.md` * remove markdown comment --- docs/language-configuration.md | 27 ++++++++++++++++++++++++ vscode-lean4/language-configuration.json | 25 +++++++++++++++++++--- 2 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 docs/language-configuration.md diff --git a/docs/language-configuration.md b/docs/language-configuration.md new file mode 100644 index 000000000..b08eed67c --- /dev/null +++ b/docs/language-configuration.md @@ -0,0 +1,27 @@ +This document serves as documentation for [`language-configuration.json`](/vscode-lean4/language-configuration.json). + +See [the official VS code documentation](https://code.visualstudio.com/api/language-extensions/language-configuration-guide) for an overview of how `language-configuration.json` files work in general. + +Section titles here are top-level fields in the JSON file, and link to their corresponding section in the official documentation. + +## [`brackets`](https://code.visualstudio.com/api/language-extensions/language-configuration-guide#brackets-definition), [`autoClosingPairs`](https://code.visualstudio.com/api/language-extensions/language-configuration-guide#autoclosing), and [`surroundingPairs`](https://code.visualstudio.com/api/language-extensions/language-configuration-guide#autosurrounding) + +All of these fields handle brackets in different ways. + +* `brackets`: determines highlighting and selection +* `autoClosingPairs`: specifies which bracket pairs should prompt automatic insertion of a closing bracket upon typing the initial bracket +* `surroundingPairs`: specifies which brackets should surround highlighted content when typed (e.g. highlighting a term then typing ( should surround the term with parentheses) + +### Markdown + +We include the following only in `surroundingPairs`: + +```json + ... + ["`", "`"], + ["*", "*"], + ["_", "_"] + ... +``` + +This means that you can highlight text in comments and italicize, bold, or code-format it easily by typing the respective marker(s). We don't want to use these as actual brackets or autoclosing pairs, however, due to their use in Lean code. diff --git a/vscode-lean4/language-configuration.json b/vscode-lean4/language-configuration.json index ed98e16bc..9a46d8aa3 100644 --- a/vscode-lean4/language-configuration.json +++ b/vscode-lean4/language-configuration.json @@ -5,7 +5,12 @@ }, "brackets": [ ["(", ")"], + ["`(", ")"], + ["``(", ")"], ["[", "]"], + ["#[", "]"], + ["@[", "]"], + ["%[", "]"], ["{", "}"], ["⁅", "⁆"], ["⁽", "⁾"], @@ -43,11 +48,19 @@ ["[", "]"], ["{", "}"], ["「", "」"], - ["\"", "\""] + ["\"", "\""], + ["s!\"", "\""], + ["f!\"", "\""], + ["m!\"", "\""] ], "autoClosingPairs": [ ["(", ")"], + ["`(", ")"], + ["``(", ")"], ["[", "]"], + ["#[", "]"], + ["@[", "]"], + ["%[", "]"], ["{", "}"], ["⁅", "⁆"], ["⟮", "⟯"], @@ -86,7 +99,10 @@ ["{", "}"], ["「", "」"], ["/-", "-/"], - ["\"", "\""] + ["\"", "\""], + ["s!\"", "\""], + ["f!\"", "\""], + ["m!\"", "\""] ], "surroundingPairs": [ ["(", ")"], @@ -128,7 +144,10 @@ ["{", "}"], ["「", "」"], ["\"", "\""], - ["'", "'"] + ["'", "'"], + ["`", "`"], + ["*", "*"], + ["_", "_"] ], "wordPattern" : "([^`~@$%^&*()\\-=+\\[{\\]}⟨⟩⦃⦄⟦⟧⟮⟯‹›<>\\\\|;:\",./\\s]+)" } From 5bba1807fa3e11db829fdc4728fe873b3d7edff3 Mon Sep 17 00:00:00 2001 From: Marc Huisinga Date: Tue, 12 Mar 2024 17:22:50 +0100 Subject: [PATCH 70/70] feat: syntactic string interpolation highlighting (#404) Co-authored-by: Trebor-Huang <2300936257@qq.com> --- vscode-lean4/syntaxes/lean4.json | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/vscode-lean4/syntaxes/lean4.json b/vscode-lean4/syntaxes/lean4.json index ac982f24a..ff77d334a 100644 --- a/vscode-lean4/syntaxes/lean4.json +++ b/vscode-lean4/syntaxes/lean4.json @@ -35,6 +35,23 @@ "name": "keyword.other.lean4" }, { "begin": "«", "end": "»", "contentName": "entity.name.lean4" }, + { + "begin": "(s!)\"", "end": "\"", + "name": "string.interpolated.lean4", + "beginCaptures": { + "1": { "name": "keyword.other.lean4" } + }, + "patterns": [ + { + "begin": "(\\{)", "end": "(\\})", + "beginCaptures": { "1": { "name": "keyword.other.lean4" } }, + "endCaptures": { "1": { "name": "keyword.other.lean4" } }, + "patterns": [ {"include": "$self"} ] }, + { "match": "\\\\[\\\\\"ntr']", "name": "constant.character.escape.lean4" }, + { "match": "\\\\x[0-9A-Fa-f][0-9A-Fa-f]", "name": "constant.character.escape.lean4" }, + { "match": "\\\\u[0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f]", "name": "constant.character.escape.lean4" } + ] + }, { "begin": "\"", "end": "\"", "name": "string.quoted.double.lean4",