diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3589981689..98f9cde0bc 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -16,7 +16,6 @@ rustfmt.toml @MichaelMauderer @mwu-tow @farmaazon @vitvakatu @Frizi @kazcw Cargo.lock Cargo.toml /lib/rust/ @MichaelMauderer @mwu-tow @farmaazon @kazcw @vitvakatu @Frizi -/lib/rust/ensogl/ @MichaelMauderer @farmaazon @kazcw @vitvakatu @Frizi /lib/rust/parser/ @MichaelMauderer @mwu-tow @farmaazon @kazcw @vitvakatu @Frizi @jaroslavtulach /integration-test/ @MichaelMauderer @farmaazon @kazcw @vitvakatu @Frizi /tools/build-performance/ @kazcw @mwu-tow @Akirathan diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 14230422ff..ee3495b767 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -53,169 +53,6 @@ jobs: outputs: ENSO_RELEASE_ID: ${{ steps.prepare.outputs.ENSO_RELEASE_ID }} ENSO_VERSION: ${{ steps.prepare.outputs.ENSO_VERSION }} - enso-build-ci-gen-job-build-wasm-linux-x86_64: - name: Build GUI (WASM) (linux, x86_64) - runs-on: - - self-hosted - - Linux - steps: - - if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent') - name: Setup conda (GH runners only) - uses: s-weigand/setup-conda@v1.2.1 - with: - update-conda: false - conda-channels: anaconda, conda-forge - - if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent') - name: Installing wasm-pack - uses: jetli/wasm-pack-action@v0.4.0 - with: - version: v0.10.2 - - name: Expose Artifact API and context information. - uses: actions/github-script@v7 - with: - script: "\n core.exportVariable(\"ACTIONS_RUNTIME_TOKEN\", process.env[\"ACTIONS_RUNTIME_TOKEN\"])\n core.exportVariable(\"ACTIONS_RUNTIME_URL\", process.env[\"ACTIONS_RUNTIME_URL\"])\n core.exportVariable(\"GITHUB_RETENTION_DAYS\", process.env[\"GITHUB_RETENTION_DAYS\"])\n console.log(context)\n " - - name: Checking out the repository - uses: actions/checkout@v4 - with: - clean: false - submodules: recursive - - name: Build Script Setup - run: ./run --help - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - if: "(contains(github.event.pull_request.labels.*.name, 'CI: Clean build required') || inputs.clean_build_required)" - name: Clean before - run: ./run git-clean - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - run: ./run wasm build --wasm-upload-artifact ${{ runner.os == 'Linux' }} - env: - ENSO_AG_GRID_LICENSE_KEY: ${{ secrets.ENSO_AG_GRID_LICENSE_KEY }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - if: failure() && runner.os == 'Windows' - name: List files if failed (Windows) - run: Get-ChildItem -Force -Recurse - - if: failure() && runner.os != 'Windows' - name: List files if failed (non-Windows) - run: ls -lAR - - if: "(always()) && (contains(github.event.pull_request.labels.*.name, 'CI: Clean build required') || inputs.clean_build_required)" - name: Clean after - run: ./run git-clean - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - enso-build-ci-gen-job-deploy-gui-linux-x86_64: - name: Upload GUI to S3 (linux, x86_64) - needs: - - enso-build-ci-gen-upload-ide-linux-x86_64 - runs-on: - - self-hosted - - Linux - steps: - - if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent') - name: Setup conda (GH runners only) - uses: s-weigand/setup-conda@v1.2.1 - with: - update-conda: false - conda-channels: anaconda, conda-forge - - if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent') - name: Installing wasm-pack - uses: jetli/wasm-pack-action@v0.4.0 - with: - version: v0.10.2 - - name: Expose Artifact API and context information. - uses: actions/github-script@v7 - with: - script: "\n core.exportVariable(\"ACTIONS_RUNTIME_TOKEN\", process.env[\"ACTIONS_RUNTIME_TOKEN\"])\n core.exportVariable(\"ACTIONS_RUNTIME_URL\", process.env[\"ACTIONS_RUNTIME_URL\"])\n core.exportVariable(\"GITHUB_RETENTION_DAYS\", process.env[\"GITHUB_RETENTION_DAYS\"])\n console.log(context)\n " - - name: Checking out the repository - uses: actions/checkout@v4 - with: - clean: false - submodules: recursive - - name: Build Script Setup - run: ./run --help - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - if: "(contains(github.event.pull_request.labels.*.name, 'CI: Clean build required') || inputs.clean_build_required)" - name: Clean before - run: ./run git-clean - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - run: ./run release deploy-gui - env: - AWS_ACCESS_KEY_ID: ${{ secrets.ARTEFACT_S3_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.ARTEFACT_S3_SECRET_ACCESS_KEY }} - ENSO_ADMIN_TOKEN: ${{ secrets.ENSO_ADMIN_TOKEN }} - GITHUB_TOKEN: ${{ secrets.CI_PRIVATE_TOKEN }} - - if: failure() && runner.os == 'Windows' - name: List files if failed (Windows) - run: Get-ChildItem -Force -Recurse - - if: failure() && runner.os != 'Windows' - name: List files if failed (non-Windows) - run: ls -lAR - - if: "(always()) && (contains(github.event.pull_request.labels.*.name, 'CI: Clean build required') || inputs.clean_build_required)" - name: Clean after - run: ./run git-clean - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - enso-build-ci-gen-job-deploy-runtime-linux-x86_64: - name: Upload Runtime to ECR (linux, x86_64) - needs: - - enso-build-ci-gen-draft-release-linux-x86_64 - - enso-build-ci-gen-job-upload-backend-linux-x86_64 - runs-on: - - self-hosted - - Linux - steps: - - if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent') - name: Setup conda (GH runners only) - uses: s-weigand/setup-conda@v1.2.1 - with: - update-conda: false - conda-channels: anaconda, conda-forge - - if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent') - name: Installing wasm-pack - uses: jetli/wasm-pack-action@v0.4.0 - with: - version: v0.10.2 - - name: Expose Artifact API and context information. - uses: actions/github-script@v7 - with: - script: "\n core.exportVariable(\"ACTIONS_RUNTIME_TOKEN\", process.env[\"ACTIONS_RUNTIME_TOKEN\"])\n core.exportVariable(\"ACTIONS_RUNTIME_URL\", process.env[\"ACTIONS_RUNTIME_URL\"])\n core.exportVariable(\"GITHUB_RETENTION_DAYS\", process.env[\"GITHUB_RETENTION_DAYS\"])\n console.log(context)\n " - - name: Checking out the repository - uses: actions/checkout@v4 - with: - clean: false - submodules: recursive - - name: Build Script Setup - run: ./run --help - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - if: "(contains(github.event.pull_request.labels.*.name, 'CI: Clean build required') || inputs.clean_build_required)" - name: Clean before - run: ./run git-clean - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - run: ./run release deploy-runtime - env: - AWS_ACCESS_KEY_ID: ${{ secrets.ECR_PUSH_RUNTIME_ACCESS_KEY_ID }} - AWS_DEFAULT_REGION: eu-west-1 - AWS_SECRET_ACCESS_KEY: ${{ secrets.ECR_PUSH_RUNTIME_SECRET_ACCESS_KEY }} - ENSO_BUILD_ECR_REPOSITORY: runtime - GITHUB_TOKEN: ${{ secrets.CI_PRIVATE_TOKEN }} - - if: failure() && runner.os == 'Windows' - name: List files if failed (Windows) - run: Get-ChildItem -Force -Recurse - - if: failure() && runner.os != 'Windows' - name: List files if failed (non-Windows) - run: ls -lAR - - if: "(always()) && (contains(github.event.pull_request.labels.*.name, 'CI: Clean build required') || inputs.clean_build_required)" - name: Clean after - run: ./run git-clean - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - env: - ENSO_RELEASE_ID: ${{ needs.enso-build-ci-gen-draft-release-linux-x86_64.outputs.ENSO_RELEASE_ID }} - ENSO_VERSION: ${{ needs.enso-build-ci-gen-draft-release-linux-x86_64.outputs.ENSO_VERSION }} enso-build-ci-gen-job-upload-backend-linux-x86_64: name: Upload Backend (linux, x86_64) needs: @@ -436,12 +273,6 @@ jobs: name: Publish release (linux, x86_64) needs: - enso-build-ci-gen-draft-release-linux-x86_64 - - enso-build-ci-gen-job-deploy-gui-linux-x86_64 - - enso-build-ci-gen-job-deploy-runtime-linux-x86_64 - - enso-build-ci-gen-upload-ide-linux-x86_64 - - enso-build-ci-gen-upload-ide-macos-aarch64 - - enso-build-ci-gen-upload-ide-macos-x86_64 - - enso-build-ci-gen-upload-ide-windows-x86_64 - enso-build-ci-gen-upload-ide2-linux-x86_64 - enso-build-ci-gen-upload-ide2-macos-aarch64 - enso-build-ci-gen-upload-ide2-macos-x86_64 @@ -499,258 +330,6 @@ jobs: AWS_SECRET_ACCESS_KEY: ${{ secrets.ARTEFACT_S3_SECRET_ACCESS_KEY }} ENSO_RELEASE_ID: ${{ needs.enso-build-ci-gen-draft-release-linux-x86_64.outputs.ENSO_RELEASE_ID }} ENSO_VERSION: ${{ needs.enso-build-ci-gen-draft-release-linux-x86_64.outputs.ENSO_VERSION }} - enso-build-ci-gen-upload-ide-linux-x86_64: - name: Build Old IDE (linux, x86_64) - needs: - - enso-build-ci-gen-draft-release-linux-x86_64 - - enso-build-ci-gen-job-build-wasm-linux-x86_64 - - enso-build-ci-gen-job-upload-backend-linux-x86_64 - runs-on: - - self-hosted - - Linux - steps: - - if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent') - name: Setup conda (GH runners only) - uses: s-weigand/setup-conda@v1.2.1 - with: - update-conda: false - conda-channels: anaconda, conda-forge - - if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent') - name: Installing wasm-pack - uses: jetli/wasm-pack-action@v0.4.0 - with: - version: v0.10.2 - - name: Expose Artifact API and context information. - uses: actions/github-script@v7 - with: - script: "\n core.exportVariable(\"ACTIONS_RUNTIME_TOKEN\", process.env[\"ACTIONS_RUNTIME_TOKEN\"])\n core.exportVariable(\"ACTIONS_RUNTIME_URL\", process.env[\"ACTIONS_RUNTIME_URL\"])\n core.exportVariable(\"GITHUB_RETENTION_DAYS\", process.env[\"GITHUB_RETENTION_DAYS\"])\n console.log(context)\n " - - name: Checking out the repository - uses: actions/checkout@v4 - with: - clean: false - submodules: recursive - - name: Build Script Setup - run: ./run --help - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - if: (always()) - name: Clean before - run: ./run git-clean - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - run: ./run ide upload --wasm-source current-ci-run --backend-source release --backend-release ${{env.ENSO_RELEASE_ID}} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - if: failure() && runner.os == 'Windows' - name: List files if failed (Windows) - run: Get-ChildItem -Force -Recurse - - if: failure() && runner.os != 'Windows' - name: List files if failed (non-Windows) - run: ls -lAR - - if: (always()) - name: Clean after - run: ./run git-clean - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - env: - ENSO_RELEASE_ID: ${{ needs.enso-build-ci-gen-draft-release-linux-x86_64.outputs.ENSO_RELEASE_ID }} - ENSO_VERSION: ${{ needs.enso-build-ci-gen-draft-release-linux-x86_64.outputs.ENSO_VERSION }} - enso-build-ci-gen-upload-ide-macos-aarch64: - name: Build Old IDE (macos, aarch64) - needs: - - enso-build-ci-gen-draft-release-linux-x86_64 - - enso-build-ci-gen-job-build-wasm-linux-x86_64 - - enso-build-ci-gen-job-upload-backend-macos-aarch64 - runs-on: - - self-hosted - - macOS - - ARM64 - steps: - - if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent') - name: Setup conda (GH runners only) - uses: s-weigand/setup-conda@v1.2.1 - with: - update-conda: false - conda-channels: anaconda, conda-forge - - if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent') - name: Installing wasm-pack - uses: jetli/wasm-pack-action@v0.4.0 - with: - version: v0.10.2 - - name: Expose Artifact API and context information. - uses: actions/github-script@v7 - with: - script: "\n core.exportVariable(\"ACTIONS_RUNTIME_TOKEN\", process.env[\"ACTIONS_RUNTIME_TOKEN\"])\n core.exportVariable(\"ACTIONS_RUNTIME_URL\", process.env[\"ACTIONS_RUNTIME_URL\"])\n core.exportVariable(\"GITHUB_RETENTION_DAYS\", process.env[\"GITHUB_RETENTION_DAYS\"])\n console.log(context)\n " - - name: Checking out the repository - uses: actions/checkout@v4 - with: - clean: false - submodules: recursive - - name: Build Script Setup - run: ./run --help - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - if: (always()) - name: Clean before - run: ./run git-clean - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: NPM install - run: npm install - - name: Uninstall old Electron Builder - run: npm uninstall --save --workspace enso electron-builder - - name: Install new Electron Builder - run: npm install --save-dev --workspace enso electron-builder@24.6.4 - - run: ./run ide upload --wasm-source current-ci-run --backend-source release --backend-release ${{env.ENSO_RELEASE_ID}} - env: - APPLEID: ${{ secrets.APPLE_NOTARIZATION_USERNAME }} - APPLEIDPASS: ${{ secrets.APPLE_NOTARIZATION_PASSWORD }} - APPLETEAMID: ${{ secrets.APPLE_NOTARIZATION_TEAM_ID }} - CSC_FOR_PULL_REQUEST: "true" - CSC_IDENTITY_AUTO_DISCOVERY: "true" - CSC_KEY_PASSWORD: ${{ secrets.APPLE_CODE_SIGNING_CERT_PASSWORD }} - CSC_LINK: ${{ secrets.APPLE_CODE_SIGNING_CERT }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - if: failure() && runner.os == 'Windows' - name: List files if failed (Windows) - run: Get-ChildItem -Force -Recurse - - if: failure() && runner.os != 'Windows' - name: List files if failed (non-Windows) - run: ls -lAR - - if: (always()) - name: Clean after - run: ./run git-clean - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - env: - ENSO_RELEASE_ID: ${{ needs.enso-build-ci-gen-draft-release-linux-x86_64.outputs.ENSO_RELEASE_ID }} - ENSO_VERSION: ${{ needs.enso-build-ci-gen-draft-release-linux-x86_64.outputs.ENSO_VERSION }} - enso-build-ci-gen-upload-ide-macos-x86_64: - name: Build Old IDE (macos, x86_64) - needs: - - enso-build-ci-gen-draft-release-linux-x86_64 - - enso-build-ci-gen-job-build-wasm-linux-x86_64 - - enso-build-ci-gen-job-upload-backend-macos-x86_64 - runs-on: - - macos-latest - steps: - - if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent') - name: Setup conda (GH runners only) - uses: s-weigand/setup-conda@v1.2.1 - with: - update-conda: false - conda-channels: anaconda, conda-forge - - if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent') - name: Installing wasm-pack - uses: jetli/wasm-pack-action@v0.4.0 - with: - version: v0.10.2 - - name: Expose Artifact API and context information. - uses: actions/github-script@v7 - with: - script: "\n core.exportVariable(\"ACTIONS_RUNTIME_TOKEN\", process.env[\"ACTIONS_RUNTIME_TOKEN\"])\n core.exportVariable(\"ACTIONS_RUNTIME_URL\", process.env[\"ACTIONS_RUNTIME_URL\"])\n core.exportVariable(\"GITHUB_RETENTION_DAYS\", process.env[\"GITHUB_RETENTION_DAYS\"])\n console.log(context)\n " - - name: Checking out the repository - uses: actions/checkout@v4 - with: - clean: false - submodules: recursive - - name: Build Script Setup - run: ./run --help - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - if: (always()) - name: Clean before - run: ./run git-clean - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: NPM install - run: npm install - - name: Uninstall old Electron Builder - run: npm uninstall --save --workspace enso electron-builder - - name: Install new Electron Builder - run: npm install --save-dev --workspace enso electron-builder@24.6.4 - - run: ./run ide upload --wasm-source current-ci-run --backend-source release --backend-release ${{env.ENSO_RELEASE_ID}} - env: - APPLEID: ${{ secrets.APPLE_NOTARIZATION_USERNAME }} - APPLEIDPASS: ${{ secrets.APPLE_NOTARIZATION_PASSWORD }} - APPLETEAMID: ${{ secrets.APPLE_NOTARIZATION_TEAM_ID }} - CSC_FOR_PULL_REQUEST: "true" - CSC_IDENTITY_AUTO_DISCOVERY: "true" - CSC_KEY_PASSWORD: ${{ secrets.APPLE_CODE_SIGNING_CERT_PASSWORD }} - CSC_LINK: ${{ secrets.APPLE_CODE_SIGNING_CERT }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - if: failure() && runner.os == 'Windows' - name: List files if failed (Windows) - run: Get-ChildItem -Force -Recurse - - if: failure() && runner.os != 'Windows' - name: List files if failed (non-Windows) - run: ls -lAR - - if: (always()) - name: Clean after - run: ./run git-clean - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - env: - ENSO_RELEASE_ID: ${{ needs.enso-build-ci-gen-draft-release-linux-x86_64.outputs.ENSO_RELEASE_ID }} - ENSO_VERSION: ${{ needs.enso-build-ci-gen-draft-release-linux-x86_64.outputs.ENSO_VERSION }} - enso-build-ci-gen-upload-ide-windows-x86_64: - name: Build Old IDE (windows, x86_64) - needs: - - enso-build-ci-gen-draft-release-linux-x86_64 - - enso-build-ci-gen-job-build-wasm-linux-x86_64 - - enso-build-ci-gen-job-upload-backend-windows-x86_64 - runs-on: - - self-hosted - - Windows - steps: - - if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent') - name: Setup conda (GH runners only) - uses: s-weigand/setup-conda@v1.2.1 - with: - update-conda: false - conda-channels: anaconda, conda-forge - - if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent') - name: Installing wasm-pack - uses: jetli/wasm-pack-action@v0.4.0 - with: - version: v0.10.2 - - name: Expose Artifact API and context information. - uses: actions/github-script@v7 - with: - script: "\n core.exportVariable(\"ACTIONS_RUNTIME_TOKEN\", process.env[\"ACTIONS_RUNTIME_TOKEN\"])\n core.exportVariable(\"ACTIONS_RUNTIME_URL\", process.env[\"ACTIONS_RUNTIME_URL\"])\n core.exportVariable(\"GITHUB_RETENTION_DAYS\", process.env[\"GITHUB_RETENTION_DAYS\"])\n console.log(context)\n " - - name: Checking out the repository - uses: actions/checkout@v4 - with: - clean: false - submodules: recursive - - name: Build Script Setup - run: ./run --help - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - if: (always()) - name: Clean before - run: ./run git-clean - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - run: ./run ide upload --wasm-source current-ci-run --backend-source release --backend-release ${{env.ENSO_RELEASE_ID}} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - WIN_CSC_KEY_PASSWORD: ${{ secrets.MICROSOFT_CODE_SIGNING_CERT_PASSWORD }} - WIN_CSC_LINK: ${{ secrets.MICROSOFT_CODE_SIGNING_CERT }} - - if: failure() && runner.os == 'Windows' - name: List files if failed (Windows) - run: Get-ChildItem -Force -Recurse - - if: failure() && runner.os != 'Windows' - name: List files if failed (non-Windows) - run: ls -lAR - - if: (always()) - name: Clean after - run: ./run git-clean - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - env: - ENSO_RELEASE_ID: ${{ needs.enso-build-ci-gen-draft-release-linux-x86_64.outputs.ENSO_RELEASE_ID }} - ENSO_VERSION: ${{ needs.enso-build-ci-gen-draft-release-linux-x86_64.outputs.ENSO_VERSION }} enso-build-ci-gen-upload-ide2-linux-x86_64: name: Build New IDE (linux, x86_64) needs: diff --git a/Cargo.lock b/Cargo.lock index d8561888b0..5d2d7f3f15 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -47,14 +47,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "analytics" -version = "0.1.0" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - [[package]] name = "android_system_properties" version = "0.1.5" @@ -79,15 +71,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "approx" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" -dependencies = [ - "num-traits", -] - [[package]] name = "arc-swap" version = "1.6.0" @@ -110,35 +93,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c07dab4369547dbe5114677b33fbbf724971019f3818172d59a97a61c774ffd" -[[package]] -name = "ast" -version = "0.1.0" -dependencies = [ - "ast-macros", - "derive_more", - "enso-data-structures", - "enso-prelude", - "enso-profiler", - "enso-shapely", - "enso-text", - "failure", - "lazy_static", - "regex", - "serde", - "uuid 0.8.2", -] - -[[package]] -name = "ast-macros" -version = "0.1.0" -dependencies = [ - "Inflector", - "enso-macro-utils", - "proc-macro2", - "quote", - "syn 1.0.107", -] - [[package]] name = "async-channel" version = "1.8.0" @@ -631,7 +585,7 @@ dependencies = [ "aws-smithy-http", "aws-smithy-types", "http", - "rustc_version 0.4.0", + "rustc_version", "tracing", "zeroize", ] @@ -644,7 +598,7 @@ checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" dependencies = [ "addr2line", "cc", - "cfg-if 1.0.0", + "cfg-if", "libc", "miniz_oxide", "object", @@ -663,15 +617,6 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" -[[package]] -name = "bimap" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "783204f24fd7724ea274d327619cfa6a6018047bb0561a68aadff6f56787591b" -dependencies = [ - "cfg-if 0.1.10", -] - [[package]] name = "bincode" version = "1.3.3" @@ -700,52 +645,19 @@ dependencies = [ "virtue", ] -[[package]] -name = "bit_field" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4" - [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "bitflags" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24a6904aef64d73cf10ab17ebace7befb918b82164785cb89907993be7f83813" - -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -dependencies = [ - "block-padding", - "byte-tools", - "byteorder", - "generic-array 0.12.4", -] - [[package]] name = "block-buffer" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" dependencies = [ - "generic-array 0.14.6", -] - -[[package]] -name = "block-padding" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -dependencies = [ - "byte-tools", + "generic-array", ] [[package]] @@ -804,12 +716,6 @@ version = "3.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b" -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" - [[package]] name = "byte-unit" version = "4.0.18" @@ -820,12 +726,6 @@ dependencies = [ "utf8-width", ] -[[package]] -name = "bytecount" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be0fdd54b507df8f22012890aadd099979befdba27713c767993f8380112ca7c" - [[package]] name = "bytemuck" version = "1.13.1" @@ -886,12 +786,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -920,7 +814,7 @@ version = "2.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ - "bitflags 1.3.2", + "bitflags", "textwrap 0.11.0", "unicode-width", ] @@ -932,7 +826,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" dependencies = [ "atty", - "bitflags 1.3.2", + "bitflags", "clap_derive", "clap_lex", "indexmap", @@ -965,13 +859,6 @@ dependencies = [ "os_str_bytes", ] -[[package]] -name = "code-builder" -version = "0.1.0" -dependencies = [ - "enso-prelude", -] - [[package]] name = "codespan-reporting" version = "0.11.1" @@ -1001,15 +888,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "config-reader" -version = "0.1.0" -dependencies = [ - "Inflector", - "serde", - "serde_yaml", -] - [[package]] name = "console" version = "0.15.5" @@ -1028,30 +906,10 @@ name = "console_error_panic_hook" version = "0.1.7" source = "git+https://github.com/enso-org/console_error_panic_hook#cdd73b81709475104b9ebfe6271c6914ff71b7b2" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "wasm-bindgen", ] -[[package]] -name = "const_format" -version = "0.2.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7309d9b4d3d2c0641e018d449232f2e28f1b22933c137f157d3dbc14228b8c0e" -dependencies = [ - "const_format_proc_macros", -] - -[[package]] -name = "const_format_proc_macros" -version = "0.2.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f47bf7270cf70d370f8f98c1abb6d2d4cf60a6845d30e05bfb90c6568650" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - [[package]] name = "convert_case" version = "0.4.0" @@ -1098,7 +956,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dfea2db42e9927a3845fb268a10a72faed6d416065f77873f05e411457c363e" dependencies = [ - "rustc_version 0.4.0", + "rustc_version", ] [[package]] @@ -1107,7 +965,7 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -1152,7 +1010,7 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", ] @@ -1162,7 +1020,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] @@ -1174,7 +1032,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" dependencies = [ "autocfg", - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", "memoffset", "scopeguard", @@ -1186,7 +1044,7 @@ version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -1195,7 +1053,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array 0.14.6", + "generic-array", "typenum", ] @@ -1327,128 +1185,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaa37046cc0f6c3cc6090fbdbf73ef0b8ef4cfcc37f6befc0020f63e8cf121e1" -[[package]] -name = "debug-scene-component-list-panel-view" -version = "0.1.0" -dependencies = [ - "enso-frp", - "enso-profiler", - "ensogl-core", - "ensogl-grid-view", - "ensogl-hardcoded-theme", - "ensogl-icons", - "ensogl-selector", - "ensogl-text", - "ensogl-text-msdf", - "ensogl-tooltip", - "ide-view-component-list-panel", - "ide-view-documentation", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "debug-scene-documentation" -version = "0.1.0" -dependencies = [ - "enso-doc-parser", - "enso-suggestion-database", - "ensogl", - "ensogl-hardcoded-theme", - "ensogl-text-msdf", - "ide-view-documentation", - "ide-view-graph-editor", - "wasm-bindgen", -] - -[[package]] -name = "debug-scene-graph-editor-edges" -version = "0.1.0" -dependencies = [ - "enso-frp", - "ensogl", - "ensogl-hardcoded-theme", - "ide-view-graph-editor", - "nalgebra", - "wasm-bindgen", -] - -[[package]] -name = "debug-scene-icons" -version = "0.1.0" -dependencies = [ - "convert_case 0.6.0", - "ensogl", - "ensogl-hardcoded-theme", - "ensogl-icons", - "ensogl-text-msdf", - "ensogl-tooltip", - "ide-view-component-list-panel-grid", - "ide-view-graph-editor", - "wasm-bindgen", -] - -[[package]] -name = "debug-scene-interface" -version = "0.1.0" -dependencies = [ - "ast", - "enso-frp", - "ensogl", - "ensogl-hardcoded-theme", - "ensogl-text-msdf", - "ide-view", - "ide-view-execution-environment-selector", - "parser", - "span-tree", - "uuid 0.8.2", - "wasm-bindgen", -] - -[[package]] -name = "debug-scene-project-view-top-bar" -version = "0.1.0" -dependencies = [ - "ensogl", - "ensogl-hardcoded-theme", - "ensogl-text-msdf", - "ide-view-execution-environment-selector", - "ide-view-project-view-top-bar", -] - -[[package]] -name = "debug-scene-text-grid-visualization" -version = "0.1.0" -dependencies = [ - "enso-frp", - "ensogl", - "ensogl-grid-view", - "ensogl-hardcoded-theme", - "ensogl-list-view", - "ensogl-text-msdf", - "ide-view", - "js-sys", - "nalgebra", - "serde_json", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "debug-scene-visualization" -version = "0.1.0" -dependencies = [ - "enso-frp", - "ensogl", - "ensogl-hardcoded-theme", - "ensogl-text-msdf", - "ide-view", - "js-sys", - "nalgebra", - "serde_json", - "wasm-bindgen", -] - [[package]] name = "dependency_runner" version = "1.0.0" @@ -1490,7 +1226,7 @@ dependencies = [ "convert_case 0.4.0", "proc-macro2", "quote", - "rustc_version 0.4.0", + "rustc_version", "syn 1.0.107", ] @@ -1506,28 +1242,13 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" -[[package]] -name = "difference" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" - -[[package]] -name = "digest" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -dependencies = [ - "generic-array 0.12.4", -] - [[package]] name = "digest" version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ - "block-buffer 0.10.3", + "block-buffer", "crypto-common", ] @@ -1558,32 +1279,6 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" -[[package]] -name = "double-representation" -version = "0.1.0" -dependencies = [ - "ast", - "const_format", - "engine-protocol", - "enso-data-structures", - "enso-prelude", - "enso-profiler", - "enso-text", - "failure", - "itertools", - "parser", - "regex", - "serde", - "uuid 0.8.2", - "wasm-bindgen-test", -] - -[[package]] -name = "downcast" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb454f0228b18c7f4c3b0ebbee346ed9c52e7443b0999cd543ff3571205701d" - [[package]] name = "either" version = "1.8.1" @@ -1602,52 +1297,7 @@ version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" dependencies = [ - "cfg-if 1.0.0", -] - -[[package]] -name = "engine-protocol" -version = "0.1.0" -dependencies = [ - "bytes", - "chrono", - "enso-build-utilities", - "enso-data-structures", - "enso-prelude", - "enso-shapely", - "enso-text", - "enso-web", - "failure", - "flatbuffers", - "flatc-rust", - "futures", - "hex", - "json-rpc", - "mockall", - "reqwest", - "serde", - "serde_json", - "sha3", - "strum", - "strum_macros", - "tokio", - "uuid 0.8.2", - "wasm-bindgen-test", - "zip", -] - -[[package]] -name = "enso-automata" -version = "0.2.0" -dependencies = [ - "enso-prelude", -] - -[[package]] -name = "enso-bitmap" -version = "0.1.0" -dependencies = [ - "thiserror", + "cfg-if", ] [[package]] @@ -1670,7 +1320,7 @@ dependencies = [ "enso-build-macros-lib", "enso-enso-font", "enso-font", - "ensogl-pack", + "enso-pack", "futures", "futures-util", "glob", @@ -1685,7 +1335,7 @@ dependencies = [ "regex", "reqwest", "scopeguard", - "semver 1.0.16", + "semver", "serde", "serde_json", "serde_yaml", @@ -1696,7 +1346,7 @@ dependencies = [ "toml", "tracing", "url", - "uuid 1.2.2", + "uuid", "walkdir", "zip", ] @@ -1720,7 +1370,6 @@ name = "enso-build-ci-gen" version = "0.1.0" dependencies = [ "enso-build", - "enso-build-shader-tools", "ide-ci", "serde_yaml", "tokio", @@ -1775,44 +1424,6 @@ dependencies = [ "syn 1.0.107", ] -[[package]] -name = "enso-build-shader-tools" -version = "0.1.0" -dependencies = [ - "html_parser", - "ide-ci", - "octocrab", - "regex", - "tempfile", - "tokio", -] - -[[package]] -name = "enso-build-utilities" -version = "0.1.0" -dependencies = [ - "ide-ci", -] - -[[package]] -name = "enso-callback" -version = "0.1.0" -dependencies = [ - "enso-prelude", -] - -[[package]] -name = "enso-config" -version = "0.1.0" -dependencies = [ - "config-reader", - "enso-json-to-struct", - "enso-prelude", - "ensogl", - "semver 1.0.16", - "thiserror", -] - [[package]] name = "enso-data-structures" version = "0.2.0" @@ -1822,9 +1433,7 @@ dependencies = [ "enso-prelude", "failure", "itertools", - "rustversion", "serde", - "typenum", ] [[package]] @@ -1838,20 +1447,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "enso-debug-scene" -version = "0.1.0" -dependencies = [ - "debug-scene-component-list-panel-view", - "debug-scene-documentation", - "debug-scene-graph-editor-edges", - "debug-scene-icons", - "debug-scene-interface", - "debug-scene-project-view-top-bar", - "debug-scene-text-grid-visualization", - "debug-scene-visualization", -] - [[package]] name = "enso-doc-parser" version = "0.1.0" @@ -1876,16 +1471,6 @@ dependencies = [ "owned_ttf_parser", ] -[[package]] -name = "enso-executor" -version = "0.1.0" -dependencies = [ - "enso-prelude", - "enso-profiler", - "ensogl-core", - "futures", -] - [[package]] name = "enso-font" version = "0.1.0" @@ -1903,136 +1488,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "enso-frp" -version = "0.1.0" -dependencies = [ - "Inflector", - "enso-callback", - "enso-generics", - "enso-prelude", - "enso-profiler", - "enso-web", - "keyboard-types", - "nalgebra", - "percent-encoding", - "unicode-segmentation", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "enso-frp2" -version = "0.1.0" -dependencies = [ - "bytemuck", - "enso-data-structures", - "enso-frp", - "enso-generics", - "enso-prelude", - "smallvec 1.10.0", -] - -[[package]] -name = "enso-generics" -version = "0.2.0" -dependencies = [ - "derivative", - "enso-zst", - "nalgebra", - "paste", - "serde", -] - -[[package]] -name = "enso-gui" -version = "0.1.0" -dependencies = [ - "analytics", - "ast", - "bimap", - "console_error_panic_hook", - "const_format", - "convert_case 0.6.0", - "double-representation", - "engine-protocol", - "enso-callback", - "enso-config", - "enso-data-structures", - "enso-debug-api", - "enso-debug-scene", - "enso-doc-parser", - "enso-executor", - "enso-frp", - "enso-notification", - "enso-prelude", - "enso-profiler", - "enso-shapely", - "enso-suggestion-database", - "enso-text", - "enso-web", - "ensogl", - "ensogl-breadcrumbs", - "ensogl-component", - "ensogl-drop-manager", - "ensogl-dynamic-assets", - "ensogl-examples", - "ensogl-hardcoded-theme", - "ensogl-icons", - "ensogl-text-msdf", - "failure", - "flo_stream", - "futures", - "fuzzly", - "ide-view", - "itertools", - "js-sys", - "json-rpc", - "mockall", - "nalgebra", - "ordered-float", - "parser", - "regex", - "semver 1.0.16", - "serde", - "serde_json", - "sha3", - "span-tree", - "superslice", - "uuid 0.8.2", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-bindgen-test", - "web-sys", -] - -[[package]] -name = "enso-integration-test" -version = "0.1.0" -dependencies = [ - "approx 0.5.1", - "engine-protocol", - "enso-executor", - "enso-frp", - "enso-gui", - "enso-prelude", - "enso-shortcuts", - "enso-web", - "ensogl", - "wasm-bindgen", - "wasm-bindgen-test", -] - -[[package]] -name = "enso-json-to-struct" -version = "0.1.0" -dependencies = [ - "enso-prelude", - "proc-macro2", - "serde", - "serde_json", -] - [[package]] name = "enso-logging" version = "0.3.1" @@ -2084,13 +1539,17 @@ dependencies = [ ] [[package]] -name = "enso-notification" +name = "enso-pack" version = "0.1.0" dependencies = [ - "enso-executor", "enso-prelude", - "flo_stream", "futures", + "ide-ci", + "manifest-dir-macros", + "serde", + "serde_json", + "tokio", + "walkdir", ] [[package]] @@ -2100,19 +1559,17 @@ dependencies = [ "bincode 1.3.3", "enso-data-structures", "enso-metamodel", - "enso-metamodel-lexpr", "enso-parser-syntax-tree-visitor", "enso-prelude", "enso-reflect", "enso-shapely-macros", "enso-types", - "lexpr", "rand 0.8.5", "rand_chacha 0.3.1", "rand_distr", "serde", "serde_json", - "uuid 1.2.2", + "uuid", "wasm-bindgen-test", ] @@ -2194,9 +1651,8 @@ dependencies = [ "paste", "serde", "serde_json", - "smallvec 1.10.0", + "smallvec", "wasm-bindgen", - "wasm-bindgen-test", "weak-table", "web-sys", ] @@ -2213,48 +1669,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "enso-profiler-data" -version = "0.1.0" -dependencies = [ - "derivative", - "enso-prelude", - "enso-profiler", - "futures", - "serde", - "serde_json", -] - -[[package]] -name = "enso-profiler-demo-data" -version = "0.1.0" -dependencies = [ - "enso-profiler", - "futures", -] - -[[package]] -name = "enso-profiler-enso-data" -version = "0.1.0" -dependencies = [ - "chrono", - "csv", - "enso-profiler", - "enso-profiler-data", - "ensogl-core", - "json-rpc", - "serde", -] - -[[package]] -name = "enso-profiler-flame-graph" -version = "0.1.0" -dependencies = [ - "enso-profiler", - "enso-profiler-data", - "futures", -] - [[package]] name = "enso-profiler-macros" version = "0.1.0" @@ -2291,7 +1705,6 @@ dependencies = [ "enso-shapely-macros", "enso-zst", "wasm-bindgen", - "wasm-bindgen-test", "web-sys", ] @@ -2309,58 +1722,6 @@ dependencies = [ "syn 1.0.107", ] -[[package]] -name = "enso-shortcuts" -version = "0.1.0" -dependencies = [ - "enso-automata", - "enso-frp", - "enso-prelude", - "enso-web", - "js-sys", - "nalgebra", - "serde", - "serde_json", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "enso-suggestion-database" -version = "0.1.0" -dependencies = [ - "ast", - "convert_case 0.6.0", - "double-representation", - "engine-protocol", - "enso-data-structures", - "enso-doc-parser", - "enso-executor", - "enso-notification", - "enso-prelude", - "enso-profiler", - "enso-text", - "ensogl-icons", - "failure", - "flo_stream", - "futures", - "parser", - "serde", - "serde_json", - "span-tree", - "wasm-bindgen-test", -] - -[[package]] -name = "enso-text" -version = "0.1.0" -dependencies = [ - "enso-prelude", - "enso-types", - "serde", - "xi-rope", -] - [[package]] name = "enso-types" version = "0.1.0" @@ -2401,766 +1762,6 @@ dependencies = [ "serde", ] -[[package]] -name = "ensogl" -version = "0.1.0" -dependencies = [ - "ensogl-core", - "ensogl-text", -] - -[[package]] -name = "ensogl-breadcrumbs" -version = "0.1.0" -dependencies = [ - "enso-frp", - "ensogl-core", - "ensogl-derive-theme", - "ensogl-grid-view", - "ensogl-hardcoded-theme", - "ensogl-icons", - "ensogl-text", -] - -[[package]] -name = "ensogl-button" -version = "0.1.0" -dependencies = [ - "enso-frp", - "ensogl-core", -] - -[[package]] -name = "ensogl-component" -version = "0.1.0" -dependencies = [ - "ensogl-breadcrumbs", - "ensogl-button", - "ensogl-drop-down", - "ensogl-drop-down-menu", - "ensogl-drop-manager", - "ensogl-dynamic-assets", - "ensogl-file-browser", - "ensogl-flame-graph", - "ensogl-grid-view", - "ensogl-label", - "ensogl-list-editor", - "ensogl-list-view", - "ensogl-scroll-area", - "ensogl-scrollbar", - "ensogl-selector", - "ensogl-shadow", - "ensogl-spinner", - "ensogl-text", - "ensogl-toggle-button", - "ensogl-tooltip", -] - -[[package]] -name = "ensogl-core" -version = "0.1.0" -dependencies = [ - "Inflector", - "bit_field", - "bitflags 2.2.1", - "bytemuck", - "code-builder", - "console_error_panic_hook", - "enso-callback", - "enso-data-structures", - "enso-debug-api", - "enso-frp", - "enso-generics", - "enso-prelude", - "enso-profiler", - "enso-shapely", - "enso-shortcuts", - "enso-types", - "enso-web", - "ensogl-derive", - "ensogl-derive-theme", - "ensogl-text-embedded-fonts", - "enum_dispatch", - "failure", - "futures", - "itertools", - "js-sys", - "nalgebra", - "num-traits", - "num_enum", - "ordered-float", - "rand 0.8.5", - "rand_chacha 0.3.1", - "rustc-hash", - "semver 1.0.16", - "serde", - "smallvec 1.10.0", - "typenum", - "wasm-bindgen", - "wasm-bindgen-test", - "web-sys", -] - -[[package]] -name = "ensogl-derive" -version = "0.1.0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.15", -] - -[[package]] -name = "ensogl-derive-theme" -version = "0.1.0" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 1.0.107", -] - -[[package]] -name = "ensogl-drop-down" -version = "0.1.0" -dependencies = [ - "enso-frp", - "ensogl-core", - "ensogl-grid-view", - "ensogl-gui-component", - "ensogl-hardcoded-theme", - "ensogl-text", -] - -[[package]] -name = "ensogl-drop-down-menu" -version = "0.1.0" -dependencies = [ - "enso-frp", - "ensogl-core", - "ensogl-hardcoded-theme", - "ensogl-list-view", - "ensogl-text", -] - -[[package]] -name = "ensogl-drop-manager" -version = "0.1.0" -dependencies = [ - "enso-frp", - "enso-prelude", - "enso-types", - "enso-web", - "ensogl-core", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "ensogl-dynamic-assets" -version = "0.1.0" -dependencies = [ - "anyhow", - "enso-bitmap", - "enso-prelude", - "enso-shapely", - "ensogl-core", - "ensogl-text", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "ensogl-example-animation" -version = "0.1.0" -dependencies = [ - "enso-frp", - "enso-prelude", - "ensogl-core", - "ensogl-text-msdf", - "wasm-bindgen", -] - -[[package]] -name = "ensogl-example-auto-layout" -version = "0.1.0" -dependencies = [ - "ensogl-core", - "ensogl-hardcoded-theme", - "wasm-bindgen", -] - -[[package]] -name = "ensogl-example-built-in-shapes" -version = "0.1.0" -dependencies = [ - "ensogl-core", - "ensogl-hardcoded-theme", - "wasm-bindgen", -] - -[[package]] -name = "ensogl-example-cached-shape" -version = "0.1.0" -dependencies = [ - "ensogl-core", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "ensogl-example-complex-shape-system" -version = "0.1.0" -dependencies = [ - "ensogl-core", - "wasm-bindgen", -] - -[[package]] -name = "ensogl-example-custom-shape-system" -version = "0.1.0" -dependencies = [ - "enso-frp", - "enso-profiler", - "ensogl-core", - "wasm-bindgen", -] - -[[package]] -name = "ensogl-example-dom-symbols" -version = "0.1.0" -dependencies = [ - "ensogl-core", - "nalgebra", - "wasm-bindgen", -] - -[[package]] -name = "ensogl-example-drop-down" -version = "0.1.0" -dependencies = [ - "enso-frp", - "ensogl-core", - "ensogl-drop-down", - "ensogl-grid-view", - "ensogl-hardcoded-theme", - "ensogl-text-msdf", - "wasm-bindgen", -] - -[[package]] -name = "ensogl-example-drop-manager" -version = "0.1.0" -dependencies = [ - "enso-frp", - "enso-prelude", - "ensogl-core", - "ensogl-drop-manager", - "wasm-bindgen", - "wasm-bindgen-futures", -] - -[[package]] -name = "ensogl-example-easing-animator" -version = "0.1.0" -dependencies = [ - "ensogl-core", - "js-sys", - "nalgebra", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "ensogl-example-focus-management" -version = "0.1.0" -dependencies = [ - "ensogl-core", - "wasm-bindgen", -] - -[[package]] -name = "ensogl-example-grid-view" -version = "0.1.0" -dependencies = [ - "enso-frp", - "enso-text", - "ensogl-core", - "ensogl-grid-view", - "ensogl-hardcoded-theme", - "ensogl-text-msdf", - "itertools", - "wasm-bindgen", -] - -[[package]] -name = "ensogl-example-instance-ordering" -version = "0.1.0" -dependencies = [ - "ensogl-core", - "getrandom 0.2.8", - "rand 0.8.5", - "rand_chacha 0.3.1", - "rand_distr", - "wasm-bindgen", -] - -[[package]] -name = "ensogl-example-list-editor" -version = "0.1.0" -dependencies = [ - "enso-frp", - "ensogl-core", - "ensogl-list-editor", - "ensogl-slider", - "ensogl-text-msdf", -] - -[[package]] -name = "ensogl-example-list-view" -version = "0.1.0" -dependencies = [ - "enso-frp", - "enso-text", - "ensogl-core", - "ensogl-hardcoded-theme", - "ensogl-list-view", - "ensogl-text-msdf", - "wasm-bindgen", -] - -[[package]] -name = "ensogl-example-mouse-events" -version = "0.1.0" -dependencies = [ - "enso-frp", - "ensogl-core", - "ensogl-text-msdf", - "wasm-bindgen", -] - -[[package]] -name = "ensogl-example-profiling-run-graph" -version = "0.1.0" -dependencies = [ - "enso-debug-api", - "enso-frp", - "enso-profiler-data", - "enso-profiler-demo-data", - "enso-profiler-enso-data", - "enso-profiler-flame-graph", - "enso-web", - "ensogl-core", - "ensogl-flame-graph", - "ensogl-hardcoded-theme", - "ensogl-sequence-diagram", - "ensogl-text", - "ensogl-text-msdf", - "ensogl-tooltip", - "futures", - "qstring", - "serde", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "ensogl-example-render-profile-flamegraph" -version = "0.1.0" -dependencies = [ - "enso-debug-api", - "enso-frp", - "enso-profiler-data", - "enso-profiler-demo-data", - "enso-profiler-flame-graph", - "enso-web", - "ensogl-core", - "ensogl-flame-graph", - "ensogl-hardcoded-theme", - "ensogl-text", - "ensogl-text-msdf", - "ensogl-tooltip", - "futures", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "ensogl-example-scroll-area" -version = "0.1.0" -dependencies = [ - "ensogl-core", - "ensogl-hardcoded-theme", - "ensogl-scroll-area", - "ensogl-text-msdf", - "wasm-bindgen", -] - -[[package]] -name = "ensogl-example-slider" -version = "0.1.0" -dependencies = [ - "enso-frp", - "ensogl-core", - "ensogl-hardcoded-theme", - "ensogl-slider", - "ensogl-text-msdf", - "wasm-bindgen", -] - -[[package]] -name = "ensogl-example-sprite-system" -version = "0.1.0" -dependencies = [ - "enso-web", - "ensogl-core", - "wasm-bindgen", -] - -[[package]] -name = "ensogl-example-sprite-system-benchmark" -version = "0.1.0" -dependencies = [ - "ensogl-core", - "nalgebra", - "wasm-bindgen", -] - -[[package]] -name = "ensogl-example-text-area" -version = "0.1.0" -dependencies = [ - "ensogl-core", - "ensogl-hardcoded-theme", - "ensogl-text", - "ensogl-text-embedded-fonts", - "ensogl-text-msdf", - "wasm-bindgen", -] - -[[package]] -name = "ensogl-examples" -version = "0.1.0" -dependencies = [ - "ensogl-example-animation", - "ensogl-example-auto-layout", - "ensogl-example-built-in-shapes", - "ensogl-example-cached-shape", - "ensogl-example-complex-shape-system", - "ensogl-example-custom-shape-system", - "ensogl-example-dom-symbols", - "ensogl-example-drop-down", - "ensogl-example-drop-manager", - "ensogl-example-easing-animator", - "ensogl-example-focus-management", - "ensogl-example-grid-view", - "ensogl-example-instance-ordering", - "ensogl-example-list-editor", - "ensogl-example-list-view", - "ensogl-example-mouse-events", - "ensogl-example-profiling-run-graph", - "ensogl-example-render-profile-flamegraph", - "ensogl-example-scroll-area", - "ensogl-example-slider", - "ensogl-example-sprite-system", - "ensogl-example-sprite-system-benchmark", - "ensogl-example-text-area", -] - -[[package]] -name = "ensogl-file-browser" -version = "0.1.0" -dependencies = [ - "enso-frp", - "ensogl-core", -] - -[[package]] -name = "ensogl-flame-graph" -version = "0.1.0" -dependencies = [ - "enso-frp", - "enso-profiler", - "enso-profiler-flame-graph", - "ensogl", - "ensogl-core", - "ensogl-gui-component", - "ensogl-hardcoded-theme", - "ensogl-text", -] - -[[package]] -name = "ensogl-grid-view" -version = "0.1.0" -dependencies = [ - "approx 0.5.1", - "enso-frp", - "ensogl-core", - "ensogl-hardcoded-theme", - "ensogl-scroll-area", - "ensogl-shadow", - "ensogl-text", - "itertools", - "segment-tree", -] - -[[package]] -name = "ensogl-gui-component" -version = "0.1.0" -dependencies = [ - "enso-frp", - "ensogl-core", - "float_eq", - "wasm-bindgen-test", -] - -[[package]] -name = "ensogl-hardcoded-theme" -version = "0.1.0" -dependencies = [ - "enso-prelude", - "enso-shapely", - "ensogl-core", - "ensogl-text", -] - -[[package]] -name = "ensogl-icons" -version = "0.1.0" -dependencies = [ - "ensogl-core", - "ensogl-hardcoded-theme", - "failure", -] - -[[package]] -name = "ensogl-label" -version = "0.1.0" -dependencies = [ - "enso-frp", - "ensogl-core", - "ensogl-hardcoded-theme", - "ensogl-shadow", - "ensogl-text", -] - -[[package]] -name = "ensogl-list-editor" -version = "0.1.0" -dependencies = [ - "enso-frp", - "ensogl-core", - "ensogl-hardcoded-theme", - "ensogl-text", -] - -[[package]] -name = "ensogl-list-view" -version = "0.1.0" -dependencies = [ - "approx 0.5.1", - "enso-frp", - "ensogl-core", - "ensogl-hardcoded-theme", - "ensogl-shadow", - "ensogl-text", -] - -[[package]] -name = "ensogl-pack" -version = "0.1.0" -dependencies = [ - "enso-prelude", - "futures", - "ide-ci", - "manifest-dir-macros", - "serde", - "serde_json", - "tokio", - "walkdir", -] - -[[package]] -name = "ensogl-scroll-area" -version = "0.1.0" -dependencies = [ - "enso-frp", - "ensogl-core", - "ensogl-scrollbar", -] - -[[package]] -name = "ensogl-scrollbar" -version = "0.1.0" -dependencies = [ - "enso-frp", - "ensogl-core", - "ensogl-gui-component", - "ensogl-hardcoded-theme", - "ensogl-selector", -] - -[[package]] -name = "ensogl-selector" -version = "0.1.0" -dependencies = [ - "enso-frp", - "ensogl-core", - "ensogl-hardcoded-theme", - "ensogl-shadow", - "ensogl-text", - "ensogl-toggle-button", - "float_eq", -] - -[[package]] -name = "ensogl-sequence-diagram" -version = "0.1.0" -dependencies = [ - "enso-frp", - "enso-profiler", - "enso-profiler-data", - "enso-profiler-enso-data", - "enso-profiler-flame-graph", - "ensogl", - "ensogl-core", - "ensogl-gui-component", - "ensogl-hardcoded-theme", - "ensogl-text", - "ensogl-tooltip", -] - -[[package]] -name = "ensogl-shadow" -version = "0.1.0" -dependencies = [ - "ensogl-core", - "ensogl-hardcoded-theme", -] - -[[package]] -name = "ensogl-slider" -version = "0.1.0" -dependencies = [ - "enso-frp", - "ensogl-core", - "ensogl-hardcoded-theme", - "ensogl-text", - "ensogl-tooltip", -] - -[[package]] -name = "ensogl-spinner" -version = "0.1.0" -dependencies = [ - "enso-frp", - "enso-prelude", - "enso-shapely", - "enso-types", - "ensogl-core", -] - -[[package]] -name = "ensogl-text" -version = "0.1.0" -dependencies = [ - "bincode 2.0.0-rc.2", - "const_format", - "enso-bitmap", - "enso-font", - "enso-frp", - "enso-prelude", - "enso-shapely", - "enso-text", - "enso-types", - "ensogl-core", - "ensogl-text-embedded-fonts", - "ensogl-text-msdf", - "ordered-float", - "owned_ttf_parser", - "rand 0.8.5", - "rand_chacha 0.3.1", - "rustybuzz", - "serde", - "serde_json", - "wasm-bindgen-test", - "xi-rope", -] - -[[package]] -name = "ensogl-text-embedded-fonts" -version = "0.1.0" -dependencies = [ - "enso-build", - "enso-enso-font", - "enso-font", - "enso-prelude", - "ide-ci", - "owned_ttf_parser", - "rustybuzz", - "tokio", -] - -[[package]] -name = "ensogl-text-msdf" -version = "0.1.0" -dependencies = [ - "enso-bitmap", - "enso-build-utilities", - "enso-font", - "enso-prelude", - "enso-profiler", - "enso-types", - "enso-web", - "ensogl-text-embedded-fonts", - "failure", - "futures", - "ide-ci", - "js-sys", - "nalgebra", - "owned_ttf_parser", - "serde", - "tokio", - "wasm-bindgen", - "wasm-bindgen-test", -] - -[[package]] -name = "ensogl-toggle-button" -version = "0.1.0" -dependencies = [ - "enso-frp", - "ensogl-core", - "ensogl-hardcoded-theme", -] - -[[package]] -name = "ensogl-tooltip" -version = "0.1.0" -dependencies = [ - "enso-frp", - "ensogl-core", - "ensogl-hardcoded-theme", - "ensogl-label", -] - -[[package]] -name = "enum_dispatch" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11f36e95862220b211a6e2aa5eca09b4fa391b13cd52ceb8035a24bf65a79de2" -dependencies = [ - "once_cell", - "proc-macro2", - "quote", - "syn 1.0.107", -] - [[package]] name = "errno" version = "0.2.8" @@ -3225,30 +1826,12 @@ version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall", "windows-sys 0.42.0", ] -[[package]] -name = "flatbuffers" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea0c34f669be9911826facafe996adfda978aeee67285a13556869e2d8b8331f" -dependencies = [ - "smallvec 0.6.14", -] - -[[package]] -name = "flatc-rust" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdce2ac68e3bccc405e0255e9b56d7841c06f6c7d36a8aa8b2966fbb3995bd9a" -dependencies = [ - "log", -] - [[package]] name = "flate2" version = "1.0.25" @@ -3259,31 +1842,6 @@ dependencies = [ "miniz_oxide", ] -[[package]] -name = "flo_stream" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b02e0d3667b27514149c1ac9b372d700f3e6df4bbaf6b7c5df12915de2996049" -dependencies = [ - "futures", - "smallvec 1.10.0", -] - -[[package]] -name = "float-cmp" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1267f4ac4f343772758f7b1bdcbe767c218bbab93bb432acbf5162bbf85a6c4" -dependencies = [ - "num-traits", -] - -[[package]] -name = "float_eq" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb23b6902f3cdc0544f9916b4c092f46f4ff984e219d5a0c538b6b3539885af3" - [[package]] name = "flume" version = "0.10.14" @@ -3339,21 +1897,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "fragile" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7464c5c4a3f014d9b2ec4073650e5c06596f385060af740fc45ad5a19f959e8" -dependencies = [ - "fragile 2.0.0", -] - -[[package]] -name = "fragile" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" - [[package]] name = "fs-err" version = "2.9.0" @@ -3476,31 +2019,12 @@ dependencies = [ "slab", ] -[[package]] -name = "fuzzly" -version = "0.1.0" -dependencies = [ - "derivative", - "enso-text", - "rand 0.8.5", - "rand_chacha 0.3.1", -] - [[package]] name = "gen-iter" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1668ac3c7b8cc5f1e31565ed509d8d70aa1a81bd7f508b620725b78c6e1d7049" -[[package]] -name = "generic-array" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" -dependencies = [ - "typenum", -] - [[package]] name = "generic-array" version = "0.14.6" @@ -3526,7 +2050,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "wasi 0.9.0+wasi-snapshot-preview1", ] @@ -3537,7 +2061,7 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", @@ -3568,19 +2092,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "gloo-utils" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037fcb07216cb3a30f7292bd0176b050b7b9a052ba830ef7d5d65f6dc64ba58e" -dependencies = [ - "js-sys", - "serde", - "serde_json", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "h2" version = "0.3.15" @@ -3636,7 +2147,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584" dependencies = [ "base64 0.13.1", - "bitflags 1.3.2", + "bitflags", "bytes", "headers-core", "http", @@ -3684,26 +2195,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "horrorshow" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8371fb981840150b1a54f7cb117bf6699f7466a1d4861daac33bc6fe2b5abea0" - -[[package]] -name = "html_parser" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec016cabcf7c9c48f9d5fdc6b03f273585bfce640a0f47a69552039e92b1959a" -dependencies = [ - "pest", - "pest_derive", - "serde", - "serde_derive", - "serde_json", - "thiserror", -] - [[package]] name = "http" version = "0.2.8" @@ -3914,7 +2405,7 @@ dependencies = [ "rand 0.8.5", "regex", "reqwest", - "semver 1.0.16", + "semver", "serde", "serde_json", "serde_yaml", @@ -3931,7 +2422,7 @@ dependencies = [ "tracing-subscriber", "unicase", "url", - "uuid 1.2.2", + "uuid", "walkdir", "warp", "which", @@ -3939,192 +2430,6 @@ dependencies = [ "zip", ] -[[package]] -name = "ide-view" -version = "0.1.0" -dependencies = [ - "ast", - "engine-protocol", - "enso-config", - "enso-frp", - "enso-prelude", - "enso-shapely", - "ensogl", - "ensogl-component", - "ensogl-gui-component", - "ensogl-hardcoded-theme", - "ensogl-text", - "ensogl-text-msdf", - "gloo-utils", - "ide-view-component-browser", - "ide-view-documentation", - "ide-view-execution-environment-selector", - "ide-view-graph-editor", - "ide-view-project-view-top-bar", - "js-sys", - "multi-map", - "nalgebra", - "ordered-float", - "parser", - "serde", - "serde_json", - "span-tree", - "strum", - "uuid 0.8.2", - "wasm-bindgen", - "wasm-bindgen-test", - "web-sys", - "welcome-screen", -] - -[[package]] -name = "ide-view-component-browser" -version = "0.1.0" -dependencies = [ - "enso-frp", - "enso-prelude", - "ensogl", - "ensogl-breadcrumbs", - "ensogl-gui-component", - "ensogl-hardcoded-theme", - "ensogl-text", - "ide-view-component-list-panel", - "ide-view-documentation", - "ide-view-graph-editor", -] - -[[package]] -name = "ide-view-component-list-panel" -version = "0.1.0" -dependencies = [ - "approx 0.5.1", - "enso-frp", - "ensogl-core", - "ensogl-grid-view", - "ensogl-gui-component", - "ensogl-hardcoded-theme", - "ensogl-icons", - "ensogl-scroll-area", - "ensogl-selector", - "ensogl-text", - "ensogl-toggle-button", - "ensogl-tooltip", - "ide-view-component-list-panel-grid", - "ordered-float", -] - -[[package]] -name = "ide-view-component-list-panel-grid" -version = "0.1.0" -dependencies = [ - "enso-frp", - "ensogl-core", - "ensogl-grid-view", - "ensogl-gui-component", - "ensogl-hardcoded-theme", - "ensogl-icons", - "ensogl-shadow", - "ensogl-text", - "ensogl-toggle-button", - "failure", - "num_enum", -] - -[[package]] -name = "ide-view-documentation" -version = "0.1.0" -dependencies = [ - "double-representation", - "enso-doc-parser", - "enso-frp", - "enso-prelude", - "enso-profiler", - "enso-suggestion-database", - "ensogl", - "ensogl-breadcrumbs", - "ensogl-component", - "ensogl-hardcoded-theme", - "horrorshow", - "ide-ci", - "ide-view-graph-editor", - "serde_json", - "tokio", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "ide-view-execution-environment-selector" -version = "0.1.0" -dependencies = [ - "engine-protocol", - "enso-frp", - "enso-prelude", - "ensogl", - "ensogl-drop-down-menu", - "ensogl-gui-component", - "ensogl-hardcoded-theme", - "ensogl-list-view", -] - -[[package]] -name = "ide-view-graph-editor" -version = "0.1.0" -dependencies = [ - "analytics", - "ast", - "base64 0.13.1", - "bimap", - "bitflags 2.2.1", - "derivative", - "engine-protocol", - "enso-config", - "enso-frp", - "enso-prelude", - "enso-shapely", - "enso-text", - "ensogl", - "ensogl-component", - "ensogl-derive-theme", - "ensogl-drop-manager", - "ensogl-hardcoded-theme", - "ensogl-icons", - "ensogl-text-msdf", - "failure", - "ide-view-execution-environment-selector", - "indexmap", - "js-sys", - "nalgebra", - "ordered-float", - "parser", - "serde", - "serde-wasm-bindgen", - "serde_json", - "sourcemap", - "span-tree", - "uuid 0.8.2", - "wasm-bindgen", - "wasm-bindgen-test", - "web-sys", -] - -[[package]] -name = "ide-view-project-view-top-bar" -version = "0.1.0" -dependencies = [ - "ast", - "engine-protocol", - "enso-config", - "enso-frp", - "enso-prelude", - "ensogl", - "ensogl-component", - "ensogl-hardcoded-theme", - "ide-view-execution-environment-selector", - "parser", - "uuid 0.8.2", -] - [[package]] name = "idna" version = "0.2.3" @@ -4136,12 +2441,6 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "if_chain" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" - [[package]] name = "indexmap" version = "1.9.2" @@ -4178,7 +2477,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -4254,21 +2553,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "json-rpc" -version = "0.1.0" -dependencies = [ - "enso-prelude", - "enso-profiler", - "enso-profiler-data", - "enso-shapely", - "enso-web", - "failure", - "futures", - "serde", - "serde_json", -] - [[package]] name = "jsonwebtoken" version = "8.2.0" @@ -4283,26 +2567,6 @@ dependencies = [ "simple_asn1", ] -[[package]] -name = "keccak" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" -dependencies = [ - "cpufeatures", -] - -[[package]] -name = "keyboard-types" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a989afac88279b0482f402d234b5fbd405bf1ad051308595b58de4e6de22346b" -dependencies = [ - "bitflags 1.3.2", - "serde", - "unicode-segmentation", -] - [[package]] name = "kv-log-macro" version = "1.0.7" @@ -4394,7 +2658,7 @@ version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "value-bag", ] @@ -4447,19 +2711,13 @@ dependencies = [ "rawpointer", ] -[[package]] -name = "maybe-uninit" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" - [[package]] name = "md-5" version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" dependencies = [ - "digest 0.10.6", + "digest", ] [[package]] @@ -4514,48 +2772,15 @@ dependencies = [ "windows-sys 0.42.0", ] -[[package]] -name = "mockall" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01458f8a19b10cb28195290942e3149161c75acf67ebc8fbf714ab67a2b943bc" -dependencies = [ - "cfg-if 0.1.10", - "downcast", - "fragile 1.2.2", - "lazy_static", - "mockall_derive", - "predicates", - "predicates-tree", -] - -[[package]] -name = "mockall_derive" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a673cb441f78cd9af4f5919c28576a3cc325fb6b54e42f7047dacce3c718c17b" -dependencies = [ - "cfg-if 0.1.10", - "proc-macro2", - "quote", - "syn 1.0.107", -] - [[package]] name = "msvc-demangler" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfb67c6dd0fa9b00619c41c5700b6f92d5f418be49b45ddb9970fbd4569df3c8" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] -[[package]] -name = "multi-map" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bba551d6d795f74a01767577ea8339560bf0a65354e0417b7e915ed608443d46" - [[package]] name = "multimap" version = "0.8.3" @@ -4589,7 +2814,7 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "476d1d59fe02fe54c86356e91650cd892f392782a1cb9fc524ec84f7aa9e1d06" dependencies = [ - "approx 0.4.0", + "approx", "matrixmultiply", "num-complex", "num-rational", @@ -4642,21 +2867,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" -[[package]] -name = "nom8" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8" -dependencies = [ - "memchr", -] - -[[package]] -name = "normalize-line-endings" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" - [[package]] name = "ntapi" version = "0.4.0" @@ -4738,27 +2948,6 @@ dependencies = [ "libc", ] -[[package]] -name = "num_enum" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d829733185c1ca374f17e52b762f24f535ec625d2cc1f070e34c8a9068f341b" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2be1598bf1c313dcdd12092e3f1920f463462525a21b7b4e11b4168353d0123e" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 1.0.107", -] - [[package]] name = "number_prefix" version = "0.4.0" @@ -4783,7 +2972,7 @@ dependencies = [ "async-trait", "base64 0.13.1", "bytes", - "cfg-if 1.0.0", + "cfg-if", "chrono", "hyperx", "jsonwebtoken", @@ -4809,20 +2998,14 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" -[[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" - [[package]] name = "openssl" version = "0.10.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b102428fd03bc5edf97f62620f7298614c45cedf287c271e7ed450bbaf83f2e1" dependencies = [ - "bitflags 1.3.2", - "cfg-if 1.0.0", + "bitflags", + "cfg-if", "foreign-types", "libc", "once_cell", @@ -4866,15 +3049,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" -[[package]] -name = "ordered-float" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d84eb1409416d254e4a9c8fa56cc24701755025b458f0fcd8e59e1f5f40c23bf" -dependencies = [ - "num-traits", -] - [[package]] name = "os_str_bytes" version = "6.4.1" @@ -4918,28 +3092,13 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall", - "smallvec 1.10.0", + "smallvec", "windows-sys 0.42.0", ] -[[package]] -name = "parser" -version = "0.1.0" -dependencies = [ - "ast", - "enso-parser", - "enso-prelude", - "enso-profiler", - "enso-text", - "failure", - "serde", - "serde_json", - "uuid 0.8.2", -] - [[package]] name = "paste" version = "1.0.11" @@ -5136,7 +3295,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22122d5ec4f9fe1b3916419b76be1e80bcb93f618d071d2edf841b137b2a2bd6" dependencies = [ "autocfg", - "cfg-if 1.0.0", + "cfg-if", "libc", "log", "wepoll-ffi", @@ -5170,35 +3329,6 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" -[[package]] -name = "predicates" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f49cfaf7fdaa3bfacc6fa3e7054e65148878354a5cfddcf661df4c851f8021df" -dependencies = [ - "difference", - "float-cmp", - "normalize-line-endings", - "predicates-core", - "regex", -] - -[[package]] -name = "predicates-core" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72f883590242d3c6fc5bf50299011695fa6590c2c70eac95ee1bdb9a733ad1a2" - -[[package]] -name = "predicates-tree" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54ff541861505aabf6ea722d2131ee980b8276e10a1297b94e896dd8b621850d" -dependencies = [ - "predicates-core", - "termtree", -] - [[package]] name = "pretty_assertions" version = "1.4.0" @@ -5209,16 +3339,6 @@ dependencies = [ "yansi", ] -[[package]] -name = "proc-macro-crate" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66618389e4ec1c7afe67d51a9bf34ff9236480f8d51e7489b7d5ab0303c13f34" -dependencies = [ - "once_cell", - "toml_edit", -] - [[package]] name = "proc-macro-error" version = "1.0.4" @@ -5264,21 +3384,12 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d9cc634bc78768157b5cbfe988ffcd1dcba95cd2b2f03a88316c08c6d00ed63" dependencies = [ - "bitflags 1.3.2", + "bitflags", "getopts", "memchr", "unicase", ] -[[package]] -name = "qstring" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" -dependencies = [ - "percent-encoding", -] - [[package]] name = "quick-error" version = "1.2.3" @@ -5409,7 +3520,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] [[package]] @@ -5546,28 +3657,13 @@ version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver 0.9.0", -] - [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.16", + "semver", ] [[package]] @@ -5576,7 +3672,7 @@ version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03" dependencies = [ - "bitflags 1.3.2", + "bitflags", "errno", "io-lifetimes", "libc", @@ -5645,22 +3741,6 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" -[[package]] -name = "rustybuzz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a617c811f5c9a7060fe511d35d13bf5b9f0463ce36d63ce666d05779df2b4eba" -dependencies = [ - "bitflags 1.3.2", - "bytemuck", - "smallvec 1.10.0", - "ttf-parser", - "unicode-bidi-mirroring", - "unicode-ccc", - "unicode-general-category", - "unicode-script", -] - [[package]] name = "ryu" version = "1.0.12" @@ -5744,7 +3824,7 @@ version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" dependencies = [ - "bitflags 1.3.2", + "bitflags", "core-foundation", "core-foundation-sys", "libc", @@ -5761,21 +3841,6 @@ dependencies = [ "libc", ] -[[package]] -name = "segment-tree" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f7dbd0d32cabaa6c7c3286d756268247538d613b621227bfe59237d7bbb271a" - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - [[package]] name = "semver" version = "1.0.16" @@ -5785,12 +3850,6 @@ dependencies = [ "serde", ] -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - [[package]] name = "serde" version = "1.0.152" @@ -5800,17 +3859,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde-wasm-bindgen" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b4c031cd0d9014307d82b8abf653c0290fbdaeb4c02d00c63cf52f728628bf" -dependencies = [ - "js-sys", - "serde", - "wasm-bindgen", -] - [[package]] name = "serde_cbor" version = "0.11.2" @@ -5894,9 +3942,9 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", - "digest 0.10.6", + "digest", ] [[package]] @@ -5914,9 +3962,9 @@ version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", - "digest 0.10.6", + "digest", ] [[package]] @@ -5931,22 +3979,9 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", - "digest 0.10.6", -] - -[[package]] -name = "sha3" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" -dependencies = [ - "block-buffer 0.7.3", - "byte-tools", - "digest 0.8.1", - "keccak", - "opaque-debug", + "digest", ] [[package]] @@ -5973,7 +4008,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5132a955559188f3d13c9ba831e77c802ddc8782783f050ed0c52f5988b95f4c" dependencies = [ - "approx 0.4.0", + "approx", "num-complex", "num-traits", "paste", @@ -6000,15 +4035,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "smallvec" -version = "0.6.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0" -dependencies = [ - "maybe-uninit", -] - [[package]] name = "smallvec" version = "1.10.0" @@ -6048,36 +4074,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "sourcemap" -version = "6.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aebe057d110ddba043708da3fb010bf562ff6e9d4d60c9ee92860527bcbeccd6" -dependencies = [ - "base64 0.13.1", - "if_chain", - "rustc_version 0.2.3", - "serde", - "serde_json", - "unicode-id", - "url", -] - -[[package]] -name = "span-tree" -version = "0.1.0" -dependencies = [ - "ast", - "enso-data-structures", - "enso-prelude", - "enso-profiler", - "enso-text", - "failure", - "parser", - "pretty_assertions", - "wasm-bindgen-test", -] - [[package]] name = "spin" version = "0.5.2" @@ -6121,12 +4117,6 @@ dependencies = [ "syn 1.0.107", ] -[[package]] -name = "superslice" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f" - [[package]] name = "symlink" version = "0.1.0" @@ -6173,7 +4163,7 @@ version = "0.29.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a18d114d420ada3a891e6bc8e96a2023402203296a47cdd65083377dad18ba5" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "core-foundation-sys", "libc", "ntapi", @@ -6199,7 +4189,7 @@ version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "fastrand", "libc", "redox_syscall", @@ -6226,12 +4216,6 @@ dependencies = [ "windows-sys 0.42.0", ] -[[package]] -name = "termtree" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95059e91184749cb66be6dc994f67f182b6d897cb3df74a5bf66b5e709295fd8" - [[package]] name = "textwrap" version = "0.11.0" @@ -6456,23 +4440,6 @@ dependencies = [ "serde", ] -[[package]] -name = "toml_datetime" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5" - -[[package]] -name = "toml_edit" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b" -dependencies = [ - "indexmap", - "nom8", - "toml_datetime", -] - [[package]] name = "tower" version = "0.4.13" @@ -6507,7 +4474,7 @@ version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "log", "pin-project-lite", "tracing-attributes", @@ -6557,7 +4524,7 @@ dependencies = [ "once_cell", "regex", "sharded-slab", - "smallvec 1.10.0", + "smallvec", "thread_local", "tracing", "tracing-core", @@ -6631,30 +4598,6 @@ version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58" -[[package]] -name = "unicode-bidi-mirroring" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56d12260fb92d52f9008be7e4bca09f584780eb2266dc8fecc6a192bec561694" - -[[package]] -name = "unicode-ccc" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2520efa644f8268dce4dcd3050eaa7fc044fca03961e9998ac7e2e92b77cf1" - -[[package]] -name = "unicode-general-category" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07547e3ee45e28326cc23faac56d44f58f16ab23e413db526debce3b0bfd2742" - -[[package]] -name = "unicode-id" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d70b6494226b36008c8366c288d77190b3fad2eb4c10533139c1c1f461127f1a" - [[package]] name = "unicode-ident" version = "1.0.6" @@ -6670,12 +4613,6 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-script" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d817255e1bed6dfd4ca47258685d14d2bdcfbc64fdc9e3819bd5848057b8ecc" - [[package]] name = "unicode-segmentation" version = "1.10.1" @@ -6736,16 +4673,6 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5190c9442dcdaf0ddd50f37420417d219ae5261bbf5db120d0f9bab996c9cba1" -[[package]] -name = "uuid" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" -dependencies = [ - "getrandom 0.2.8", - "serde", -] - [[package]] name = "uuid" version = "1.2.2" @@ -6872,7 +4799,7 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "wasm-bindgen-macro", ] @@ -6897,7 +4824,7 @@ version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "wasm-bindgen", "web-sys", @@ -7047,16 +4974,6 @@ dependencies = [ "websocket-codec", ] -[[package]] -name = "welcome-screen" -version = "0.1.0" -dependencies = [ - "enso-frp", - "ensogl", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "wepoll-ffi" version = "0.1.2" @@ -7288,18 +5205,6 @@ dependencies = [ "libc", ] -[[package]] -name = "xi-rope" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1266c6612194a86462905372bc7bbc9887e3f3826da6b82ea4a35492bc65d5a" -dependencies = [ - "bytecount", - "memchr", - "regex", - "unicode-segmentation", -] - [[package]] name = "xmlparser" version = "0.13.3" diff --git a/Cargo.toml b/Cargo.toml index b9a5246e4f..01d427f766 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,33 +7,24 @@ resolver = "2" # path, e.g. `lib/rust/ensogl/examples`, or `app/gui/view/examples`; this is used to optimize the application for # loading the IDE. members = [ - "app/gui", - "app/gui/language/parser", - "app/gui/enso-profiler-enso-data", - "app/gui2/rust-ffi", - "build/cli", - "build/macros/proc-macro", - "build/ci-gen", - "build/cli", - "build/intellij-run-config-gen", - "build/deprecated/rust-scripts", - "build/shader-tools", - "lib/rust/*", - "lib/rust/parser/doc-parser", - "lib/rust/parser/src/syntax/tree/visitor", - "lib/rust/parser/jni", - "lib/rust/parser/generate-java", - "lib/rust/parser/schema", - "lib/rust/parser/debug", - "lib/rust/ensogl/pack", - "lib/rust/profiler/data", - "lib/rust/profiler/demo-data", - "integration-test", - "tools/language-server/logstat", - "tools/language-server/wstest", + "app/gui2/rust-ffi", + "build/cli", + "build/macros/proc-macro", + "build/ci-gen", + "build/cli", + "build/intellij-run-config-gen", + "build/deprecated/rust-scripts", + "lib/rust/*", + "lib/rust/parser/doc-parser", + "lib/rust/parser/src/syntax/tree/visitor", + "lib/rust/parser/jni", + "lib/rust/parser/generate-java", + "lib/rust/parser/schema", + "lib/rust/parser/debug", + "lib/rust/enso-pack", + "tools/language-server/logstat", + "tools/language-server/wstest", ] -# The default memebers are those we want to check and test by default. -default-members = ["app/gui", "lib/rust/*"] # We are using a version with extended functionality. The changes have been PR'd upstream: # https://github.com/rustwasm/console_error_panic_hook/pull/24 @@ -88,7 +79,7 @@ console-subscriber = "0.1.8" dirs = { version = "5.0.1" } nix = { version = "0.27.1" } octocrab = { git = "https://github.com/enso-org/octocrab", default-features = false, features = [ - "rustls", + "rustls", ] } platforms = { version = "3.2.0", features = ["serde"] } portpicker = { version = "0.1.1" } @@ -131,25 +122,25 @@ bytes = { version = "1.1.0" } matches = { version = "0.1" } console_error_panic_hook = { version = "0.1.6" } reqwest = { version = "0.11.5", default-features = false, features = [ - "rustls-tls", - "stream" + "rustls-tls", + "stream" ] } proc-macro2 = { version = "1.0.50" } syn = { version = "2.0", features = [ - "full", - "extra-traits", - "printing", - "parsing", - "visit", - "visit-mut", + "full", + "extra-traits", + "printing", + "parsing", + "visit", + "visit-mut", ] } syn_1 = { package = "syn", version = "1.0", features = [ - "full", - "extra-traits", - "printing", - "parsing", - "visit", - "visit-mut", + "full", + "extra-traits", + "printing", + "parsing", + "visit", + "visit-mut", ] } quote = { version = "1.0.23" } semver = { version = "1.0.0", features = ["serde"] } diff --git a/app/gui/Cargo.toml b/app/gui/Cargo.toml deleted file mode 100644 index f4a0048dea..0000000000 --- a/app/gui/Cargo.toml +++ /dev/null @@ -1,92 +0,0 @@ -[package] -name = "enso-gui" -version = "0.1.0" -authors = ["Enso Team "] -edition = "2021" - -[lib] -crate-type = ["cdylib", "rlib"] - -[dependencies] -analytics = { path = "analytics" } -double-representation = { path = "controller/double-representation" } -enso-config = { path = "config" } -enso-callback = { path = "../../lib/rust/callback" } -enso-data-structures = { path = "../../lib/rust/data-structures" } -enso-debug-api = { path = "../../lib/rust/debug-api" } -enso-debug-scene = { path = "view/examples" } -enso-frp = { path = "../../lib/rust/frp" } -enso-doc-parser = { path = "../../lib/rust/parser/doc-parser" } -enso-prelude = { path = "../../lib/rust/prelude" } -enso-profiler = { path = "../../lib/rust/profiler" } -enso-executor = { path = "../../lib/rust/executor" } -enso-notification = { path = "../../lib/rust/notification" } -enso-shapely = { path = "../../lib/rust/shapely" } -enso-text = { path = "../../lib/rust/text" } -enso-web = { path = "../../lib/rust/web" } -enso-suggestion-database = { path = "suggestion-database" } -ensogl = { path = "../../lib/rust/ensogl" } -ensogl-examples = { path = "../../lib/rust/ensogl/examples" } -ensogl-component = { path = "../../lib/rust/ensogl/component" } -ensogl-icons = { path = "../../lib/rust/ensogl/component/icons" } -ensogl-dynamic-assets = { path = "../../lib/rust/ensogl/component/dynamic-assets" } -ensogl-text-msdf = { path = "../../lib/rust/ensogl/component/text/src/font/msdf" } -ensogl-hardcoded-theme = { path = "../../lib/rust/ensogl/app/theme/hardcoded" } -ensogl-drop-manager = { path = "../../lib/rust/ensogl/component/drop-manager" } -ensogl-breadcrumbs = { path = "../../lib/rust/ensogl/component/breadcrumbs" } -fuzzly = { path = "../../lib/rust/fuzzly" } -ast = { path = "language/ast/impl" } -parser = { path = "language/parser" } -ide-view = { path = "view" } -engine-protocol = { path = "controller/engine-protocol" } -json-rpc = { path = "../../lib/rust/json-rpc" } -span-tree = { path = "language/span-tree" } -bimap = { version = "0.4.0" } -console_error_panic_hook = { workspace = true } -const_format = { workspace = true } -convert_case = { workspace = true } -failure = { workspace = true } -flo_stream = { version = "0.4.0" } -futures = { workspace = true } -itertools = { workspace = true } -js-sys = { workspace = true } -mockall = { version = "0.7.1", features = ["nightly"] } -nalgebra = { workspace = true } -semver = { workspace = true } -serde = { workspace = true } -serde_json = { workspace = true } -sha3 = { version = "0.8.2" } -superslice = { workspace = true } -uuid = { version = "0.8", features = ["serde", "v4", "wasm-bindgen"] } -ordered-float = "3.4.0" -# wasm-bindgen version 0.2.79 is causing issues with clippy. -# See for more information. https://github.com/rustwasm/wasm-bindgen/issues/2774 -# Should be removed once 0.2.80 is available. -wasm-bindgen = { workspace = true } -wasm-bindgen-futures = "0.4" - -[dev-dependencies] -regex = { workspace = true } -wasm-bindgen-test = { workspace = true } - -[dependencies.web-sys] -version = "0.3.22" -features = [ - 'BinaryType', - 'Blob', - 'console', - 'CloseEvent', - 'Document', - 'Element', - 'ErrorEvent', - 'EventTarget', - 'MessageEvent', - 'HtmlElement', - 'Node', - 'WebSocket', - 'Window', -] - -# Stop wasm-pack from running wasm-opt, because we run it from our build scripts in order to customize options. -[package.metadata.wasm-pack.profile.release] -wasm-opt = false diff --git a/app/gui/LICENSE b/app/gui/LICENSE deleted file mode 100644 index 0ad25db4bd..0000000000 --- a/app/gui/LICENSE +++ /dev/null @@ -1,661 +0,0 @@ - GNU AFFERO GENERAL PUBLIC LICENSE - Version 3, 19 November 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU Affero General Public License is a free, copyleft license for -software and other kinds of works, specifically designed to ensure -cooperation with the community in the case of network server software. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -our General Public Licenses are intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - Developers that use our General Public Licenses protect your rights -with two steps: (1) assert copyright on the software, and (2) offer -you this License which gives you legal permission to copy, distribute -and/or modify the software. - - A secondary benefit of defending all users' freedom is that -improvements made in alternate versions of the program, if they -receive widespread use, become available for other developers to -incorporate. Many developers of free software are heartened and -encouraged by the resulting cooperation. However, in the case of -software used on network servers, this result may fail to come about. -The GNU General Public License permits making a modified version and -letting the public access it on a server without ever releasing its -source code to the public. - - The GNU Affero General Public License is designed specifically to -ensure that, in such cases, the modified source code becomes available -to the community. It requires the operator of a network server to -provide the source code of the modified version running there to the -users of that server. Therefore, public use of a modified version, on -a publicly accessible server, gives the public access to the source -code of the modified version. - - An older license, called the Affero General Public License and -published by Affero, was designed to accomplish similar goals. This is -a different license, not a version of the Affero GPL, but Affero has -released a new version of the Affero GPL which permits relicensing under -this license. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU Affero General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Remote Network Interaction; Use with the GNU General Public License. - - Notwithstanding any other provision of this License, if you modify the -Program, your modified version must prominently offer all users -interacting with it remotely through a computer network (if your version -supports such interaction) an opportunity to receive the Corresponding -Source of your version by providing access to the Corresponding Source -from a network server at no charge, through some standard or customary -means of facilitating copying of software. This Corresponding Source -shall include the Corresponding Source for any work covered by version 3 -of the GNU General Public License that is incorporated pursuant to the -following paragraph. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the work with which it is combined will remain governed by version -3 of the GNU General Public License. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU Affero General Public License from time to time. Such new versions -will be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU Affero General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU Affero General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU Affero General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If your software can interact with users remotely through a computer -network, you should also make sure that it provides a way for users to -get its source. For example, if your program is a web application, its -interface could display a "Source" link that leads users to an archive -of the code. There are many ways you could offer source, and different -solutions will be better for different programs; see section 13 for the -specific requirements. - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU AGPL, see -. diff --git a/app/gui/README.md b/app/gui/README.md deleted file mode 100644 index 89529c9b4e..0000000000 --- a/app/gui/README.md +++ /dev/null @@ -1,88 +0,0 @@ -# This is the subtree for Enso's graphical interface component. If you're looking for the repository root, you may find it at at 👉 github.com/enso-org/enso 👈 - -
- -# Enso IDE - -### Overview - -

- - Chat - - - License - - - License - -

- -Enso is an award-winning interactive programming language with dual visual and -textual representations. It is a tool that spans the entire stack, going from -high-level visualization and communication to the nitty-gritty of backend -services, all in a single language. Watch the following introduction video to -learn what Enso is, and how it helps companies build data workflows in minutes -instead of weeks. - -This repository contains the source code of Enso interface only. If you are -interested in how the interface is build or you want to develop it with us, you -are in the right place. See the -[development and contributing guidelines](docs/CONTRIBUTING.md) to learn more -about the code structure and the development process. - -
- -### Getting Started - -Enso is distributed both in form of -[pre-build packages for MacOS, Windows, or Linux](https://github.com/enso-org/ide/releases), -as well as the [source code](https://github.com/enso-org). See the -[demo scenes](http://TODO), and read the [documentation](docs/product) to learn -more. - -
- -### Building - -The project builds on macOS, Linux, and Windows. Build functionality is provided -by our build script, that are accessible through `run` (Linux and macOS) or -`run.cmd` (Windows) wrappers. - -To build the project, simply run `./run ide build` (on Linux or macOS) or -`.\run.cmd ide build` (Windows) to build IDE. To learn more about other -available commands use `--help` argument. Read the detailed -[development guide](docs/CONTRIBUTING.md) to learn more. - -
- -### License - -The Enso Language Compiler is released under the terms of the -[Apache v2 License](https://github.com/enso-org/enso/blob/develop/LICENSE). The -Enso Graphical Interface and it's rendering engine are released under the terms -of the -[AGPL v3 License](https://github.com/enso-org/enso/blob/develop/app/gui/LICENSEE). -This license set was choosen to both provide you with a complete freedom to use -Enso, create libraries, and release them under any license of your choice, while -also allowing us to release commercial products on top of the platform, -including Enso Cloud and Enso Enterprise on-premise server managers. - -
- -### Contributing - -Enso is a community-driven open source project which is and will always be open -and free to use. We are committed to a fully transparent development process and -highly appreciate every contribution. If you love the vision behind Enso and you -want to redefine the data processing world, join us and help us track down bugs, -implement new features, improve the documentation or spread the word! Join our -community on a [Discord chat](http://chat.enso.org) and read the -[development and contributing guidelines](docs/CONTRIBUTING.md). - - - - diff --git a/app/gui/analytics/Cargo.toml b/app/gui/analytics/Cargo.toml deleted file mode 100644 index 5865d3fb06..0000000000 --- a/app/gui/analytics/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "analytics" -version = "0.1.0" -authors = ["Enso Team "] -edition = "2021" - -[dependencies] -js-sys = { workspace = true } -wasm-bindgen = { workspace = true } diff --git a/app/gui/analytics/src/data.rs b/app/gui/analytics/src/data.rs deleted file mode 100644 index 304e334d0a..0000000000 --- a/app/gui/analytics/src/data.rs +++ /dev/null @@ -1,50 +0,0 @@ -//! Provides data wrappers for our analytics api. This is intended to ensure we are conscious of -//! whether we are sending public or private data. No private data should be logged at the moment. -//! -//! Note: this is meant to be a little bit un-ergonomic to ensure the data has been vetted by the -//! API user and allow the reader of the code to see the intent behind the data. - -use wasm_bindgen::JsValue; - - - -/// Trait that allows us to log an object remotely. -pub trait Loggable { - /// Return the log message as JsValue. - fn get(self) -> JsValue; -} - -impl Loggable for bool { - fn get(self) -> JsValue { - self.into() - } -} -impl Loggable for &str { - fn get(self) -> JsValue { - self.into() - } -} -impl Loggable for String { - fn get(self) -> JsValue { - self.into() - } -} -impl Loggable for &String { - fn get(self) -> JsValue { - self.into() - } -} -impl Loggable for F -where - F: Fn() -> S, - S: Loggable, -{ - fn get(self) -> JsValue { - self().get() - } -} - - -/// Wrapper struct for data that can be made public and has no privacy implications. -#[derive(Clone, Copy, Debug)] -pub struct AnonymousData(pub T); diff --git a/app/gui/analytics/src/lib.rs b/app/gui/analytics/src/lib.rs deleted file mode 100644 index c4afb34bb4..0000000000 --- a/app/gui/analytics/src/lib.rs +++ /dev/null @@ -1,23 +0,0 @@ -//! Remote analytics logging. - -// === Standard Linter Configuration === -#![deny(non_ascii_idents)] -#![warn(unsafe_code)] -#![allow(clippy::bool_to_int_with_if)] -#![allow(clippy::let_and_return)] -// === Non-Standard Linter Configuration === -#![warn(missing_docs)] -#![warn(trivial_casts)] -#![warn(trivial_numeric_casts)] -#![warn(unused_import_braces)] -#![warn(unused_qualifications)] -#![warn(missing_copy_implementations)] -#![warn(missing_debug_implementations)] - - - -mod data; -mod remote_log; - -pub use data::*; -pub use remote_log::*; diff --git a/app/gui/analytics/src/remote_log.rs b/app/gui/analytics/src/remote_log.rs deleted file mode 100644 index 75ccaa8a52..0000000000 --- a/app/gui/analytics/src/remote_log.rs +++ /dev/null @@ -1,67 +0,0 @@ -//! Provides an API to send data to our remote logging service. Requires the remote logging -//! to be already set up on the JS side. That means, there needs to exist a `window.enso.remoteLog` -//! method that takes a string and does the actual logging. - -use crate::data::*; - - -// ============== -// === Export === -// ============== - -pub use wasm_bindgen::prelude::*; - - - -mod js { - use super::*; - - #[wasm_bindgen(inline_js = " -export function remote_log(msg, value) { - window.ensoglApp.remoteLog(msg, value).catch((error) => { - console.error(`Error while logging message. ${error}`) - }) -} - -export function remote_log_value(msg, field_name, value) { - const data = {} - data[field_name] = value - remote_log(msg, data) -} -")] - extern "C" { - #[allow(unsafe_code)] - pub fn remote_log_value(msg: JsValue, field_name: JsValue, value: JsValue); - #[allow(unsafe_code)] - pub fn remote_log(msg: JsValue, value: JsValue); - } -} - - -/// Send the provided public event to our logging service. -#[allow(unused_variables)] // used only on wasm target -pub fn remote_log_event(message: &str) { - // Note: Disabling on non-wasm targets - #[cfg(target_arch = "wasm32")] - { - js::remote_log(JsValue::from(message.to_string()), JsValue::UNDEFINED); - } -} - -/// Send the provided public event with a named value to our logging service. -#[allow(unused_variables)] // used only on wasm target -pub fn remote_log_value(message: &str, field_name: &str, data: AnonymousData) { - // Note: Disabling on non-wasm targets - #[cfg(target_arch = "wasm32")] - { - let msg = JsValue::from(message.to_string()); - let field_name = JsValue::from(field_name.to_string()); - js::remote_log_value(msg, field_name, data.0.get()); - } -} - -// Note: Disabling on non-wasm targets -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// The code must be disabled on non-wasm targets, because trying to construct JS values would -// immediately panic. As remote logs are invoked from controller code, that would prevent having -// some controller tests native. diff --git a/app/gui/config/Cargo.toml b/app/gui/config/Cargo.toml deleted file mode 100644 index bb4bc0343e..0000000000 --- a/app/gui/config/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "enso-config" -version = "0.1.0" -authors = ["Enso Team "] -edition = "2021" - -[dependencies] -ensogl = { path = "../../../lib/rust/ensogl" } -enso-prelude = { path = "../../../lib/rust/prelude" } -enso-json-to-struct = { path = "../../../lib/rust/json-to-struct" } -semver = { workspace = true } -thiserror = { workspace = true } - -[build-dependencies] -config-reader = { path = "../../../lib/rust/config-reader" } diff --git a/app/gui/config/build.rs b/app/gui/config/build.rs deleted file mode 100644 index 49654ca243..0000000000 --- a/app/gui/config/build.rs +++ /dev/null @@ -1,16 +0,0 @@ -const CONFIG_PATH: &str = "../config.yaml"; - -const JSON_CONFIG: &[&str] = &[ - "../../../lib/rust/ensogl/pack/js/src/runner/config.json", - "../../../app/ide-desktop/lib/content-config/src/config.json", -]; - -fn main() { - println!("cargo:rerun-if-changed={CONFIG_PATH}"); - println!("cargo:rerun-if-changed=build.rs"); - for path in JSON_CONFIG { - println!("cargo:rerun-if-changed={path}"); - } - - config_reader::generate_config_module_from_yaml(CONFIG_PATH); -} diff --git a/app/gui/config/src/lib.rs b/app/gui/config/src/lib.rs deleted file mode 100644 index 87ad9eff8c..0000000000 --- a/app/gui/config/src/lib.rs +++ /dev/null @@ -1,180 +0,0 @@ -//! Startup arguments definition. - -// === Standard Linter Configuration === -#![deny(non_ascii_idents)] -#![warn(unsafe_code)] -#![allow(clippy::bool_to_int_with_if)] -#![allow(clippy::let_and_return)] -// === Non-Standard Linter Configuration === -#![warn(trivial_casts)] -#![warn(trivial_numeric_casts)] -#![warn(unused_import_braces)] -#![warn(unused_qualifications)] -#![warn(missing_copy_implementations)] -#![warn(missing_debug_implementations)] - -use enso_prelude::*; - -use enso_json_to_struct::json_to_struct; - - - -// ================= -// === Constants === -// ================= - -const LOCAL_ENGINE_VERSION: &str = "0.0.0-dev"; - - -// ============== -// === Errors === -// ============== - -///Error type with information that the Engine version does not meet the requirements. -#[derive(Clone, Debug, thiserror::Error)] -#[error("Unsupported Engine version: required {required} (or newer), found {found}.")] -pub struct UnsupportedEngineVersion { - /// The version of the Engine that is required. - pub required: semver::Version, - /// The version of the Engine that was found. - pub found: semver::Version, -} - - - -// =============== -// === Version === -// =============== - -include!(concat!(env!("OUT_DIR"), "/config.rs")); - -pub use generated::*; - -/// The minimum supported engine version. -pub fn engine_version_required() -> semver::Version { - // Safe to unwrap, as `engine_version_supported` compile-time and is validated by the test. - semver::Version::parse(engine_version_supported).unwrap() -} - -fn local_engine_version() -> semver::Version { - // Safe to unwrap, as `LOCAL_ENGINE_VERSION` compile-time and is validated by the test. - semver::Version::parse(LOCAL_ENGINE_VERSION).unwrap() -} - -/// Check if the given Engine version meets the requirements. -/// -/// Effectively, this checks if the given version is greater or equal to the minimum supported. -/// "Greater or equal" is defined by the [Semantic Versioning specification](https://semver.org/) -/// term of precedence. -/// -/// There is a special exception for locally built engine's version, as they may be theoretically -/// lower versions, but we don't want to treat them as unsupported. -pub fn check_engine_version_requirement( - required_version: &semver::Version, - tested_version: &semver::Version, -) -> Result<(), UnsupportedEngineVersion> { - // We don't want to rely on the `semver::VersionReq` semantics here. Unfortunately the - // [Semantic Versioning specification](https://semver.org/) does not define the semantics of - // the version requirement operators, so different implementations may behave differently. - // - // The `semver::VersionReq` implementation follows the Cargo's implementation, namely: - // ``` - // In particular, in order for any VersionReq to match a pre-release version, the VersionReq - // must contain at least one Comparator that has an explicit major, minor, and patch version - // identical to the pre-release being matched, and that has a nonempty pre-release component. - // ``` - // See: https://docs.rs/semver/latest/semver/struct.VersionReq.html#associatedconstant.STAR - // This leads to counter-intuitive behavior, where `2023.0.0-dev` does not fulfill the - // `>= 2022.0.0-dev` requirement. - if tested_version < required_version && tested_version != &local_engine_version() { - Err(UnsupportedEngineVersion { - required: required_version.clone(), - found: tested_version.clone(), - }) - } else { - Ok(()) - } -} - -/// Check if the given Engine version meets the requirements for this build. -/// -/// See [`check_engine_version_requirement`] for more details. -pub fn check_engine_version( - engine_version: &semver::Version, -) -> Result<(), UnsupportedEngineVersion> { - check_engine_version_requirement(&engine_version_required(), engine_version) -} - - - -// ============ -// === Args === -// ============ - -json_to_struct!( - "../../../../lib/rust/ensogl/pack/js/src/runner/config.json", - "../../../../app/ide-desktop/lib/content-config/src/config.json" -); - -pub fn read_args() -> Args { - debug_span!("Reading application arguments from JS.").in_scope(|| { - let mut args = Args::default(); - if let Ok(js_app) = ensogl::system::js::app::app() { - for param in js_app.config().params() { - if let Some(value) = param.value() { - let path = format!("{}.value", param.structural_name()); - if let Some(err) = args.set(&path, value) { - error!("{}", err.display()) - } - } - } - } else { - error!("Could not connect to JS application. Using default configuration.") - } - args - }) -} - -lazy_static! { - pub static ref ARGS: Args = read_args(); -} - - - -// ============= -// === Tests === -// ============= - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn check_that_version_requirement_parses() { - // We just expect that it won't panic. - engine_version_required(); - } - - #[test] - fn check_that_local_engine_version_constant_parses() { - // We just expect that it won't panic. - local_engine_version(); - } - - #[test] - fn new_project_engine_version_fills_requirements() { - // Sanity check: required version must be supported. - assert!(check_engine_version(&engine_version_required()).is_ok()); - } - - #[test] - fn newer_prerelease_matches() -> anyhow::Result<()> { - // Whatever version we have currently defined with `-dev` prerelease. - let current = - semver::Version { pre: semver::Prerelease::new("dev")?, ..engine_version_required() }; - let newer = semver::Version { major: current.major + 1, ..current.clone() }; - - check_engine_version_requirement(¤t, &newer)?; - Ok(()) - } -} diff --git a/app/gui/controller/Cargo.toml b/app/gui/controller/Cargo.toml deleted file mode 100644 index 0fa9c209a4..0000000000 --- a/app/gui/controller/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "controller" -version = "0.1.0" -authors = ["Enso Team "] -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[dependencies] diff --git a/app/gui/controller/double-representation/Cargo.toml b/app/gui/controller/double-representation/Cargo.toml deleted file mode 100644 index 3f7d9b3c86..0000000000 --- a/app/gui/controller/double-representation/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "double-representation" -version = "0.1.0" -authors = ["Enso Team "] -edition = "2021" - -[lib] -crate-type = ["cdylib", "rlib"] - -[dependencies] -ast = { path = "../../language/ast/impl" } -parser = { path = "../../language/parser" } -engine-protocol = { path = "../engine-protocol" } -enso-data-structures = { path = "../../../../lib/rust/data-structures" } -enso-prelude = { path = "../../../../lib/rust/prelude" } -enso-profiler = { path = "../../../../lib/rust/profiler" } -enso-text = { path = "../../../../lib/rust/text" } -const_format = { workspace = true } -failure = { workspace = true } -itertools = { workspace = true } -serde = { workspace = true } -uuid = { version = "0.8", features = ["serde", "v4", "wasm-bindgen"] } - -[dev-dependencies] -regex = { workspace = true } -wasm-bindgen-test = { workspace = true } diff --git a/app/gui/controller/double-representation/src/alias_analysis.rs b/app/gui/controller/double-representation/src/alias_analysis.rs deleted file mode 100644 index b622fa3872..0000000000 --- a/app/gui/controller/double-representation/src/alias_analysis.rs +++ /dev/null @@ -1,454 +0,0 @@ -//! Module with alias analysis — allows telling what identifiers are used and introduced by each -//! node in the graph. - -use crate::prelude::*; - -use crate::definition::DefinitionInfo; -use crate::definition::ScopeKind; - -use ast::crumbs::Crumb; -use ast::crumbs::InfixCrumb; -use ast::crumbs::Located; -use ast::opr::match_named_argument; -use std::borrow::Borrow; - - -// ============== -// === Export === -// ============== - -#[cfg(test)] -pub mod test_utils; - - - -// ======================= -// === IdentifierUsage === -// ======================= - -/// Description of how some node is interacting with the graph's scope. -#[derive(Clone, Debug, Default)] -pub struct IdentifierUsage { - /// Identifiers from the graph's scope that node is using. - pub introduced: Vec>, - /// Identifiers that node introduces into the parent scope. - pub used: Vec>, -} - -impl IdentifierUsage { - /// Returns all identifiers that are either used from or introduced into the scope. - pub fn all_identifiers(&self) -> Vec> { - self.introduced.iter().chain(self.used.iter()).cloned().collect() - } -} - - - -// ================ -// === Analysis === -// ================ - - -// === Helper Datatypes === - -/// Says whether the identifier occurrence introduces it into scope or uses it from scope. -#[allow(missing_docs)] -#[derive(Clone, Copy, Debug, Display, PartialEq, Eq)] -pub enum OccurrenceKind { - Used, - Introduced, -} - -/// If the current context in the AST processor is a pattern context. -// TODO [mwu] Refer to the specification once it is merged. -#[allow(missing_docs)] -#[derive(Clone, Copy, Debug, Display, PartialEq, Eq)] -pub enum Context { - NonPattern, - Pattern, -} - -/// Represents scope and information about identifiers usage within it. -#[derive(Clone, Debug, Default)] -pub struct Scope { - #[allow(missing_docs)] - pub symbols: IdentifierUsage, -} - -impl Scope { - /// Iterates over identifiers that are used in this scope but are not introduced in this scope - /// i.e. the identifiers that parent scope must provide. - pub fn used_from_parent(self) -> impl Iterator> { - let available = self.symbols.introduced.into_iter().map(|located_name| located_name.item); - let available = available.collect::>(); - let all_used = self.symbols.used.into_iter(); - all_used.filter(move |name| !available.contains(&name.item)) - } - - /// Drops the information about nested child scope by: - /// 1) disregarding any usage of identifiers introduced in the child scope; - /// 2) propagating all non-shadowed identifier usage from this scope into this scope usage list. - fn coalesce_child(&mut self, child: Scope) { - let symbols_to_use = child.used_from_parent(); - self.symbols.used.extend(symbols_to_use); - } -} - - -// === AliasAnalyzer === - -/// Traverser AST and analyzes identifier usage. -#[derive(Clone, Debug, Default)] -pub struct AliasAnalyzer { - /// Root scope for this analyzer. - pub root_scope: Scope, - /// Stack of scopes that shadow the root one. - shadowing_scopes: Vec, - /// Stack of context. Lack of any context information is considered non-pattern context. - context: Vec, - /// Current location, relative to the input AST root. - location: Vec, -} - -impl AliasAnalyzer { - /// Creates a new analyzer. - pub fn new() -> AliasAnalyzer { - AliasAnalyzer::default() - } - - /// Adds items to the target vector, calls the callback `f` then removes the items. - fn with_items_added( - &mut self, - vec: impl Fn(&mut Self) -> &mut Vec, - items: impl IntoIterator>, - f: impl FnOnce(&mut Self) -> R, - ) -> R { - let original_count = vec(self).len(); - vec(self).extend(items.into_iter().map(|item| item.into())); - let ret = f(self); - vec(self).truncate(original_count); - ret - } - - /// Pushes a new scope, then runs a given `f` function. Once it finished, scope is removed and - /// its unshadowed variable usage propagated onto the current scope. - fn in_new_scope(&mut self, f: impl FnOnce(&mut Self)) { - let scope = Scope::default(); - self.shadowing_scopes.push(scope); - f(self); - let scope = self.shadowing_scopes.pop().unwrap(); - self.current_scope_mut().coalesce_child(scope); - } - - /// Temporarily sets contest and invokes `f` within it. - fn in_context(&mut self, context: Context, f: impl FnOnce(&mut Self)) { - self.with_items_added(|this| &mut this.context, iter::once(context), f); - } - - /// Enters a new location (relative to the current one), invokes `f`, leaves the location. - fn in_location(&mut self, crumbs: Cs, f: F) -> R - where - Cs: IntoIterator, - F: FnOnce(&mut Self) -> R, { - self.with_items_added(|this| &mut this.location, crumbs, f) - } - - /// Enters a new location (relative to the current one), invokes `f`, leaves the location. - fn in_location_of(&mut self, located_item: &Located, f: F) -> R - where F: FnOnce(&mut Self) -> R { - self.in_location(located_item.crumbs.iter().cloned(), f) - } - - /// Obtains a mutable reference to the current scope. - fn current_scope_mut(&mut self) -> &mut Scope { - self.shadowing_scopes.last_mut().unwrap_or(&mut self.root_scope) - } - - /// Returns the current context kind. (pattern or not) - fn current_context(&self) -> Context { - self.context.last().copied().unwrap_or(Context::NonPattern) - } - - /// Records identifier occurrence in the current scope. - fn record_identifier(&mut self, kind: OccurrenceKind, identifier: String) { - let identifier = Located::new(self.location.clone(), identifier); - let symbols = &mut self.current_scope_mut().symbols; - let target = match kind { - OccurrenceKind::Used => &mut symbols.used, - OccurrenceKind::Introduced => &mut symbols.introduced, - }; - target.push(identifier) - } - - /// Checks if we are currently in the pattern context. - fn is_in_pattern(&self) -> bool { - self.current_context() == Context::Pattern - } - - /// If given AST is an identifier, records its occurrence. - /// Returns boolean saying if the identifier was recorded. - fn try_recording_identifier(&mut self, kind: OccurrenceKind, ast: &Ast) -> bool { - let name = ast::identifier::name(ast); - name.map(|name| self.record_identifier(kind, name.to_owned())).is_some() - } - - /// If the given located AST-like entity is an identifier, records its occurrence. - fn store_if_name<'a, T>(&mut self, kind: OccurrenceKind, located: Located) -> bool - where T: Into<&'a Ast> + 'a + Copy { - let ast = located.item.into(); - self.in_location_of(&located, |this| this.try_recording_identifier(kind, ast)) - } - - /// Processes the given AST, while crumb is temporarily pushed to the current location. - fn process_subtree_at(&mut self, crumb: impl Into, subtree: &Ast) { - self.in_location(crumb.into(), |this| this.process_ast(subtree)) - } - - /// Processes the given AST, while crumb is temporarily pushed to the current location. - fn process_located_ast(&mut self, located_ast: &Located>) { - self.in_location_of(located_ast, |this| this.process_ast(located_ast.item.borrow())) - } - - /// Processes subtrees of the given AST denoted by given crumbs - pub fn process_given_subtrees(&mut self, ast: &C, crumbs: impl Iterator) - where - C: Crumbable, - C::Crumb: Into, { - for crumb in crumbs { - // Failure should never happen but we don't really care enough to crash anything - // otherwise. - if let Ok(subtree) = ast.get(&crumb) { - self.process_subtree_at(crumb.into(), subtree) - } - } - } - - /// Processes all subtrees of the given AST in their respective locations. - pub fn process_subtrees(&mut self, ast: &impl Crumbable) { - for (crumb, ast) in ast.enumerate() { - self.process_subtree_at(crumb, ast) - } - } - - /// Processes the given AST, along with its subtree. - /// - /// This is the primary function that is recursively being called as the AST is being traversed. - pub fn process_ast(&mut self, ast: &Ast) { - if let Some(definition) = DefinitionInfo::from_line_ast(ast, ScopeKind::NonRoot, default()) - { - self.process_definition(&definition) - } else if let Some(assignment) = ast::opr::to_assignment(ast) { - self.process_assignment(&assignment); - } else if let Some(lambda) = ast::macros::as_lambda(ast) { - self.process_lambda(&lambda); - } else if self.is_in_pattern() { - // We are in the pattern (be it a lambda's or assignment's left side). Three options: - // 1) This is a destructuring pattern match using infix syntax, like `head,tail`. - // 2) This is a destructuring pattern match with prefix syntax, like `Point x y`. - // 3) This is a single AST node, like `foo` or `Foo`. - // (the possibility of definition has been already excluded) - if let Some(infix_chain) = ast::opr::Chain::try_new(ast) { - // Infix always acts as pattern-match in left-side. - for operand in infix_chain.enumerate_non_empty_operands() { - self.process_located_ast(&operand.map(|operand| &operand.arg)) - } - for operator in infix_chain.enumerate_operators() { - // Operators in infix positions are treated as constructors, i.e. they are used. - self.store_if_name(OccurrenceKind::Used, operator); - } - } else if let Some(prefix_chain) = ast::prefix::Chain::from_ast(ast) { - // Constructor we match against is used. Its arguments introduce names. - if ast::known::Cons::try_from(&prefix_chain.func).is_ok() { - self.store_if_name(OccurrenceKind::Used, prefix_chain.located_func()); - } - - // Arguments introduce names, we ignore function name. - // Arguments will just introduce names in pattern context. - for argument in prefix_chain.enumerate_args() { - self.process_located_ast(&argument) - } - } else { - // Single AST node on the assignment LHS. Deal with identifiers, otherwise - // recursively process subtrees. - match ast.shape() { - ast::Shape::Cons(_) => { - self.try_recording_identifier(OccurrenceKind::Used, ast); - } - ast::Shape::Var(_) => { - self.try_recording_identifier(OccurrenceKind::Introduced, ast); - } - _ => { - self.process_subtrees(ast); - } - } - } - } else { - // Non-pattern context. - if ast::known::Block::try_from(ast).is_ok() { - self.in_new_scope(|this| this.process_subtrees(ast)) - } else if self.try_recording_identifier(OccurrenceKind::Used, ast) { - // Plain identifier: we just added as the condition side-effect. - // No need to do anything more. - } else if let Some(prefix_chain) = ast::prefix::Chain::from_ast(ast) { - self.process_located_ast(&prefix_chain.located_func()); - for argument in prefix_chain.enumerate_args() { - // Ignore the assignment used for named arguments. Descend directly into the - // argument value. - if let Some(named) = match_named_argument(argument.item) { - let rhs = argument.descendant(InfixCrumb::RightOperand, named.rarg); - self.process_located_ast(&rhs) - } else { - self.process_located_ast(&argument) - } - } - } else { - self.process_subtrees(ast); - } - } - } - - fn process_definition(&mut self, definition: &DefinitionInfo) { - // Handle the definition name. - self.in_location(definition.name.crumbs.clone(), |this| - // We take the base name (ignoring extension components) and mark it as introduced. - this.in_location(definition.name.name.crumbs.clone(), |this| { - let name = definition.name.name.item.clone(); - this.record_identifier(OccurrenceKind::Introduced,name); - })); - - - // The scoping for definitions is not entirely clean (should each argument introduce a new - // subscope?) but we do not really care that much. Mostly we are just interested in knowing - // what identifiers are taken in / introduced into the parent scope. - // What happens in the definition body, stays in the definition body. - self.in_new_scope(|this| { - // Args are just patterns. - this.in_context(Context::Pattern, |this| { - for arg in &definition.args { - this.process_located_ast(arg) - } - }); - this.process_located_ast(&definition.body()); - }); - } - - /// Processes the assignment AST node. Left side is pattern, right side is business as usual. - fn process_assignment(&mut self, assignment: &ast::known::Infix) { - self.in_context(Context::Pattern, |this| { - this.process_subtree_at(InfixCrumb::LeftOperand, &assignment.larg) - }); - self.process_subtree_at(InfixCrumb::RightOperand, &assignment.rarg); - } - - /// Processes the matched lambda macro. Argument is in pattern context, and the whole lambda is - /// a new scope. - fn process_lambda(&mut self, lambda: &ast::macros::LambdaInfo) { - self.in_new_scope(|this| { - this.in_context(Context::Pattern, |this| this.process_located_ast(&lambda.arg)); - this.process_located_ast(&lambda.body) - }) - } -} - -/// Describes identifiers that code represented by AST introduces into the graph and identifiers -/// from graph's scope that code uses. This logic serves as a base for connection discovery, -/// where ASTs are typically the node's ASTs. -pub fn analyze_ast(ast: &Ast) -> IdentifierUsage { - let mut analyzer = AliasAnalyzer::new(); - analyzer.process_ast(ast); - analyzer.root_scope.symbols -} - -/// Describes variable usage within a given Ast-like crumbable entity. -pub fn analyze_crumbable(crumbable: &impl Crumbable) -> IdentifierUsage { - let mut analyzer = AliasAnalyzer::default(); - analyzer.process_subtrees(crumbable); - analyzer.root_scope.symbols -} - - - -// ============= -// === Tests === -// ============= - -#[cfg(test)] -mod tests { - use super::test_utils::*; - use super::*; - - /// Checks if actual observed sequence of located identifiers matches the expected one. - /// Expected identifiers are described as code spans in the node's text representation. - fn validate_identifiers( - name: impl Str, - ast: &Ast, - expected: Vec>, - actual: &[Located], - ) { - let mut checker = IdentifierValidator::new(name, ast, expected); - checker.validate_identifiers(actual); - } - - /// Runs the test for the given test case description. - fn run_case(parser: &parser::Parser, case: Case) { - debug!("\n===========================================================================\n"); - debug!("Case: {}", case.code); - let ast = parser.parse_line_ast(&case.code).unwrap(); - let result = analyze_ast(&ast); - debug!("Analysis results: {result:?}"); - validate_identifiers("introduced", &ast, case.expected_introduced, &result.introduced); - validate_identifiers("used", &ast, case.expected_used, &result.used); - } - - /// Runs the test for the test case expressed using markdown notation. See `Case` for details. - fn run_markdown_case(parser: &parser::Parser, marked_code: impl AsRef) { - debug!("Running test case for {}", marked_code.as_ref()); - let case = Case::from_markdown(marked_code.as_ref()); - run_case(parser, case) - } - - #[test] - fn test_alias_analysis() { - let parser = parser::Parser::new(); - let test_cases = [ - "»foo«", - "«five» = 5", - "»Five« = 5", - "«foo» = »bar«", - "«foo» = »foo« »+« »bar«", - "«foo» = »Bar«", - "5 = »Bar«", - "«sum» = »a« »+« »b«", - "»Point« «x» «u» = »point«", - "«x» »,« «y» = »pair«", - r"«inc» = - »foo« »+« 1", - r"«inc» = - foo = 2 - foo »+« 1", - // Below should know that "foo + 1" does not uses "foo" from scope. - // That requires at least partial support for definitions. - r"«inc» = - foo x = 2 - foo »+« 1", - // === Macros Match === - "a -> a", - "a -> »b«", - "»A« -> »b«", - "a -> »A« -> a", - "a -> a -> »A«", - "(»foo«)", - "(«foo») = (»bar«)", - "if »A« then »B«", - "if »a« then »b« else »c«", - "(»foo«", - // === Definition === - "«foo» a b c = »foo« a »d«", - "«foo» a b c = d -> a d", - "«foo» a (»Point« x y) c = »foo« a x »d«", - ]; - for case in &test_cases { - run_markdown_case(&parser, case) - } - } -} diff --git a/app/gui/controller/double-representation/src/alias_analysis/test_utils.rs b/app/gui/controller/double-representation/src/alias_analysis/test_utils.rs deleted file mode 100644 index 8d90816ae5..0000000000 --- a/app/gui/controller/double-representation/src/alias_analysis/test_utils.rs +++ /dev/null @@ -1,205 +0,0 @@ -//! Utilities to facilitate testing of alias-analysis-related code. - -use crate::prelude::*; - -use crate::test_utils::MarkdownProcessor; - -use ast::crumbs::Located; -use regex::Captures; -use regex::Regex; -use regex::Replacer; - - - -// ============ -// === Case === -// ============ - -/// Test case for testing identifier resolution for nodes. -/// Can be expressed using markdown notation, see `from_markdown` method. -#[derive(Clone, Debug, Default)] -pub struct Case { - /// The code: the text of the block line that is considered to be a node of a graph. - /// Any markers are already removed. - pub code: String, - /// List of spans in the code where the identifiers are introduced into the graph's scope. - pub expected_introduced: Vec>, - /// List of spans in the code where the identifiers from the graph's scope are used. - pub expected_used: Vec>, -} - -impl Case { - /// Constructs a test case using a markdown. Input should be text representation of the node's - /// AST in which all identifiers introduced into the graph's scope are marked like `«foo»`, and - /// all identifiers used from graph's scope are marked like `»sum«`. - pub fn from_markdown(marked_code: impl Str) -> Case { - // Regexp that matches either «sth» or »sth« into a group named `introduced` or `used`, - // respectively. See: https://regex101.com/r/pboF8O/2 for detailed explanation. - let regex = format!(r"«(?P<{INTRODUCED}>[^»]*)»|»(?P<{USED}>[^«]*)«"); - // As this is test utils, we don't try nicely handling failure nor reusing the compiled - // regexp between calls to save some cycles. - let regex = Regex::new(®ex).unwrap(); - let mut replacer = MarkdownReplacer::default(); - let code = regex.replace_all(marked_code.as_ref(), replacer.by_ref()).into(); - Case { code, expected_introduced: replacer.introduced, expected_used: replacer.used } - } -} - - - -// ======================== -// === MarkdownReplacer === -// ======================== - -/// We want to recognize two kinds of marked identifiers: ones introduced into the graph's scope and -/// ones used from the graph's scope. -#[derive(Clone, Copy, Debug, Display)] -pub enum Kind { - Introduced, - Used, -} - -/// Name of the pattern group matching introduced identifier. -const INTRODUCED: &str = "introduced"; - -/// Name of the pattern group matching used identifier. -const USED: &str = "used"; - -/// Replacer that is called with each marked token. Does the following: -/// * removes the markdown, i.e. replaces `»foo«` with `foo`; -/// * counts removed markdown bytes, so it is possible to translate between indices in marked and -/// unmarked code; -/// * accumulates spans of introduced and used identifiers. -#[derive(Debug, Default)] -struct MarkdownReplacer { - processor: MarkdownProcessor, - /// Spans in the unmarked code. - introduced: Vec>, - /// Spans in the unmarked code. - used: Vec>, -} - -// Processes every single match for a marked entity. -impl Replacer for MarkdownReplacer { - fn replace_append(&mut self, captures: &Captures, dst: &mut String) { - let (kind, matched) = if let Some(introduced) = captures.name(INTRODUCED) { - (Kind::Introduced, introduced) - } else if let Some(used) = captures.name(USED) { - (Kind::Used, used) - } else { - panic!("Unexpected capture: expected named capture `{INTRODUCED}` or `{USED}`.") - }; - - let span = self.processor.process_match(captures, &matched, dst); - match kind { - Kind::Introduced => self.introduced.push(span), - Kind::Used => self.used.push(span), - }; - } -} - - - -// =========================== -// === IdentifierValidator === -// =========================== - -#[derive(Clone, Copy, Debug, Display, PartialEq)] -enum HasBeenValidated { - No, - Yes, -} - -/// Helper test structure that requires that each given identifier is validated at least once. -/// Otherwise, it shall panic when dropped. -#[derive(Clone, Debug)] -pub struct IdentifierValidator<'a> { - ast: &'a Ast, - name: String, - validations: HashMap, -} - -impl<'a> IdentifierValidator<'a> { - /// Creates a new checker, with identifier set obtained from given node's representation - /// spans. - pub fn new(name: impl Str, ast: &Ast, spans: Vec>) -> IdentifierValidator { - let name = name.into(); - let repr = ast.repr(); - let mut validations = HashMap::default(); - for span in spans { - let name = repr[span].to_owned(); - validations.insert(name, HasBeenValidated::No); - } - IdentifierValidator { ast, name, validations } - } - - /// Marks given identifier as checked. - pub fn validate_identifier(&mut self, name: &str) { - let err = format!("{}: unexpected identifier `{name}` validated", self.name); - let used = self.validations.get_mut(name).expect(&err); - *used = HasBeenValidated::Yes; - } - - /// Marks given sequence of identifiers as checked. - pub fn validate_identifiers( - &mut self, - identifiers: impl IntoIterator>, - ) { - for identifier in identifiers { - self.validate_identifier(&identifier.item); - - let crumbs = &identifier.crumbs; - let ast_result = self.ast.get_traversing(crumbs); - let ast = ast_result.expect("failed to retrieve ast from crumb"); - let name_err = || panic!("Failed to use AST {} as an identifier name", ast.repr()); - let name = ast::identifier::name(ast).unwrap_or_else(name_err); - assert_eq!(name, identifier.item) - } - } -} - -/// Panics if there are remaining identifiers that were not checked. -impl<'a> Drop for IdentifierValidator<'a> { - fn drop(&mut self) { - if !std::thread::panicking() { - for elem in &self.validations { - assert_eq!( - elem.1, - &HasBeenValidated::Yes, - "{}: identifier `{}` was not validated)", - self.name, - elem.0 - ) - } - } else { - debug!("Skipping identifier validation, because thread is already in panic."); - } - } -} - - - -// ============= -// === Tests === -// ============= - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn parsing_markdown_to_test_case() { - let code = "«sum» = »a« + »b«"; - let case = Case::from_markdown(code); - assert_eq!(case.code, "sum = a + b"); - assert_eq!(case.expected_introduced.len(), 1); - assert_eq!(case.expected_introduced[0], 0..3); - assert_eq!(&case.code[case.expected_introduced[0].clone()], "sum"); - - assert_eq!(case.expected_used.len(), 2); - assert_eq!(case.expected_used[0], 6..7); // these are utf-8 byte indices - assert_eq!(&case.code[case.expected_used[0].clone()], "a"); - assert_eq!(case.expected_used[1], 10..11); - assert_eq!(&case.code[case.expected_used[1].clone()], "b"); - } -} diff --git a/app/gui/controller/double-representation/src/connection.rs b/app/gui/controller/double-representation/src/connection.rs deleted file mode 100644 index 27be9c4814..0000000000 --- a/app/gui/controller/double-representation/src/connection.rs +++ /dev/null @@ -1,266 +0,0 @@ -//! Code related to connection discovery and operations. - -use crate::prelude::*; - -use crate::alias_analysis::analyze_crumbable; -use crate::definition::DefinitionInfo; -use crate::definition::ScopeKind; -use crate::node::Id; -use crate::node::MainLine; - -use ast::crumbs::Crumb; -use ast::crumbs::Crumbs; -use ast::crumbs::Located; - - - -// ================ -// === Endpoint === -// ================ - -/// A connection endpoint. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct Endpoint { - /// Id of the node where the endpoint is located. - pub node: Id, - /// The AST ID and location of a port to which this endpoint is connected. The location is - /// relative to the entire node's AST, including both its expression and assignment pattern. - pub port: Located, -} - -impl Endpoint { - /// First crumb identifies line in a given block, i.e. the node. Remaining crumbs identify - /// AST within the node's AST. - /// - /// Returns None if first crumb is not present or does not denote a valid node. - fn new_in_block(block: &ast::Block, mut crumbs: Crumbs) -> Option { - let Some(Crumb::Block(line_crumb)) = crumbs.pop_front() else { return None }; - let line_ast = block.get(&line_crumb).ok()?; - let definition = DefinitionInfo::from_line_ast(line_ast, ScopeKind::NonRoot, block.indent); - let is_non_def = definition.is_none(); - let node = is_non_def.and_option_from(|| MainLine::from_ast(line_ast))?.id(); - let port_id = line_ast.get_traversing(&crumbs).ok()?.id?; - Some(Endpoint { node, port: Located::new(crumbs, port_id) }) - } -} - - -// ================== -// === Connection === -// ================== - -/// Describes a connection between two endpoints: from `source` to `target`. -#[allow(missing_docs)] -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct Connection { - pub source: Endpoint, - pub target: Endpoint, -} - -/// Lists all the connection in the graph for the given code block. -pub fn list_block(block: &ast::Block) -> Vec { - let identifiers = analyze_crumbable(block); - let introduced = identifiers.introduced.into_iter(); - let used = identifiers.used.into_iter(); - let introduced_names: HashMap = introduced - .flat_map(|ident| Some((ident.item, Endpoint::new_in_block(block, ident.crumbs)?))) - .collect(); - used.flat_map(|ident| { - // If name is both introduced and used in the graph's scope; and both of these - // occurrences can be represented as endpoints, then we have a connection. - let source = introduced_names.get(&ident.item)?.clone(); - let target = Endpoint::new_in_block(block, ident.crumbs)?; - Some(Connection { source, target }) - }) - .collect() -} - -/// Lists all the connection in the single-expression definition body. -pub fn list_expression(_ast: &Ast) -> Vec { - // At this points single-expression graphs do not have any connection. - // This will change when there will be input/output pseudo-nodes. - vec![] -} - -/// Lists connections in the given definition body. For now it only makes sense for block shape. -pub fn list(body: &Ast) -> Vec { - match body.shape() { - ast::Shape::Block(block) => list_block(block), - _ => list_expression(body), - } -} - - - -// ============================ -// === Connections Analysis === -// ============================ - -/// A function grouping a set of connections by their source node. -pub fn group_by_source_node( - connections: impl IntoIterator, -) -> HashMap> { - let mut result = HashMap::>::new(); - for connection in connections { - result.entry(connection.source.node).or_default().push(connection) - } - result -} - -/// Returns a set of nodes dependent of the given node in the block. -/// -/// A node _A_ is dependent on node _B_ if its input is connected to _B_'s output, or to at least -/// one node dependent on _B_. -pub fn dependent_nodes_in_def(body: &Ast, node: Id) -> HashSet { - let connections = list(body); - let node_out_connections = group_by_source_node(connections); - let mut result = HashSet::new(); - let mut to_visit = vec![node]; - while let Some(current_node) = to_visit.pop() { - let opt_out_connections = node_out_connections.get(¤t_node); - let out_connections = opt_out_connections.iter().flat_map(|v| v.iter()); - let out_nodes = out_connections.map(|c| c.target.node); - let new_nodes_in_result = out_nodes.filter(|n| result.insert(*n)); - for node in new_nodes_in_result { - to_visit.push(node) - } - } - result -} - - - -// ============= -// === Tests === -// ============= - -#[cfg(test)] -mod tests { - use super::*; - - use crate::definition::DefinitionInfo; - use crate::graph::GraphInfo; - - use ast::crumbs; - use ast::crumbs::InfixCrumb; - use parser::Parser; - - struct TestRun { - graph: GraphInfo, - connections: Vec, - } - - impl TestRun { - fn from_definition(definition: DefinitionInfo) -> TestRun { - let graph = GraphInfo::from_definition(definition); - let repr_of = |connection: &Connection| { - let endpoint = &connection.source; - let node = graph.find_node(endpoint.node).unwrap(); - let ast = node.ast().get_traversing(&endpoint.port.crumbs).unwrap(); - ast.repr() - }; - - let mut connections = graph.connections(); - connections.sort_by_key(|con| repr_of(con)); - - TestRun { graph, connections } - } - - fn from_main_def(code: impl Str) -> TestRun { - let parser = Parser::new(); - let module = parser.parse_module(code, default()).unwrap(); - let definition = DefinitionInfo::from_root_line(&module.lines[0]).unwrap(); - Self::from_definition(definition) - } - - fn from_block(code: impl Str) -> TestRun { - let body = code.as_ref().lines().map(|line| format!(" {}", line.trim())).join("\n"); - let definition_code = format!("main =\n{body}"); - Self::from_main_def(definition_code) - } - - fn endpoint_node_repr(&self, endpoint: &Endpoint) -> String { - self.graph.find_node(endpoint.node).unwrap().ast().clone().repr() - } - } - - #[test] - pub fn connection_listing_test_plain() { - use InfixCrumb::LeftOperand; - use InfixCrumb::RightOperand; - - let code_block = r" -d = p -a = d -b = d -c = a + b -fun a = a b -f = fun 2"; - - - let run = TestRun::from_block(code_block); - let c = &run.connections[0]; - assert_eq!(run.endpoint_node_repr(&c.source), "a = d"); - assert_eq!(&c.source.port.crumbs, &crumbs![LeftOperand]); - assert_eq!(run.endpoint_node_repr(&c.target), "c = a + b"); - assert_eq!(&c.target.port.crumbs, &crumbs![RightOperand, LeftOperand]); - - let c = &run.connections[1]; - assert_eq!(run.endpoint_node_repr(&c.source), "b = d"); - assert_eq!(&c.source.port.crumbs, &crumbs![LeftOperand]); - assert_eq!(run.endpoint_node_repr(&c.target), "c = a + b"); - assert_eq!(&c.target.port.crumbs, &crumbs![RightOperand, RightOperand]); - - let c = &run.connections[2]; - assert_eq!(run.endpoint_node_repr(&c.source), "d = p"); - assert_eq!(&c.source.port.crumbs, &crumbs![LeftOperand]); - assert_eq!(run.endpoint_node_repr(&c.target), "a = d"); - assert_eq!(&c.target.port.crumbs, &crumbs![RightOperand]); - - let c = &run.connections[3]; - assert_eq!(run.endpoint_node_repr(&c.source), "d = p"); - assert_eq!(&c.source.port.crumbs, &crumbs![LeftOperand]); - assert_eq!(run.endpoint_node_repr(&c.target), "b = d"); - assert_eq!(&c.target.port.crumbs, &crumbs![RightOperand]); - - // Note that line `fun a = a b` des not introduce any connections, as it is a definition. - - assert_eq!(run.connections.len(), 4); - } - - #[test] - pub fn inline_definition() { - let run = TestRun::from_main_def("main = a"); - assert!(run.connections.is_empty()); - } - - #[test] - pub fn listing_dependent_nodes() { - let code_block = "\ - f,g = p - a = f - b = g - c = 2 - d = a + b - e = b"; - let mut expected_dependent_nodes = HashMap::<&'static str, Vec<&'static str>>::new(); - expected_dependent_nodes.insert("a = f", vec!["d = a + b"]); - expected_dependent_nodes.insert("b = g", vec!["d = a + b", "e = b"]); - expected_dependent_nodes.insert("c = 2", vec![]); - expected_dependent_nodes.insert("d = a + b", vec![]); - expected_dependent_nodes.insert("e = b", vec![]); - - let TestRun { graph, .. } = TestRun::from_block(code_block); - let nodes = graph.nodes(); - assert_eq!(nodes.len(), expected_dependent_nodes.len()); - for node in nodes { - let node_repr = node.ast().repr(); - let expected = expected_dependent_nodes.get(node_repr.as_str()).unwrap(); - let result = dependent_nodes_in_def(graph.source.body().item, node.id()); - let result_node = result.iter().map(|id| graph.find_node(*id).unwrap()); - let mut result_repr = result_node.map(|n| n.ast().repr()).collect_vec(); - result_repr.sort(); - assert_eq!(result_repr, *expected); - } - } -} diff --git a/app/gui/controller/double-representation/src/context_switch.rs b/app/gui/controller/double-representation/src/context_switch.rs deleted file mode 100644 index 689b42ca3b..0000000000 --- a/app/gui/controller/double-representation/src/context_switch.rs +++ /dev/null @@ -1,245 +0,0 @@ -//! A module containing utilities for managing execution context switch expressions. -//! -//! The context switch expressions are used to enable or disable a certain context for a single -//! node. -//! -//! For example, the following code: -//! ```ignore -//! operator11 = Runtime.with_enabled_context Context.Output environment="design" <| -//! operator10.write "C:\Temp\Test.xlsx" -//! ``` -//! will enable the [`Context::Output`] context for the `operator11` node in `design` environment. - -use crate::prelude::*; - -use crate::name::QualifiedName; -use crate::name::QualifiedNameRef; - -use ast::known; -use ast::opr::qualified_name_chain; - - - -// ================= -// === Constants === -// ================= - -/// FQN for the [`Context::Output`]. -const OUTPUT: [&str; 5] = ["Standard", "Base", "Runtime", "Context", "Output"]; -/// FQN for the `Runtime.with_enabled_context`, which corresponds to [`ContextSwitch::Enable`]. -const ENABLE: [&str; 4] = ["Standard", "Base", "Runtime", "with_enabled_context"]; -/// FQN for the `Runtime.with_disabled_context`, which corresponds to [`ContextSwitch::Disable`]. -const DISABLE: [&str; 4] = ["Standard", "Base", "Runtime", "with_disabled_context"]; - - - -// =============================== -// === ContextSwitchExpression === -// =============================== - -// === ContextSwitch - -/// The two possible context switches. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[allow(missing_docs)] -pub enum ContextSwitch { - Enable, - Disable, -} - -impl<'a> TryFrom> for ContextSwitch { - type Error = anyhow::Error; - - fn try_from(qualified_name: QualifiedNameRef<'a>) -> Result { - // Unwraps are safe, because this function is tested. - let enable_name = QualifiedName::from_all_segments(ENABLE).unwrap(); - let disable_name = QualifiedName::from_all_segments(DISABLE).unwrap(); - - if qualified_name == enable_name { - Ok(ContextSwitch::Enable) - } else if qualified_name == disable_name { - Ok(ContextSwitch::Disable) - } else { - Err(anyhow::anyhow!("Invalid context switch name: {:?}.", qualified_name)) - } - } -} - - -// === Context === - -/// Available execution contexts. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[allow(missing_docs)] -pub enum Context { - Output, -} - -impl<'a> TryFrom> for Context { - type Error = anyhow::Error; - - fn try_from(qualified_name: QualifiedNameRef<'a>) -> Result { - // Unwrap is safe, because this function is tested. - let output_name = QualifiedName::from_all_segments(OUTPUT).unwrap(); - - if qualified_name == output_name { - Ok(Context::Output) - } else { - Err(anyhow::anyhow!("Invalid context name: {:?}.", qualified_name)) - } - } -} - - -// === Environment === - -im_string_newtype! { - /// The name of the execution environment. - Environment -} - - -// === ContextSwitchExpression === - -/// A representation of a single context switch expression. -#[derive(Debug, Clone, PartialEq)] -#[allow(missing_docs)] -pub struct ContextSwitchExpression { - pub switch: ContextSwitch, - pub context: Context, - pub environment: Environment, -} - -impl ContextSwitchExpression { - /// Parse the context switch expression from the given AST. - pub fn parse(ast: &Ast) -> Option { - let infix = known::Infix::try_new(ast.clone()).ok()?; - if ast::opr::is_right_assoc_opr(&infix.opr) { - let prefix = ast::prefix::Chain::from_ast(&infix.larg)?; - let context_switch = QualifiedName::try_from(&prefix.func).ok()?; - let switch = ContextSwitch::try_from(context_switch.as_ref()).ok()?; - if let [context, environment] = &prefix.args[..] { - let context_name = QualifiedName::try_from(&context.sast.wrapped).ok()?; - let context = Context::try_from(context_name.as_ref()).ok()?; - let environment = environment.sast.wrapped.clone(); - let environment = known::Tree::try_from(environment).ok(); - let environment = environment.map(|t| t.as_text().map(Into::into)); - let environment = environment.flatten()?; - Some(ContextSwitchExpression { switch, context, environment }) - } else { - None - } - } else { - None - } - } - - /// Convert the context switch expression to an AST. - pub fn to_ast(&self) -> Ast { - let func = match self.switch { - ContextSwitch::Enable => ENABLE, - ContextSwitch::Disable => DISABLE, - }; - let context = match self.context { - Context::Output => OUTPUT, - }; - let func = qualified_name_chain(func.into_iter()).unwrap().into_ast(); - let context = qualified_name_chain(context.into_iter()).unwrap().into_ast(); - let environment = format!("\"{}\"", self.environment.deref()); - let environment: Ast = ast::Tree::text(environment).into(); - let args = vec![context, environment]; - ast::prefix::Chain::new(func, args).into_ast() - } - - /// Remove the context switch expression from the given AST. The unmodified `ast` is returned - /// if it does not contain any context switch expression. - pub fn without_expression(ast: &Ast) -> Ast { - if ContextSwitchExpression::parse(ast).is_some() { - let crumb = ast::crumbs::InfixCrumb::RightOperand.into(); - let rarg = ast.get(&crumb).unwrap_or(ast); - rarg.clone() - } else { - ast.clone() - } - } -} - - - -// ============= -// === Tests === -// ============= - -#[cfg(test)] -mod tests { - use super::*; - use parser::Parser; - - #[test] - fn test_recognizing_execution_context_switch() { - #[derive(Debug)] - struct Case { - input: &'static str, - expected: Option, - } - - #[rustfmt::skip] - let cases = vec![ - Case { - input: "foo", - expected: None, - }, - Case { - input: "foo <| bar", - expected: None, - }, - Case { - input: "foo <| bar <| baz", - expected: None, - }, - Case { - input: "Runtime.with_enabled_context blabla <| bar", - expected: None, - }, - Case { - input: "Runtime.with_enabled_context Context.Output \"context\" <| bar", - expected: None, - }, - Case { - input: "Standard.Base.Runtime.with_enabled_context Context.Output \"context\" <| bar", - expected: None, - }, - Case { - input: "Standard.Base.Runtime.with_enabled_context Standard.Base.Runtime.Context.Output \"context\" <| bar", - expected: Some(ContextSwitchExpression { - switch: ContextSwitch::Enable, - context: Context::Output, - environment: "context".into(), - }), - }, - Case { - input: "Standard.Base.Runtime.with_disabled_context Standard.Base.Runtime.Context.Output \"context_name\" <| bar", - expected: Some(ContextSwitchExpression { - switch: ContextSwitch::Disable, - context: Context::Output, - environment: "context_name".into(), - }), - }, - Case { - input: "Standard.Base.Runtime.with_disabled_context Standard.Base.Runtime.Context.Output \"context_name\" <| bar <| baz", - expected: Some(ContextSwitchExpression { - switch: ContextSwitch::Disable, - context: Context::Output, - environment: "context_name".into(), - }), - }, - ]; - - let parser = Parser::new(); - for case in cases.iter() { - let ast = parser.parse_line_ast(case.input).unwrap(); - let result = ContextSwitchExpression::parse(&ast); - assert_eq!(result, case.expected, "{case:?}"); - } - } -} diff --git a/app/gui/controller/double-representation/src/definition.rs b/app/gui/controller/double-representation/src/definition.rs deleted file mode 100644 index 5b5848ce55..0000000000 --- a/app/gui/controller/double-representation/src/definition.rs +++ /dev/null @@ -1,814 +0,0 @@ -//! Code for definition discovery in the blocks, finding definition by name and related utilities. - -use crate::prelude::*; - -use crate::LineKind; -use crate::INDENT; - -use ast::crumbs::ChildAst; -use ast::crumbs::Crumbable; -use ast::crumbs::InfixCrumb; -use ast::crumbs::Located; -use ast::known; -use ast::opr; -use parser::Parser; -use std::iter::FusedIterator; - - - -// ===================== -// === Definition Id === -// ===================== - -#[allow(missing_docs)] -#[derive(Copy, Fail, Clone, Debug)] -#[fail(display = "Encountered an empty definition ID. It must contain at least one crumb.")] -pub struct EmptyDefinitionId; - -/// Crumb describes step that needs to be done when going from context (for graph being a module) -/// to the target. -// TODO [mwu] -// Currently we support only entering named definitions. -pub type Crumb = DefinitionName; - -/// Identifies graph in the module. -#[derive(Clone, Debug, Eq, Hash, PartialEq)] -pub struct Id { - /// Sequence of traverses from module root up to the identified graph. - pub crumbs: Vec, -} - -impl Id { - /// Creates a new graph identifier consisting of a single crumb. - pub fn new_single_crumb(crumb: DefinitionName) -> Id { - let crumbs = vec![crumb]; - Id { crumbs } - } - - /// Creates a new identifier with a single plain name. - pub fn new_plain_name(name: impl Str) -> Id { - Self::new_plain_names(std::iter::once(name.into())) - } - - /// Creates a new identifier from a sequence of plain definition names. - pub fn new_plain_names(names: impl IntoIterator) -> Id - where S: ToString { - let crumbs = - names.into_iter().map(|name| DefinitionName::new_plain(name.to_string())).collect_vec(); - Id { crumbs } - } -} - -impl Display for Id { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut iter = self.crumbs.iter(); - if let Some(crumb) = iter.next() { - write!(f, "{crumb}")? - } - for crumb in iter { - write!(f, "⮚{crumb}")? - } - Ok(()) - } -} - - - -// ============= -// === Error === -// ============= - -#[derive(Fail, Debug)] -#[fail( - display = "Cannot set Block lines because no line with Some(Ast) was found. Block must have \ -at least one non-empty line." -)] -struct MissingLineWithAst; - -#[allow(missing_docs)] -#[derive(Fail, Clone, Debug)] -#[fail(display = "Cannot find definition child with id {:?}.", _0)] -pub struct CannotFindChild(Crumb); - - - -// ================= -// === ScopeKind === -// ================= - -/// Describes the kind of code block (scope) to which definition can belong. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum ScopeKind { - /// Module scope is a file's top-level block. - Root, - /// Any other block, e.g. introduced as body of some definition binding. - NonRoot, -} - - - -// ====================== -// === DefinitionName === -// ====================== - -/// Structure representing definition name. If this is an extension method, extended type is -/// also included. -#[derive(Clone, Debug, Eq, Hash, PartialEq)] -pub struct DefinitionName { - /// Name of the function itself. - pub name: Located, - /// Used when definition is an extension method. Then it stores the segments - /// of the extended target type path. - pub extended_target: Vec>, -} - -impl DefinitionName { - /// Creates a new name consisting of a single unqualified identifier (not an explicit extension - /// method). - pub fn new_plain(name: impl Into) -> DefinitionName { - let name = Located::new_root(name.into()); - DefinitionName { name, extended_target: default() } - } - - /// Creates a new explicit extension method name. - pub fn new_method(extended_atom: impl Str, name: impl Str) -> DefinitionName { - let extended_atom = Located::new(InfixCrumb::LeftOperand, extended_atom.into()); - let name = Located::new(InfixCrumb::RightOperand, name.into()); - let extended_target = vec![extended_atom]; - DefinitionName { name, extended_target } - } - - /// Tries describing given Ast piece as a definition name. Typically, passed Ast - /// should be the binding's left-hand side. - /// - /// Returns `None` if is not name-like entity. - pub fn from_ast(ast: &Ast) -> Option { - let accessor_chain = opr::as_access_chain(ast); - let (extended_target, name) = match accessor_chain { - Some(accessor_chain) => { - // Not really clear how the incomplete names should be supported. For now we just - // reject them. When use-cases appear, this check might need to be relaxed. - if !accessor_chain.all_operands_set() { - return None; - } - - let mut pieces = Vec::new(); - for piece in accessor_chain.enumerate_non_empty_operands() { - let name = ast::identifier::name(&piece.item.arg)?.to_owned(); - pieces.push(piece.map(|_| name)); - } - - let name = pieces.pop()?; - (pieces, name) - } - None => { - let name = match ast.shape() { - ast::Shape::Var(var) => Some(var.name.as_str()), - ast::Shape::Opr(opr) => Some(opr.name.as_str()), - ast::Shape::SectionSides(sides) => ast::identifier::name(&sides.opr), - // Shape::Cons is intentionally omitted. - // It serves to pattern-match, not as definition name. - _ => None, - }?; - let name = Located::new_root(name.to_owned()); - (Vec::new(), name) - } - }; - Some(DefinitionName { name, extended_target }) - } - - /// Iterate over name segments of this name, left to right. - pub fn name_segments(&self) -> impl Iterator { - let path = self.extended_target.iter().map(|segment| segment.as_str()); - let last = std::iter::once(self.name.as_str()); - path.chain(last) - } - - /// Get AST of this name. - pub fn ast(&self, parser: &Parser) -> FallibleResult { - // We can't assume that string pieces we have are valid identifiers. - // But neither this is our responsibility. If it parses, we can store it in the Ast. - parser.parse_line_ast(self.to_string()) - } - - /// Checks if the given definition name is a method defined on given expected atom name. - /// - /// E.g. `Main.foo` is a method of `Main`. Also, if `Main` is a name of module, than root-scoped - /// definition named `foo` will be treated as an extension method on `Main`. To handle such case - /// properly, function takes `parent_name` - it is a name of module or type where the - /// definition is located. - pub fn method_of(&self, parent_name: &str, expected_atom: &str) -> bool { - if self.extended_target.is_empty() { - parent_name == expected_atom - } else { - self.explicitly_extends_type(expected_atom) - } - } - - /// Check if this name is an explicit extension method for given atom. - /// - /// For example `Int.add` is an extension method for `Int`, whereas plain name `add` is not. - pub fn explicitly_extends_type(&self, expected_typename: &str) -> bool { - let expected_segments = ast::opr::name_segments(expected_typename); - let segments = &self.extended_target; - expected_segments.eq_by(segments, |lhs, rhs| lhs == rhs.item.as_str()) - } -} - -impl Display for DefinitionName { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let text = self.name_segments().join(ast::opr::predefined::ACCESS); - write!(f, "{text}") - } -} - - - -// ====================== -// === DefinitionInfo === -// ====================== - -/// Information about definition binding. -#[derive(Clone, Debug)] -pub struct DefinitionInfo { - /// The whole definition. It is an Infix shape with `=` operator. Its left-hand side is - /// an App. - pub ast: known::Infix, - /// Name of this definition. Includes typename, if this is an extension method. - pub name: Located, - /// Arguments for this definition. Does not include any implicit ones (e.g. no `this`). - pub args: Vec>, - /// The absolute indentation of the code block that introduced this definition. - pub context_indent: usize, -} - -impl DefinitionInfo { - /// Returns the definition body, i.e. Ast standing on the assignment's right-hand side. - pub fn body(&self) -> Located<&Ast> { - Located::new(InfixCrumb::RightOperand, &self.ast.rarg) - } - - /// Gets the definition block lines. If `body` is a `Block`, it returns its `BlockLine`s, - /// concatenating `empty_lines`, `first_line` and `lines`, in this exact order. If `body` is - /// `Infix`, it returns a single `BlockLine`. - pub fn block_lines(&self) -> Vec>> { - if let Ok(block) = known::Block::try_from(*self.body()) { - block.iter_all_lines().map(|line| line.map_opt(CloneRef::clone_ref)).collect() - } else { - let elem = Some((*self.body()).clone()); - let off = 0; - vec![ast::BlockLine { elem, off }] - } - } - - /// Sets the definition block lines. `lines` must contain at least one non-empty line to - /// succeed. - pub fn set_block_lines( - &mut self, - mut lines: Vec>>, - ) -> FallibleResult { - // FIXME [mwu] - // This doesn't deal correctly with offsets, but I have no idea how it should behave, - // as the current parser's behavior and AST is inconsistent. - // Basically `empty_lines` currently use absolute offsets, while `BlockLines` use relative - // offsets. This is not desirable, as e.g. an empty line in the middle of block is not - // possible to express with the current AST (it won't round-trip). - - let indent = self.indent(); - let mut empty_lines = Vec::new(); - let mut line = lines.pop_front().ok_or(MissingLineWithAst)?; - while line.elem.is_none() { - empty_lines.push(line.off + indent); - line = lines.pop_front().ok_or(MissingLineWithAst)?; - } - let elem = line.elem.ok_or(MissingLineWithAst)?; - let off = line.off; - let first_line = ast::BlockLine { elem, off }; - let block = ast::Block { indent, empty_lines, first_line, lines }; - let body_ast = Ast::new(block, None); - self.set_body_ast(body_ast); - Ok(()) - } - - /// Sets the definition body to expression with given Ast. - pub fn set_body_ast(&mut self, expression: Ast) { - self.ast.update_shape(|infix| { - // Keep at least one space after `=` for inline expressions, so it - // doesn't look ugly when converting from previous block definition body. - match expression.shape() { - ast::Shape::Block(_) => {} - _ => infix.roff = std::cmp::max(1, infix.roff), - } - infix.rarg = expression; - }) - } - - /// Tries to interpret a root line (i.e. the AST being placed in a line directly in the module - /// scope) as a definition. - pub fn from_root_line(line: &ast::BlockLine>) -> Option { - Self::from_root_line_ast(line.elem.as_ref()?) - } - - /// Tries to interpret a root line's AST as a definition. - pub fn from_root_line_ast(ast: &Ast) -> Option { - let indent = 0; - Self::from_line_ast(ast, ScopeKind::Root, indent) - } - - /// Tries to interpret `Line`'s `Ast` as a function definition. - /// - /// Assumes that the AST represents the contents of line (and not e.g. right-hand side of - /// some binding or other kind of subtree). - pub fn from_line_ast( - ast: &Ast, - kind: ScopeKind, - context_indent: usize, - ) -> Option { - if let LineKind::Definition { ast, args, name } = LineKind::discern(ast, kind) { - Some(DefinitionInfo { ast, name, args, context_indent }) - } else { - None - } - } -} - -/// Definition stored under some known crumbs path. -pub type ChildDefinition = Located; - -/// Tries to add a new crumb to current path to obtain a deeper child. -/// Its crumbs will accumulate both current crumbs and the passed one. -pub fn resolve_single_name(def: ChildDefinition, id: &Crumb) -> FallibleResult { - let child = def.item.def_iter().find_by_name(id)?; - Ok(def.into_descendant(child)) -} - - - -// ================= -// === Iterators === -// ================= - -// === DefinitionIterator === - -/// Iterator that iterates over child definitions. -#[allow(missing_debug_implementations)] -pub struct DefinitionIterator<'a> { - /// Iterator going over ASTs of potential child definitions. - pub iterator: Box> + 'a>, - /// What kind of scope are we getting our ASTs from. - pub scope_kind: ScopeKind, - /// Absolute indentation of the child ASTs we iterate over. - pub indent: usize, -} - -impl<'a> Iterator for DefinitionIterator<'a> { - type Item = ChildDefinition; - fn next(&mut self) -> Option { - let scope_kind = self.scope_kind; - let indent = self.indent; - self.iterator.find_map(|ChildAst { item, crumbs }| { - let definition_opt = DefinitionInfo::from_line_ast(item, scope_kind, indent); - definition_opt.map(|def| ChildDefinition::new(crumbs, def)) - }) - } -} - -impl<'a> DefinitionIterator<'a> { - /// Yields vector of all child definition infos, discarding the crumbs. - pub fn infos_vec(self) -> Vec { - self.map(|child_def| child_def.item).collect_vec() - } - - /// Looks up direct child definition by given name. - pub fn find_by_name( - mut self, - name: &DefinitionName, - ) -> Result { - let err = || CannotFindChild(name.clone()); - self.find(|child_def| &*child_def.item.name == name).ok_or_else(err) - } -} - - -// === RecursiveDefinitionIterator === - -/// An recursive iterator over child definitions, returned by -/// [`DefinitionProvider::recursive_def_iter`]. -#[derive(Clone, Debug, Default)] -pub struct RecursiveDefinitionIterator { - stack: Vec, -} - -impl Iterator for RecursiveDefinitionIterator { - type Item = ChildDefinition; - - fn next(&mut self) -> Option { - let next_item = self.stack.pop(); - if let Some(some_item) = &next_item { - self.stack.extend(some_item.def_iter()) - } - next_item - } -} - -impl FusedIterator for RecursiveDefinitionIterator {} - - -// ========================== -// === DefinitionProvider === -// ========================== - - - -/// An entity that contains lines that we want to interpret as definitions. -pub trait DefinitionProvider { - /// Absolute indentation level of the scope of this provider's body. - /// (i.e. the indents of the child definitions) - fn indent(&self) -> usize; - - /// What kind of scope this is. - fn scope_kind(&self) -> ScopeKind; - - /// Iterator going over all line-like Ast's that can hold a child definition. - fn enumerate_asts<'a>(&'a self) -> Box> + 'a>; - - /// Returns a scope iterator allowing browsing definition provided under this provider. - fn def_iter(&self) -> DefinitionIterator { - let iterator = self.enumerate_asts(); - let scope_kind = self.scope_kind(); - let indent = self.indent(); - DefinitionIterator { iterator, scope_kind, indent } - } - - /// Returns an iterator iterating recursively over definitions provided by this provider and - /// their nested definitions (as [`ChildDefinition`] is also a provider). - fn recursive_def_iter(&self) -> RecursiveDefinitionIterator { - RecursiveDefinitionIterator { stack: self.def_iter().collect() } - } -} - -impl DefinitionProvider for known::Block { - fn indent(&self) -> usize { - self.indent - } - - fn scope_kind(&self) -> ScopeKind { - ScopeKind::NonRoot - } - - fn enumerate_asts<'a>(&'a self) -> Box> + 'a> { - self.ast().children() - } -} - -impl DefinitionProvider for DefinitionInfo { - fn indent(&self) -> usize { - match self.ast.rarg.shape() { - ast::Shape::Block(block) => block.indent, - // If definition has no block of its own, it does not introduce any children and - // returned value here is not used anywhere currently. Might matter in the future, - // when we deal with lambdas. Anyway, whatever block we might introduce, it should - // be more indented than our current context. - _ => self.context_indent + INDENT, - } - } - - fn scope_kind(&self) -> ScopeKind { - ScopeKind::NonRoot - } - - fn enumerate_asts<'a>(&'a self) -> Box> + 'a> { - use ast::crumbs::Crumb; - match self.ast.rarg.shape() { - ast::Shape::Block(_) => { - let parent_crumb = Crumb::Infix(InfixCrumb::RightOperand); - let rarg = &self.ast.rarg; - let iter = rarg.enumerate().map(move |(crumb, ast)| { - let crumbs = vec![parent_crumb, crumb]; - ChildAst::new(crumbs, ast) - }); - Box::new(iter) - } - _ => Box::new(std::iter::empty()), - } - } -} - -impl DefinitionProvider for ChildDefinition { - fn indent(&self) -> usize { - self.item.indent() - } - - fn scope_kind(&self) -> ScopeKind { - self.item.scope_kind() - } - - fn enumerate_asts<'a>(&'a self) -> Box> + 'a> { - Box::new( - self.item - .enumerate_asts() - .map(|child_ast| self.descendant(child_ast.crumbs, child_ast.item)), - ) - } -} - - - -// ============= -// === ToAdd === -// ============= - -/// Describes a definition to be created. -/// -/// Type meant to be easily constructable in the code and be translated into AST. -/// Information-wise it corresponds to DefinitionInfo. -#[derive(Clone, Debug)] -pub struct ToAdd { - /// The name of the introduced definition. May represent plain identifier or an extension. - /// E.g. `add` or `Int.add`. - pub name: DefinitionName, - /// Names of explicit parameters. `this` parameter must not be included. - pub explicit_parameter_names: Vec, - /// The first non-empty line of the definition body. - pub body_head: Ast, - /// Further definition body lines. `None` represents an empty line. - pub body_tail: Vec>, -} - -impl ToAdd { - /// Create ToAdd description from an arbitrary AST. - pub fn new_with_body( - name: DefinitionName, - explicit_parameter_names: Vec, - body: Ast, - ) -> Self { - let (body_head, body_tail) = match body.shape() { - ast::Shape::Block(ast::Block { first_line, lines, .. }) => ( - first_line.elem.clone_ref(), - lines.iter().map(|line| line.elem.as_ref().cloned()).collect_vec(), - ), - _ => (body.clone_ref(), default()), - }; - ToAdd { name, explicit_parameter_names, body_head, body_tail } - } - - /// The definition's head, i.e. the left-hand side of the primary assignment. - pub fn head(&self, parser: &Parser) -> FallibleResult { - let name = self.name.ast(parser)?; - let args = self.explicit_parameter_names.iter().map(Ast::var); - let head = ast::prefix::Chain::new(name, args).into_ast(); - Ok(head) - } - - /// The definition's body, i.e. the right-hand side of the primary assignment. - pub fn body(&self, scope_indent: usize) -> Ast { - // Assignment always must be in a block - if self.body_tail.is_empty() && !ast::opr::is_assignment(&self.body_head) { - self.body_head.clone_ref() - } else { - let mut block = ast::Block::from_lines(&self.body_head, &self.body_tail); - block.indent = scope_indent + INDENT; - Ast::from(block) - } - } - - /// Generate the definition's Ast from the description. - pub fn ast(&self, scope_indent: usize, parser: &Parser) -> FallibleResult { - let body = self.body(scope_indent); - let body_is_block = matches!(body.shape(), ast::Shape::Block { .. }); - let infix_shape = ast::Infix { - larg: self.head(parser)?, - loff: 1, - opr: Ast::opr(ast::opr::predefined::ASSIGNMENT), - roff: if body_is_block { 0 } else { 1 }, - rarg: body, - }; - let ast = Ast::from(infix_shape); - Ok(ast) - } -} - - - -// ============= -// === Tests === -// ============= - -#[cfg(test)] -mod tests { - use super::*; - - use crate::module; - use crate::INDENT; - - fn assert_eq_strings(lhs: Vec, rhs: Vec) { - let lhs = lhs.iter().map(|s| s.as_ref()).collect_vec(); - let rhs = rhs.iter().map(|s| s.as_ref()).collect_vec(); - assert_eq!(lhs, rhs) - } - - fn to_names(defs: &[DefinitionInfo]) -> Vec { - defs.iter().map(|def| def.name.to_string()).collect() - } - - fn indented(line: impl Display) -> String { - format!(" {line}") - } - - #[test] - fn generating_definition_to_add() { - let parser = Parser::new(); - let mut to_add = ToAdd { - name: DefinitionName::new_method("Main", "add"), - explicit_parameter_names: vec!["arg1".into(), "arg2".into()], - body_head: Ast::infix_var("ret", "=", "arg2"), - body_tail: default(), - }; - - // First, if we generate definition with single line and it is assignment, - // it should be placed in a block of its own. - let ast = to_add.ast(4, &parser).unwrap(); - assert_eq!(ast.repr(), "Main.add arg1 arg2 =\n ret = arg2"); - - // Now the single line body will be non-assignment, so it will be safe to place inline. - to_add.body_head = Ast::infix_var("arg1", "+", "arg2"); - let ast = to_add.ast(4, &parser).unwrap(); - assert_eq!(ast.repr(), "Main.add arg1 arg2 = arg1 + arg2"); - - // Having more than a single line always requires a block. - to_add.body_tail.push(Some(Ast::infix_var("arg1", "-", "arg2"))); - let ast = to_add.ast(4, &parser).unwrap(); - // Note 8 spaces indents for definition block lines (as the parent scope was at 4). - // Also, note that there is no space after the definition's assignment operator. - assert_eq!(ast.repr(), "Main.add arg1 arg2 =\n arg1 + arg2\n arg1 - arg2"); - } - - #[test] - fn definition_name_tests() { - let parser = parser::Parser::new(); - let ast = parser.parse_line_ast("Foo.Bar.baz").unwrap(); - let name = DefinitionName::from_ast(&ast).unwrap(); - - assert_eq!(*name.name, "baz"); - assert_eq!(name.extended_target[0].as_str(), "Foo"); - assert_eq!(name.extended_target[1].as_str(), "Bar"); - - assert_eq!(ast.get_traversing(&name.name.crumbs).unwrap().repr(), "baz"); - assert_eq!(ast.get_traversing(&name.extended_target[0].crumbs).unwrap().repr(), "Foo"); - assert_eq!(ast.get_traversing(&name.extended_target[1].crumbs).unwrap().repr(), "Bar"); - } - - #[test] - fn definition_name_rejecting_incomplete_names() { - let parser = parser::Parser::new(); - let ast = parser.parse_line_ast("Foo. .baz").unwrap(); - assert!(DefinitionName::from_ast(&ast).is_none()); - } - - #[test] - fn definition_info_name() { - let parser = parser::Parser::new(); - let ast = parser.parse_line_ast("Foo.bar a b c = baz").unwrap(); - let definition = DefinitionInfo::from_root_line_ast(&ast).unwrap(); - - assert_eq!(definition.name.to_string(), "Foo.bar"); - assert_eq!(ast.get_traversing(&definition.name.crumbs).unwrap().repr(), "Foo.bar"); - } - - #[test] - fn located_definition_args() { - let parser = parser::Parser::new(); - let ast = parser.parse_line_ast("foo bar baz = a + b + c").unwrap(); - let definition = DefinitionInfo::from_root_line_ast(&ast).unwrap(); - let (arg0, arg1) = definition.args.expect_tuple(); - - use ast::crumbs; - use ast::crumbs::InfixCrumb::*; - use ast::crumbs::PrefixCrumb::*; - assert_eq!(arg0.crumbs, crumbs![LeftOperand, Func, Arg]); - assert_eq!(arg1.crumbs, crumbs![LeftOperand, Arg]); - - assert_eq!(arg0.item.repr(), "bar"); - assert_eq!(ast.get_traversing(&arg0.crumbs).unwrap(), &arg0.item); - assert_eq!(arg1.item.repr(), "baz"); - assert_eq!(ast.get_traversing(&arg1.crumbs).unwrap(), &arg1.item); - } - - #[test] - fn match_is_not_definition() { - let cons = Ast::cons("Foo"); - let arg = Ast::number(5); - let lhs = Ast::prefix(cons, arg.clone()); - let rhs = Ast::var("bar"); - let ast = Ast::infix(lhs, "=", rhs.clone()); - - // Not a definition, it is a pattern match/ - assert_eq!(ast.repr(), "Foo 5 = bar"); - let def_opt = DefinitionInfo::from_line_ast(&ast, ScopeKind::NonRoot, INDENT); - assert!(def_opt.is_none()); - - let var = Ast::var("foo"); - let lhs = Ast::prefix(var, arg); - let ast = Ast::infix(lhs, "=", rhs); - - // Now it is a definition. - assert_eq!(ast.repr(), "foo 5 = bar"); - let def_opt = DefinitionInfo::from_line_ast(&ast, ScopeKind::NonRoot, INDENT); - assert!(def_opt.is_some()); - } - - #[test] - fn list_definition_test() { - let parser = parser::Parser::new(); - - let definition_lines = vec![ - "main = _", - "Foo.Bar.foo = _", - "Foo.Bar.baz a b = _", - "+ a = _", - "Int.+ a = _", - "bar = _", - "add a b = 50", - "* a b = _", - ]; - let expected_def_names_in_module = - vec!["main", "Foo.Bar.foo", "Foo.Bar.baz", "+", "Int.+", "bar", "add", "*"]; - // In definition there are no extension methods nor arg-less definitions. - let expected_def_names_in_def = vec!["+", "add", "*"]; - - // === Program with definitions in root === - let program = definition_lines.join("\n"); - let module = parser.parse_module(program, default()).unwrap(); - let definitions = module.def_iter().infos_vec(); - assert_eq_strings(to_names(&definitions), expected_def_names_in_module); - - // Check that definition can be found and their body is properly described. - let add_name = DefinitionName::new_plain("add"); - let add = module.def_iter().find_by_name(&add_name).expect("failed to find `add` function"); - let body = known::Number::try_from(*add.body()).expect("add body should be a Block"); - assert_eq!(body.int, "50"); - - // === Program with definition in `some_func`'s body `Block` === - let indented_lines = definition_lines.iter().map(indented).collect_vec(); - let program = format!("some_func arg1 arg2 =\n{}", indented_lines.join("\n")); - let module = parser.parse_module(program, default()).unwrap(); - let root_defs = module.def_iter().infos_vec(); - let (only_def,) = root_defs.expect_tuple(); - assert_eq!(&only_def.name.to_string(), "some_func"); - let body_block = known::Block::try_from(*only_def.body()).unwrap(); - let nested_defs = body_block.def_iter().infos_vec(); - assert_eq_strings(to_names(&nested_defs), expected_def_names_in_def); - } - - #[test] - fn finding_root_definition() { - let program_to_expected_main_pos = vec![ - ("main = bar", 0), - ("\nmain = bar", 1), - ("\n\nmain = bar", 2), - ("foo = bar\nmain = bar", 1), - ("foo = bar\n\nmain = bar", 2), - ]; - - let parser = parser::Parser::new(); - let main_id = Id::new_plain_name("main"); - for (program, expected_line_index) in program_to_expected_main_pos { - let module = parser.parse_module(program, default()).unwrap(); - let location = module::locate(&module, &main_id).unwrap(); - let (crumb,) = location.crumbs.expect_tuple(); - match crumb { - ast::crumbs::Crumb::Module(m) => assert_eq!(m.line_index, expected_line_index), - _ => panic!("Expected module crumb, got: {crumb:?}."), - } - } - } - - #[test] - fn getting_nested_definition() { - let program = r" -main = - foo = 2 - add a b = a + b - baz arg = - subbaz arg = 4 - baz2 arg = - subbaz2 = 4 - - add foo bar"; - - let module = parser::Parser::new().parse_module(program, default()).unwrap(); - let check_def = |id, expected_body| { - let definition = module::get_definition(&module, &id).unwrap(); - assert_eq!(definition.body().repr(), expected_body); - }; - let check_not_found = |id| assert!(module::get_definition(&module, &id).is_err()); - - check_def(Id::new_plain_names(["main", "add"]), "a + b"); - check_def(Id::new_plain_names(["main", "baz"]), "\n subbaz arg = 4"); - check_def(Id::new_plain_names(["main", "baz", "subbaz"]), "4"); - - // Node are not definitions - check_not_found(Id::new_plain_names(["main", "foo"])); - check_not_found(Id::new_plain_names(["main", "baz2", "subbaz2"])); - } -} diff --git a/app/gui/controller/double-representation/src/graph.rs b/app/gui/controller/double-representation/src/graph.rs deleted file mode 100644 index 56c55fa114..0000000000 --- a/app/gui/controller/double-representation/src/graph.rs +++ /dev/null @@ -1,543 +0,0 @@ -//! Code for retrieving graph description from AST. - -use crate::prelude::*; - -use crate::connection; -use crate::connection::Connection; -use crate::context_switch::ContextSwitch; -use crate::definition; -use crate::definition::DefinitionInfo; -use crate::definition::DefinitionProvider; -use crate::node; -use crate::node::LocatedNode; -use crate::node::NodeInfo; - -use ast::known; -use ast::Ast; -use ast::BlockLine; -use engine_protocol::language_server::ExecutionEnvironment; - - - -/// Graph uses the same `Id` as the definition which introduces the graph. -pub type Id = definition::Id; - - - -// ==================== -// === LocationHint === -// ==================== - -/// Describes the desired position of the node's line in the graph's code block. -#[derive(Clone, Copy, Debug)] -pub enum LocationHint { - /// Try placing this node's line before the line described by id. - Before(ast::Id), - /// Try placing this node's line after the line described by id. - After(ast::Id), - /// Try placing this node's line at the start of the graph's code block. - Start, - /// Try placing this node's line at the end of the graph's code block. - End, -} - - - -// ================= -// === GraphInfo === -// ================= - -/// Description of the graph, based on information available in AST. -#[derive(Clone, Debug, Deref)] -pub struct GraphInfo { - /// The definition providing this graph. - pub source: DefinitionInfo, -} - -impl GraphInfo { - /// Look for a node with given id in the graph. - pub fn locate_node(&self, id: node::Id) -> FallibleResult { - let lines = self.source.block_lines(); - node::locate(&lines, self.source.context_indent, id) - } - - /// Describe graph of the given definition. - pub fn from_definition(source: DefinitionInfo) -> GraphInfo { - GraphInfo { source } - } - - /// Gets the AST of this graph definition. - pub fn ast(&self) -> Ast { - self.source.ast.clone().into() - } - - /// Gets all known nodes in this graph (does not include special pseudo-nodes like graph - /// inputs and outputs). - pub fn nodes(&self) -> Vec { - let ast = &self.source.ast; - let body = &ast.rarg; - if Self::is_empty_graph_body(body) { - // Empty graph body is represented as a single `Nothing` value. It has no nodes. - vec![] - } else if let Ok(body_block) = known::Block::try_new(body.clone()) { - let context_indent = self.source.indent(); - let lines_iter = body_block.enumerate_non_empty_lines(); - let nodes_iter = node::NodeIterator { lines_iter, context_indent }; - nodes_iter.map(|n| n.node).collect() - } else if let Some(node) = node::NodeInfo::from_main_line_ast(body) { - // There's no way to attach a documentation comment to an inline node, it consists only - // of the main line. - vec![node] - } else { - // It should not be possible to have empty definition without any nodes but it is - // possible to represent such thing in AST. Anyway, it has no nodes. - vec![] - } - } - - /// Gets the list of connections between the nodes in this graph. - pub fn connections(&self) -> Vec { - connection::list(&self.source.ast.rarg) - } - - /// Adds a new node to this graph. - pub fn add_node(&mut self, node: &NodeInfo, location_hint: LocationHint) -> FallibleResult { - let body = self.source.body(); - let mut lines = if Self::is_empty_graph_body(body.item) { - // Adding first node to empty graph. We need to remove the placeholder value. - default() - } else { - self.source.block_lines() - }; - let last_non_empty = || lines.iter().rposition(|line| line.elem.is_some()); - let index = match location_hint { - LocationHint::Start => 0, - LocationHint::End => last_non_empty().map_or(lines.len(), |ix| ix + 1), - LocationHint::After(id) => self.locate_node(id)?.index.last() + 1, - LocationHint::Before(id) => self.locate_node(id)?.index.first(), - }; - let elem = Some(node.ast().clone_ref()); - let off = 0; - lines.insert(index, BlockLine { elem, off }); - if let Some(documentation) = &node.documentation { - let elem = Some(documentation.ast().into()); - let line = BlockLine { elem, off }; - lines.insert(index, line); - } - self.source.set_block_lines(lines) - } - - /// Locates a node with the given id. - pub fn find_node(&self, id: ast::Id) -> Option { - self.nodes().iter().find(|node| node.id() == id).cloned() - } - - /// After removing last node, we want to insert a placeholder value for definition value. - /// This defines its AST. Currently it is just `Nothing`. - fn empty_graph_body() -> Ast { - Ast::cons(ast::constants::keywords::NOTHING).with_new_id() - } - - /// Check if the graph is empty. (is filled with [`Self::empty_graph_body`]) - fn is_empty_graph_body(ast: &Ast) -> bool { - let cons = known::Cons::try_from(ast); - cons.map_or(false, |cons| cons.name == ast::constants::keywords::NOTHING) - } - - /// Removes the node from graph. - pub fn remove_node(&mut self, node_id: ast::Id) -> FallibleResult { - self.update_node(node_id, |_| None) - } - - /// Sets a new state for the node. The id of the described node must denote already existing - /// node. - pub fn set_node(&mut self, node: &NodeInfo) -> FallibleResult { - self.update_node(node.id(), |_| Some(node.clone())) - } - - /// Sets a new state for the node. The id of the described node must denote already existing - /// node. - pub fn update_node( - &mut self, - id: ast::Id, - f: impl FnOnce(NodeInfo) -> Option, - ) -> FallibleResult { - let LocatedNode { index, node } = self.locate_node(id)?; - - let mut lines = self.source.block_lines(); - if let Some(updated_node) = f(node) { - lines[index.main_line].elem = Some(updated_node.main_line.ast().clone_ref()); - match (index.documentation_line, updated_node.documentation) { - (Some(old_comment_index), None) => { - lines.remove(old_comment_index); - } - (Some(old_comment_index), Some(new_comment)) => - lines[old_comment_index] = new_comment.block_line(), - (None, Some(new_comment)) => - lines.insert(index.main_line, new_comment.block_line()), - (None, None) => {} - } - } else { - lines.remove(index.main_line); - if let Some(doc_index) = index.documentation_line { - lines.remove(doc_index); - } - } - let non_empty_lines_count = lines.iter().filter(|line| line.elem.is_some()).count(); - if non_empty_lines_count == 0 { - self.source.set_body_ast(Self::empty_graph_body()); - Ok(()) - } else { - self.source.set_block_lines(lines) - } - - // TODO tests for cases with comments involved - } - - /// Sets expression of the given node. - #[profile(Debug)] - pub fn edit_node(&mut self, node_id: ast::Id, new_expression: Ast) -> FallibleResult { - self.update_node(node_id, |mut node| { - node.set_expression(new_expression); - Some(node) - }) - } - - /// Sets expression of the previewed node. Similar to `edit_node`, but also adds the context - /// switch statement to disable the output context. This way execution of the previewed node - /// will not produce unwanted side effects. `execution_environment` is the name of environment - /// output context should be disabled in. - #[profile(Debug)] - pub fn edit_preview_node( - &mut self, - node_id: ast::Id, - new_expression: Ast, - execution_environment: ExecutionEnvironment, - ) -> FallibleResult { - self.update_node(node_id, |mut node| { - node.set_expression(new_expression); - node.set_context_switch(crate::context_switch::ContextSwitchExpression { - switch: ContextSwitch::Disable, - context: crate::context_switch::Context::Output, - environment: execution_environment.to_string().into(), - }); - Some(node) - }) - } - - #[cfg(test)] - pub fn expect_code(&self, expected_code: impl Str) { - let code = self.source.ast.repr(); - assert_eq!(code, expected_code.as_ref()); - } -} - - - -// ============= -// === Tests === -// ============= - -#[cfg(test)] -mod tests { - use super::*; - - use crate::definition::DefinitionName; - use crate::definition::DefinitionProvider; - use crate::module::get_definition; - - use ast::macros::DocumentationCommentInfo; - use ast::test_utils::expect_single_line; - use ast::HasRepr; - - /// Takes a program with main definition in root and returns main's graph. - fn main_graph(parser: &parser::Parser, program: impl Str) -> GraphInfo { - let module = parser.parse_module(program.as_ref(), default()).unwrap(); - let name = DefinitionName::new_plain("main"); - let main = module.def_iter().find_by_name(&name).unwrap(); - GraphInfo::from_definition(main.item) - } - - fn find_graph(parser: &parser::Parser, program: impl Str, name: impl Str) -> GraphInfo { - let module = parser.parse_module(program.as_ref(), default()).unwrap(); - let crumbs = name.into().split('.').map(DefinitionName::new_plain).collect(); - let id = Id { crumbs }; - let definition = get_definition(&module, &id).unwrap(); - GraphInfo::from_definition(definition) - } - - #[test] - fn detect_a_node() { - let parser = parser::Parser::new(); - // Each of these programs should have a `main` definition with a single `2+2` node. - let programs = vec![ - "main = 2+2", - "main = \n 2+2", - "main = \n foo = 2+2", - "main = \n foo = 2+2\n bar b = 2+2", // `bar` is a definition, not a node - ]; - for program in programs { - let graph = main_graph(&parser, program); - let nodes = graph.nodes(); - assert_eq!(nodes.len(), 1); - let node = &nodes[0]; - assert_eq!(node.expression().repr(), "2+2"); - let _ = node.id(); // just to make sure it is available - } - } - - fn new_expression_node(parser: &parser::Parser, expression: &str) -> NodeInfo { - let node_ast = parser.parse(expression, default()); - let line_ast = expect_single_line(&node_ast).clone(); - NodeInfo::from_main_line_ast(&line_ast).unwrap() - } - - fn assert_all(nodes: &[NodeInfo], expected: &[NodeInfo]) { - assert_eq!(nodes.len(), expected.len()); - for (left, right) in nodes.iter().zip(expected) { - assert_same(left, right) - } - } - - fn assert_same(left: &NodeInfo, right: &NodeInfo) { - assert_eq!(left.id(), right.id()); - assert_eq!( - left.documentation.as_ref().map(DocumentationCommentInfo::pretty_text), - right.documentation.as_ref().map(DocumentationCommentInfo::pretty_text) - ); - assert_eq!(left.main_line.repr(), right.main_line.repr()); - } - - #[test] - fn add_node_to_graph_with_single_line() { - let program = "main = print \"hello\""; - let parser = parser::Parser::new(); - let mut graph = main_graph(&parser, program); - let nodes = graph.nodes(); - assert_eq!(nodes.len(), 1); - let initial_node = nodes[0].clone(); - assert_eq!(initial_node.expression().repr(), "print \"hello\""); - - let expr0 = "a + 2"; - let expr1 = "b + 3"; - let node_to_add0 = new_expression_node(&parser, expr0); - let node_to_add1 = new_expression_node(&parser, expr1); - - graph.add_node(&node_to_add0, LocationHint::Start).unwrap(); - assert_eq!(graph.nodes().len(), 2); - graph.add_node(&node_to_add1, LocationHint::Before(graph.nodes()[0].id())).unwrap(); - - let nodes = graph.nodes(); - assert_all(nodes.as_slice(), &[node_to_add1, node_to_add0, initial_node]); - } - - #[test] - fn add_node_to_graph_with_multiple_lines() { - // TODO [dg] Also add test for binding node when it's possible to update its id. - let program = r#"main = - foo = node - foo a = not_node - print "hello""#; - let parser = parser::Parser::new(); - let mut graph = main_graph(&parser, program); - - let node_to_add0 = new_expression_node(&parser, "4 + 4"); - let node_to_add1 = new_expression_node(&parser, "a + b"); - let node_to_add2 = new_expression_node(&parser, "x * x"); - let node_to_add3 = new_expression_node(&parser, "x / x"); - let node_to_add4 = new_expression_node(&parser, "2 - 2"); - - graph.add_node(&node_to_add0, LocationHint::Start).unwrap(); - graph.add_node(&node_to_add1, LocationHint::Before(graph.nodes()[0].id())).unwrap(); - graph.add_node(&node_to_add2, LocationHint::After(graph.nodes()[1].id())).unwrap(); - graph.add_node(&node_to_add3, LocationHint::End).unwrap(); - // Node 4 will be added later. - - let nodes = graph.nodes(); - assert_eq!(nodes.len(), 6); - assert_eq!(nodes[0].expression().repr(), "a + b"); - assert_eq!(nodes[0].id(), node_to_add1.id()); - // Sic: `node_to_add1` was added at index `0`. - assert_eq!(nodes[1].expression().repr(), "4 + 4"); - assert_eq!(nodes[1].id(), node_to_add0.id()); - assert_eq!(nodes[2].expression().repr(), "x * x"); - assert_eq!(nodes[2].id(), node_to_add2.id()); - assert_eq!(nodes[3].expression().repr(), "node"); - assert_eq!(nodes[4].expression().repr(), "print \"hello\""); - assert_eq!(nodes[5].expression().repr(), "x / x"); - assert_eq!(nodes[5].id(), node_to_add3.id()); - - let expected_code = r#"main = - a + b - 4 + 4 - x * x - foo = node - foo a = not_node - print "hello" - x / x"#; - graph.expect_code(expected_code); - - let mut graph = find_graph(&parser, program, "main.foo"); - assert_eq!(graph.nodes().len(), 1); - graph.add_node(&node_to_add4, LocationHint::Start).unwrap(); - assert_eq!(graph.nodes().len(), 2); - assert_eq!(graph.nodes()[0].expression().repr(), "2 - 2"); - assert_eq!(graph.nodes()[0].id(), node_to_add4.id()); - assert_eq!(graph.nodes()[1].expression().repr(), "not_node"); - } - - #[test] - fn add_node_to_graph_with_blank_line() { - // The trailing `foo` definition is necessary for the blank line after "node2" to be - // included in the `main` block. Otherwise, the block would end on "node2" and the blank - // line would be parented to the module. - - let program = r"main = - - node2 - -foo = 5"; - let parser = parser::Parser::new(); - let mut graph = main_graph(&parser, program); - - let id2 = graph.nodes()[0].id(); - let node_to_add0 = new_expression_node(&parser, "node0"); - let node_to_add1 = new_expression_node(&parser, "node1"); - let node_to_add3 = new_expression_node(&parser, "node3"); - let node_to_add4 = new_expression_node(&parser, "node4"); - - graph.add_node(&node_to_add0, LocationHint::Start).unwrap(); - graph.add_node(&node_to_add1, LocationHint::Before(id2)).unwrap(); - graph.add_node(&node_to_add3, LocationHint::After(id2)).unwrap(); - graph.add_node(&node_to_add4, LocationHint::End).unwrap(); - - let expected_code = r"main = - node0 - - node1 - node2 - node3 - node4"; - // `foo` is not part of expected code, as it belongs to module, not `main` graph. - graph.expect_code(expected_code); - } - - #[test] - fn multiple_node_graph() { - let parser = parser::Parser::new(); - let program = r" -main = - ## Faux docstring - ## Docstring 0 - foo = node0 - ## Docstring 1 - # disabled node1 - foo a = not_node - ## Docstring 2 - node2 - node3 -"; - // TODO [mwu] - // Add case like `Int.+ a = not_node` once https://github.com/enso-org/enso/issues/565 is fixed - - let graph = main_graph(&parser, program); - let nodes = graph.nodes(); - assert_eq!(nodes[0].documentation_text(), Some(" Docstring 0".into())); - assert_eq!(nodes[0].ast().repr(), "foo = node0"); - assert_eq!(nodes[1].documentation_text(), Some(" Docstring 1".into())); - assert_eq!(nodes[1].ast().repr(), "# disabled node1"); - assert_eq!(nodes[2].documentation_text(), Some(" Docstring 2".into())); - assert_eq!(nodes[2].ast().repr(), "node2"); - assert_eq!(nodes[3].documentation_text(), None); - assert_eq!(nodes[3].ast().repr(), "node3"); - assert_eq!(nodes.len(), 4); - } - - #[test] - fn removing_node_from_graph() { - let parser = parser::Parser::new(); - let program = r" -main = - foo = 2 + 2 - bar = 3 + 17"; - let mut graph = main_graph(&parser, program); - let nodes = graph.nodes(); - assert_eq!(nodes.len(), 2); - assert_eq!(nodes[0].expression().repr(), "2 + 2"); - assert_eq!(nodes[1].expression().repr(), "3 + 17"); - - graph.remove_node(nodes[0].id()).unwrap(); - - let nodes = graph.nodes(); - assert_eq!(nodes.len(), 1); - assert_eq!(nodes[0].expression().repr(), "3 + 17"); - - let expected_code = "main =\n bar = 3 + 17"; - graph.expect_code(expected_code); - - assert!(graph.remove_node(uuid::Uuid::new_v4()).is_err()); - graph.expect_code(expected_code); - } - - #[test] - fn removing_last_node_from_graph() { - let parser = parser::Parser::new(); - let program = r" -main = - foo = 2 + 2"; - let mut graph = main_graph(&parser, program); - debug!("aa"); - let (node,) = graph.nodes().expect_tuple(); - assert_eq!(node.expression().repr(), "2 + 2"); - debug!("vv"); - graph.remove_node(node.id()).unwrap(); - debug!("zz"); - - assert!(graph.nodes().is_empty()); - graph.expect_code("main = Nothing"); - } - - #[test] - fn add_first_node_to_empty_graph() { - let parser = parser::Parser::new(); - let program = r"main = Nothing"; - let mut graph = main_graph(&parser, program); - assert!(graph.nodes().is_empty()); - let node_to_add = new_expression_node(&parser, "node0"); - graph.add_node(&node_to_add, LocationHint::Start).unwrap(); - assert_eq!(graph.nodes().len(), 1); - assert_eq!(graph.nodes()[0].expression().repr(), "node0"); - } - - #[test] - fn editing_nodes_expression_in_graph() { - let parser = parser::Parser::new(); - let program = r" -main = - foo = 2 + 2 - bar = 3 + 17"; - let new_expression = parser.parse("print \"HELLO\"", default()); - let new_expression = expect_single_line(&new_expression).clone(); - - let mut graph = main_graph(&parser, program); - let nodes = graph.nodes(); - assert_eq!(nodes.len(), 2); - assert_eq!(nodes[0].expression().repr(), "2 + 2"); - assert_eq!(nodes[1].expression().repr(), "3 + 17"); - - graph.edit_node(nodes[0].id(), new_expression).unwrap(); - - let nodes = graph.nodes(); - assert_eq!(nodes.len(), 2); - assert_eq!(nodes[0].expression().repr(), "print \"HELLO\""); - assert_eq!(nodes[1].expression().repr(), "3 + 17"); - - let expected_code = r#"main = - foo = print "HELLO" - bar = 3 + 17"#; - graph.expect_code(expected_code); - - assert!(graph.edit_node(uuid::Uuid::new_v4(), Ast::var("foo")).is_err()); - graph.expect_code(expected_code); - } -} diff --git a/app/gui/controller/double-representation/src/identifier.rs b/app/gui/controller/double-representation/src/identifier.rs deleted file mode 100644 index 6b7c73e9d3..0000000000 --- a/app/gui/controller/double-representation/src/identifier.rs +++ /dev/null @@ -1,209 +0,0 @@ -//! Module for types and utilities related to dealing with identifiers. - -use crate::prelude::*; - -use std::cmp::Ordering; - - - -// ================== -// === Identifier === -// ================== - -// === Errors === - -#[allow(missing_docs)] -#[derive(Clone, Debug, Fail)] -#[fail(display = "Identifier contains operator `{}`, so it cannot be made into var.", _0)] -pub struct OperatorCantBeMadeIntoVar(String); - -#[allow(missing_docs)] -#[derive(Clone, Debug, Fail)] -#[fail(display = "The `{}` is not a valid identifier.", _0)] -pub struct NotAnIdentifier(String); - -#[allow(missing_docs)] -#[derive(Clone, Copy, Debug, Fail)] -#[fail(display = "Empty string is not a valid identifier.")] -pub struct IdentifierCannotBeEmpty; - - -// === Definition === - -/// Wrapper over an Ast that holds an atomic identifier of any kind. -/// -/// Comparisons compare the underlying name strings. -/// -/// Invariants: can get identifier name, the name is non-empty. -#[derive(Clone, Debug, Deref)] -pub struct Identifier(Ast); - -impl Identifier { - /// Wrap the `Ast` into `Identifier` if it actually is an identifier. - pub fn new(ast: Ast) -> Option { - let name = ast::identifier::name(&ast)?; - (!name.is_empty()).as_some(Identifier(ast)) - } - - /// Convert given text into an identifier Ast and wrap. - /// - /// Can fail if a given string is not a valid identifier, however the exact scope of validation - /// is currently unspecified. - pub fn from_text(text: impl Into) -> FallibleResult { - // TODO? [mwu] - // We should be able to call parser or sth to verify that other requirements for the - // referent form identifiers are fulfilled. - // This is expected to become properly possible when the Rust rewrite of parser is done. - // See: https://github.com/enso-org/enso/issues/435 - // On the other hand it is not clear how strict we want to be here, so as not to break - // processing invalid syntactically code. - - let text = text.into(); - let empty_string_error = failure::Error::from(IdentifierCannotBeEmpty); - let first_char = text.chars().next().ok_or(empty_string_error)?; - match first_char { - c if c.is_lowercase() => Ok(Ast::var(text)), - c if c.is_uppercase() => Ok(Ast::cons(text)), - c if ast::opr::SYMBOLS.contains(&c) => Ok(Ast::opr(text)), - _ => Err(NotAnIdentifier(text).into()), - } - .map(Identifier) - } - - /// Get the identifier name. - pub fn name(&self) -> &str { - // Unwrap here is safe, as identifiers always allow obtaining an Identifier. - ast::identifier::name(&self.0).unwrap() - } - - /// Convert identifier to the variable form (i.e. non-referent). Fails if this is an operator. - pub fn as_var(&self) -> Result { - let name = self.name(); - // Unwrap below is safe, as identifier is always non-empty. - let first_char = name.chars().next().unwrap(); - if first_char.is_alphabetic() { - let name = name.to_lowercase(); - Ok(ast::Var { name }) - } else { - Err(OperatorCantBeMadeIntoVar(name.to_owned())) - } - } - - /// Get the identifier's node with a newly assigned, unique id. - /// - /// This is needed if the identifier from AST is to be reused in a different part of the tree. - /// Cloning it without generating a new ID would introduce two nodes with same id. - pub fn with_new_id(&self) -> Self { - Self(self.0.with_new_id()) - } -} - - -// === Implementations === - -impl PartialOrd for Identifier { - fn partial_cmp(&self, other: &Self) -> Option { - self.name().partial_cmp(other.name()) - } -} - -impl Ord for Identifier { - fn cmp(&self, other: &Self) -> Ordering { - self.name().cmp(other.name()) - } -} - -impl TryFrom for Identifier { - type Error = failure::Error; - fn try_from(value: String) -> Result { - Identifier::from_text(value) - } -} -impl From for String { - fn from(value: Identifier) -> Self { - value.name().into() - } -} - -impl TryFrom<&str> for Identifier { - type Error = failure::Error; - fn try_from(value: &str) -> Result { - Identifier::from_text(value) - } -} - -impl From for Identifier { - fn from(value: ast::known::Var) -> Self { - Identifier(value.into()) - } -} - -impl From for Identifier { - fn from(value: ast::known::Cons) -> Self { - Identifier(value.into()) - } -} - -impl From for Identifier { - fn from(value: ast::known::Opr) -> Self { - Identifier(value.into()) - } -} - -impl From for Ast { - fn from(value: Identifier) -> Self { - value.0 - } -} - -impl From<&Identifier> for Ast { - fn from(value: &Identifier) -> Self { - value.0.clone() - } -} - -impl Display for Identifier { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Display::fmt(&self.name(), f) - } -} - -impl PartialEq for Identifier { - fn eq(&self, other: &Self) -> bool { - self.name().eq(other.name()) - } -} - -impl Eq for Identifier {} - -impl Hash for Identifier { - fn hash(&self, state: &mut H) { - self.name().hash(state) - } -} - - - -// ================= -// === Utilities === -// ================= - -/// Generate an identifier name that is not present in the given sequence. -/// -/// The name is generated by taking `base` string and appending subsequent integers. -pub fn generate_name<'a>( - base: &str, - unavailable_names: impl IntoIterator, -) -> FallibleResult { - let unavailable_suffixes = unavailable_names - .into_iter() - .filter_map(|name| name.strip_prefix(base).and_then(|suffix| suffix.parse::().ok())) - .collect::>(); - let name = (1..) - .find_map(|i| { - let available = !unavailable_suffixes.contains(&i); - available.then(|| format!("{base}{i}")) - }) - .unwrap(); // It never yields `None`, as we iterate infinite sequence until we find match. - Identifier::from_text(name) -} diff --git a/app/gui/controller/double-representation/src/import.rs b/app/gui/controller/double-representation/src/import.rs deleted file mode 100644 index 2ac18b7d82..0000000000 --- a/app/gui/controller/double-representation/src/import.rs +++ /dev/null @@ -1,240 +0,0 @@ -//! A module with utilities managing imports. - -use crate::prelude::*; - -use crate::name::NamePath; -use crate::name::QualifiedName; - -use ast::Ast; -use std::collections::BTreeSet; - - - -// ================= -// === Constants === -// ================= - -const ALIAS_KEYWORD: &str = "as"; -const ALL_KEYWORD: &str = "all"; -const HIDING_KEYWORD: &str = "hiding"; - - - -// =============== -// === Aliases === -// =============== - -/// Id for an import. -pub type Id = u64; - - - -// ===================== -// === ImportedNames === -// ===================== - -/// A structure describing what names are imported from the module in a specific import declaration. -#[allow(missing_docs)] -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub enum ImportedNames { - /// The import is `import [as ]` and only module name is imported. - Module { alias: Option }, - /// The import is `from import all`, and all names defined in the module are imported. - All, - /// The import is `from import all hiding `, and all names except - /// specified in `not_imported` list are imported - AllExcept { not_imported: BTreeSet }, - /// The import is `from import `, and only the specified `names` are imported. - List { names: BTreeSet }, -} - -/// Representation of a single import declaration. -#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)] -pub struct Info { - /// The path of the qualified name of the imported module. - pub module: NamePath, - /// Imported names from [`module`]. - pub imported: ImportedNames, -} - -impl Info { - /// Create qualified import (i.e. `import `) importing the given module without - /// alias. - pub fn new_qualified(module: impl Into) -> Self { - Self { module: module.into(), imported: ImportedNames::Module { alias: None } } - } - - /// Create a unqualified import importing one name from given module (i. e. `from - /// import `). - pub fn new_single_name(module: impl Into, name: impl Into) -> Self { - Self { - module: module.into(), - imported: ImportedNames::List { names: [name.into()].into() }, - } - } - - /// Return the module path as [`QualifiedName`]. Returns [`Err`] if the path is not a valid - /// module name. - pub fn qualified_module_name(&self) -> FallibleResult { - QualifiedName::from_all_segments(&self.module) - } - - /// Construct from an AST, if the Ast is an import declaration. - pub fn from_ast(ast: &Ast) -> Option { - if let ast::Shape::Tree(ast::Tree { - type_info: ast::TreeType::Import { module, imported }, - .. - }) = ast.shape() - { - let module = module.clone(); - let imported = match imported.clone() { - ast::ImportedNames::All { except } if except.is_empty() => ImportedNames::All, - ast::ImportedNames::All { except } => - ImportedNames::AllExcept { not_imported: except }, - ast::ImportedNames::List { names } => ImportedNames::List { names }, - ast::ImportedNames::Module { alias } => ImportedNames::Module { alias }, - }; - Some(Info { module, imported }) - } else { - None - } - } - - /// Return the ID of the import. - /// - /// The ID is based on a hash of the qualified name of the imported target. This ID is GUI - /// internal and not known in the engine. - pub fn id(&self) -> Id { - let mut hasher = DefaultHasher::new(); - self.hash(&mut hasher); - hasher.finish() - } -} - -impl Display for Info { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let module = self.module.iter().map(ImString::as_str).join(ast::opr::predefined::ACCESS); - let import_kw = ast::macros::QUALIFIED_IMPORT_KEYWORD; - let from_kw = ast::macros::UNQUALIFIED_IMPORT_KEYWORD; - match &self.imported { - ImportedNames::Module { alias } => { - write!(f, "{import_kw} {module}")?; - if let Some(alias) = alias { - write!(f, " {ALIAS_KEYWORD} {alias}")?; - } - Ok(()) - } - ImportedNames::All => write!(f, "{from_kw} {module} {import_kw} {ALL_KEYWORD}"), - ImportedNames::List { names } => { - let names = names.iter().join(", "); - write!(f, "{from_kw} {module} {import_kw} {names}") - } - ImportedNames::AllExcept { not_imported: hidden_names } => { - let names = hidden_names.iter().join(", "); - write!(f, "{from_kw} {module} {import_kw} {ALL_KEYWORD} {HIDING_KEYWORD} {names}") - } - } - } -} - - - -// ============= -// === Tests === -// ============= - -#[cfg(test)] -mod tests { - use super::*; - use parser::Parser; - - struct Fixture { - parser: Parser, - } - - impl Fixture { - fn new() -> Self { - Self { parser: Parser::new() } - } - - fn run_case(&self, code: &str, expected: Info) { - let ast = self.parser.parse_line_ast(code).expect("Parsing import declaration failed"); - let info = Info::from_ast(&ast); - assert_eq!(info, Some(expected)); - } - } - - #[test] - fn qualified_import_info_from_ast() { - let test = Fixture::new(); - let make_info = |module: &[&str]| Info { - module: module.iter().map(|&s| ImString::new(s)).collect(), - imported: ImportedNames::Module { alias: None }, - }; - - let normal_case = "import Standard.Base.Data"; - let normal_case_expected = make_info(&["Standard", "Base", "Data"]); - test.run_case(normal_case, normal_case_expected); - - let single_segment = "import local"; - let single_segment_expected = make_info(&["local"]); - test.run_case(single_segment, single_segment_expected); - } - - #[test] - fn unrestricted_import_info_from_ast() { - let test = Fixture::new(); - let make_info = |module: &[&str]| Info { - module: module.iter().map(|&s| ImString::new(s)).collect(), - imported: ImportedNames::All, - }; - - let normal_case = "from Standard.Base import all"; - let normal_case_expected = make_info(&["Standard", "Base"]); - test.run_case(normal_case, normal_case_expected); - } - - #[test] - fn restricted_import_info_from_ast() { - let test = Fixture::new(); - let make_info = |module: &[&str], names: &[&str]| Info { - module: module.iter().map(|&s| ImString::new(s)).collect(), - imported: ImportedNames::List { names: names.iter().map(|&s| s.to_owned()).collect() }, - }; - - let normal_case = "from Standard.Base import Foo, Bar"; - let normal_case_expected = make_info(&["Standard", "Base"], &["Foo", "Bar"]); - test.run_case(normal_case, normal_case_expected); - - let weird_spaces = "from Standard . Base import Foo , Bar ,Buz"; - let weird_spaces_expected = make_info(&["Standard", "Base"], &["Foo", "Bar", "Buz"]); - test.run_case(weird_spaces, weird_spaces_expected); - - let single_name = "from Standard.Base import Foo"; - let single_name_expected = make_info(&["Standard", "Base"], &["Foo"]); - test.run_case(single_name, single_name_expected); - } - - #[test] - fn hiding_import_info_from_ast() { - let test = Fixture::new(); - let make_info = |module: &[&str], hidden_names: &[&str]| Info { - module: module.iter().map(|&s| ImString::new(s)).collect(), - imported: ImportedNames::AllExcept { - not_imported: hidden_names.iter().map(|&s| s.to_owned()).collect(), - }, - }; - - let normal_case = "from Standard.Base import all hiding Foo, Bar"; - let normal_case_expected = make_info(&["Standard", "Base"], &["Foo", "Bar"]); - test.run_case(normal_case, normal_case_expected); - - let weird_spaces = "from Standard . Base import all hiding Foo , Bar ,Buz"; - let weird_spaces_expected = make_info(&["Standard", "Base"], &["Foo", "Bar", "Buz"]); - test.run_case(weird_spaces, weird_spaces_expected); - - let single_name = "from Standard.Base import all hiding Foo"; - let single_name_expected = make_info(&["Standard", "Base"], &["Foo"]); - test.run_case(single_name, single_name_expected); - } -} diff --git a/app/gui/controller/double-representation/src/lib.rs b/app/gui/controller/double-representation/src/lib.rs deleted file mode 100644 index e4a36f379e..0000000000 --- a/app/gui/controller/double-representation/src/lib.rs +++ /dev/null @@ -1,276 +0,0 @@ -//! A crate with all functions used to synchronize different representations of our language - -// === Features === -#![feature(associated_type_bounds)] -#![feature(drain_filter)] -#![feature(iter_order_by)] -#![feature(option_result_contains)] -#![feature(type_alias_impl_trait)] -#![feature(iter_next_chunk)] -// === Standard Linter Configuration === -#![deny(non_ascii_idents)] -#![warn(unsafe_code)] -#![allow(clippy::bool_to_int_with_if)] -#![allow(clippy::let_and_return)] -// === Non-Standard Linter Configuration === -#![warn(missing_docs)] -#![warn(trivial_casts)] -#![warn(trivial_numeric_casts)] -#![warn(unused_import_braces)] -#![warn(unused_qualifications)] -#![warn(missing_copy_implementations)] -#![warn(missing_debug_implementations)] - -use crate::prelude::*; - -use crate::definition::DefinitionName; -use crate::definition::ScopeKind; - -use ast::crumbs::InfixCrumb; -use ast::crumbs::Located; -use ast::known; -use ast::macros::DocumentationCommentAst; -use ast::opr; -use ast::prefix; -use ast::Ast; - - -// ============== -// === Export === -// ============== - -pub mod alias_analysis; -pub mod connection; -pub mod context_switch; -pub mod definition; -pub mod graph; -pub mod identifier; -pub mod import; -pub mod module; -pub mod name; -pub mod node; -pub mod refactorings; -#[cfg(test)] -pub mod test_utils; -pub mod text; - - - -// =============== -// === Prelude === -// =============== - -/// Common types that should be visible across the whole IDE crate. -pub mod prelude { - pub use ast::prelude::*; - pub use enso_prelude::*; - pub use enso_profiler as profiler; - pub use enso_profiler::prelude::*; -} - - - -// ============== -// === Consts === -// ============== - -/// Indentation value from language specification: -/// -/// Indentation: Indentation is four spaces, and all tabs are converted to 4 spaces. This is not -/// configurable on purpose. -/// -/// Link: https://github.com/enso-org/enso/blob/develop/doc/syntax/encoding.md -pub const INDENT: usize = 4; - - - -// ======================== -// === Discerning Lines === -// ======================== - -/// What kind of node or definition a line should be treated as. -#[derive(Clone, Debug)] -pub enum LineKind { - /// Definition is a binding, which defines a new entity with arguments. - Definition { - /// The binding that introduces the definition. - ast: known::Infix, - /// Name of this definition. Includes typename, if this is an extension method. - name: Located, - /// Arguments for this definition. Does not include any implicit ones (e.g. no `self`). - args: Vec>, - }, - /// Node in a binding form. - ExpressionAssignment { - /// Ast of the whole binding. - ast: known::Infix, - }, - /// Node consisting of a plain expression, with no pattern binding. - ExpressionPlain { - /// Ast of the whole expression. - ast: Ast, - }, - /// Documentation comment lines are not nodes. - /// Instead, they are discovered and processed as part of nodes that follow them. - DocumentationComment { - /// The comment representation. - documentation: DocumentationCommentAst, - }, -} - -impl LineKind { - /// Tell how the given line (described by an Ast) should be treated. - // TODO [mwu] This method deserves unit tests of its own. - pub fn discern(ast: &Ast, kind: ScopeKind) -> Self { - use LineKind::*; - - // First of all, if non-empty line is not an infix (i.e. binding) it can be only a node or - // a documentation comment. - let ast = match opr::to_assignment(ast) { - Some(infix) => infix, - None => - return if let Some(documentation) = DocumentationCommentAst::new(ast) { - // e.g. `## My comment.` - DocumentationComment { documentation } - } else { - // The simplest form of node, e.g. `Point 5 10` - ExpressionPlain { ast: ast.clone_ref() } - }, - }; - - // Assignment can be either nodes or definitions. To discern, we check the left hand side. - // For definition it is a prefix chain, where first is the name, then arguments (if - // explicit). For node it is a pattern, either in a form of Var without args on Cons - // application. - let crumb = InfixCrumb::LeftOperand; - let lhs = Located::new(crumb, prefix::Chain::from_ast_non_strict(&ast.larg)); - let name = lhs - .entered(|chain| { - let name_ast = chain.located_func(); - name_ast.map(DefinitionName::from_ast) - }) - .into_opt(); - - // If this is a pattern match, `name` will fail to construct and we'll treat line as a node. - // e.g. for `Point x y = get_point …` - let name = match name { - Some(name) => name, - None => return ExpressionAssignment { ast }, - }; - - let args = lhs - .enumerate_args() - .map(|Located { crumbs, item }| { - // We already in the left side of assignment, so we need to prepend this crumb. - let crumbs = lhs.crumbs.clone().into_iter().chain(crumbs); - let ast = item.clone(); - Located::new(crumbs, ast) - }) - .collect_vec(); - - // Note [Scope Differences] - if kind == ScopeKind::NonRoot { - // 1. Not an extension method but an old setter syntax. Currently not supported in the - // language, treated as node with invalid pattern. - // e.g. `point.x = 5` - let is_setter = !name.extended_target.is_empty(); - // 2. No explicit args -- this is a proper node, not a definition. - // e.g. `point = Point 5 10` - let is_node = args.is_empty(); - if is_setter || is_node { - return ExpressionAssignment { ast }; - } - }; - - Definition { ast, name, args } - } -} - -// Note [Scope Differences] -// ======================== -// When we are in definition scope (as opposed to global scope) certain patterns should not be -// considered to be function definitions. These are: -// 1. Expressions like "Int.x = …". In module, they'd be treated as extension methods. In -// definition scope they are treated as invalid constructs (setter syntax in the old design). -// 2. Expression like "foo = 5". In module, this is treated as method definition (with implicit -// this parameter). In definition, this is just a node (evaluated expression). - -#[cfg(test)] -mod tests { - use super::*; - - use crate::definition::DefinitionProvider; - - use ast::macros::DocumentationCommentInfo; - use parser::Parser; - - - /// Expect `main` method, where first line is a documentation comment. - /// The text of this comment should match the expected one. - fn run_case(parser: &Parser, code: &str, expected_comment_text: &str) { - let ast = parser.parse_module(code, default()).unwrap(); - let main_id = definition::Id::new_plain_name("main"); - let main = module::get_definition(&ast, &main_id).unwrap(); - let lines = main.block_lines(); - let first_line = lines[0].transpose_ref().unwrap(); - let doc = DocumentationCommentInfo::new(&first_line, main.indent()).unwrap(); - let text = doc.pretty_text(); - assert_eq!(text, expected_comment_text); - - // Now, if we convert our pretty text to code, will it be the same as original line? - let code = DocumentationCommentInfo::text_to_repr(main.indent(), &text); - let ast2 = parser.parse_line(&code).unwrap(); - let doc2 = DocumentationCommentInfo::new(&ast2.as_ref(), main.indent()) - .unwrap_or_else(|| panic!("Failed to parse `{code}` as comment")); - assert_eq!(doc.line().repr(), doc2.line().repr()) - } - - #[test] - fn parse_single_line_comment() { - let parser = parser::Parser::new(); - - // Typical single line case. - let code = r#" -main = - ## Single line - node"#; - let expected = " Single line"; - run_case(&parser, code, expected); - - // Single line case without space after `##`. - let code = r#" -main = - ##Single line - node"#; - let expected = "Single line"; - run_case(&parser, code, expected); - - // Single line case with a single trailing space after `##`. - let code = r#" -main = - ## - node"#; - let expected = " "; - run_case(&parser, code, expected); - - // Single line case without content. - let code = r#" -main = - ## - node"#; - let expected = ""; - run_case(&parser, code, expected); - } - - #[test] - fn parse_multi_line_comment() { - let parser = parser::Parser::new(); - let code = r#" -main = - ## First line - Second line - node"#; - let expected = " First line\nSecond line"; - run_case(&parser, code, expected); - } -} diff --git a/app/gui/controller/double-representation/src/module.rs b/app/gui/controller/double-representation/src/module.rs deleted file mode 100644 index 7cd2285b1f..0000000000 --- a/app/gui/controller/double-representation/src/module.rs +++ /dev/null @@ -1,719 +0,0 @@ -//! Code for module-level double representation processing. - -use crate::prelude::*; -use enso_text::index::*; - -use crate::alias_analysis; -use crate::definition; -use crate::definition::DefinitionProvider; -use crate::definition::EmptyDefinitionId; -use crate::identifier; -use crate::identifier::Identifier; -use crate::import; -use crate::name::NamePath; -use crate::name::QualifiedName; - -use ast::crumbs::ChildAst; -use ast::crumbs::Located; -use ast::crumbs::ModuleCrumb; -use ast::known; -use ast::BlockLine; -use engine_protocol::language_server; -use std::fmt::Formatter; - - - -// ============== -// === Errors === -// ============== - -#[derive(Copy, Clone, Debug, Fail)] -#[fail(display = "Id segment list is empty.")] -#[allow(missing_docs)] -pub struct EmptySegments; - -#[derive(Clone, Debug, Fail)] -#[fail(display = "Import `{}` was not found in the module.", _0)] -#[allow(missing_docs)] -pub struct ImportNotFound(pub String); - -#[derive(Clone, Copy, Debug, Fail)] -#[fail(display = "Import with ID `{}` was not found in the module.", _0)] -#[allow(missing_docs)] -pub struct ImportIdNotFound(pub import::Id); - -#[derive(Clone, Copy, Debug, Fail)] -#[fail(display = "Line index is out of bounds.")] -#[allow(missing_docs)] -pub struct LineIndexOutOfBounds; - -#[allow(missing_docs)] -#[derive(Fail, Clone, Debug)] -#[fail(display = "Cannot find method with pointer {:?}.", _0)] -pub struct CannotFindMethod(language_server::MethodPointer); - -#[allow(missing_docs)] -#[derive(Fail, Clone, Debug)] -#[fail(display = "The definition with crumbs {:?} is not a direct child of the module.", _0)] -pub struct NotDirectChild(ast::Crumbs); - - - -// ========== -// === Id === -// ========== - -/// The segments of module name. Allow finding module in the project. -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Id { - /// The last segment being a module name. For project's main module it should be equal - /// to [`PROJECTS_MAIN_MODULE`]. - pub name: ImString, - /// The segments of all parent modules, from the top module to the direct parent. Does **not** - /// include project name. - pub parent_modules: Vec, -} - -impl Id { - /// Create module id from list of segments. The list shall not contain the project name nor - /// namespace. Fails if the list is empty (the module name is required). - pub fn try_from_segments( - segments: impl IntoIterator>, - ) -> FallibleResult { - let mut segments = segments.into_iter().map(Into::into).collect_vec(); - let name = segments.pop().ok_or(EmptySegments)?; - Ok(Self { name, parent_modules: segments }) - } - - /// Return the iterator over id's segments. - pub fn segments(&self) -> impl Iterator { - self.parent_modules.iter().chain(iter::once(&self.name)) - } -} - -impl IntoIterator for Id { - type Item = ImString; - type IntoIter = impl Iterator; - - fn into_iter(self) -> Self::IntoIter { - self.parent_modules.into_iter().chain(iter::once(self.name)) - } -} - -impl From for NamePath { - fn from(id: Id) -> Self { - id.into_iter().collect() - } -} - -impl Display for Id { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.segments().format(".")) - } -} - - -// ============ -// === Info === -// ============ - -/// Wrapper allowing getting information about the module and updating it. -#[derive(Clone, Debug)] -pub struct Info { - #[allow(missing_docs)] - pub ast: known::Module, -} - -impl Info { - /// Generate a name for a definition that can be introduced without side-effects. - /// - /// The name shall be generated by appending number to the given base string. - pub fn generate_name(&self, base: &str) -> FallibleResult { - let used_names = self.used_names(); - let used_names = used_names.iter().map(|name| name.item.as_str()); - identifier::generate_name(base, used_names) - } - - /// Identifiers introduced or referred to in the module's scope. - /// - /// Introducing identifier not included on this list should have no side-effects on the name - /// resolution in the code in this graph. - pub fn used_names(&self) -> Vec> { - let usage = alias_analysis::analyze_crumbable(self.ast.shape()); - usage.all_identifiers() - } - - /// Iterate over all lines in module that contain an import declaration. - pub fn enumerate_imports(&self) -> impl Iterator + '_ { - let children = self.ast.shape().enumerate(); - children.filter_map(|(crumb, ast)| Some((crumb, import::Info::from_ast(ast)?))) - } - - /// Iterate over all import declarations in the module. - /// - /// If the caller wants to know *where* the declarations are, use `enumerate_imports`. - pub fn iter_imports(&self) -> impl Iterator + '_ { - self.enumerate_imports().map(|(_, import)| import) - } - - /// Check if module contains import with given id. - pub fn contains_import(&self, id: import::Id) -> bool { - self.iter_imports().any(|import| import.id() == id) - } - - /// Add a new line to the module's block. - /// - /// Note that indices are the "module line" indices, which usually are quite different from text - /// API line indices (because nested blocks doesn't count as separate "module lines"). - pub fn add_line(&mut self, index: usize, ast: Option) { - let line = BlockLine::new(ast); - self.ast.update_shape(|shape| shape.lines.insert(index, line)) - } - - /// Remove line with given index. - /// - /// Returns removed line. Fails if the index is out of bounds. - pub fn remove_line(&mut self, index: usize) -> FallibleResult>> { - self.ast.update_shape(|shape| { - shape.lines.try_remove(index).ok_or_else(|| LineIndexOutOfBounds.into()) - }) - } - - /// Remove a line that matches given import description. - /// - /// If there is more than one line matching, only the first one will be removed. - /// Fails if there is no import matching given argument. - pub fn remove_import(&mut self, to_remove: &import::Info) -> FallibleResult { - let lookup_result = self.enumerate_imports().find(|(_, import)| import == to_remove); - let (crumb, _) = lookup_result.ok_or_else(|| ImportNotFound(to_remove.to_string()))?; - self.remove_line(crumb.line_index)?; - Ok(()) - } - - /// Remove a line that matches given import ID. - /// - /// If there is more than one line matching, only the first one will be removed. - /// Fails if there is no import matching given argument. - pub fn remove_import_by_id(&mut self, to_remove: import::Id) -> FallibleResult { - let lookup_result = self.enumerate_imports().find(|(_, import)| import.id() == to_remove); - let (crumb, _) = lookup_result.ok_or(ImportIdNotFound(to_remove))?; - self.remove_line(crumb.line_index)?; - Ok(()) - } - - /// Add a new import declaration to a module. - /// - /// This function will try to keep imports in lexicographic order. It returns the index where - /// import was added (index of import - an element on the list returned by `enumerate_imports`). - // TODO [mwu] - // Ideally we should not require parser but should use some sane way of generating AST from - // the `ImportInfo` value. - pub fn add_import(&mut self, parser: &parser::Parser, to_add: import::Info) -> usize { - // Find last import that is not "after" the added one lexicographically. - let previous_import = - self.enumerate_imports().take_while(|(_, import)| &to_add > import).last(); - - let index_to_place_at = previous_import.map_or(0, |(crumb, _)| crumb.line_index + 1); - let import_ast = parser.parse_line_ast(to_add.to_string()).unwrap(); - self.add_line(index_to_place_at, Some(import_ast)); - index_to_place_at - } - - /// Add a new import declaration to a module. - /// - /// For more details the mechanics see [`add_import`] documentation. - pub fn add_import_if_missing( - &mut self, - parser: &parser::Parser, - to_add: import::Info, - ) -> Option { - (!self.contains_import(to_add.id())).then(|| self.add_import(parser, to_add)) - } - - /// Place the line with given AST in the module's body. - /// - /// Unlike `add_line` (which is more low-level) will introduce empty lines around introduced - /// line and describes the added line location in relation to other definitions. - /// - /// Typically used to place lines with definitions in the module. - pub fn add_ast(&mut self, ast: Ast, location: Placement) -> FallibleResult { - #[derive(Clone, Copy, Debug, Eq, PartialEq)] - enum BlankLinePlacement { - Before, - After, - None, - } - let blank_line = match location { - _ if self.ast.lines.is_empty() => BlankLinePlacement::None, - Placement::Begin => BlankLinePlacement::After, - Placement::End => BlankLinePlacement::Before, - Placement::After(_) => BlankLinePlacement::Before, - Placement::Before(_) => BlankLinePlacement::After, - }; - - let mut index = match location { - Placement::Begin => 0, - Placement::End => self.ast.lines.len(), - Placement::Before(next_def) => locate_line_with(&self.ast, &next_def)?.line_index, - Placement::After(next_def) => locate_line_with(&self.ast, &next_def)?.line_index + 1, - }; - - let mut add_line = |ast_opt: Option| { - self.add_line(index, ast_opt); - index += 1; - }; - - if blank_line == BlankLinePlacement::Before { - add_line(None); - } - add_line(Some(ast)); - if blank_line == BlankLinePlacement::After { - add_line(None); - } - - Ok(()) - } - - /// Add a new method definition to the module. - pub fn add_method( - &mut self, - method: definition::ToAdd, - location: Placement, - parser: &parser::Parser, - ) -> FallibleResult { - let no_indent = 0; - let definition_ast = method.ast(no_indent, parser)?; - self.add_ast(definition_ast, location) - } - - /// Updates the given definition using the passed invokable. - pub fn update_definition( - &mut self, - id: &definition::Id, - f: impl FnOnce(definition::DefinitionInfo) -> FallibleResult, - ) -> FallibleResult { - let definition = locate(&self.ast, id)?; - let new_definition = f(definition.item)?; - let new_ast = new_definition.ast.into(); - self.ast = self.ast.set_traversing(&definition.crumbs, new_ast)?; - Ok(()) - } - - #[cfg(test)] - pub fn expect_code(&self, expected_code: impl AsRef) { - assert_eq!(self.ast.repr(), expected_code.as_ref()); - } -} - -impl From for Info { - fn from(ast: known::Module) -> Self { - Info { ast } - } -} - - - -// ================= -// === Placement === -// ================= - -/// Structure describing where to place something being added to the module. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum Placement { - /// Place at the beginning of the module. - Begin, - /// Place at the end of the module. - End, - /// Place after given definition; - Before(definition::Crumb), - /// Place before given definition; - After(definition::Crumb), -} - - - -// ======================= -// === ChildDefinition === -// ======================= - -/// Represents information about a definition being a direct child of this module, including its -/// location. -/// -/// Internally it is `definition::ChildDefinition` with only a single `ModuleCrumb` as location. -#[derive(Clone, Debug, Deref)] -pub struct ChildDefinition(definition::ChildDefinition); - -impl ChildDefinition { - fn try_retrieving_crumb(child: &definition::ChildDefinition) -> Option { - match child.crumbs.as_slice() { - [ast::crumbs::Crumb::Module(crumb)] => Some(*crumb), - _ => None, - } - } - - /// Try constructing value from `definition::ChildDefinition`. Fails if it is not a direct child - /// of a module. - pub fn new(child: definition::ChildDefinition) -> Result { - if Self::try_retrieving_crumb(&child).is_some() { - Ok(Self(child)) - } else { - Err(NotDirectChild(child.crumbs)) - } - } - - /// The location of this definition child in the module. - pub fn crumb(&self) -> ModuleCrumb { - // Safe, because our only constructor checks that this works. This is the type's invariant. - Self::try_retrieving_crumb(&self.0).unwrap() - } -} - -impl TryFrom for ChildDefinition { - type Error = NotDirectChild; - fn try_from(value: definition::ChildDefinition) -> Result { - Self::new(value) - } -} - - - -// ======================== -// === Module Utilities === -// ======================== - -/// Looks up graph in the module. -pub fn get_definition( - ast: &known::Module, - id: &definition::Id, -) -> FallibleResult { - Ok(locate(ast, id)?.item) -} - -/// Locate the line with given definition and return crumb that denotes it. -/// -/// Fails if there is no matching definition being a direct child of the module. -pub fn locate_line_with( - ast: &known::Module, - crumb: &definition::Crumb, -) -> FallibleResult { - locate_child(ast, crumb).map(|child| child.crumb()) -} - -/// Locate the definition being the module's direct child. -pub fn locate_child( - ast: &known::Module, - crumb: &definition::Crumb, -) -> FallibleResult { - let child = ast.def_iter().find_by_name(crumb)?; - Ok(ChildDefinition::try_from(child)?) -} - -/// Traverses the module's definition tree following the given Id crumbs, looking up the definition. -pub fn locate( - ast: &known::Module, - id: &definition::Id, -) -> FallibleResult { - let mut crumbs_iter = id.crumbs.iter(); - // Not exactly regular - we need special case for the first crumb as it is not a definition nor - // a children. After this we can go just from one definition to another. - let first_crumb = crumbs_iter.next().ok_or(EmptyDefinitionId)?; - let mut child = ast.def_iter().find_by_name(first_crumb)?; - for crumb in crumbs_iter { - child = definition::resolve_single_name(child, crumb)?; - } - Ok(child) -} - -/// Get a definition ID that points to a method matching given pointer. -/// -/// The module is assumed to be in the file identified by the `method.file` (for the purpose of -/// desugaring implicit extensions methods for modules). -/// -/// The `module_name` parameter is the name of the module that contains `ast`. -pub fn lookup_method( - module_name: &QualifiedName, - ast: &known::Module, - method: &language_server::MethodPointer, -) -> FallibleResult { - let qualified_typename = QualifiedName::from_text(&method.defined_on_type)?; - let defined_in_this_module = module_name == &qualified_typename; - let method_module_name = QualifiedName::from_text(&method.module)?; - let implicit_extension_allowed = method.defined_on_type == method_module_name.to_string(); - for child in ast.def_iter() { - let child_name = &child.name.item; - let name_matches = child_name.name.item == method.name; - let type_matches = match child_name.extended_target.as_slice() { - [] => implicit_extension_allowed || defined_in_this_module, - [typename] => typename.item == qualified_typename.name(), - _ => child_name.explicitly_extends_type(&method.defined_on_type), - }; - if name_matches && type_matches { - return Ok(definition::Id::new_single_crumb(child_name.clone())); - } - } - - Err(CannotFindMethod(method.clone()).into()) -} - -/// Get a span in module's text representation where the given definition is located. -pub fn definition_span( - ast: &known::Module, - id: &definition::Id, -) -> FallibleResult> { - let location = locate(ast, id)?; - ast.range_of_descendant_at(&location.crumbs) -} - -impl DefinitionProvider for known::Module { - fn indent(&self) -> usize { - 0 - } - - fn scope_kind(&self) -> definition::ScopeKind { - definition::ScopeKind::Root - } - - fn enumerate_asts<'a>(&'a self) -> Box> + 'a> { - self.ast().children() - } -} - - - -// ================ -// === MethodId === -// ================ - -/// A structure identifying a method. -/// -/// It is very similar to MethodPointer from language_server API, however it may point to the method -/// outside the currently opened project. -#[derive(Clone, Debug, serde::Deserialize, Eq, Hash, PartialEq, serde::Serialize)] -#[allow(missing_docs)] -pub struct MethodId { - pub module: QualifiedName, - pub defined_on_type: QualifiedName, - pub name: String, -} - - - -// ============ -// === Test === -// ============ - -#[cfg(test)] -mod tests { - use super::*; - - use crate::definition::DefinitionName; - - use engine_protocol::language_server::MethodPointer; - - #[test] - fn import_listing() { - let parser = parser::Parser::new(); - let expect_imports = |code: &str, expected: &[&[&str]]| { - let ast = parser.parse_module(code, default()).unwrap(); - let info = Info { ast }; - let imports = info.iter_imports().collect_vec(); - assert_eq!(imports.len(), expected.len()); - for (import, expected_segments) in imports.iter().zip(expected) { - itertools::assert_equal(import.module.iter(), expected_segments.iter()); - } - }; - - // TODO [mwu] waiting for fix https://github.com/enso-org/enso/issues/1016 - // expect_imports("import", &[&[]]); - expect_imports("import Foo", &[&["Foo"]]); - expect_imports("import Foo.Bar", &[&["Foo", "Bar"]]); - expect_imports("foo = bar\nimport Foo.Bar", &[&["Foo", "Bar"]]); - expect_imports("import Foo.Bar\nfoo=bar\nimport Foo.Bar", &[&["Foo", "Bar"], &[ - "Foo", "Bar", - ]]); - } - - #[test] - fn import_adding_and_removing() { - let parser = parser::Parser::new(); - let code = "import Foo.Bar.Baz"; - let ast = parser.parse_module(code, default()).unwrap(); - let mut info = Info { ast }; - let import = |code| { - let ast = parser.parse_line_ast(code).unwrap(); - import::Info::from_ast(&ast).unwrap() - }; - - info.add_import(&parser, import("import Bar.Gar")); - info.expect_code("import Bar.Gar\nimport Foo.Bar.Baz"); - info.add_import(&parser, import("import Gar.Bar")); - info.expect_code("import Bar.Gar\nimport Foo.Bar.Baz\nimport Gar.Bar"); - - info.remove_import(&import("import Foo.Bar.Baz")).unwrap(); - info.expect_code("import Bar.Gar\nimport Gar.Bar"); - info.remove_import(&import("import Foo.Bar.Baz")).unwrap_err(); - info.expect_code("import Bar.Gar\nimport Gar.Bar"); - info.remove_import(&import("import Gar.Bar")).unwrap(); - info.expect_code("import Bar.Gar"); - info.remove_import(&import("import Bar.Gar")).unwrap(); - info.expect_code(""); - - info.add_import(&parser, import("import Bar.Gar")); - info.expect_code("import Bar.Gar"); - } - - #[test] - fn implicit_method_resolution() { - let parser = parser::Parser::new(); - let module_name = - QualifiedName::from_all_segments(["local", "ProjectName", "Main"]).unwrap(); - let expect_find = |method: &MethodPointer, code, expected: &definition::Id| { - let module = parser.parse_module(code, default()).unwrap(); - let result = lookup_method(&module_name, &module, method); - assert_eq!(result.unwrap().to_string(), expected.to_string()); - - // TODO [mwu] - // We should be able to use `assert_eq!(result.unwrap(),expected);` - // But we can't, because definition::Id uses located fields and crumbs won't match. - // Eventually we'll likely need to split definition names into located and unlocated - // ones. Definition ID should not require any location info. - }; - - let expect_not_found = |method: &MethodPointer, code| { - let module = parser.parse_module(code, default()).unwrap(); - lookup_method(&module_name, &module, method).expect_err("expected method not found"); - }; - - - // === Lookup the Main (local module type) extension method === - - let ptr = MethodPointer { - defined_on_type: "local.ProjectName.Main".into(), - module: "local.ProjectName.Main".into(), - name: "foo".into(), - }; - - // Implicit module extension method. - let id = definition::Id::new_plain_name("foo"); - expect_find(&ptr, "foo a b = a + b", &id); - // Explicit module extension method. - let id = definition::Id::new_single_crumb(DefinitionName::new_method("Main", "foo")); - expect_find(&ptr, "Main.foo a b = a + b", &id); - // Matching name but extending wrong type. - expect_not_found(&ptr, "Number.foo a b = a + b"); - // Mismatched name. - expect_not_found(&ptr, "bar a b = a + b"); - - - // === Lookup the Int (non-local type) extension method === - - let ptr = MethodPointer { - defined_on_type: "std.Base.Main.Number".into(), - module: "local.ProjectName.Main".into(), - name: "foo".into(), - }; - - expect_not_found(&ptr, "foo a b = a + b"); - let id = definition::Id::new_single_crumb(DefinitionName::new_method("Number", "foo")); - expect_find(&ptr, "Number.foo a b = a + b", &id); - expect_not_found(&ptr, "Text.foo a b = a + b"); - expect_not_found(&ptr, "bar a b = a + b"); - } - - #[test] - fn test_definition_location() { - let code = r" -some def = - first line - second line - -other def = - first line - second line - nested def = - nested body - last line of other def - -last def = inline expression"; - - let parser = parser::Parser::new(); - let module = parser.parse_module(code, default()).unwrap(); - let module = Info { ast: module }; - - let id = definition::Id::new_plain_name("other"); - let span = definition_span(&module.ast, &id).unwrap(); - assert!(code[span].ends_with("last line of other def")); - - let id = definition::Id::new_plain_name("last"); - let span = definition_span(&module.ast, &id).unwrap(); - assert!(code[span].ends_with("inline expression")); - - let id = definition::Id::new_plain_names(["other", "nested"]); - let span = definition_span(&module.ast, &id).unwrap(); - assert!(code[span].ends_with("nested body")); - } - - #[test] - fn add_method() { - let parser = parser::Parser::new(); - let module = r#"Main.method1 arg = body - -main = Main.method1 10"#; - - let module = Info::from(parser.parse_module(module, default()).unwrap()); - let method1_id = DefinitionName::new_method("Main", "method1"); - let main_id = DefinitionName::new_plain("main"); - let to_add = definition::ToAdd { - name: DefinitionName::new_method("Main", "add"), - explicit_parameter_names: vec!["arg1".into(), "arg2".into()], - body_head: Ast::infix_var("arg1", "+", "arg2"), - body_tail: default(), - }; - - let repr_after_insertion = |location| { - let mut module = module.clone(); - module.add_method(to_add.clone(), location, &parser).unwrap(); - module.ast.repr() - }; - - let expected = r#"Main.add arg1 arg2 = arg1 + arg2 - -Main.method1 arg = body - -main = Main.method1 10"#; - assert_eq!(repr_after_insertion(Placement::Begin), expected); - - let expected = r#"Main.method1 arg = body - -main = Main.method1 10 - -Main.add arg1 arg2 = arg1 + arg2"#; - assert_eq!(repr_after_insertion(Placement::End), expected); - - let expected = r#"Main.method1 arg = body - -Main.add arg1 arg2 = arg1 + arg2 - -main = Main.method1 10"#; - assert_eq!(repr_after_insertion(Placement::After(method1_id.clone())), expected); - - assert_eq!( - repr_after_insertion(Placement::Before(method1_id.clone())), - repr_after_insertion(Placement::Begin) - ); - assert_eq!( - repr_after_insertion(Placement::After(method1_id)), - repr_after_insertion(Placement::Before(main_id.clone())) - ); - assert_eq!( - repr_after_insertion(Placement::After(main_id)), - repr_after_insertion(Placement::End) - ); - - // TODO [mwu] - // This test doesn't include multi-lines functions, as the result may seem somewhat - // unexpected due to the way that parser assigns blank lines to the former block - // rather than module. If anyone will care, we might revisit this after the parser - // 2.0 rewrite. - } -} diff --git a/app/gui/controller/double-representation/src/name.rs b/app/gui/controller/double-representation/src/name.rs deleted file mode 100644 index e3059f1471..0000000000 --- a/app/gui/controller/double-representation/src/name.rs +++ /dev/null @@ -1,523 +0,0 @@ -//! The structures representing the name paths which may appear in Enso code. - -use crate::prelude::*; - -use crate::module; - -use ast::constants::PROJECTS_MAIN_MODULE; -use ast::opr::predefined::ACCESS; -use enso_prelude::serde_reexports::Deserialize; -use enso_prelude::serde_reexports::Serialize; -use std::cmp::Ordering; - - -// ============== -// === Export === -// ============== - -pub mod project; - - - -// ============== -// === Errors === -// ============== - -#[allow(missing_docs)] -#[derive(Copy, Clone, Debug, Fail)] -pub enum InvalidQualifiedName { - #[fail(display = "The qualified name is empty.")] - EmptyName, - #[fail(display = "Too few segments in qualified name.")] - TooFewSegments, - #[fail(display = "Too many segments in qualified name.")] - TooManySegments, -} - -#[allow(missing_docs)] -#[derive(Copy, Clone, Debug, Fail)] -#[fail(display = "No qualified name found in AST")] -pub struct QualifiedNameNotFoundInAst; - - - -// ================ -// === NamePath === -// ================ - -/// Representation of name path: the list of segments which is separated by dots in the code. -pub type NamePath = Vec; - -/// Reference to [`NamePath`] or its fragment. -pub type NamePathRef<'a> = &'a [ImString]; - - - -// ===================== -// === QualifiedName === -// ===================== - -/// A QualifiedName template without specified type of segment's list container. -/// -/// Usually you should use one of its specialization: the owned [`QualifiedName`] or borrowed -/// [`QualifiedNameRef`]. -#[derive(Clone, Debug, Default, Deserialize, Hash, Serialize)] -#[serde(into = "String")] -#[serde(try_from = "String")] -#[serde(bound( - serialize = "Self: Into, Segments: Clone", - deserialize = "Self: TryFrom" -))] -pub struct QualifiedNameTemplate { - project: project::QualifiedName, - path: Segments, -} - -/// The Fully Qualified Name of language's entity (type, module, method, etc.). -/// -/// It's represented in the code as list of identifiers separated by dots, where two first segments -/// are project namespace and name. -/// -/// This structure removes project's main module name from the path upon construction to avoid -/// having different [`QualifiedName`]s representing same logical path (what helps when we want to, -/// for example, look up things by their qualified name. -pub type QualifiedName = QualifiedNameTemplate; - -/// A reference to [`QualifiedName`] or ots fragment. -pub type QualifiedNameRef<'a> = QualifiedNameTemplate>; - -impl_clone_ref_as_clone!(['a] QualifiedNameRef<'a>); - - -// === Construction === - -impl QualifiedNameTemplate { - fn new(project: project::QualifiedName, path: Segments) -> Self { - Self { project, path } - } -} - -impl QualifiedName { - /// Create a qualified name for the project's main module. - pub fn new_main(project: project::QualifiedName) -> Self { - Self::new(project, default()) - } - - /// Create a qualified name for module in `project` identified by `id`. - pub fn new_module(project: project::QualifiedName, id: module::Id) -> Self { - let without_main = id.into_iter().skip_while(|s| s == PROJECTS_MAIN_MODULE); - Self::new(project, without_main.collect_vec()) - } - - /// Create a qualified name with new segment pushed at end of the path. - pub fn new_child(mut self, child: impl Into) -> Self { - self.push_segment(child); - self - } - - /// Constructs a qualified name from its text representation. - /// - /// Note, that there is no guarantee that `QualifiedName::from_text(s).to_string() = s`, as the - /// `Main` segment is removed upon constructing [`QualifiedName`]. - /// - /// Fails, if the text is not a valid name. - /// - /// # Example - /// - /// ```rust - /// use double_representation::name::QualifiedName; - /// let name = QualifiedName::from_text("ns.Project.Module.Type").unwrap(); - /// assert_eq!(name.project().namespace, "ns"); - /// assert_eq!(name.project().project, "Project"); - /// assert_eq!(name.path()[0], "Module"); - /// assert_eq!(name.path()[1], "Type"); - /// - /// // The "Main" module segment is removed. - /// let main_module_name = QualifiedName::from_text("ns.Project.Main.Type").unwrap(); - /// assert_eq!(main_module_name.to_string(), "ns.Project.Type"); - /// ``` - pub fn from_text(text: impl AsRef) -> FallibleResult { - let text = text.as_ref(); - Self::from_all_segments(text.split(ACCESS)) - } - - /// Build a module's full qualified name from its name segments and the project name. - /// - /// ``` - /// # use double_representation::name::QualifiedName; - /// - /// let name = QualifiedName::from_all_segments(["Project", "Main"]).unwrap(); - /// assert_eq!(name.to_string(), "Project.Main"); - /// ``` - pub fn from_all_segments(segments: impl IntoIterator) -> FallibleResult - where for<'s> Seg: Into + PartialEq<&'s str> { - let mut iter = segments.into_iter().map(|name| name.into()); - let project_name = match (iter.next(), iter.next()) { - (Some(ns), Some(name)) => project::QualifiedName::new(ns, name), - _ => return Err(InvalidQualifiedName::TooFewSegments.into()), - }; - let without_main = iter.skip_while(|s| *s == PROJECTS_MAIN_MODULE); - Ok(Self::new(project_name, without_main.collect())) - } -} - - -// === Methods Shared By QualifiedName and QualifiedNameRef === - -impl> QualifiedNameTemplate { - /// The project name segments. - pub fn project(&self) -> &project::QualifiedName { - &self.project - } - - /// The path part of the qualified name - everything what goes after the project name. - pub fn path(&self) -> &[ImString] { - self.path.as_ref() - } - - /// Get the entity's name. In case of Main module it's `Main`, not the project name. - pub fn name(&self) -> &str { - self.path.as_ref().last().map_or(PROJECTS_MAIN_MODULE, ImString::as_str) - } - - /// Get the entity's name as visible in the code. In case of Main module it's the project name, - /// not `Main`. - pub fn alias_name(&self) -> &ImString { - let module_name = (!self.is_main_module()).and_option_from(|| self.path.as_ref().last()); - module_name.unwrap_or(&self.project.project) - } - - /// Check if the name refers to some project's Main module. - pub fn is_main_module(&self) -> bool { - self.path.as_ref().is_empty() - } - - /// Check if this name refers to a descendant of another name. - /// - /// ```rust - /// # use double_representation::name::QualifiedName; - /// - /// let parent = QualifiedName::from_text("ns.Project.Module").unwrap(); - /// let descendant = QualifiedName::from_text("ns.Project.Module.SubModule.Element").unwrap(); - /// let not_descendant = QualifiedName::from_text("ns.Project.Module2.Element").unwrap(); - /// - /// assert!(descendant.is_descendant_of(parent.as_ref())); - /// assert!(!not_descendant.is_descendant_of(parent.as_ref())); - /// assert!(parent.is_descendant_of(parent.as_ref())); - pub fn is_descendant_of(&self, other: QualifiedNameRef) -> bool { - self.project == other.project && self.path.as_ref().starts_with(other.path) - } - - /// The iterator over name's segments (including project namespace and name). - pub fn segments(&self) -> impl Iterator { - self.project.segments().chain(self.path.as_ref()) - } - - /// The iterator over name's segments (including project namespace and name) with added - /// [`PROJECTS_MAIN_MODULE`] segment in case of the main module. - pub fn segments_with_main_segment(&self) -> impl Iterator { - let main_segment = self.is_main_module().then_some(PROJECTS_MAIN_MODULE); - self.segments().map(|s| s.as_str()).chain(main_segment) - } - - /// Return the module identifier pointed by this qualified name. - pub fn module_id(&self) -> module::Id { - let module_path = self.path.as_ref(); - let parent_modules = &module_path[0..module_path.len().saturating_sub(1)]; - module::Id { name: self.name().into(), parent_modules: parent_modules.to_vec() } - } - - /// Check if the name refers to entity defined/reexported in library's main module. - pub fn is_top_element(&self) -> bool { - self.path.as_ref().len() == 1 - } - - /// Return the qualified name referring to same project and some fragment of the [`path`] part. - pub fn sub_path( - &self, - range: impl SliceIndex<[ImString], Output = [ImString]>, - ) -> QualifiedNameRef { - QualifiedNameRef { project: self.project.clone_ref(), path: &self.path.as_ref()[range] } - } - - /// Split the qualified into two parts: the qualified name of a nth parent module and the - /// remaining access chain of requested length. Returns `None` if the requested access chain - /// length is too long to split off. - pub fn split_chain(&self, access_chain_length: usize) -> Option<(QualifiedNameRef, String)> { - let path = self.path.as_ref(); - if access_chain_length >= path.len() { - return None; - } - - let (path, chain) = path.split_at(path.len() - access_chain_length); - let parent_name = QualifiedNameRef { project: self.project.clone_ref(), path }; - let chain = chain.iter().map(|s| s.as_str()).join(ACCESS); - Some((parent_name, chain)) - } - - /// Return the [`QualifiedNameRef`] referring to the this name's parent. - /// - /// ```rust - /// use double_representation::name::QualifiedName; - /// let name = QualifiedName::from_text("ns.Project.Module.Type").unwrap(); - /// let parent = QualifiedName::from_text("ns.Project.Module").unwrap(); - /// assert_eq!(name.parent(), Some(parent.as_ref())); - /// ``` - pub fn parent(&self) -> Option { - let shorter_len = self.path.as_ref().len().checked_sub(1)?; - Some(self.sub_path(0..shorter_len)) - } - - /// Returns an iterator over all parent entities. The `self` is not included. - /// - /// ```rust - /// use double_representation::name::QualifiedName; - /// let name = QualifiedName::from_text("ns.Project.Module.Type").unwrap(); - /// let parents: Vec = name.parents().map(|qn| qn.to_string()).collect(); - /// assert_eq!(parents, vec!["ns.Project.Module", "ns.Project"]); - /// ``` - pub fn parents(&self) -> impl Iterator { - let mut path_upper_bounds = (0..self.path.as_ref().len()).rev(); - iter::from_fn(move || { - let upper_bound = path_upper_bounds.next()?; - Some(self.sub_path(0..upper_bound)) - }) - } - - /// Convert to [`QualifiedNameRef`]. - pub fn as_ref(&self) -> QualifiedNameRef { - QualifiedNameRef { project: self.project.clone_ref(), path: self.path.as_ref() } - } - - /// Create a new owned version of this qualified name. - pub fn to_owned(&self) -> QualifiedName { - QualifiedName { project: self.project.clone_ref(), path: self.path.as_ref().into() } - } - - /// Convert qualified name to [`String`] adding the [`PROJECTS_MAIN_SEGMENT`] at the end in case - /// of main module. - /// - /// ```rust - /// use double_representation::name::QualifiedName; - /// let name = QualifiedName::from_text("ns.Project").unwrap(); - /// assert_eq!(name.to_string_with_main_segment(), "ns.Project.Main"); - /// ``` - pub fn to_string_with_main_segment(&self) -> String { - self.segments_with_main_segment().join(ACCESS) - } -} - - -// === Owned QualifiedName only Methods === - -impl QualifiedName { - /// Add a segment to this qualified name. - /// - /// Because the [`QualifiedName`] always omit the "Main" module name in its path, this function - /// may result in leaving exactly the same name as before (see an example). - /// - /// ```rust - /// use double_representation::name::QualifiedName; - /// let mut name = QualifiedName::from_text("ns.Proj.Foo").unwrap(); - /// name.push_segment("Bar"); - /// assert_eq!(name.to_string(), "ns.Proj.Foo.Bar"); - /// - /// let mut name = QualifiedName::from_text("ns.Proj").unwrap(); - /// name.push_segment("Main"); - /// assert_eq!(name.to_string(), "ns.Proj"); - /// ``` - pub fn push_segment(&mut self, name: impl Into) { - let name = name.into(); - if name != PROJECTS_MAIN_MODULE || !self.path.is_empty() { - self.path.push(name); - } - } - - /// Remove a segment to this qualified name. - /// - /// ```rust - /// use double_representation::name::QualifiedName; - /// use enso_prelude::ImString; - /// - /// let mut name = QualifiedName::from_text("ns.Proj.Foo").unwrap(); - /// assert_eq!(name.pop_segment(), Some(ImString::new("Foo"))); - /// assert_eq!(name.pop_segment(), None); - /// ``` - pub fn pop_segment(&mut self) -> Option { - self.path.pop() - } -} - - -// === Conversion from AST === - -impl TryFrom<&Ast> for QualifiedName { - type Error = failure::Error; - - fn try_from(ast: &Ast) -> Result { - let segments = ast::opr::Chain::try_new(ast) - .ok_or(QualifiedNameNotFoundInAst)? - .as_qualified_name_segments() - .ok_or(QualifiedNameNotFoundInAst)?; - Self::from_all_segments(segments) - } -} - - -// === Conversions From and Into String === - -impl TryFrom<&str> for QualifiedName { - type Error = failure::Error; - - fn try_from(text: &str) -> Result { - Self::from_text(text) - } -} - -impl TryFrom for QualifiedName { - type Error = failure::Error; - - fn try_from(text: String) -> Result { - Self::from_text(text) - } -} - -impl TryFrom<&String> for QualifiedName { - type Error = failure::Error; - - fn try_from(text: &String) -> Result { - Self::from_text(text) - } -} - - -impl From for String { - fn from(name: QualifiedName) -> Self { - String::from(&name) - } -} - -impl From<&QualifiedName> for String { - fn from(name: &QualifiedName) -> Self { - name.to_string() - } -} - -impl> Display for QualifiedNameTemplate { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.segments().format(ACCESS)) - } -} - - -// === Conversion Between Name Representations - -impl From for QualifiedName { - fn from(project: project::QualifiedName) -> Self { - Self::new_main(project) - } -} - -impl From for NamePath { - fn from(qualified: QualifiedName) -> Self { - qualified.into_iter().collect() - } -} - -impl<'a> From<&'a QualifiedName> for NamePath { - fn from(qualified: &'a QualifiedName) -> Self { - qualified.segments().cloned().collect() - } -} - -impl<'a, 'b> From<&'a QualifiedNameRef<'b>> for NamePath { - fn from(qualified: &'a QualifiedNameRef<'b>) -> Self { - qualified.segments().cloned().collect() - } -} - -impl<'a> From<&'a QualifiedName> for QualifiedNameRef<'a> { - fn from(qualified: &'a QualifiedName) -> Self { - qualified.as_ref() - } -} - - -// === Conversion Into Iterator === - -impl<'a, 'b> IntoIterator for &'a QualifiedNameRef<'b> { - type Item = &'a ImString; - type IntoIter = impl Iterator; - fn into_iter(self) -> Self::IntoIter { - self.segments() - } -} - -impl<'a> IntoIterator for &'a QualifiedName { - type Item = &'a ImString; - type IntoIter = impl Iterator; - fn into_iter(self) -> Self::IntoIter { - self.segments() - } -} - -impl IntoIterator for QualifiedName { - type Item = ImString; - type IntoIter = impl Iterator; - fn into_iter(self) -> Self::IntoIter { - iter::once(self.project.namespace).chain(iter::once(self.project.project)).chain(self.path) - } -} - - -// === Comparing Various Name Representations === - -impl, S2: AsRef<[ImString]>> PartialEq> - for QualifiedNameTemplate -{ - fn eq(&self, other: &QualifiedNameTemplate) -> bool { - self.project == other.project && self.path.as_ref() == other.path.as_ref() - } -} - -impl> Eq for QualifiedNameTemplate {} - -impl> PartialEq - for QualifiedNameTemplate -{ - fn eq(&self, other: &project::QualifiedName) -> bool { - self.project == *other && self.path.as_ref().is_empty() - } -} - -impl> PartialEq for QualifiedNameTemplate { - fn eq(&self, other: &NamePath) -> bool { - self.segments().eq(other.iter()) - } -} - -impl> PartialEq> for NamePath { - fn eq(&self, other: &QualifiedNameTemplate) -> bool { - other == self - } -} - -impl<'a, Segments: AsRef<[ImString]>> PartialEq> - for QualifiedNameTemplate -{ - fn eq(&self, other: &NamePathRef<'a>) -> bool { - self.segments().eq(other.iter()) - } -} - -impl> PartialOrd for QualifiedNameTemplate { - fn partial_cmp(&self, other: &QualifiedNameTemplate) -> Option { - Some(self.cmp(other)) - } -} - -impl> Ord for QualifiedNameTemplate { - fn cmp(&self, other: &QualifiedNameTemplate) -> Ordering { - self.project.cmp(&other.project).then(self.path.as_ref().cmp(other.path.as_ref())) - } -} diff --git a/app/gui/controller/double-representation/src/name/project.rs b/app/gui/controller/double-representation/src/name/project.rs deleted file mode 100644 index 6646d145ca..0000000000 --- a/app/gui/controller/double-representation/src/name/project.rs +++ /dev/null @@ -1,238 +0,0 @@ -//! The structures related to the project name in the code. - -use crate::prelude::*; - -use crate::name::InvalidQualifiedName; -use crate::name::NamePath; -use crate::name::NamePathRef; - -use ast::opr::predefined::ACCESS; -use const_format::concatcp; -use enso_prelude::serde_reexports::Deserialize; -use enso_prelude::serde_reexports::Serialize; - - - -// ================= -// === Constants === -// ================= - -/// The namespace of the standard library. -pub const STANDARD_NAMESPACE: &str = "Standard"; - -/// The name of the project in the [`STANDARD_NAMESPACE`] containing the base standard library. -pub const BASE_LIBRARY_NAME: &str = "Base"; - -/// The full path of the [`BASE_LIBRARY_NAME`] project in the [`STANDARD_NAMESPACE`]. -pub const STANDARD_BASE_LIBRARY_PATH: &str = concatcp!(STANDARD_NAMESPACE, ".", BASE_LIBRARY_NAME); - - - -// ================ -// === Template === -// ================ - -#[allow(missing_docs)] -#[derive(Copy, Clone, Debug, Fail)] -pub enum InvalidTemplateName { - #[fail(display = "The template name contains invalid characters.")] - ContainsInvalidCharacters, -} - -/// The project template name. -#[derive(Clone, Debug)] -pub struct Template { - name: String, -} - -impl Template { - /// Create the project template from string. - /// - /// # Example - /// - /// ```rust - /// # use double_representation::name::project::Template; - /// assert!(Template::from_text("hello").is_ok()); - /// assert!(Template::from_text("hello_world").is_err()); - /// ``` - pub fn from_text(text: impl AsRef) -> FallibleResult { - if text.as_ref().contains(|c: char| !c.is_ascii_alphanumeric()) { - Err(InvalidTemplateName::ContainsInvalidCharacters.into()) - } else { - Ok(Template { name: text.as_ref().to_owned() }) - } - } - - /// Create the project template from string without validation. - pub fn unsafe_from_text(text: impl AsRef) -> Self { - Template { name: text.as_ref().to_owned() } - } - - /// Create a project name from the template name. - /// # Example - /// - /// ```rust - /// # use double_representation::name::project::Template; - /// let template = Template::unsafe_from_text("hello"); - /// assert_eq!(template.to_project_name(), "Hello".to_owned()); - /// ``` - pub fn to_project_name(&self) -> String { - let mut name = self.name.to_string(); - // Capitalize - if let Some(r) = name.get_mut(0..1) { - r.make_ascii_uppercase(); - } - - name - } -} - -// === Conversions From and Into String === - -impl TryFrom<&str> for Template { - type Error = failure::Error; - - fn try_from(text: &str) -> Result { - Self::from_text(text) - } -} - -impl TryFrom for Template { - type Error = failure::Error; - - fn try_from(text: String) -> Result { - Self::from_text(text) - } -} - -impl From