diff --git a/.github/workflows/eval.yml b/.github/workflows/eval.yml
deleted file mode 100644
index b5da9e7b7c8e293fb565f4de269a1ae266c19692..0000000000000000000000000000000000000000
--- a/.github/workflows/eval.yml
+++ /dev/null
@@ -1,71 +0,0 @@
-name: Run Agent Eval
-
-on:
- schedule:
- - cron: "0 0 * * *"
-
- pull_request:
- branches:
- - "**"
- types: [synchronize, reopened, labeled]
-
- workflow_dispatch:
-
-concurrency:
- # Allow only one workflow per any non-`main` branch.
- group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.ref_name == 'main' && github.sha || 'anysha' }}
- cancel-in-progress: true
-
-env:
- CARGO_TERM_COLOR: always
- CARGO_INCREMENTAL: 0
- RUST_BACKTRACE: 1
- ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
- ZED_EVAL_TELEMETRY: 1
-
-jobs:
- run_eval:
- timeout-minutes: 60
- name: Run Agent Eval
- if: >
- github.repository_owner == 'zed-industries' &&
- (github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'run-eval'))
- runs-on:
- - namespace-profile-16x32-ubuntu-2204
- steps:
- - name: Add Rust to the PATH
- run: echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
-
- - name: Checkout repo
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- with:
- clean: false
-
- - name: Cache dependencies
- uses: swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2
- with:
- save-if: ${{ github.ref == 'refs/heads/main' }}
- # cache-provider: "buildjet"
-
- - name: Install Linux dependencies
- run: ./script/linux
-
- - name: Configure CI
- run: |
- mkdir -p ./../.cargo
- cp ./.cargo/ci-config.toml ./../.cargo/config.toml
-
- - name: Compile eval
- run: cargo build --package=eval
-
- - name: Run eval
- run: cargo run --package=eval -- --repetitions=8 --concurrency=1
-
- # Even the Linux runner is not stateful, in theory there is no need to do this cleanup.
- # But, to avoid potential issues in the future if we choose to use a stateful Linux runner and forget to add code
- # to clean up the config file, I’ve included the cleanup code here as a precaution.
- # While it’s not strictly necessary at this moment, I believe it’s better to err on the side of caution.
- - name: Clean CI config file
- if: always()
- run: rm -rf ./../.cargo
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 56ea875d5cefec240d554984a8c0e1c1992a574c..f047f3064a6828d6121169f7f9cca189d5dbe73f 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -3,10 +3,7 @@
name: release
env:
CARGO_TERM_COLOR: always
- CARGO_INCREMENTAL: '0'
RUST_BACKTRACE: '1'
- ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
- ZED_MINIDUMP_ENDPOINT: ${{ secrets.ZED_SENTRY_MINIDUMP_ENDPOINT }}
on:
push:
tags:
@@ -66,6 +63,10 @@ jobs:
- name: steps::install_mold
run: ./script/install-mold
shell: bash -euxo pipefail {0}
+ - name: steps::cache_rust_dependencies_namespace
+ uses: namespacelabs/nscloud-cache-action@v1
+ with:
+ cache: rust
- name: steps::setup_node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
@@ -77,7 +78,7 @@ jobs:
run: cargo install cargo-nextest --locked
shell: bash -euxo pipefail {0}
- name: steps::clear_target_dir_if_large
- run: ./script/clear-target-dir-if-larger-than 100
+ run: ./script/clear-target-dir-if-larger-than 250
shell: bash -euxo pipefail {0}
- name: steps::cargo_nextest
run: cargo nextest run --workspace --no-fail-fast --failure-output immediate-final
@@ -177,11 +178,15 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
timeout-minutes: 60
- bundle_linux_arm64:
+ bundle_linux_aarch64:
needs:
- run_tests_linux
- check_scripts
runs-on: namespace-profile-8x32-ubuntu-2004-arm-m4
+ env:
+ CARGO_INCREMENTAL: 0
+ ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
+ ZED_MINIDUMP_ENDPOINT: ${{ secrets.ZED_SENTRY_MINIDUMP_ENDPOINT }}
steps:
- name: steps::checkout_repo
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
@@ -200,27 +205,28 @@ jobs:
- name: ./script/bundle-linux
run: ./script/bundle-linux
shell: bash -euxo pipefail {0}
- - name: '@actions/upload-artifact zed-${{ github.event.pull_request.head.sha || github.sha }}-aarch64-unknown-linux-gnu.tar.gz'
+ - name: '@actions/upload-artifact zed-linux-aarch64.tar.gz'
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
with:
- name: zed-${{ github.event.pull_request.head.sha || github.sha }}-aarch64-unknown-linux-gnu.tar.gz
- path: target/release/zed-*.tar.gz
+ name: zed-linux-aarch64.tar.gz
+ path: target/release/zed-linux-aarch64.tar.gz
if-no-files-found: error
- - name: '@actions/upload-artifact zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-aarch64-unknown-linux-gnu.tar.gz'
+ - name: '@actions/upload-artifact zed-remote-server-linux-aarch64.gz'
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
with:
- name: zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-aarch64-unknown-linux-gnu.tar.gz
- path: target/zed-remote-server-*.gz
+ name: zed-remote-server-linux-aarch64.gz
+ path: target/zed-remote-server-linux-aarch64.gz
if-no-files-found: error
- outputs:
- zed: zed-${{ github.event.pull_request.head.sha || github.sha }}-aarch64-unknown-linux-gnu.tar.gz
- remote-server: zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-aarch64-unknown-linux-gnu.tar.gz
timeout-minutes: 60
bundle_linux_x86_64:
needs:
- run_tests_linux
- check_scripts
runs-on: namespace-profile-32x64-ubuntu-2004
+ env:
+ CARGO_INCREMENTAL: 0
+ ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
+ ZED_MINIDUMP_ENDPOINT: ${{ secrets.ZED_SENTRY_MINIDUMP_ENDPOINT }}
steps:
- name: steps::checkout_repo
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
@@ -239,28 +245,28 @@ jobs:
- name: ./script/bundle-linux
run: ./script/bundle-linux
shell: bash -euxo pipefail {0}
- - name: '@actions/upload-artifact zed-${{ github.event.pull_request.head.sha || github.sha }}-x86_64-unknown-linux-gnu.tar.gz'
+ - name: '@actions/upload-artifact zed-linux-x86_64.tar.gz'
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
with:
- name: zed-${{ github.event.pull_request.head.sha || github.sha }}-x86_64-unknown-linux-gnu.tar.gz
- path: target/release/zed-*.tar.gz
+ name: zed-linux-x86_64.tar.gz
+ path: target/release/zed-linux-x86_64.tar.gz
if-no-files-found: error
- - name: '@actions/upload-artifact zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-x86_64-unknown-linux-gnu.tar.gz'
+ - name: '@actions/upload-artifact zed-remote-server-linux-x86_64.gz'
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
with:
- name: zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-x86_64-unknown-linux-gnu.tar.gz
- path: target/zed-remote-server-*.gz
+ name: zed-remote-server-linux-x86_64.gz
+ path: target/zed-remote-server-linux-x86_64.gz
if-no-files-found: error
- outputs:
- zed: zed-${{ github.event.pull_request.head.sha || github.sha }}-x86_64-unknown-linux-gnu.tar.gz
- remote-server: zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-x86_64-unknown-linux-gnu.tar.gz
timeout-minutes: 60
- bundle_mac_arm64:
+ bundle_mac_aarch64:
needs:
- run_tests_mac
- check_scripts
runs-on: self-mini-macos
env:
+ CARGO_INCREMENTAL: 0
+ ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
+ ZED_MINIDUMP_ENDPOINT: ${{ secrets.ZED_SENTRY_MINIDUMP_ENDPOINT }}
MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
APPLE_NOTARIZATION_KEY: ${{ secrets.APPLE_NOTARIZATION_KEY }}
@@ -282,24 +288,21 @@ jobs:
- name: steps::clear_target_dir_if_large
run: ./script/clear-target-dir-if-larger-than 300
shell: bash -euxo pipefail {0}
- - name: run_bundling::bundle_mac
+ - name: run_bundling::bundle_mac::bundle_mac
run: ./script/bundle-mac aarch64-apple-darwin
shell: bash -euxo pipefail {0}
- - name: '@actions/upload-artifact Zed_${{ github.event.pull_request.head.sha || github.sha }}-aarch64.dmg'
+ - name: '@actions/upload-artifact Zed-aarch64.dmg'
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
with:
- name: Zed_${{ github.event.pull_request.head.sha || github.sha }}-aarch64.dmg
- path: target/aarch64-apple-darwin/release/Zed.dmg
+ name: Zed-aarch64.dmg
+ path: target/aarch64-apple-darwin/release/Zed-aarch64.dmg
if-no-files-found: error
- - name: '@actions/upload-artifact zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-macos-aarch64.gz'
+ - name: '@actions/upload-artifact zed-remote-server-macos-aarch64.gz'
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
with:
- name: zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-macos-aarch64.gz
+ name: zed-remote-server-macos-aarch64.gz
path: target/zed-remote-server-macos-aarch64.gz
if-no-files-found: error
- outputs:
- zed: Zed_${{ github.event.pull_request.head.sha || github.sha }}-aarch64.dmg
- remote-server: zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-macos-aarch64.gz
timeout-minutes: 60
bundle_mac_x86_64:
needs:
@@ -307,6 +310,9 @@ jobs:
- check_scripts
runs-on: self-mini-macos
env:
+ CARGO_INCREMENTAL: 0
+ ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
+ ZED_MINIDUMP_ENDPOINT: ${{ secrets.ZED_SENTRY_MINIDUMP_ENDPOINT }}
MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
APPLE_NOTARIZATION_KEY: ${{ secrets.APPLE_NOTARIZATION_KEY }}
@@ -328,31 +334,31 @@ jobs:
- name: steps::clear_target_dir_if_large
run: ./script/clear-target-dir-if-larger-than 300
shell: bash -euxo pipefail {0}
- - name: run_bundling::bundle_mac
+ - name: run_bundling::bundle_mac::bundle_mac
run: ./script/bundle-mac x86_64-apple-darwin
shell: bash -euxo pipefail {0}
- - name: '@actions/upload-artifact Zed_${{ github.event.pull_request.head.sha || github.sha }}-x86_64.dmg'
+ - name: '@actions/upload-artifact Zed-x86_64.dmg'
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
with:
- name: Zed_${{ github.event.pull_request.head.sha || github.sha }}-x86_64.dmg
- path: target/x86_64-apple-darwin/release/Zed.dmg
+ name: Zed-x86_64.dmg
+ path: target/x86_64-apple-darwin/release/Zed-x86_64.dmg
if-no-files-found: error
- - name: '@actions/upload-artifact zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-macos-x86_64.gz'
+ - name: '@actions/upload-artifact zed-remote-server-macos-x86_64.gz'
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
with:
- name: zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-macos-x86_64.gz
+ name: zed-remote-server-macos-x86_64.gz
path: target/zed-remote-server-macos-x86_64.gz
if-no-files-found: error
- outputs:
- zed: Zed_${{ github.event.pull_request.head.sha || github.sha }}-x86_64.dmg
- remote-server: zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-macos-x86_64.gz
timeout-minutes: 60
- bundle_windows_arm64:
+ bundle_windows_aarch64:
needs:
- run_tests_windows
- check_scripts
runs-on: self-32vcpu-windows-2022
env:
+ CARGO_INCREMENTAL: 0
+ ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
+ ZED_MINIDUMP_ENDPOINT: ${{ secrets.ZED_SENTRY_MINIDUMP_ENDPOINT }}
AZURE_TENANT_ID: ${{ secrets.AZURE_SIGNING_TENANT_ID }}
AZURE_CLIENT_ID: ${{ secrets.AZURE_SIGNING_CLIENT_ID }}
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_SIGNING_CLIENT_SECRET }}
@@ -371,18 +377,16 @@ jobs:
uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b
with:
token: ${{ secrets.SENTRY_AUTH_TOKEN }}
- - name: run_bundling::bundle_windows
+ - name: run_bundling::bundle_windows::bundle_windows
run: script/bundle-windows.ps1 -Architecture aarch64
shell: pwsh
working-directory: ${{ env.ZED_WORKSPACE }}
- - name: '@actions/upload-artifact Zed_${{ github.event.pull_request.head.sha || github.sha }}-aarch64.exe'
+ - name: '@actions/upload-artifact Zed-aarch64.exe'
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
with:
- name: Zed_${{ github.event.pull_request.head.sha || github.sha }}-aarch64.exe
- path: ${{ env.SETUP_PATH }}
+ name: Zed-aarch64.exe
+ path: target/Zed-aarch64.exe
if-no-files-found: error
- outputs:
- zed: Zed_${{ github.event.pull_request.head.sha || github.sha }}-aarch64.exe
timeout-minutes: 60
bundle_windows_x86_64:
needs:
@@ -390,6 +394,9 @@ jobs:
- check_scripts
runs-on: self-32vcpu-windows-2022
env:
+ CARGO_INCREMENTAL: 0
+ ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
+ ZED_MINIDUMP_ENDPOINT: ${{ secrets.ZED_SENTRY_MINIDUMP_ENDPOINT }}
AZURE_TENANT_ID: ${{ secrets.AZURE_SIGNING_TENANT_ID }}
AZURE_CLIENT_ID: ${{ secrets.AZURE_SIGNING_CLIENT_ID }}
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_SIGNING_CLIENT_SECRET }}
@@ -408,51 +415,49 @@ jobs:
uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b
with:
token: ${{ secrets.SENTRY_AUTH_TOKEN }}
- - name: run_bundling::bundle_windows
+ - name: run_bundling::bundle_windows::bundle_windows
run: script/bundle-windows.ps1 -Architecture x86_64
shell: pwsh
working-directory: ${{ env.ZED_WORKSPACE }}
- - name: '@actions/upload-artifact Zed_${{ github.event.pull_request.head.sha || github.sha }}-x86_64.exe'
+ - name: '@actions/upload-artifact Zed-x86_64.exe'
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
with:
- name: Zed_${{ github.event.pull_request.head.sha || github.sha }}-x86_64.exe
- path: ${{ env.SETUP_PATH }}
+ name: Zed-x86_64.exe
+ path: target/Zed-x86_64.exe
if-no-files-found: error
- outputs:
- zed: Zed_${{ github.event.pull_request.head.sha || github.sha }}-x86_64.exe
timeout-minutes: 60
upload_release_assets:
needs:
- create_draft_release
- - bundle_linux_arm64
+ - bundle_linux_aarch64
- bundle_linux_x86_64
- - bundle_mac_arm64
+ - bundle_mac_aarch64
- bundle_mac_x86_64
- - bundle_windows_arm64
+ - bundle_windows_aarch64
- bundle_windows_x86_64
runs-on: namespace-profile-4x8-ubuntu-2204
steps:
- - name: release::upload_release_assets::download_workflow_artifacts
+ - name: release::download_workflow_artifacts
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53
with:
path: ./artifacts/
- name: ls -lR ./artifacts
run: ls -lR ./artifacts
shell: bash -euxo pipefail {0}
- - name: release::upload_release_assets::prep_release_artifacts
+ - name: release::prep_release_artifacts
run: |-
mkdir -p release-artifacts/
- mv ./artifacts/${{ needs.bundle_mac_x86_64.outputs.zed }}/* release-artifacts/Zed-x86_64.dmg
- mv ./artifacts/${{ needs.bundle_mac_arm64.outputs.zed }}/* release-artifacts/Zed-aarch64.dmg
- mv ./artifacts/${{ needs.bundle_windows_x86_64.outputs.zed }}/* release-artifacts/Zed-x86_64.exe
- mv ./artifacts/${{ needs.bundle_windows_arm64.outputs.zed }}/* release-artifacts/Zed-aarch64.exe
- mv ./artifacts/${{ needs.bundle_linux_arm64.outputs.zed }}/* release-artifacts/zed-linux-aarch64.tar.gz
- mv ./artifacts/${{ needs.bundle_linux_x86_64.outputs.zed }}/* release-artifacts/zed-linux-x86_64.tar.gz
- mv ./artifacts/${{ needs.bundle_linux_x86_64.outputs.remote-server }}/* release-artifacts/zed-remote-server-linux-x86_64.gz
- mv ./artifacts/${{ needs.bundle_linux_arm64.outputs.remote-server }}/* release-artifacts/zed-remote-server-linux-aarch64.gz
- mv ./artifacts/${{ needs.bundle_mac_x86_64.outputs.remote-server }}/* release-artifacts/zed-remote-server-macos-x86_64.gz
- mv ./artifacts/${{ needs.bundle_mac_arm64.outputs.remote-server }}/* release-artifacts/zed-remote-server-macos-aarch64.gz
+ mv ./artifacts/Zed-aarch64.dmg/Zed-aarch64.dmg release-artifacts/Zed-aarch64.dmg
+ mv ./artifacts/Zed-x86_64.dmg/Zed-x86_64.dmg release-artifacts/Zed-x86_64.dmg
+ mv ./artifacts/zed-linux-aarch64.tar.gz/zed-linux-aarch64.tar.gz release-artifacts/zed-linux-aarch64.tar.gz
+ mv ./artifacts/zed-linux-x86_64.tar.gz/zed-linux-x86_64.tar.gz release-artifacts/zed-linux-x86_64.tar.gz
+ mv ./artifacts/Zed-x86_64.exe/Zed-x86_64.exe release-artifacts/Zed-x86_64.exe
+ mv ./artifacts/Zed-aarch64.exe/Zed-aarch64.exe release-artifacts/Zed-aarch64.exe
+ mv ./artifacts/zed-remote-server-macos-aarch64.gz/zed-remote-server-macos-aarch64.gz release-artifacts/zed-remote-server-macos-aarch64.gz
+ mv ./artifacts/zed-remote-server-macos-x86_64.gz/zed-remote-server-macos-x86_64.gz release-artifacts/zed-remote-server-macos-x86_64.gz
+ mv ./artifacts/zed-remote-server-linux-aarch64.gz/zed-remote-server-linux-aarch64.gz release-artifacts/zed-remote-server-linux-aarch64.gz
+ mv ./artifacts/zed-remote-server-linux-x86_64.gz/zed-remote-server-linux-x86_64.gz release-artifacts/zed-remote-server-linux-x86_64.gz
shell: bash -euxo pipefail {0}
- name: gh release upload "$GITHUB_REF_NAME" --repo=zed-industries/zed release-artifacts/*
run: gh release upload "$GITHUB_REF_NAME" --repo=zed-industries/zed release-artifacts/*
@@ -473,7 +478,7 @@ jobs:
shell: bash -euxo pipefail {0}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- - name: release::auto_release_preview::create_sentry_release
+ - name: release::create_sentry_release
uses: getsentry/action-release@526942b68292201ac6bbb99b9a0747d4abee354c
with:
environment: production
diff --git a/.github/workflows/release_nightly.yml b/.github/workflows/release_nightly.yml
index 20230fb499ea9fa892a316bd1762424869004262..f3efe70a498e5718740adca572358c8b7bb81609 100644
--- a/.github/workflows/release_nightly.yml
+++ b/.github/workflows/release_nightly.yml
@@ -3,12 +3,7 @@
name: release_nightly
env:
CARGO_TERM_COLOR: always
- CARGO_INCREMENTAL: '0'
RUST_BACKTRACE: '1'
- ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
- ZED_MINIDUMP_ENDPOINT: ${{ secrets.ZED_SENTRY_MINIDUMP_ENDPOINT }}
- DIGITALOCEAN_SPACES_ACCESS_KEY: ${{ secrets.DIGITALOCEAN_SPACES_ACCESS_KEY }}
- DIGITALOCEAN_SPACES_SECRET_KEY: ${{ secrets.DIGITALOCEAN_SPACES_SECRET_KEY }}
on:
push:
tags:
@@ -32,41 +27,6 @@ jobs:
run: ./script/clippy
shell: bash -euxo pipefail {0}
timeout-minutes: 60
- run_tests_mac:
- if: github.repository_owner == 'zed-industries'
- runs-on: self-mini-macos
- steps:
- - name: steps::checkout_repo
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- with:
- clean: false
- - name: steps::setup_cargo_config
- run: |
- mkdir -p ./../.cargo
- cp ./.cargo/ci-config.toml ./../.cargo/config.toml
- shell: bash -euxo pipefail {0}
- - name: steps::setup_node
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
- with:
- node-version: '20'
- - name: steps::clippy
- run: ./script/clippy
- shell: bash -euxo pipefail {0}
- - name: steps::cargo_install_nextest
- run: cargo install cargo-nextest --locked
- shell: bash -euxo pipefail {0}
- - name: steps::clear_target_dir_if_large
- run: ./script/clear-target-dir-if-larger-than 300
- shell: bash -euxo pipefail {0}
- - name: steps::cargo_nextest
- run: cargo nextest run --workspace --no-fail-fast --failure-output immediate-final
- shell: bash -euxo pipefail {0}
- - name: steps::cleanup_cargo_config
- if: always()
- run: |
- rm -rf ./../.cargo
- shell: bash -euxo pipefail {0}
- timeout-minutes: 60
run_tests_windows:
if: github.repository_owner == 'zed-industries'
runs-on: self-32vcpu-windows-2022
@@ -102,55 +62,109 @@ jobs:
Remove-Item -Recurse -Path "./../.cargo" -Force -ErrorAction SilentlyContinue
shell: pwsh
timeout-minutes: 60
- bundle_mac_nightly_x86_64:
+ bundle_linux_aarch64:
needs:
- check_style
- - run_tests_mac
- if: github.repository_owner == 'zed-industries'
- runs-on: self-mini-macos
+ - run_tests_windows
+ runs-on: namespace-profile-8x32-ubuntu-2004-arm-m4
env:
- MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
- MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
- APPLE_NOTARIZATION_KEY: ${{ secrets.APPLE_NOTARIZATION_KEY }}
- APPLE_NOTARIZATION_KEY_ID: ${{ secrets.APPLE_NOTARIZATION_KEY_ID }}
- APPLE_NOTARIZATION_ISSUER_ID: ${{ secrets.APPLE_NOTARIZATION_ISSUER_ID }}
+ CARGO_INCREMENTAL: 0
+ ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
+ ZED_MINIDUMP_ENDPOINT: ${{ secrets.ZED_SENTRY_MINIDUMP_ENDPOINT }}
steps:
- name: steps::checkout_repo
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
clean: false
- - name: steps::setup_node
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
- with:
- node-version: '20'
+ - name: run_bundling::set_release_channel_to_nightly
+ run: |
+ set -eu
+ version=$(git rev-parse --short HEAD)
+ echo "Publishing version: ${version} on release channel nightly"
+ echo "nightly" > crates/zed/RELEASE_CHANNEL
+ shell: bash -euxo pipefail {0}
- name: steps::setup_sentry
uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b
with:
token: ${{ secrets.SENTRY_AUTH_TOKEN }}
- - name: steps::clear_target_dir_if_large
- run: ./script/clear-target-dir-if-larger-than 300
+ - name: steps::setup_linux
+ run: ./script/linux
+ shell: bash -euxo pipefail {0}
+ - name: steps::install_mold
+ run: ./script/install-mold
shell: bash -euxo pipefail {0}
- - name: release_nightly::set_release_channel_to_nightly
+ - name: ./script/bundle-linux
+ run: ./script/bundle-linux
+ shell: bash -euxo pipefail {0}
+ - name: '@actions/upload-artifact zed-linux-aarch64.tar.gz'
+ uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
+ with:
+ name: zed-linux-aarch64.tar.gz
+ path: target/release/zed-linux-aarch64.tar.gz
+ if-no-files-found: error
+ - name: '@actions/upload-artifact zed-remote-server-linux-aarch64.gz'
+ uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
+ with:
+ name: zed-remote-server-linux-aarch64.gz
+ path: target/zed-remote-server-linux-aarch64.gz
+ if-no-files-found: error
+ timeout-minutes: 60
+ bundle_linux_x86_64:
+ needs:
+ - check_style
+ - run_tests_windows
+ runs-on: namespace-profile-32x64-ubuntu-2004
+ env:
+ CARGO_INCREMENTAL: 0
+ ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
+ ZED_MINIDUMP_ENDPOINT: ${{ secrets.ZED_SENTRY_MINIDUMP_ENDPOINT }}
+ steps:
+ - name: steps::checkout_repo
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ with:
+ clean: false
+ - name: run_bundling::set_release_channel_to_nightly
run: |
set -eu
version=$(git rev-parse --short HEAD)
echo "Publishing version: ${version} on release channel nightly"
echo "nightly" > crates/zed/RELEASE_CHANNEL
shell: bash -euxo pipefail {0}
- - name: run_bundling::bundle_mac
- run: ./script/bundle-mac x86_64-apple-darwin
+ - name: steps::setup_sentry
+ uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b
+ with:
+ token: ${{ secrets.SENTRY_AUTH_TOKEN }}
+ - name: steps::setup_linux
+ run: ./script/linux
shell: bash -euxo pipefail {0}
- - name: release_nightly::upload_zed_nightly
- run: script/upload-nightly macos x86_64
+ - name: steps::install_mold
+ run: ./script/install-mold
+ shell: bash -euxo pipefail {0}
+ - name: ./script/bundle-linux
+ run: ./script/bundle-linux
shell: bash -euxo pipefail {0}
+ - name: '@actions/upload-artifact zed-linux-x86_64.tar.gz'
+ uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
+ with:
+ name: zed-linux-x86_64.tar.gz
+ path: target/release/zed-linux-x86_64.tar.gz
+ if-no-files-found: error
+ - name: '@actions/upload-artifact zed-remote-server-linux-x86_64.gz'
+ uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
+ with:
+ name: zed-remote-server-linux-x86_64.gz
+ path: target/zed-remote-server-linux-x86_64.gz
+ if-no-files-found: error
timeout-minutes: 60
- bundle_mac_nightly_aarch64:
+ bundle_mac_aarch64:
needs:
- check_style
- - run_tests_mac
- if: github.repository_owner == 'zed-industries'
+ - run_tests_windows
runs-on: self-mini-macos
env:
+ CARGO_INCREMENTAL: 0
+ ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
+ ZED_MINIDUMP_ENDPOINT: ${{ secrets.ZED_SENTRY_MINIDUMP_ENDPOINT }}
MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
APPLE_NOTARIZATION_KEY: ${{ secrets.APPLE_NOTARIZATION_KEY }}
@@ -161,6 +175,13 @@ jobs:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
clean: false
+ - name: run_bundling::set_release_channel_to_nightly
+ run: |
+ set -eu
+ version=$(git rev-parse --short HEAD)
+ echo "Publishing version: ${version} on release channel nightly"
+ echo "nightly" > crates/zed/RELEASE_CHANNEL
+ shell: bash -euxo pipefail {0}
- name: steps::setup_node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
@@ -172,100 +193,84 @@ jobs:
- name: steps::clear_target_dir_if_large
run: ./script/clear-target-dir-if-larger-than 300
shell: bash -euxo pipefail {0}
- - name: release_nightly::set_release_channel_to_nightly
- run: |
- set -eu
- version=$(git rev-parse --short HEAD)
- echo "Publishing version: ${version} on release channel nightly"
- echo "nightly" > crates/zed/RELEASE_CHANNEL
- shell: bash -euxo pipefail {0}
- - name: run_bundling::bundle_mac
+ - name: run_bundling::bundle_mac::bundle_mac
run: ./script/bundle-mac aarch64-apple-darwin
shell: bash -euxo pipefail {0}
- - name: release_nightly::upload_zed_nightly
- run: script/upload-nightly macos aarch64
- shell: bash -euxo pipefail {0}
+ - name: '@actions/upload-artifact Zed-aarch64.dmg'
+ uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
+ with:
+ name: Zed-aarch64.dmg
+ path: target/aarch64-apple-darwin/release/Zed-aarch64.dmg
+ if-no-files-found: error
+ - name: '@actions/upload-artifact zed-remote-server-macos-aarch64.gz'
+ uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
+ with:
+ name: zed-remote-server-macos-aarch64.gz
+ path: target/zed-remote-server-macos-aarch64.gz
+ if-no-files-found: error
timeout-minutes: 60
- bundle_linux_nightly_x86_64:
+ bundle_mac_x86_64:
needs:
- check_style
- - run_tests_mac
- if: github.repository_owner == 'zed-industries'
- runs-on: namespace-profile-32x64-ubuntu-2004
+ - run_tests_windows
+ runs-on: self-mini-macos
+ env:
+ CARGO_INCREMENTAL: 0
+ ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
+ ZED_MINIDUMP_ENDPOINT: ${{ secrets.ZED_SENTRY_MINIDUMP_ENDPOINT }}
+ MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
+ MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
+ APPLE_NOTARIZATION_KEY: ${{ secrets.APPLE_NOTARIZATION_KEY }}
+ APPLE_NOTARIZATION_KEY_ID: ${{ secrets.APPLE_NOTARIZATION_KEY_ID }}
+ APPLE_NOTARIZATION_ISSUER_ID: ${{ secrets.APPLE_NOTARIZATION_ISSUER_ID }}
steps:
- name: steps::checkout_repo
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
clean: false
- - name: steps::setup_sentry
- uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b
- with:
- token: ${{ secrets.SENTRY_AUTH_TOKEN }}
- - name: ./script/linux
- run: ./script/linux
- shell: bash -euxo pipefail {0}
- - name: ./script/install-mold
- run: ./script/install-mold
- shell: bash -euxo pipefail {0}
- - name: steps::clear_target_dir_if_large
- run: ./script/clear-target-dir-if-larger-than 100
- shell: bash -euxo pipefail {0}
- - name: release_nightly::set_release_channel_to_nightly
+ - name: run_bundling::set_release_channel_to_nightly
run: |
set -eu
version=$(git rev-parse --short HEAD)
echo "Publishing version: ${version} on release channel nightly"
echo "nightly" > crates/zed/RELEASE_CHANNEL
shell: bash -euxo pipefail {0}
- - name: ./script/bundle-linux
- run: ./script/bundle-linux
- shell: bash -euxo pipefail {0}
- - name: release_nightly::upload_zed_nightly
- run: script/upload-nightly linux-targz x86_64
- shell: bash -euxo pipefail {0}
- timeout-minutes: 60
- bundle_linux_nightly_aarch64:
- needs:
- - check_style
- - run_tests_mac
- if: github.repository_owner == 'zed-industries'
- runs-on: namespace-profile-8x32-ubuntu-2004-arm-m4
- steps:
- - name: steps::checkout_repo
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - name: steps::setup_node
+ uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
- clean: false
+ node-version: '20'
- name: steps::setup_sentry
uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b
with:
token: ${{ secrets.SENTRY_AUTH_TOKEN }}
- - name: ./script/linux
- run: ./script/linux
- shell: bash -euxo pipefail {0}
- name: steps::clear_target_dir_if_large
- run: ./script/clear-target-dir-if-larger-than 100
- shell: bash -euxo pipefail {0}
- - name: release_nightly::set_release_channel_to_nightly
- run: |
- set -eu
- version=$(git rev-parse --short HEAD)
- echo "Publishing version: ${version} on release channel nightly"
- echo "nightly" > crates/zed/RELEASE_CHANNEL
- shell: bash -euxo pipefail {0}
- - name: ./script/bundle-linux
- run: ./script/bundle-linux
+ run: ./script/clear-target-dir-if-larger-than 300
shell: bash -euxo pipefail {0}
- - name: release_nightly::upload_zed_nightly
- run: script/upload-nightly linux-targz aarch64
+ - name: run_bundling::bundle_mac::bundle_mac
+ run: ./script/bundle-mac x86_64-apple-darwin
shell: bash -euxo pipefail {0}
+ - name: '@actions/upload-artifact Zed-x86_64.dmg'
+ uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
+ with:
+ name: Zed-x86_64.dmg
+ path: target/x86_64-apple-darwin/release/Zed-x86_64.dmg
+ if-no-files-found: error
+ - name: '@actions/upload-artifact zed-remote-server-macos-x86_64.gz'
+ uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
+ with:
+ name: zed-remote-server-macos-x86_64.gz
+ path: target/zed-remote-server-macos-x86_64.gz
+ if-no-files-found: error
timeout-minutes: 60
- bundle_windows_nightly_x86_64:
+ bundle_windows_aarch64:
needs:
- check_style
- run_tests_windows
- if: github.repository_owner == 'zed-industries'
runs-on: self-32vcpu-windows-2022
env:
+ CARGO_INCREMENTAL: 0
+ ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
+ ZED_MINIDUMP_ENDPOINT: ${{ secrets.ZED_SENTRY_MINIDUMP_ENDPOINT }}
AZURE_TENANT_ID: ${{ secrets.AZURE_SIGNING_TENANT_ID }}
AZURE_CLIENT_ID: ${{ secrets.AZURE_SIGNING_CLIENT_ID }}
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_SIGNING_CLIENT_SECRET }}
@@ -280,11 +285,7 @@ jobs:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
clean: false
- - name: steps::setup_sentry
- uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b
- with:
- token: ${{ secrets.SENTRY_AUTH_TOKEN }}
- - name: release_nightly::set_release_channel_to_nightly
+ - name: run_bundling::set_release_channel_to_nightly
run: |
$ErrorActionPreference = "Stop"
$version = git rev-parse --short HEAD
@@ -292,22 +293,30 @@ jobs:
"nightly" | Set-Content -Path "crates/zed/RELEASE_CHANNEL"
shell: pwsh
working-directory: ${{ env.ZED_WORKSPACE }}
- - name: run_bundling::bundle_windows
- run: script/bundle-windows.ps1 -Architecture x86_64
- shell: pwsh
- working-directory: ${{ env.ZED_WORKSPACE }}
- - name: release_nightly::upload_zed_nightly
- run: script/upload-nightly.ps1 -Architecture x86_64
+ - name: steps::setup_sentry
+ uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b
+ with:
+ token: ${{ secrets.SENTRY_AUTH_TOKEN }}
+ - name: run_bundling::bundle_windows::bundle_windows
+ run: script/bundle-windows.ps1 -Architecture aarch64
shell: pwsh
working-directory: ${{ env.ZED_WORKSPACE }}
+ - name: '@actions/upload-artifact Zed-aarch64.exe'
+ uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
+ with:
+ name: Zed-aarch64.exe
+ path: target/Zed-aarch64.exe
+ if-no-files-found: error
timeout-minutes: 60
- bundle_windows_nightly_aarch64:
+ bundle_windows_x86_64:
needs:
- check_style
- run_tests_windows
- if: github.repository_owner == 'zed-industries'
runs-on: self-32vcpu-windows-2022
env:
+ CARGO_INCREMENTAL: 0
+ ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
+ ZED_MINIDUMP_ENDPOINT: ${{ secrets.ZED_SENTRY_MINIDUMP_ENDPOINT }}
AZURE_TENANT_ID: ${{ secrets.AZURE_SIGNING_TENANT_ID }}
AZURE_CLIENT_ID: ${{ secrets.AZURE_SIGNING_CLIENT_ID }}
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_SIGNING_CLIENT_SECRET }}
@@ -322,11 +331,7 @@ jobs:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
clean: false
- - name: steps::setup_sentry
- uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b
- with:
- token: ${{ secrets.SENTRY_AUTH_TOKEN }}
- - name: release_nightly::set_release_channel_to_nightly
+ - name: run_bundling::set_release_channel_to_nightly
run: |
$ErrorActionPreference = "Stop"
$version = git rev-parse --short HEAD
@@ -334,19 +339,25 @@ jobs:
"nightly" | Set-Content -Path "crates/zed/RELEASE_CHANNEL"
shell: pwsh
working-directory: ${{ env.ZED_WORKSPACE }}
- - name: run_bundling::bundle_windows
- run: script/bundle-windows.ps1 -Architecture aarch64
- shell: pwsh
- working-directory: ${{ env.ZED_WORKSPACE }}
- - name: release_nightly::upload_zed_nightly
- run: script/upload-nightly.ps1 -Architecture aarch64
+ - name: steps::setup_sentry
+ uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b
+ with:
+ token: ${{ secrets.SENTRY_AUTH_TOKEN }}
+ - name: run_bundling::bundle_windows::bundle_windows
+ run: script/bundle-windows.ps1 -Architecture x86_64
shell: pwsh
working-directory: ${{ env.ZED_WORKSPACE }}
+ - name: '@actions/upload-artifact Zed-x86_64.exe'
+ uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
+ with:
+ name: Zed-x86_64.exe
+ path: target/Zed-x86_64.exe
+ if-no-files-found: error
timeout-minutes: 60
build_nix_linux_x86_64:
needs:
- check_style
- - run_tests_mac
+ - run_tests_windows
if: github.repository_owner == 'zed-industries'
runs-on: namespace-profile-32x64-ubuntu-2004
env:
@@ -377,7 +388,7 @@ jobs:
build_nix_mac_aarch64:
needs:
- check_style
- - run_tests_mac
+ - run_tests_windows
if: github.repository_owner == 'zed-industries'
runs-on: self-mini-macos
env:
@@ -414,20 +425,48 @@ jobs:
continue-on-error: true
update_nightly_tag:
needs:
- - bundle_mac_nightly_x86_64
- - bundle_mac_nightly_aarch64
- - bundle_linux_nightly_x86_64
- - bundle_linux_nightly_aarch64
- - bundle_windows_nightly_x86_64
- - bundle_windows_nightly_aarch64
+ - bundle_linux_aarch64
+ - bundle_linux_x86_64
+ - bundle_mac_aarch64
+ - bundle_mac_x86_64
+ - bundle_windows_aarch64
+ - bundle_windows_x86_64
if: github.repository_owner == 'zed-industries'
- runs-on: namespace-profile-2x4-ubuntu-2404
+ runs-on: namespace-profile-4x8-ubuntu-2204
steps:
- name: steps::checkout_repo
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
clean: false
fetch-depth: 0
+ - name: release::download_workflow_artifacts
+ uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53
+ with:
+ path: ./artifacts/
+ - name: ls -lR ./artifacts
+ run: ls -lR ./artifacts
+ shell: bash -euxo pipefail {0}
+ - name: release::prep_release_artifacts
+ run: |-
+ mkdir -p release-artifacts/
+
+ mv ./artifacts/Zed-aarch64.dmg/Zed-aarch64.dmg release-artifacts/Zed-aarch64.dmg
+ mv ./artifacts/Zed-x86_64.dmg/Zed-x86_64.dmg release-artifacts/Zed-x86_64.dmg
+ mv ./artifacts/zed-linux-aarch64.tar.gz/zed-linux-aarch64.tar.gz release-artifacts/zed-linux-aarch64.tar.gz
+ mv ./artifacts/zed-linux-x86_64.tar.gz/zed-linux-x86_64.tar.gz release-artifacts/zed-linux-x86_64.tar.gz
+ mv ./artifacts/Zed-x86_64.exe/Zed-x86_64.exe release-artifacts/Zed-x86_64.exe
+ mv ./artifacts/Zed-aarch64.exe/Zed-aarch64.exe release-artifacts/Zed-aarch64.exe
+ mv ./artifacts/zed-remote-server-macos-aarch64.gz/zed-remote-server-macos-aarch64.gz release-artifacts/zed-remote-server-macos-aarch64.gz
+ mv ./artifacts/zed-remote-server-macos-x86_64.gz/zed-remote-server-macos-x86_64.gz release-artifacts/zed-remote-server-macos-x86_64.gz
+ mv ./artifacts/zed-remote-server-linux-aarch64.gz/zed-remote-server-linux-aarch64.gz release-artifacts/zed-remote-server-linux-aarch64.gz
+ mv ./artifacts/zed-remote-server-linux-x86_64.gz/zed-remote-server-linux-x86_64.gz release-artifacts/zed-remote-server-linux-x86_64.gz
+ shell: bash -euxo pipefail {0}
+ - name: ./script/upload-nightly
+ run: ./script/upload-nightly
+ shell: bash -euxo pipefail {0}
+ env:
+ DIGITALOCEAN_SPACES_ACCESS_KEY: ${{ secrets.DIGITALOCEAN_SPACES_ACCESS_KEY }}
+ DIGITALOCEAN_SPACES_SECRET_KEY: ${{ secrets.DIGITALOCEAN_SPACES_SECRET_KEY }}
- name: release_nightly::update_nightly_tag_job::update_nightly_tag
run: |
if [ "$(git rev-parse nightly)" = "$(git rev-parse HEAD)" ]; then
@@ -439,7 +478,7 @@ jobs:
git tag -f nightly
git push origin nightly --force
shell: bash -euxo pipefail {0}
- - name: release_nightly::update_nightly_tag_job::create_sentry_release
+ - name: release::create_sentry_release
uses: getsentry/action-release@526942b68292201ac6bbb99b9a0747d4abee354c
with:
environment: production
diff --git a/.github/workflows/run_agent_evals.yml b/.github/workflows/run_agent_evals.yml
new file mode 100644
index 0000000000000000000000000000000000000000..fa686148590785f1ba93501ecd873d19af6bcb2b
--- /dev/null
+++ b/.github/workflows/run_agent_evals.yml
@@ -0,0 +1,62 @@
+# Generated from xtask::workflows::run_agent_evals
+# Rebuild with `cargo xtask workflows`.
+name: run_agent_evals
+env:
+ CARGO_TERM_COLOR: always
+ CARGO_INCREMENTAL: '0'
+ RUST_BACKTRACE: '1'
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
+ ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
+ ZED_EVAL_TELEMETRY: '1'
+on:
+ pull_request:
+ types:
+ - synchronize
+ - reopened
+ - labeled
+ branches:
+ - '**'
+ schedule:
+ - cron: 0 0 * * *
+ workflow_dispatch: {}
+jobs:
+ agent_evals:
+ if: |
+ github.repository_owner == 'zed-industries' &&
+ (github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'run-eval'))
+ runs-on: namespace-profile-16x32-ubuntu-2204
+ steps:
+ - name: steps::checkout_repo
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ with:
+ clean: false
+ - name: steps::cache_rust_dependencies_namespace
+ uses: namespacelabs/nscloud-cache-action@v1
+ with:
+ cache: rust
+ - name: steps::setup_linux
+ run: ./script/linux
+ shell: bash -euxo pipefail {0}
+ - name: steps::install_mold
+ run: ./script/install-mold
+ shell: bash -euxo pipefail {0}
+ - name: steps::setup_cargo_config
+ run: |
+ mkdir -p ./../.cargo
+ cp ./.cargo/ci-config.toml ./../.cargo/config.toml
+ shell: bash -euxo pipefail {0}
+ - name: cargo build --package=eval
+ run: cargo build --package=eval
+ shell: bash -euxo pipefail {0}
+ - name: run_agent_evals::agent_evals::run_eval
+ run: cargo run --package=eval -- --repetitions=8 --concurrency=1
+ shell: bash -euxo pipefail {0}
+ - name: steps::cleanup_cargo_config
+ if: always()
+ run: |
+ rm -rf ./../.cargo
+ shell: bash -euxo pipefail {0}
+ timeout-minutes: 60
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.ref_name == 'main' && github.sha || 'anysha' }}
+ cancel-in-progress: true
diff --git a/.github/workflows/run_bundling.yml b/.github/workflows/run_bundling.yml
index a6d563b5b12faa2d5f2cf03b644cfcacbdd17400..5cf10d11f3f9444c9b57f594897dbfa0e435f0b4 100644
--- a/.github/workflows/run_bundling.yml
+++ b/.github/workflows/run_bundling.yml
@@ -3,192 +3,194 @@
name: run_bundling
env:
CARGO_TERM_COLOR: always
- CARGO_INCREMENTAL: '0'
RUST_BACKTRACE: '1'
- ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
- ZED_MINIDUMP_ENDPOINT: ${{ secrets.ZED_SENTRY_MINIDUMP_ENDPOINT }}
on:
pull_request:
types:
- labeled
- synchronize
jobs:
- bundle_mac_x86_64:
+ bundle_linux_aarch64:
if: |-
(github.event.action == 'labeled' && github.event.label.name == 'run-bundling') ||
(github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'run-bundling'))
- runs-on: self-mini-macos
+ runs-on: namespace-profile-8x32-ubuntu-2004-arm-m4
env:
- MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
- MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
- APPLE_NOTARIZATION_KEY: ${{ secrets.APPLE_NOTARIZATION_KEY }}
- APPLE_NOTARIZATION_KEY_ID: ${{ secrets.APPLE_NOTARIZATION_KEY_ID }}
- APPLE_NOTARIZATION_ISSUER_ID: ${{ secrets.APPLE_NOTARIZATION_ISSUER_ID }}
+ CARGO_INCREMENTAL: 0
+ ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
+ ZED_MINIDUMP_ENDPOINT: ${{ secrets.ZED_SENTRY_MINIDUMP_ENDPOINT }}
steps:
- name: steps::checkout_repo
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
clean: false
- - name: steps::setup_node
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
- with:
- node-version: '20'
- name: steps::setup_sentry
uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b
with:
token: ${{ secrets.SENTRY_AUTH_TOKEN }}
- - name: steps::clear_target_dir_if_large
- run: ./script/clear-target-dir-if-larger-than 300
+ - name: steps::setup_linux
+ run: ./script/linux
shell: bash -euxo pipefail {0}
- - name: run_bundling::bundle_mac
- run: ./script/bundle-mac x86_64-apple-darwin
+ - name: steps::install_mold
+ run: ./script/install-mold
shell: bash -euxo pipefail {0}
- - name: '@actions/upload-artifact Zed_${{ github.event.pull_request.head.sha || github.sha }}-x86_64.dmg'
+ - name: ./script/bundle-linux
+ run: ./script/bundle-linux
+ shell: bash -euxo pipefail {0}
+ - name: '@actions/upload-artifact zed-linux-aarch64.tar.gz'
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
with:
- name: Zed_${{ github.event.pull_request.head.sha || github.sha }}-x86_64.dmg
- path: target/x86_64-apple-darwin/release/Zed.dmg
+ name: zed-linux-aarch64.tar.gz
+ path: target/release/zed-linux-aarch64.tar.gz
if-no-files-found: error
- - name: '@actions/upload-artifact zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-macos-x86_64.gz'
+ - name: '@actions/upload-artifact zed-remote-server-linux-aarch64.gz'
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
with:
- name: zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-macos-x86_64.gz
- path: target/zed-remote-server-macos-x86_64.gz
+ name: zed-remote-server-linux-aarch64.gz
+ path: target/zed-remote-server-linux-aarch64.gz
if-no-files-found: error
- outputs:
- zed: Zed_${{ github.event.pull_request.head.sha || github.sha }}-x86_64.dmg
- remote-server: zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-macos-x86_64.gz
timeout-minutes: 60
- bundle_mac_arm64:
+ bundle_linux_x86_64:
if: |-
(github.event.action == 'labeled' && github.event.label.name == 'run-bundling') ||
(github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'run-bundling'))
- runs-on: self-mini-macos
+ runs-on: namespace-profile-32x64-ubuntu-2004
env:
- MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
- MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
- APPLE_NOTARIZATION_KEY: ${{ secrets.APPLE_NOTARIZATION_KEY }}
- APPLE_NOTARIZATION_KEY_ID: ${{ secrets.APPLE_NOTARIZATION_KEY_ID }}
- APPLE_NOTARIZATION_ISSUER_ID: ${{ secrets.APPLE_NOTARIZATION_ISSUER_ID }}
+ CARGO_INCREMENTAL: 0
+ ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
+ ZED_MINIDUMP_ENDPOINT: ${{ secrets.ZED_SENTRY_MINIDUMP_ENDPOINT }}
steps:
- name: steps::checkout_repo
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
clean: false
- - name: steps::setup_node
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
- with:
- node-version: '20'
- name: steps::setup_sentry
uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b
with:
token: ${{ secrets.SENTRY_AUTH_TOKEN }}
- - name: steps::clear_target_dir_if_large
- run: ./script/clear-target-dir-if-larger-than 300
+ - name: steps::setup_linux
+ run: ./script/linux
shell: bash -euxo pipefail {0}
- - name: run_bundling::bundle_mac
- run: ./script/bundle-mac aarch64-apple-darwin
+ - name: steps::install_mold
+ run: ./script/install-mold
+ shell: bash -euxo pipefail {0}
+ - name: ./script/bundle-linux
+ run: ./script/bundle-linux
shell: bash -euxo pipefail {0}
- - name: '@actions/upload-artifact Zed_${{ github.event.pull_request.head.sha || github.sha }}-aarch64.dmg'
+ - name: '@actions/upload-artifact zed-linux-x86_64.tar.gz'
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
with:
- name: Zed_${{ github.event.pull_request.head.sha || github.sha }}-aarch64.dmg
- path: target/aarch64-apple-darwin/release/Zed.dmg
+ name: zed-linux-x86_64.tar.gz
+ path: target/release/zed-linux-x86_64.tar.gz
if-no-files-found: error
- - name: '@actions/upload-artifact zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-macos-aarch64.gz'
+ - name: '@actions/upload-artifact zed-remote-server-linux-x86_64.gz'
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
with:
- name: zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-macos-aarch64.gz
- path: target/zed-remote-server-macos-aarch64.gz
+ name: zed-remote-server-linux-x86_64.gz
+ path: target/zed-remote-server-linux-x86_64.gz
if-no-files-found: error
- outputs:
- zed: Zed_${{ github.event.pull_request.head.sha || github.sha }}-aarch64.dmg
- remote-server: zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-macos-aarch64.gz
timeout-minutes: 60
- bundle_linux_x86_64:
+ bundle_mac_aarch64:
if: |-
(github.event.action == 'labeled' && github.event.label.name == 'run-bundling') ||
(github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'run-bundling'))
- runs-on: namespace-profile-32x64-ubuntu-2004
+ runs-on: self-mini-macos
+ env:
+ CARGO_INCREMENTAL: 0
+ ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
+ ZED_MINIDUMP_ENDPOINT: ${{ secrets.ZED_SENTRY_MINIDUMP_ENDPOINT }}
+ MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
+ MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
+ APPLE_NOTARIZATION_KEY: ${{ secrets.APPLE_NOTARIZATION_KEY }}
+ APPLE_NOTARIZATION_KEY_ID: ${{ secrets.APPLE_NOTARIZATION_KEY_ID }}
+ APPLE_NOTARIZATION_ISSUER_ID: ${{ secrets.APPLE_NOTARIZATION_ISSUER_ID }}
steps:
- name: steps::checkout_repo
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
clean: false
+ - name: steps::setup_node
+ uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
+ with:
+ node-version: '20'
- name: steps::setup_sentry
uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b
with:
token: ${{ secrets.SENTRY_AUTH_TOKEN }}
- - name: steps::setup_linux
- run: ./script/linux
- shell: bash -euxo pipefail {0}
- - name: steps::install_mold
- run: ./script/install-mold
+ - name: steps::clear_target_dir_if_large
+ run: ./script/clear-target-dir-if-larger-than 300
shell: bash -euxo pipefail {0}
- - name: ./script/bundle-linux
- run: ./script/bundle-linux
+ - name: run_bundling::bundle_mac::bundle_mac
+ run: ./script/bundle-mac aarch64-apple-darwin
shell: bash -euxo pipefail {0}
- - name: '@actions/upload-artifact zed-${{ github.event.pull_request.head.sha || github.sha }}-x86_64-unknown-linux-gnu.tar.gz'
+ - name: '@actions/upload-artifact Zed-aarch64.dmg'
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
with:
- name: zed-${{ github.event.pull_request.head.sha || github.sha }}-x86_64-unknown-linux-gnu.tar.gz
- path: target/release/zed-*.tar.gz
+ name: Zed-aarch64.dmg
+ path: target/aarch64-apple-darwin/release/Zed-aarch64.dmg
if-no-files-found: error
- - name: '@actions/upload-artifact zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-x86_64-unknown-linux-gnu.tar.gz'
+ - name: '@actions/upload-artifact zed-remote-server-macos-aarch64.gz'
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
with:
- name: zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-x86_64-unknown-linux-gnu.tar.gz
- path: target/zed-remote-server-*.gz
+ name: zed-remote-server-macos-aarch64.gz
+ path: target/zed-remote-server-macos-aarch64.gz
if-no-files-found: error
- outputs:
- zed: zed-${{ github.event.pull_request.head.sha || github.sha }}-x86_64-unknown-linux-gnu.tar.gz
- remote-server: zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-x86_64-unknown-linux-gnu.tar.gz
timeout-minutes: 60
- bundle_linux_arm64:
+ bundle_mac_x86_64:
if: |-
(github.event.action == 'labeled' && github.event.label.name == 'run-bundling') ||
(github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'run-bundling'))
- runs-on: namespace-profile-8x32-ubuntu-2004-arm-m4
+ runs-on: self-mini-macos
+ env:
+ CARGO_INCREMENTAL: 0
+ ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
+ ZED_MINIDUMP_ENDPOINT: ${{ secrets.ZED_SENTRY_MINIDUMP_ENDPOINT }}
+ MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
+ MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
+ APPLE_NOTARIZATION_KEY: ${{ secrets.APPLE_NOTARIZATION_KEY }}
+ APPLE_NOTARIZATION_KEY_ID: ${{ secrets.APPLE_NOTARIZATION_KEY_ID }}
+ APPLE_NOTARIZATION_ISSUER_ID: ${{ secrets.APPLE_NOTARIZATION_ISSUER_ID }}
steps:
- name: steps::checkout_repo
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
clean: false
+ - name: steps::setup_node
+ uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
+ with:
+ node-version: '20'
- name: steps::setup_sentry
uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b
with:
token: ${{ secrets.SENTRY_AUTH_TOKEN }}
- - name: steps::setup_linux
- run: ./script/linux
- shell: bash -euxo pipefail {0}
- - name: steps::install_mold
- run: ./script/install-mold
+ - name: steps::clear_target_dir_if_large
+ run: ./script/clear-target-dir-if-larger-than 300
shell: bash -euxo pipefail {0}
- - name: ./script/bundle-linux
- run: ./script/bundle-linux
+ - name: run_bundling::bundle_mac::bundle_mac
+ run: ./script/bundle-mac x86_64-apple-darwin
shell: bash -euxo pipefail {0}
- - name: '@actions/upload-artifact zed-${{ github.event.pull_request.head.sha || github.sha }}-aarch64-unknown-linux-gnu.tar.gz'
+ - name: '@actions/upload-artifact Zed-x86_64.dmg'
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
with:
- name: zed-${{ github.event.pull_request.head.sha || github.sha }}-aarch64-unknown-linux-gnu.tar.gz
- path: target/release/zed-*.tar.gz
+ name: Zed-x86_64.dmg
+ path: target/x86_64-apple-darwin/release/Zed-x86_64.dmg
if-no-files-found: error
- - name: '@actions/upload-artifact zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-aarch64-unknown-linux-gnu.tar.gz'
+ - name: '@actions/upload-artifact zed-remote-server-macos-x86_64.gz'
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
with:
- name: zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-aarch64-unknown-linux-gnu.tar.gz
- path: target/zed-remote-server-*.gz
+ name: zed-remote-server-macos-x86_64.gz
+ path: target/zed-remote-server-macos-x86_64.gz
if-no-files-found: error
- outputs:
- zed: zed-${{ github.event.pull_request.head.sha || github.sha }}-aarch64-unknown-linux-gnu.tar.gz
- remote-server: zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-aarch64-unknown-linux-gnu.tar.gz
timeout-minutes: 60
- bundle_windows_x86_64:
+ bundle_windows_aarch64:
if: |-
(github.event.action == 'labeled' && github.event.label.name == 'run-bundling') ||
(github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'run-bundling'))
runs-on: self-32vcpu-windows-2022
env:
+ CARGO_INCREMENTAL: 0
+ ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
+ ZED_MINIDUMP_ENDPOINT: ${{ secrets.ZED_SENTRY_MINIDUMP_ENDPOINT }}
AZURE_TENANT_ID: ${{ secrets.AZURE_SIGNING_TENANT_ID }}
AZURE_CLIENT_ID: ${{ secrets.AZURE_SIGNING_CLIENT_ID }}
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_SIGNING_CLIENT_SECRET }}
@@ -207,25 +209,26 @@ jobs:
uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b
with:
token: ${{ secrets.SENTRY_AUTH_TOKEN }}
- - name: run_bundling::bundle_windows
- run: script/bundle-windows.ps1 -Architecture x86_64
+ - name: run_bundling::bundle_windows::bundle_windows
+ run: script/bundle-windows.ps1 -Architecture aarch64
shell: pwsh
working-directory: ${{ env.ZED_WORKSPACE }}
- - name: '@actions/upload-artifact Zed_${{ github.event.pull_request.head.sha || github.sha }}-x86_64.exe'
+ - name: '@actions/upload-artifact Zed-aarch64.exe'
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
with:
- name: Zed_${{ github.event.pull_request.head.sha || github.sha }}-x86_64.exe
- path: ${{ env.SETUP_PATH }}
+ name: Zed-aarch64.exe
+ path: target/Zed-aarch64.exe
if-no-files-found: error
- outputs:
- zed: Zed_${{ github.event.pull_request.head.sha || github.sha }}-x86_64.exe
timeout-minutes: 60
- bundle_windows_arm64:
+ bundle_windows_x86_64:
if: |-
(github.event.action == 'labeled' && github.event.label.name == 'run-bundling') ||
(github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, 'run-bundling'))
runs-on: self-32vcpu-windows-2022
env:
+ CARGO_INCREMENTAL: 0
+ ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
+ ZED_MINIDUMP_ENDPOINT: ${{ secrets.ZED_SENTRY_MINIDUMP_ENDPOINT }}
AZURE_TENANT_ID: ${{ secrets.AZURE_SIGNING_TENANT_ID }}
AZURE_CLIENT_ID: ${{ secrets.AZURE_SIGNING_CLIENT_ID }}
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_SIGNING_CLIENT_SECRET }}
@@ -244,18 +247,16 @@ jobs:
uses: matbour/setup-sentry-cli@3e938c54b3018bdd019973689ef984e033b0454b
with:
token: ${{ secrets.SENTRY_AUTH_TOKEN }}
- - name: run_bundling::bundle_windows
- run: script/bundle-windows.ps1 -Architecture aarch64
+ - name: run_bundling::bundle_windows::bundle_windows
+ run: script/bundle-windows.ps1 -Architecture x86_64
shell: pwsh
working-directory: ${{ env.ZED_WORKSPACE }}
- - name: '@actions/upload-artifact Zed_${{ github.event.pull_request.head.sha || github.sha }}-aarch64.exe'
+ - name: '@actions/upload-artifact Zed-x86_64.exe'
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4
with:
- name: Zed_${{ github.event.pull_request.head.sha || github.sha }}-aarch64.exe
- path: ${{ env.SETUP_PATH }}
+ name: Zed-x86_64.exe
+ path: target/Zed-x86_64.exe
if-no-files-found: error
- outputs:
- zed: Zed_${{ github.event.pull_request.head.sha || github.sha }}-aarch64.exe
timeout-minutes: 60
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml
index 51ff9ee331ca69b251bb00905e22213527cbf118..002044580a89bb9d894237fa490cca2b8d9d438f 100644
--- a/.github/workflows/run_tests.yml
+++ b/.github/workflows/run_tests.yml
@@ -66,6 +66,10 @@ jobs:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
clean: false
+ - name: steps::cache_rust_dependencies_namespace
+ uses: namespacelabs/nscloud-cache-action@v1
+ with:
+ cache: rust
- name: steps::setup_pnpm
uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2
with:
@@ -145,6 +149,10 @@ jobs:
- name: steps::install_mold
run: ./script/install-mold
shell: bash -euxo pipefail {0}
+ - name: steps::cache_rust_dependencies_namespace
+ uses: namespacelabs/nscloud-cache-action@v1
+ with:
+ cache: rust
- name: steps::setup_node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
@@ -156,7 +164,7 @@ jobs:
run: cargo install cargo-nextest --locked
shell: bash -euxo pipefail {0}
- name: steps::clear_target_dir_if_large
- run: ./script/clear-target-dir-if-larger-than 100
+ run: ./script/clear-target-dir-if-larger-than 250
shell: bash -euxo pipefail {0}
- name: steps::cargo_nextest
run: cargo nextest run --workspace --no-fail-fast --failure-output immediate-final
@@ -214,10 +222,10 @@ jobs:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
clean: false
- - name: steps::cache_rust_dependencies
- uses: swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6
+ - name: steps::cache_rust_dependencies_namespace
+ uses: namespacelabs/nscloud-cache-action@v1
with:
- save-if: ${{ github.ref == 'refs/heads/main' }}
+ cache: rust
- name: steps::setup_linux
run: ./script/linux
shell: bash -euxo pipefail {0}
@@ -261,6 +269,10 @@ jobs:
- name: steps::install_mold
run: ./script/install-mold
shell: bash -euxo pipefail {0}
+ - name: steps::cache_rust_dependencies_namespace
+ uses: namespacelabs/nscloud-cache-action@v1
+ with:
+ cache: rust
- name: cargo build -p collab
run: cargo build -p collab
shell: bash -euxo pipefail {0}
@@ -317,6 +329,10 @@ jobs:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
clean: false
+ - name: steps::cache_rust_dependencies_namespace
+ uses: namespacelabs/nscloud-cache-action@v1
+ with:
+ cache: rust
- name: run_tests::check_dependencies::install_cargo_machete
uses: clechasseur/rs-cargo@8435b10f6e71c2e3d4d3b7573003a8ce4bfc6386
with:
@@ -350,10 +366,10 @@ jobs:
mkdir -p ./../.cargo
cp ./.cargo/ci-config.toml ./../.cargo/config.toml
shell: bash -euxo pipefail {0}
- - name: steps::cache_rust_dependencies
- uses: swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6
+ - name: steps::cache_rust_dependencies_namespace
+ uses: namespacelabs/nscloud-cache-action@v1
with:
- save-if: ${{ github.ref == 'refs/heads/main' }}
+ cache: rust
- name: run_tests::check_docs::lychee_link_check
uses: lycheeverse/lychee-action@82202e5e9c2f4ef1a55a3d02563e1cb6041e5332
with:
@@ -392,6 +408,10 @@ jobs:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
clean: false
+ - name: steps::cache_rust_dependencies_namespace
+ uses: namespacelabs/nscloud-cache-action@v1
+ with:
+ cache: rust
- name: ./script/check-licenses
run: ./script/check-licenses
shell: bash -euxo pipefail {0}
diff --git a/.github/workflows/run_unit_evals.yml b/.github/workflows/run_unit_evals.yml
new file mode 100644
index 0000000000000000000000000000000000000000..e4a22c3f164b78699e36ea55854731f4657c3c79
--- /dev/null
+++ b/.github/workflows/run_unit_evals.yml
@@ -0,0 +1,63 @@
+# Generated from xtask::workflows::run_agent_evals
+# Rebuild with `cargo xtask workflows`.
+name: run_agent_evals
+env:
+ CARGO_TERM_COLOR: always
+ CARGO_INCREMENTAL: '0'
+ RUST_BACKTRACE: '1'
+ ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
+on:
+ schedule:
+ - cron: 47 1 * * 2
+ workflow_dispatch: {}
+jobs:
+ unit_evals:
+ runs-on: namespace-profile-16x32-ubuntu-2204
+ steps:
+ - name: steps::checkout_repo
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ with:
+ clean: false
+ - name: steps::setup_cargo_config
+ run: |
+ mkdir -p ./../.cargo
+ cp ./.cargo/ci-config.toml ./../.cargo/config.toml
+ shell: bash -euxo pipefail {0}
+ - name: steps::cache_rust_dependencies_namespace
+ uses: namespacelabs/nscloud-cache-action@v1
+ with:
+ cache: rust
+ - name: steps::setup_linux
+ run: ./script/linux
+ shell: bash -euxo pipefail {0}
+ - name: steps::install_mold
+ run: ./script/install-mold
+ shell: bash -euxo pipefail {0}
+ - name: steps::cargo_install_nextest
+ run: cargo install cargo-nextest --locked
+ shell: bash -euxo pipefail {0}
+ - name: steps::clear_target_dir_if_large
+ run: ./script/clear-target-dir-if-larger-than 250
+ shell: bash -euxo pipefail {0}
+ - name: ./script/run-unit-evals
+ run: ./script/run-unit-evals
+ shell: bash -euxo pipefail {0}
+ env:
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
+ - name: run_agent_evals::unit_evals::send_failure_to_slack
+ if: ${{ failure() }}
+ uses: slackapi/slack-github-action@b0fa283ad8fea605de13dc3f449259339835fc52
+ with:
+ method: chat.postMessage
+ token: ${{ secrets.SLACK_APP_ZED_UNIT_EVALS_BOT_TOKEN }}
+ payload: |
+ channel: C04UDRNNJFQ
+ text: "Unit Evals Failed: https://github.com/zed-industries/zed/actions/runs/${{ github.run_id }}"
+ - name: steps::cleanup_cargo_config
+ if: always()
+ run: |
+ rm -rf ./../.cargo
+ shell: bash -euxo pipefail {0}
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.ref_name == 'main' && github.sha || 'anysha' }}
+ cancel-in-progress: true
diff --git a/.github/workflows/unit_evals.yml b/.github/workflows/unit_evals.yml
deleted file mode 100644
index 53ed33a1af300d6b641b3b9430de0bb6846b27cc..0000000000000000000000000000000000000000
--- a/.github/workflows/unit_evals.yml
+++ /dev/null
@@ -1,86 +0,0 @@
-name: Run Unit Evals
-
-on:
- schedule:
- # GitHub might drop jobs at busy times, so we choose a random time in the middle of the night.
- - cron: "47 1 * * 2"
- workflow_dispatch:
-
-concurrency:
- # Allow only one workflow per any non-`main` branch.
- group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.ref_name == 'main' && github.sha || 'anysha' }}
- cancel-in-progress: true
-
-env:
- CARGO_TERM_COLOR: always
- CARGO_INCREMENTAL: 0
- RUST_BACKTRACE: 1
- ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
-
-jobs:
- unit_evals:
- if: github.repository_owner == 'zed-industries'
- timeout-minutes: 60
- name: Run unit evals
- runs-on:
- - namespace-profile-16x32-ubuntu-2204
- steps:
- - name: Add Rust to the PATH
- run: echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
-
- - name: Checkout repo
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- with:
- clean: false
-
- - name: Cache dependencies
- uses: swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2
- with:
- save-if: ${{ github.ref == 'refs/heads/main' }}
- # cache-provider: "buildjet"
-
- - name: Install Linux dependencies
- run: ./script/linux
-
- - name: Configure CI
- run: |
- mkdir -p ./../.cargo
- cp ./.cargo/ci-config.toml ./../.cargo/config.toml
-
- - name: Install Rust
- shell: bash -euxo pipefail {0}
- run: |
- cargo install cargo-nextest --locked
-
- - name: Install Node
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
- with:
- node-version: "18"
-
- - name: Limit target directory size
- shell: bash -euxo pipefail {0}
- run: script/clear-target-dir-if-larger-than 100
-
- - name: Run unit evals
- shell: bash -euxo pipefail {0}
- run: cargo nextest run --workspace --no-fail-fast --features unit-eval --no-capture -E 'test(::eval_)'
- env:
- ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
-
- - name: Send failure message to Slack channel if needed
- if: ${{ failure() }}
- uses: slackapi/slack-github-action@b0fa283ad8fea605de13dc3f449259339835fc52
- with:
- method: chat.postMessage
- token: ${{ secrets.SLACK_APP_ZED_UNIT_EVALS_BOT_TOKEN }}
- payload: |
- channel: C04UDRNNJFQ
- text: "Unit Evals Failed: https://github.com/zed-industries/zed/actions/runs/${{ github.run_id }}"
-
- # Even the Linux runner is not stateful, in theory there is no need to do this cleanup.
- # But, to avoid potential issues in the future if we choose to use a stateful Linux runner and forget to add code
- # to clean up the config file, I’ve included the cleanup code here as a precaution.
- # While it’s not strictly necessary at this moment, I believe it’s better to err on the side of caution.
- - name: Clean CI config file
- if: always()
- run: rm -rf ./../.cargo
diff --git a/Cargo.lock b/Cargo.lock
index 71bc1406166d7468b9f8ad684d68befb5c5ac06b..0ae2b1697a9f6ddbb76e0b26a60199b6af538610 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1339,6 +1339,7 @@ dependencies = [
"settings",
"smol",
"tempfile",
+ "util",
"which 6.0.3",
"workspace",
]
@@ -4935,6 +4936,7 @@ dependencies = [
"editor",
"gpui",
"indoc",
+ "itertools 0.14.0",
"language",
"log",
"lsp",
@@ -7077,6 +7079,7 @@ dependencies = [
"serde_json",
"settings",
"url",
+ "urlencoding",
"util",
]
@@ -12714,12 +12717,6 @@ version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5da3b0203fd7ee5720aa0b5e790b591aa5d3f41c3ed2c34a3a393382198af2f7"
-[[package]]
-name = "pollster"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3"
-
[[package]]
name = "portable-atomic"
version = "1.11.1"
@@ -12768,7 +12765,7 @@ dependencies = [
"log",
"parking_lot",
"pin-project",
- "pollster 0.2.5",
+ "pollster",
"static_assertions",
"thiserror 1.0.69",
]
@@ -14320,6 +14317,7 @@ dependencies = [
"gpui",
"log",
"rand 0.9.2",
+ "rayon",
"sum_tree",
"unicode-segmentation",
"util",
@@ -16245,7 +16243,6 @@ checksum = "2b2231b7c3057d5e4ad0156fb3dc807d900806020c5ffa3ee6ff2c8c76fb8520"
name = "streaming_diff"
version = "0.1.0"
dependencies = [
- "gpui",
"ordered-float 2.10.1",
"rand 0.9.2",
"rope",
@@ -16364,11 +16361,9 @@ version = "0.1.0"
dependencies = [
"arrayvec",
"ctor",
- "futures 0.3.31",
- "itertools 0.14.0",
"log",
- "pollster 0.4.0",
"rand 0.9.2",
+ "rayon",
"zlog",
]
@@ -18053,7 +18048,7 @@ dependencies = [
[[package]]
name = "tree-sitter-gomod"
version = "1.1.1"
-source = "git+https://github.com/camdencheek/tree-sitter-go-mod?rev=6efb59652d30e0e9cd5f3b3a669afd6f1a926d3c#6efb59652d30e0e9cd5f3b3a669afd6f1a926d3c"
+source = "git+https://github.com/camdencheek/tree-sitter-go-mod?rev=2e886870578eeba1927a2dc4bd2e2b3f598c5f9a#2e886870578eeba1927a2dc4bd2e2b3f598c5f9a"
dependencies = [
"cc",
"tree-sitter-language",
@@ -21231,6 +21226,7 @@ dependencies = [
"project_symbols",
"prompt_store",
"proto",
+ "rayon",
"recent_projects",
"release_channel",
"remote",
diff --git a/Cargo.toml b/Cargo.toml
index 369082ff16736f9f682ad8c5bd09634c03434609..7674b0bacc12e9f9ae78a3f299dc0f538e26bd35 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -680,7 +680,7 @@ tree-sitter-elixir = "0.3"
tree-sitter-embedded-template = "0.23.0"
tree-sitter-gitcommit = { git = "https://github.com/zed-industries/tree-sitter-git-commit", rev = "88309716a69dd13ab83443721ba6e0b491d37ee9" }
tree-sitter-go = "0.23"
-tree-sitter-go-mod = { git = "https://github.com/camdencheek/tree-sitter-go-mod", rev = "6efb59652d30e0e9cd5f3b3a669afd6f1a926d3c", package = "tree-sitter-gomod" }
+tree-sitter-go-mod = { git = "https://github.com/camdencheek/tree-sitter-go-mod", rev = "2e886870578eeba1927a2dc4bd2e2b3f598c5f9a", package = "tree-sitter-gomod" }
tree-sitter-gowork = { git = "https://github.com/zed-industries/tree-sitter-go-work", rev = "acb0617bf7f4fda02c6217676cc64acb89536dc7" }
tree-sitter-heex = { git = "https://github.com/zed-industries/tree-sitter-heex", rev = "1dd45142fbb05562e35b2040c6129c9bca346592" }
tree-sitter-html = "0.23"
diff --git a/assets/icons/chevron_down_up.svg b/assets/icons/chevron_down_up.svg
new file mode 100644
index 0000000000000000000000000000000000000000..340b8d1ad93113a1affe5c723c9b5f5e12a228a8
--- /dev/null
+++ b/assets/icons/chevron_down_up.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/keymaps/default-linux.json b/assets/keymaps/default-linux.json
index 979e5a6ccc1d4520db65981fb3b8a01094f9c625..6f57e6f689a30543ee0b7d6b95d451af885d502a 100644
--- a/assets/keymaps/default-linux.json
+++ b/assets/keymaps/default-linux.json
@@ -407,6 +407,7 @@
"bindings": {
"escape": "project_search::ToggleFocus",
"shift-find": "search::FocusSearch",
+ "shift-enter": "project_search::ToggleAllSearchResults",
"ctrl-shift-f": "search::FocusSearch",
"ctrl-shift-h": "search::ToggleReplace",
"alt-ctrl-g": "search::ToggleRegex",
@@ -479,6 +480,7 @@
"alt-w": "search::ToggleWholeWord",
"alt-find": "project_search::ToggleFilters",
"alt-ctrl-f": "project_search::ToggleFilters",
+ "shift-enter": "project_search::ToggleAllSearchResults",
"ctrl-alt-shift-r": "search::ToggleRegex",
"ctrl-alt-shift-x": "search::ToggleRegex",
"alt-r": "search::ToggleRegex",
diff --git a/assets/keymaps/default-macos.json b/assets/keymaps/default-macos.json
index 4f9b85ff03790a8c9a59a657a3e0ca0710d41e25..a1d38b6028f8ec7690f7133b765ffdbb8d261f17 100644
--- a/assets/keymaps/default-macos.json
+++ b/assets/keymaps/default-macos.json
@@ -468,6 +468,7 @@
"bindings": {
"escape": "project_search::ToggleFocus",
"cmd-shift-j": "project_search::ToggleFilters",
+ "shift-enter": "project_search::ToggleAllSearchResults",
"cmd-shift-f": "search::FocusSearch",
"cmd-shift-h": "search::ToggleReplace",
"alt-cmd-g": "search::ToggleRegex",
@@ -496,6 +497,7 @@
"bindings": {
"escape": "project_search::ToggleFocus",
"cmd-shift-j": "project_search::ToggleFilters",
+ "shift-enter": "project_search::ToggleAllSearchResults",
"cmd-shift-h": "search::ToggleReplace",
"alt-cmd-g": "search::ToggleRegex",
"alt-cmd-x": "search::ToggleRegex"
diff --git a/assets/keymaps/default-windows.json b/assets/keymaps/default-windows.json
index 29146f3080d6ecad75bb9754503bb93c6710ff30..2dd72845b196c029bb2c575bcdd07b5ef07ae970 100644
--- a/assets/keymaps/default-windows.json
+++ b/assets/keymaps/default-windows.json
@@ -488,6 +488,7 @@
"alt-c": "search::ToggleCaseSensitive",
"alt-w": "search::ToggleWholeWord",
"alt-f": "project_search::ToggleFilters",
+ "shift-enter": "project_search::ToggleAllSearchResults",
"alt-r": "search::ToggleRegex",
// "ctrl-shift-alt-x": "search::ToggleRegex",
"ctrl-k shift-enter": "pane::TogglePinTab"
diff --git a/assets/settings/default.json b/assets/settings/default.json
index f62cc1844732db2a49dc835a155e861f4268632f..1852ace708c53f6a651420b77d7e83f9afc978c3 100644
--- a/assets/settings/default.json
+++ b/assets/settings/default.json
@@ -255,6 +255,19 @@
// Whether to display inline and alongside documentation for items in the
// completions menu
"show_completion_documentation": true,
+ // When to show the scrollbar in the completion menu.
+ // This setting can take four values:
+ //
+ // 1. Show the scrollbar if there's important information or
+ // follow the system's configured behavior
+ // "auto"
+ // 2. Match the system's configured behavior:
+ // "system"
+ // 3. Always show the scrollbar:
+ // "always"
+ // 4. Never show the scrollbar:
+ // "never" (default)
+ "completion_menu_scrollbar": "never",
// Show method signatures in the editor, when inside parentheses.
"auto_signature_help": false,
// Whether to show the signature help after completion or a bracket pair inserted.
@@ -602,7 +615,9 @@
"whole_word": false,
"case_sensitive": false,
"include_ignored": false,
- "regex": false
+ "regex": false,
+ // Whether to center the cursor on each search match when navigating.
+ "center_on_match": false
},
// When to populate a new search's query based on the text under the cursor.
// This setting can take the following three values:
@@ -1719,6 +1734,9 @@
"allowed": true
}
},
+ "HTML+ERB": {
+ "language_servers": ["herb", "!ruby-lsp", "..."]
+ },
"Java": {
"prettier": {
"allowed": true,
@@ -1741,6 +1759,9 @@
"allowed": true
}
},
+ "JS+ERB": {
+ "language_servers": ["!ruby-lsp", "..."]
+ },
"Kotlin": {
"language_servers": ["!kotlin-language-server", "kotlin-lsp", "..."]
},
@@ -1755,6 +1776,7 @@
"Markdown": {
"format_on_save": "off",
"use_on_type_format": false,
+ "remove_trailing_whitespace_on_save": false,
"allow_rewrap": "anywhere",
"soft_wrap": "editor_width",
"prettier": {
@@ -1845,6 +1867,9 @@
"allowed": true
}
},
+ "YAML+ERB": {
+ "language_servers": ["!ruby-lsp", "..."]
+ },
"Zig": {
"language_servers": ["zls", "..."]
}
diff --git a/crates/acp_thread/src/acp_thread.rs b/crates/acp_thread/src/acp_thread.rs
index 5ecf2be445ecf8afc6a93e2961302758ea0037ae..37622d004a2e9cd27a3686263ffd1aa98979104f 100644
--- a/crates/acp_thread/src/acp_thread.rs
+++ b/crates/acp_thread/src/acp_thread.rs
@@ -3,7 +3,6 @@ mod diff;
mod mention;
mod terminal;
-use ::terminal::terminal_settings::TerminalSettings;
use agent_settings::AgentSettings;
use collections::HashSet;
pub use connection::*;
@@ -12,7 +11,7 @@ use language::language_settings::FormatOnSave;
pub use mention::*;
use project::lsp_store::{FormatTrigger, LspFormatTarget};
use serde::{Deserialize, Serialize};
-use settings::{Settings as _, SettingsLocation};
+use settings::Settings as _;
use task::{Shell, ShellBuilder};
pub use terminal::*;
@@ -2141,17 +2140,9 @@ impl AcpThread {
) -> Task>> {
let env = match &cwd {
Some(dir) => self.project.update(cx, |project, cx| {
- let worktree = project.find_worktree(dir.as_path(), cx);
- let shell = TerminalSettings::get(
- worktree.as_ref().map(|(worktree, path)| SettingsLocation {
- worktree_id: worktree.read(cx).id(),
- path: &path,
- }),
- cx,
- )
- .shell
- .clone();
- project.directory_environment(&shell, dir.as_path().into(), cx)
+ project.environment().update(cx, |env, cx| {
+ env.directory_environment(dir.as_path().into(), cx)
+ })
}),
None => Task::ready(None).shared(),
};
diff --git a/crates/acp_thread/src/diff.rs b/crates/acp_thread/src/diff.rs
index 39cd8ad38e5bf223987dc8efe771614b3ed2172b..055b2f7fb86ffe9d7f12459b6b16405ce77815a0 100644
--- a/crates/acp_thread/src/diff.rs
+++ b/crates/acp_thread/src/diff.rs
@@ -361,12 +361,10 @@ async fn build_buffer_diff(
) -> Result> {
let buffer = cx.update(|cx| buffer.read(cx).snapshot())?;
- let executor = cx.background_executor().clone();
let old_text_rope = cx
.background_spawn({
let old_text = old_text.clone();
- let executor = executor.clone();
- async move { Rope::from_str(old_text.as_str(), &executor) }
+ async move { Rope::from(old_text.as_str()) }
})
.await;
let base_buffer = cx
diff --git a/crates/acp_thread/src/terminal.rs b/crates/acp_thread/src/terminal.rs
index 9ca6d4021b316231930ab7803957dab3a0139f1e..8b08868616e19b0d1855558a057af8eebc314e4a 100644
--- a/crates/acp_thread/src/terminal.rs
+++ b/crates/acp_thread/src/terminal.rs
@@ -5,10 +5,8 @@ use gpui::{App, AppContext, AsyncApp, Context, Entity, Task};
use language::LanguageRegistry;
use markdown::Markdown;
use project::Project;
-use settings::{Settings as _, SettingsLocation};
use std::{path::PathBuf, process::ExitStatus, sync::Arc, time::Instant};
use task::Shell;
-use terminal::terminal_settings::TerminalSettings;
use util::get_default_system_shell_preferring_bash;
pub struct Terminal {
@@ -187,17 +185,9 @@ pub async fn create_terminal_entity(
let mut env = if let Some(dir) = &cwd {
project
.update(cx, |project, cx| {
- let worktree = project.find_worktree(dir.as_path(), cx);
- let shell = TerminalSettings::get(
- worktree.as_ref().map(|(worktree, path)| SettingsLocation {
- worktree_id: worktree.read(cx).id(),
- path: &path,
- }),
- cx,
- )
- .shell
- .clone();
- project.directory_environment(&shell, dir.clone().into(), cx)
+ project.environment().update(cx, |env, cx| {
+ env.directory_environment(dir.clone().into(), cx)
+ })
})?
.await
.unwrap_or_default()
diff --git a/crates/acp_tools/src/acp_tools.rs b/crates/acp_tools/src/acp_tools.rs
index a40bcbd93c878a85c85d7edd312e713988234966..7615784676c7d9ff1782a6e9537e608cb927154d 100644
--- a/crates/acp_tools/src/acp_tools.rs
+++ b/crates/acp_tools/src/acp_tools.rs
@@ -19,7 +19,7 @@ use markdown::{CodeBlockRenderer, Markdown, MarkdownElement, MarkdownStyle};
use project::Project;
use settings::Settings;
use theme::ThemeSettings;
-use ui::{Tooltip, prelude::*};
+use ui::{Tooltip, WithScrollbar, prelude::*};
use util::ResultExt as _;
use workspace::{
Item, ItemHandle, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace,
@@ -291,17 +291,19 @@ impl AcpTools {
let expanded = self.expanded.contains(&index);
v_flex()
+ .id(index)
+ .group("message")
+ .cursor_pointer()
+ .font_buffer(cx)
.w_full()
- .px_4()
.py_3()
- .border_color(colors.border)
- .border_b_1()
+ .pl_4()
+ .pr_5()
.gap_2()
.items_start()
- .font_buffer(cx)
.text_size(base_size)
- .id(index)
- .group("message")
+ .border_color(colors.border)
+ .border_b_1()
.hover(|this| this.bg(colors.element_background.opacity(0.5)))
.on_click(cx.listener(move |this, _, _, cx| {
if this.expanded.contains(&index) {
@@ -323,15 +325,14 @@ impl AcpTools {
h_flex()
.w_full()
.gap_2()
- .items_center()
.flex_shrink_0()
.child(match message.direction {
- acp::StreamMessageDirection::Incoming => {
- ui::Icon::new(ui::IconName::ArrowDown).color(Color::Error)
- }
- acp::StreamMessageDirection::Outgoing => {
- ui::Icon::new(ui::IconName::ArrowUp).color(Color::Success)
- }
+ acp::StreamMessageDirection::Incoming => Icon::new(IconName::ArrowDown)
+ .color(Color::Error)
+ .size(IconSize::Small),
+ acp::StreamMessageDirection::Outgoing => Icon::new(IconName::ArrowUp)
+ .color(Color::Success)
+ .size(IconSize::Small),
})
.child(
Label::new(message.name.clone())
@@ -501,7 +502,7 @@ impl Focusable for AcpTools {
}
impl Render for AcpTools {
- fn render(&mut self, _window: &mut Window, cx: &mut Context) -> impl IntoElement {
+ fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement {
v_flex()
.track_focus(&self.focus_handle)
.size_full()
@@ -516,13 +517,19 @@ impl Render for AcpTools {
.child("No messages recorded yet")
.into_any()
} else {
- list(
- connection.list_state.clone(),
- cx.processor(Self::render_message),
- )
- .with_sizing_behavior(gpui::ListSizingBehavior::Auto)
- .flex_grow()
- .into_any()
+ div()
+ .size_full()
+ .flex_grow()
+ .child(
+ list(
+ connection.list_state.clone(),
+ cx.processor(Self::render_message),
+ )
+ .with_sizing_behavior(gpui::ListSizingBehavior::Auto)
+ .size_full(),
+ )
+ .vertical_scrollbar_for(connection.list_state.clone(), window, cx)
+ .into_any()
}
}
None => h_flex()
diff --git a/crates/action_log/src/action_log.rs b/crates/action_log/src/action_log.rs
index 1730163a4ce7b53aa051a6af87da8ab10ad4320f..b7722f211afda3a77bc96292a50acf869e7424d6 100644
--- a/crates/action_log/src/action_log.rs
+++ b/crates/action_log/src/action_log.rs
@@ -3,9 +3,7 @@ use buffer_diff::BufferDiff;
use clock;
use collections::BTreeMap;
use futures::{FutureExt, StreamExt, channel::mpsc};
-use gpui::{
- App, AppContext, AsyncApp, BackgroundExecutor, Context, Entity, Subscription, Task, WeakEntity,
-};
+use gpui::{App, AppContext, AsyncApp, Context, Entity, Subscription, Task, WeakEntity};
use language::{Anchor, Buffer, BufferEvent, DiskState, Point, ToPoint};
use project::{Project, ProjectItem, lsp_store::OpenLspBufferHandle};
use std::{cmp, ops::Range, sync::Arc};
@@ -323,7 +321,6 @@ impl ActionLog {
let unreviewed_edits = tracked_buffer.unreviewed_edits.clone();
let edits = diff_snapshots(&old_snapshot, &new_snapshot);
let mut has_user_changes = false;
- let executor = cx.background_executor().clone();
async move {
if let ChangeAuthor::User = author {
has_user_changes = apply_non_conflicting_edits(
@@ -331,7 +328,6 @@ impl ActionLog {
edits,
&mut base_text,
new_snapshot.as_rope(),
- &executor,
);
}
@@ -386,7 +382,6 @@ impl ActionLog {
let agent_diff_base = tracked_buffer.diff_base.clone();
let git_diff_base = git_diff.read(cx).base_text().as_rope().clone();
let buffer_text = tracked_buffer.snapshot.as_rope().clone();
- let executor = cx.background_executor().clone();
anyhow::Ok(cx.background_spawn(async move {
let mut old_unreviewed_edits = old_unreviewed_edits.into_iter().peekable();
let committed_edits = language::line_diff(
@@ -421,11 +416,8 @@ impl ActionLog {
),
new_agent_diff_base.max_point(),
));
- new_agent_diff_base.replace(
- old_byte_start..old_byte_end,
- &unreviewed_new,
- &executor,
- );
+ new_agent_diff_base
+ .replace(old_byte_start..old_byte_end, &unreviewed_new);
row_delta +=
unreviewed.new_len() as i32 - unreviewed.old_len() as i32;
}
@@ -619,7 +611,6 @@ impl ActionLog {
.snapshot
.text_for_range(new_range)
.collect::(),
- cx.background_executor(),
);
delta += edit.new_len() as i32 - edit.old_len() as i32;
false
@@ -833,7 +824,6 @@ fn apply_non_conflicting_edits(
edits: Vec>,
old_text: &mut Rope,
new_text: &Rope,
- executor: &BackgroundExecutor,
) -> bool {
let mut old_edits = patch.edits().iter().cloned().peekable();
let mut new_edits = edits.into_iter().peekable();
@@ -887,7 +877,6 @@ fn apply_non_conflicting_edits(
old_text.replace(
old_bytes,
&new_text.chunks_in_range(new_bytes).collect::(),
- executor,
);
applied_delta += new_edit.new_len() as i32 - new_edit.old_len() as i32;
has_made_changes = true;
@@ -2293,7 +2282,6 @@ mod tests {
old_text.replace(
old_start..old_end,
&new_text.slice_rows(edit.new.clone()).to_string(),
- cx.background_executor(),
);
}
pretty_assertions::assert_eq!(old_text.to_string(), new_text.to_string());
diff --git a/crates/agent/src/edit_agent/edit_parser.rs b/crates/agent/src/edit_agent/edit_parser.rs
index 8411171ba4ea491d2603014a0715ce471b34e36f..425bf93efff115d4daef380e3f82abcdb8c0746f 100644
--- a/crates/agent/src/edit_agent/edit_parser.rs
+++ b/crates/agent/src/edit_agent/edit_parser.rs
@@ -13,7 +13,15 @@ const EDITS_END_TAG: &str = "";
const SEARCH_MARKER: &str = "<<<<<<< SEARCH";
const SEPARATOR_MARKER: &str = "=======";
const REPLACE_MARKER: &str = ">>>>>>> REPLACE";
-const END_TAGS: [&str; 3] = [OLD_TEXT_END_TAG, NEW_TEXT_END_TAG, EDITS_END_TAG];
+const SONNET_PARAMETER_INVOKE_1: &str = "\n";
+const SONNET_PARAMETER_INVOKE_2: &str = "";
+const END_TAGS: [&str; 5] = [
+ OLD_TEXT_END_TAG,
+ NEW_TEXT_END_TAG,
+ EDITS_END_TAG,
+ SONNET_PARAMETER_INVOKE_1, // Remove this after switching to streaming tool call
+ SONNET_PARAMETER_INVOKE_2,
+];
#[derive(Debug)]
pub enum EditParserEvent {
@@ -547,6 +555,37 @@ mod tests {
);
}
+ #[gpui::test(iterations = 1000)]
+ fn test_xml_edits_with_closing_parameter_invoke(mut rng: StdRng) {
+ // This case is a regression with Claude Sonnet 4.5.
+ // Sometimes Sonnet thinks that it's doing a tool call
+ // and closes its response with ''
+ // instead of properly closing
+
+ let mut parser = EditParser::new(EditFormat::XmlTags);
+ assert_eq!(
+ parse_random_chunks(
+ indoc! {"
+ some textupdated text
+ "},
+ &mut parser,
+ &mut rng
+ ),
+ vec![Edit {
+ old_text: "some text".to_string(),
+ new_text: "updated text".to_string(),
+ line_hint: None,
+ },]
+ );
+ assert_eq!(
+ parser.finish(),
+ EditParserMetrics {
+ tags: 2,
+ mismatched_tags: 1
+ }
+ );
+ }
+
#[gpui::test(iterations = 1000)]
fn test_xml_nested_tags(mut rng: StdRng) {
let mut parser = EditParser::new(EditFormat::XmlTags);
@@ -1035,6 +1074,11 @@ mod tests {
last_ix = chunk_ix;
}
+ if new_text.is_some() {
+ pending_edit.new_text = new_text.take().unwrap();
+ edits.push(pending_edit);
+ }
+
edits
}
}
diff --git a/crates/agent/src/edit_agent/streaming_fuzzy_matcher.rs b/crates/agent/src/edit_agent/streaming_fuzzy_matcher.rs
index 021892e738eed229568c909f72f327d93199cdc0..904ec05a8c7565d5052cd546fc0bf6d723ffa375 100644
--- a/crates/agent/src/edit_agent/streaming_fuzzy_matcher.rs
+++ b/crates/agent/src/edit_agent/streaming_fuzzy_matcher.rs
@@ -305,20 +305,18 @@ impl SearchMatrix {
#[cfg(test)]
mod tests {
use super::*;
- use gpui::TestAppContext;
use indoc::indoc;
use language::{BufferId, TextBuffer};
use rand::prelude::*;
use text::ReplicaId;
use util::test::{generate_marked_text, marked_text_ranges};
- #[gpui::test]
- fn test_empty_query(cx: &mut gpui::TestAppContext) {
+ #[test]
+ fn test_empty_query() {
let buffer = TextBuffer::new(
ReplicaId::LOCAL,
BufferId::new(1).unwrap(),
"Hello world\nThis is a test\nFoo bar baz",
- cx.background_executor(),
);
let snapshot = buffer.snapshot();
@@ -327,13 +325,12 @@ mod tests {
assert_eq!(finish(finder), None);
}
- #[gpui::test]
- fn test_streaming_exact_match(cx: &mut gpui::TestAppContext) {
+ #[test]
+ fn test_streaming_exact_match() {
let buffer = TextBuffer::new(
ReplicaId::LOCAL,
BufferId::new(1).unwrap(),
"Hello world\nThis is a test\nFoo bar baz",
- cx.background_executor(),
);
let snapshot = buffer.snapshot();
@@ -352,8 +349,8 @@ mod tests {
assert_eq!(finish(finder), Some("This is a test".to_string()));
}
- #[gpui::test]
- fn test_streaming_fuzzy_match(cx: &mut gpui::TestAppContext) {
+ #[test]
+ fn test_streaming_fuzzy_match() {
let buffer = TextBuffer::new(
ReplicaId::LOCAL,
BufferId::new(1).unwrap(),
@@ -366,7 +363,6 @@ mod tests {
return x * y;
}
"},
- cx.background_executor(),
);
let snapshot = buffer.snapshot();
@@ -387,13 +383,12 @@ mod tests {
);
}
- #[gpui::test]
- fn test_incremental_improvement(cx: &mut gpui::TestAppContext) {
+ #[test]
+ fn test_incremental_improvement() {
let buffer = TextBuffer::new(
ReplicaId::LOCAL,
BufferId::new(1).unwrap(),
"Line 1\nLine 2\nLine 3\nLine 4\nLine 5",
- cx.background_executor(),
);
let snapshot = buffer.snapshot();
@@ -413,8 +408,8 @@ mod tests {
assert_eq!(finish(finder), Some("Line 3\nLine 4".to_string()));
}
- #[gpui::test]
- fn test_incomplete_lines_buffering(cx: &mut gpui::TestAppContext) {
+ #[test]
+ fn test_incomplete_lines_buffering() {
let buffer = TextBuffer::new(
ReplicaId::LOCAL,
BufferId::new(1).unwrap(),
@@ -423,7 +418,6 @@ mod tests {
jumps over the lazy dog
Pack my box with five dozen liquor jugs
"},
- cx.background_executor(),
);
let snapshot = buffer.snapshot();
@@ -441,8 +435,8 @@ mod tests {
);
}
- #[gpui::test]
- fn test_multiline_fuzzy_match(cx: &mut gpui::TestAppContext) {
+ #[test]
+ fn test_multiline_fuzzy_match() {
let buffer = TextBuffer::new(
ReplicaId::LOCAL,
BufferId::new(1).unwrap(),
@@ -462,7 +456,6 @@ mod tests {
}
}
"#},
- cx.background_executor(),
);
let snapshot = buffer.snapshot();
@@ -516,7 +509,7 @@ mod tests {
}
#[gpui::test(iterations = 100)]
- fn test_resolve_location_single_line(mut rng: StdRng, cx: &mut TestAppContext) {
+ fn test_resolve_location_single_line(mut rng: StdRng) {
assert_location_resolution(
concat!(
" Lorem\n",
@@ -526,12 +519,11 @@ mod tests {
),
"ipsum",
&mut rng,
- cx,
);
}
#[gpui::test(iterations = 100)]
- fn test_resolve_location_multiline(mut rng: StdRng, cx: &mut TestAppContext) {
+ fn test_resolve_location_multiline(mut rng: StdRng) {
assert_location_resolution(
concat!(
" Lorem\n",
@@ -541,12 +533,11 @@ mod tests {
),
"ipsum\ndolor sit amet",
&mut rng,
- cx,
);
}
#[gpui::test(iterations = 100)]
- fn test_resolve_location_function_with_typo(mut rng: StdRng, cx: &mut TestAppContext) {
+ fn test_resolve_location_function_with_typo(mut rng: StdRng) {
assert_location_resolution(
indoc! {"
«fn foo1(a: usize) -> usize {
@@ -559,12 +550,11 @@ mod tests {
"},
"fn foo1(a: usize) -> u32 {\n40\n}",
&mut rng,
- cx,
);
}
#[gpui::test(iterations = 100)]
- fn test_resolve_location_class_methods(mut rng: StdRng, cx: &mut TestAppContext) {
+ fn test_resolve_location_class_methods(mut rng: StdRng) {
assert_location_resolution(
indoc! {"
class Something {
@@ -585,12 +575,11 @@ mod tests {
six() { return 6666; }
"},
&mut rng,
- cx,
);
}
#[gpui::test(iterations = 100)]
- fn test_resolve_location_imports_no_match(mut rng: StdRng, cx: &mut TestAppContext) {
+ fn test_resolve_location_imports_no_match(mut rng: StdRng) {
assert_location_resolution(
indoc! {"
use std::ops::Range;
@@ -620,12 +609,11 @@ mod tests {
use std::sync::Arc;
"},
&mut rng,
- cx,
);
}
#[gpui::test(iterations = 100)]
- fn test_resolve_location_nested_closure(mut rng: StdRng, cx: &mut TestAppContext) {
+ fn test_resolve_location_nested_closure(mut rng: StdRng) {
assert_location_resolution(
indoc! {"
impl Foo {
@@ -653,12 +641,11 @@ mod tests {
" });",
),
&mut rng,
- cx,
);
}
#[gpui::test(iterations = 100)]
- fn test_resolve_location_tool_invocation(mut rng: StdRng, cx: &mut TestAppContext) {
+ fn test_resolve_location_tool_invocation(mut rng: StdRng) {
assert_location_resolution(
indoc! {r#"
let tool = cx
@@ -686,12 +673,11 @@ mod tests {
" .output;",
),
&mut rng,
- cx,
);
}
#[gpui::test]
- fn test_line_hint_selection(cx: &mut TestAppContext) {
+ fn test_line_hint_selection() {
let text = indoc! {r#"
fn first_function() {
return 42;
@@ -710,7 +696,6 @@ mod tests {
ReplicaId::LOCAL,
BufferId::new(1).unwrap(),
text.to_string(),
- cx.background_executor(),
);
let snapshot = buffer.snapshot();
let mut matcher = StreamingFuzzyMatcher::new(snapshot.clone());
@@ -742,19 +727,9 @@ mod tests {
}
#[track_caller]
- fn assert_location_resolution(
- text_with_expected_range: &str,
- query: &str,
- rng: &mut StdRng,
- cx: &mut TestAppContext,
- ) {
+ fn assert_location_resolution(text_with_expected_range: &str, query: &str, rng: &mut StdRng) {
let (text, expected_ranges) = marked_text_ranges(text_with_expected_range, false);
- let buffer = TextBuffer::new(
- ReplicaId::LOCAL,
- BufferId::new(1).unwrap(),
- text.clone(),
- cx.background_executor(),
- );
+ let buffer = TextBuffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), text.clone());
let snapshot = buffer.snapshot();
let mut matcher = StreamingFuzzyMatcher::new(snapshot);
diff --git a/crates/agent/src/tools/edit_file_tool.rs b/crates/agent/src/tools/edit_file_tool.rs
index 078273dbb8a4399e1770ca08daeb1f7f44491e2a..0adff2dee3571f09b40ee69896c05e50c56b51b9 100644
--- a/crates/agent/src/tools/edit_file_tool.rs
+++ b/crates/agent/src/tools/edit_file_tool.rs
@@ -569,7 +569,6 @@ mod tests {
use prompt_store::ProjectContext;
use serde_json::json;
use settings::SettingsStore;
- use text::Rope;
use util::{path, rel_path::rel_path};
#[gpui::test]
@@ -742,7 +741,7 @@ mod tests {
// Create the file
fs.save(
path!("/root/src/main.rs").as_ref(),
- &Rope::from_str_small("initial content"),
+ &"initial content".into(),
language::LineEnding::Unix,
)
.await
@@ -909,7 +908,7 @@ mod tests {
// Create a simple file with trailing whitespace
fs.save(
path!("/root/src/main.rs").as_ref(),
- &Rope::from_str_small("initial content"),
+ &"initial content".into(),
language::LineEnding::Unix,
)
.await
diff --git a/crates/agent_ui/src/acp/entry_view_state.rs b/crates/agent_ui/src/acp/entry_view_state.rs
index 4c058b984f4fa24074ea9e9d81e43c1d73d87d1f..382d0ee3c96ef002372046ee6a6111f8e814f892 100644
--- a/crates/agent_ui/src/acp/entry_view_state.rs
+++ b/crates/agent_ui/src/acp/entry_view_state.rs
@@ -4,7 +4,7 @@ use acp_thread::{AcpThread, AgentThreadEntry};
use agent::HistoryStore;
use agent_client_protocol::{self as acp, ToolCallId};
use collections::HashMap;
-use editor::{Editor, EditorMode, MinimapVisibility};
+use editor::{Editor, EditorMode, MinimapVisibility, SizingBehavior};
use gpui::{
AnyEntity, App, AppContext as _, Entity, EntityId, EventEmitter, FocusHandle, Focusable,
ScrollHandle, SharedString, TextStyleRefinement, WeakEntity, Window,
@@ -357,7 +357,7 @@ fn create_editor_diff(
EditorMode::Full {
scale_ui_elements_with_buffer_font_size: false,
show_active_line_background: false,
- sized_by_content: true,
+ sizing_behavior: SizingBehavior::SizeByContent,
},
diff.read(cx).multibuffer().clone(),
None,
diff --git a/crates/agent_ui/src/acp/thread_view.rs b/crates/agent_ui/src/acp/thread_view.rs
index a4b3106fa9d9ded053ff2f33b720ec3b10512d01..b19e0434be054b63676e2c5623c6f305b7a7c472 100644
--- a/crates/agent_ui/src/acp/thread_view.rs
+++ b/crates/agent_ui/src/acp/thread_view.rs
@@ -17,7 +17,9 @@ use client::zed_urls;
use cloud_llm_client::PlanV1;
use collections::{HashMap, HashSet};
use editor::scroll::Autoscroll;
-use editor::{Editor, EditorEvent, EditorMode, MultiBuffer, PathKey, SelectionEffects};
+use editor::{
+ Editor, EditorEvent, EditorMode, MultiBuffer, PathKey, SelectionEffects, SizingBehavior,
+};
use file_icons::FileIcons;
use fs::Fs;
use futures::FutureExt as _;
@@ -881,6 +883,7 @@ impl AcpThreadView {
cx: &mut Context,
) {
self.set_editor_is_expanded(!self.editor_expanded, cx);
+ cx.stop_propagation();
cx.notify();
}
@@ -892,7 +895,7 @@ impl AcpThreadView {
EditorMode::Full {
scale_ui_elements_with_buffer_font_size: false,
show_active_line_background: false,
- sized_by_content: false,
+ sizing_behavior: SizingBehavior::ExcludeOverscrollMargin,
},
cx,
)
@@ -3631,6 +3634,7 @@ impl AcpThreadView {
.child(
h_flex()
.id("edits-container")
+ .cursor_pointer()
.gap_1()
.child(Disclosure::new("edits-disclosure", expanded))
.map(|this| {
@@ -3770,6 +3774,7 @@ impl AcpThreadView {
Label::new(name.to_string())
.size(LabelSize::XSmall)
.buffer_font(cx)
+ .ml_1p5()
});
let file_icon = FileIcons::get_icon(path.as_std_path(), cx)
@@ -3801,14 +3806,30 @@ impl AcpThreadView {
})
.child(
h_flex()
+ .id(("file-name-row", index))
.relative()
- .id(("file-name", index))
.pr_8()
- .gap_1p5()
.w_full()
.overflow_x_scroll()
- .child(file_icon)
- .child(h_flex().gap_0p5().children(file_name).children(file_path))
+ .child(
+ h_flex()
+ .id(("file-name-path", index))
+ .cursor_pointer()
+ .pr_0p5()
+ .gap_0p5()
+ .hover(|s| s.bg(cx.theme().colors().element_hover))
+ .rounded_xs()
+ .child(file_icon)
+ .children(file_name)
+ .children(file_path)
+ .tooltip(Tooltip::text("Go to File"))
+ .on_click({
+ let buffer = buffer.clone();
+ cx.listener(move |this, _, window, cx| {
+ this.open_edited_buffer(&buffer, window, cx);
+ })
+ }),
+ )
.child(
div()
.absolute()
@@ -3818,13 +3839,7 @@ impl AcpThreadView {
.bottom_0()
.right_0()
.bg(overlay_gradient),
- )
- .on_click({
- let buffer = buffer.clone();
- cx.listener(move |this, _, window, cx| {
- this.open_edited_buffer(&buffer, window, cx);
- })
- }),
+ ),
)
.child(
h_flex()
@@ -3966,8 +3981,12 @@ impl AcpThreadView {
)
}
})
- .on_click(cx.listener(|_, _, window, cx| {
- window.dispatch_action(Box::new(ExpandMessageEditor), cx);
+ .on_click(cx.listener(|this, _, window, cx| {
+ this.expand_message_editor(
+ &ExpandMessageEditor,
+ window,
+ cx,
+ );
})),
),
),
diff --git a/crates/agent_ui/src/agent_configuration.rs b/crates/agent_ui/src/agent_configuration.rs
index 61f8ee60a794cbd6622759a89efb6f40c8f1503d..cf154f3e95e25e5058e43f693e14a032ac04826a 100644
--- a/crates/agent_ui/src/agent_configuration.rs
+++ b/crates/agent_ui/src/agent_configuration.rs
@@ -23,16 +23,17 @@ use language::LanguageRegistry;
use language_model::{
LanguageModelProvider, LanguageModelProviderId, LanguageModelRegistry, ZED_CLOUD_PROVIDER_ID,
};
+use language_models::AllLanguageModelSettings;
use notifications::status_toast::{StatusToast, ToastIcon};
use project::{
agent_server_store::{AgentServerStore, CLAUDE_CODE_NAME, CODEX_NAME, GEMINI_NAME},
context_server_store::{ContextServerConfiguration, ContextServerStatus, ContextServerStore},
};
-use rope::Rope;
-use settings::{SettingsStore, update_settings_file};
+use settings::{Settings, SettingsStore, update_settings_file};
use ui::{
- Chip, CommonAnimationExt, ContextMenu, Disclosure, Divider, DividerColor, ElevationIndex,
- Indicator, PopoverMenu, Switch, SwitchColor, Tooltip, WithScrollbar, prelude::*,
+ Button, ButtonStyle, Chip, CommonAnimationExt, ContextMenu, Disclosure, Divider, DividerColor,
+ ElevationIndex, IconName, IconPosition, IconSize, Indicator, LabelSize, PopoverMenu, Switch,
+ SwitchColor, Tooltip, WithScrollbar, prelude::*,
};
use util::ResultExt as _;
use workspace::{Workspace, create_and_open_local_file};
@@ -304,10 +305,76 @@ impl AgentConfiguration {
}
})),
)
- }),
+ })
+ .when(
+ is_expanded && is_removable_provider(&provider.id(), cx),
+ |this| {
+ this.child(
+ Button::new(
+ SharedString::from(format!("delete-provider-{provider_id}")),
+ "Remove Provider",
+ )
+ .full_width()
+ .style(ButtonStyle::Outlined)
+ .icon_position(IconPosition::Start)
+ .icon(IconName::Trash)
+ .icon_size(IconSize::Small)
+ .icon_color(Color::Muted)
+ .label_size(LabelSize::Small)
+ .on_click(cx.listener({
+ let provider = provider.clone();
+ move |this, _event, window, cx| {
+ this.delete_provider(provider.clone(), window, cx);
+ }
+ })),
+ )
+ },
+ ),
)
}
+ fn delete_provider(
+ &mut self,
+ provider: Arc,
+ window: &mut Window,
+ cx: &mut Context,
+ ) {
+ let fs = self.fs.clone();
+ let provider_id = provider.id();
+
+ cx.spawn_in(window, async move |_, cx| {
+ cx.update(|_window, cx| {
+ update_settings_file(fs.clone(), cx, {
+ let provider_id = provider_id.clone();
+ move |settings, _| {
+ if let Some(ref mut openai_compatible) = settings
+ .language_models
+ .as_mut()
+ .and_then(|lm| lm.openai_compatible.as_mut())
+ {
+ let key_to_remove: Arc = Arc::from(provider_id.0.as_ref());
+ openai_compatible.remove(&key_to_remove);
+ }
+ }
+ });
+ })
+ .log_err();
+
+ cx.update(|_window, cx| {
+ LanguageModelRegistry::global(cx).update(cx, {
+ let provider_id = provider_id.clone();
+ move |registry, cx| {
+ registry.unregister_provider(provider_id, cx);
+ }
+ })
+ })
+ .log_err();
+
+ anyhow::Ok(())
+ })
+ .detach_and_log_err(cx);
+ }
+
fn render_provider_configuration_section(
&mut self,
cx: &mut Context,
@@ -1115,11 +1182,8 @@ async fn open_new_agent_servers_entry_in_settings_editor(
) -> Result<()> {
let settings_editor = workspace
.update_in(cx, |_, window, cx| {
- create_and_open_local_file(paths::settings_file(), window, cx, |cx| {
- Rope::from_str(
- &settings::initial_user_settings_content(),
- cx.background_executor(),
- )
+ create_and_open_local_file(paths::settings_file(), window, cx, || {
+ settings::initial_user_settings_content().as_ref().into()
})
})?
.await?
@@ -1225,3 +1289,14 @@ fn find_text_in_buffer(
None
}
}
+
+// OpenAI-compatible providers are user-configured and can be removed,
+// whereas built-in providers (like Anthropic, OpenAI, Google, etc.) can't.
+//
+// If in the future we have more "API-compatible-type" of providers,
+// they should be included here as removable providers.
+fn is_removable_provider(provider_id: &LanguageModelProviderId, cx: &App) -> bool {
+ AllLanguageModelSettings::get_global(cx)
+ .openai_compatible
+ .contains_key(provider_id.0.as_ref())
+}
diff --git a/crates/agent_ui/src/agent_diff.rs b/crates/agent_ui/src/agent_diff.rs
index a0f117b0bf30abee9d2182cf8c3fadd10099b1f0..63eb2ac49731a5e57b4eae5bf33b821b2e223c25 100644
--- a/crates/agent_ui/src/agent_diff.rs
+++ b/crates/agent_ui/src/agent_diff.rs
@@ -70,14 +70,6 @@ impl AgentDiffThread {
}
}
- fn is_generating(&self, cx: &App) -> bool {
- match self {
- AgentDiffThread::AcpThread(thread) => {
- thread.read(cx).status() == acp_thread::ThreadStatus::Generating
- }
- }
- }
-
fn has_pending_edit_tool_uses(&self, cx: &App) -> bool {
match self {
AgentDiffThread::AcpThread(thread) => thread.read(cx).has_pending_edit_tool_calls(),
@@ -970,9 +962,7 @@ impl AgentDiffToolbar {
None => ToolbarItemLocation::Hidden,
Some(AgentDiffToolbarItem::Pane(_)) => ToolbarItemLocation::PrimaryRight,
Some(AgentDiffToolbarItem::Editor { state, .. }) => match state {
- EditorState::Generating | EditorState::Reviewing => {
- ToolbarItemLocation::PrimaryRight
- }
+ EditorState::Reviewing => ToolbarItemLocation::PrimaryRight,
EditorState::Idle => ToolbarItemLocation::Hidden,
},
}
@@ -1050,7 +1040,6 @@ impl Render for AgentDiffToolbar {
let content = match state {
EditorState::Idle => return Empty.into_any(),
- EditorState::Generating => vec![spinner_icon],
EditorState::Reviewing => vec![
h_flex()
.child(
@@ -1222,7 +1211,6 @@ pub struct AgentDiff {
pub enum EditorState {
Idle,
Reviewing,
- Generating,
}
struct WorkspaceThread {
@@ -1545,15 +1533,11 @@ impl AgentDiff {
multibuffer.add_diff(diff_handle.clone(), cx);
});
- let new_state = if thread.is_generating(cx) {
- EditorState::Generating
- } else {
- EditorState::Reviewing
- };
+ let reviewing_state = EditorState::Reviewing;
let previous_state = self
.reviewing_editors
- .insert(weak_editor.clone(), new_state.clone());
+ .insert(weak_editor.clone(), reviewing_state.clone());
if previous_state.is_none() {
editor.update(cx, |editor, cx| {
@@ -1566,7 +1550,9 @@ impl AgentDiff {
unaffected.remove(weak_editor);
}
- if new_state == EditorState::Reviewing && previous_state != Some(new_state) {
+ if reviewing_state == EditorState::Reviewing
+ && previous_state != Some(reviewing_state)
+ {
// Jump to first hunk when we enter review mode
editor.update(cx, |editor, cx| {
let snapshot = multibuffer.read(cx).snapshot(cx);
diff --git a/crates/agent_ui/src/agent_panel.rs b/crates/agent_ui/src/agent_panel.rs
index 173059ee535d4417cd0ff493842d889559b85ef4..b9aff018dbb520ad524e182800ffe057cbf9305a 100644
--- a/crates/agent_ui/src/agent_panel.rs
+++ b/crates/agent_ui/src/agent_panel.rs
@@ -19,7 +19,6 @@ use settings::{
use zed_actions::OpenBrowser;
use zed_actions::agent::{OpenClaudeCodeOnboardingModal, ReauthenticateAgent};
-use crate::acp::{AcpThreadHistory, ThreadHistoryEvent};
use crate::context_store::ContextStore;
use crate::ui::{AcpOnboardingModal, ClaudeCodeOnboardingModal};
use crate::{
@@ -33,6 +32,10 @@ use crate::{
text_thread_editor::{AgentPanelDelegate, TextThreadEditor, make_lsp_adapter_delegate},
ui::{AgentOnboardingModal, EndTrialUpsell},
};
+use crate::{
+ ExpandMessageEditor,
+ acp::{AcpThreadHistory, ThreadHistoryEvent},
+};
use crate::{
ExternalAgent, NewExternalAgentThread, NewNativeAgentThreadFromSummary, placeholder_command,
};
@@ -106,6 +109,12 @@ pub fn init(cx: &mut App) {
}
},
)
+ .register_action(|workspace, _: &ExpandMessageEditor, window, cx| {
+ if let Some(panel) = workspace.panel::(cx) {
+ workspace.focus_panel::(window, cx);
+ panel.update(cx, |panel, cx| panel.expand_message_editor(window, cx));
+ }
+ })
.register_action(|workspace, _: &OpenHistory, window, cx| {
if let Some(panel) = workspace.panel::(cx) {
workspace.focus_panel::(window, cx);
@@ -944,6 +953,15 @@ impl AgentPanel {
.detach_and_log_err(cx);
}
+ fn expand_message_editor(&mut self, window: &mut Window, cx: &mut Context) {
+ if let Some(thread_view) = self.active_thread_view() {
+ thread_view.update(cx, |view, cx| {
+ view.expand_message_editor(&ExpandMessageEditor, window, cx);
+ view.focus_handle(cx).focus(window);
+ });
+ }
+ }
+
fn open_history(&mut self, window: &mut Window, cx: &mut Context) {
if matches!(self.active_view, ActiveView::History) {
if let Some(previous_view) = self.previous_view.take() {
diff --git a/crates/agent_ui/src/buffer_codegen.rs b/crates/agent_ui/src/buffer_codegen.rs
index f9269e0bb62160633dc991b147d1d779a517e2e8..215e2a74d7be9cbcb18442dcefa1581d08eec7b2 100644
--- a/crates/agent_ui/src/buffer_codegen.rs
+++ b/crates/agent_ui/src/buffer_codegen.rs
@@ -487,10 +487,9 @@ impl CodegenAlternative {
) {
let start_time = Instant::now();
let snapshot = self.snapshot.clone();
- let selected_text = Rope::from_iter(
- snapshot.text_for_range(self.range.start..self.range.end),
- cx.background_executor(),
- );
+ let selected_text = snapshot
+ .text_for_range(self.range.start..self.range.end)
+ .collect::();
let selection_start = self.range.start.to_point(&snapshot);
diff --git a/crates/agent_ui/src/context.rs b/crates/agent_ui/src/context.rs
index 2a1ff4a1d9d3e0bb6c8b128cf7f944e9ed3ff657..022f4e4d2ff4ce79aa17efce241b84f1a0640ae3 100644
--- a/crates/agent_ui/src/context.rs
+++ b/crates/agent_ui/src/context.rs
@@ -620,8 +620,18 @@ impl TextThreadContextHandle {
impl Display for TextThreadContext {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
- // TODO: escape title?
- writeln!(f, "", self.title)?;
+ write!(f, " write!(f, "&")?,
+ '<' => write!(f, "<")?,
+ '>' => write!(f, ">")?,
+ '"' => write!(f, """)?,
+ '\'' => write!(f, "'")?,
+ _ => write!(f, "{}", c)?,
+ }
+ }
+ writeln!(f, "\">")?;
write!(f, "{}", self.text.trim())?;
write!(f, "\n")
}
diff --git a/crates/assistant_text_thread/src/text_thread.rs b/crates/assistant_text_thread/src/text_thread.rs
index ddc8912aef5c08ecb9406cc27fbcdf5418ec48e2..9ad383cdfd43eed236268349e2ff97c34a0178c0 100644
--- a/crates/assistant_text_thread/src/text_thread.rs
+++ b/crates/assistant_text_thread/src/text_thread.rs
@@ -744,13 +744,12 @@ impl TextThread {
telemetry: Option>,
cx: &mut Context,
) -> Self {
- let buffer = cx.new(|cx| {
+ let buffer = cx.new(|_cx| {
let buffer = Buffer::remote(
language::BufferId::new(1).unwrap(),
replica_id,
capability,
"",
- cx.background_executor(),
);
buffer.set_language_registry(language_registry.clone());
buffer
diff --git a/crates/auto_update/Cargo.toml b/crates/auto_update/Cargo.toml
index 08db9f8a97bb0783da987f84991ad1aaa62c2141..630be043dca120ca76b2552f0a729a03a684f934 100644
--- a/crates/auto_update/Cargo.toml
+++ b/crates/auto_update/Cargo.toml
@@ -26,6 +26,7 @@ serde_json.workspace = true
settings.workspace = true
smol.workspace = true
tempfile.workspace = true
+util.workspace = true
workspace.workspace = true
[target.'cfg(not(target_os = "windows"))'.dependencies]
diff --git a/crates/auto_update/src/auto_update.rs b/crates/auto_update/src/auto_update.rs
index 9f93dd27900e4b90de8c6d61d41b3b6c287eaaf0..331a58414958a48feaad70babee2dc2ea3b730e0 100644
--- a/crates/auto_update/src/auto_update.rs
+++ b/crates/auto_update/src/auto_update.rs
@@ -962,7 +962,7 @@ pub async fn finalize_auto_update_on_quit() {
.parent()
.map(|p| p.join("tools").join("auto_update_helper.exe"))
{
- let mut command = smol::process::Command::new(helper);
+ let mut command = util::command::new_smol_command(helper);
command.arg("--launch");
command.arg("false");
if let Ok(mut cmd) = command.spawn() {
diff --git a/crates/breadcrumbs/src/breadcrumbs.rs b/crates/breadcrumbs/src/breadcrumbs.rs
index 08c0915c58ae50741238574cec5b6f2474d06eb8..7664de3c87673a405118911526cb6606a2fecacf 100644
--- a/crates/breadcrumbs/src/breadcrumbs.rs
+++ b/crates/breadcrumbs/src/breadcrumbs.rs
@@ -100,13 +100,21 @@ impl Render for Breadcrumbs {
let breadcrumbs_stack = h_flex().gap_1().children(breadcrumbs);
+ let prefix_element = active_item.breadcrumb_prefix(window, cx);
+
+ let breadcrumbs = if let Some(prefix) = prefix_element {
+ h_flex().gap_1p5().child(prefix).child(breadcrumbs_stack)
+ } else {
+ breadcrumbs_stack
+ };
+
match active_item
.downcast::()
.map(|editor| editor.downgrade())
{
Some(editor) => element.child(
ButtonLike::new("toggle outline view")
- .child(breadcrumbs_stack)
+ .child(breadcrumbs)
.style(ButtonStyle::Transparent)
.on_click({
let editor = editor.clone();
@@ -141,7 +149,7 @@ impl Render for Breadcrumbs {
// Match the height and padding of the `ButtonLike` in the other arm.
.h(rems_from_px(22.))
.pl_1()
- .child(breadcrumbs_stack),
+ .child(breadcrumbs),
}
}
}
diff --git a/crates/buffer_diff/src/buffer_diff.rs b/crates/buffer_diff/src/buffer_diff.rs
index b8ce85b6db25fdcad21245b41e4979ef61220485..d6ae5545200bb47976554814e346be3039fa276e 100644
--- a/crates/buffer_diff/src/buffer_diff.rs
+++ b/crates/buffer_diff/src/buffer_diff.rs
@@ -1,9 +1,6 @@
use futures::channel::oneshot;
use git2::{DiffLineType as GitDiffLineType, DiffOptions as GitOptions, Patch as GitPatch};
-use gpui::{
- App, AppContext as _, AsyncApp, BackgroundExecutor, Context, Entity, EventEmitter, Task,
- TaskLabel,
-};
+use gpui::{App, AppContext as _, AsyncApp, Context, Entity, EventEmitter, Task, TaskLabel};
use language::{Language, LanguageRegistry};
use rope::Rope;
use std::{
@@ -194,7 +191,7 @@ impl BufferDiffSnapshot {
let base_text_exists;
let base_text_snapshot;
if let Some(text) = &base_text {
- let base_text_rope = Rope::from_str(text.as_str(), cx.background_executor());
+ let base_text_rope = Rope::from(text.as_str());
base_text_pair = Some((text.clone(), base_text_rope.clone()));
let snapshot =
language::Buffer::build_snapshot(base_text_rope, language, language_registry, cx);
@@ -314,7 +311,6 @@ impl BufferDiffInner {
hunks: &[DiffHunk],
buffer: &text::BufferSnapshot,
file_exists: bool,
- cx: &BackgroundExecutor,
) -> Option {
let head_text = self
.base_text_exists
@@ -509,7 +505,7 @@ impl BufferDiffInner {
for (old_range, replacement_text) in edits {
new_index_text.append(index_cursor.slice(old_range.start));
index_cursor.seek_forward(old_range.end);
- new_index_text.push(&replacement_text, cx);
+ new_index_text.push(&replacement_text);
}
new_index_text.append(index_cursor.suffix());
Some(new_index_text)
@@ -966,7 +962,6 @@ impl BufferDiff {
hunks,
buffer,
file_exists,
- cx.background_executor(),
);
cx.emit(BufferDiffEvent::HunksStagedOrUnstaged(
@@ -1390,12 +1385,7 @@ mod tests {
"
.unindent();
- let mut buffer = Buffer::new(
- ReplicaId::LOCAL,
- BufferId::new(1).unwrap(),
- buffer_text,
- cx.background_executor(),
- );
+ let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), buffer_text);
let mut diff = BufferDiffSnapshot::new_sync(buffer.clone(), diff_base.clone(), cx);
assert_hunks(
diff.hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &buffer),
@@ -1404,7 +1394,7 @@ mod tests {
&[(1..2, "two\n", "HELLO\n", DiffHunkStatus::modified_none())],
);
- buffer.edit([(0..0, "point five\n")], cx.background_executor());
+ buffer.edit([(0..0, "point five\n")]);
diff = BufferDiffSnapshot::new_sync(buffer.clone(), diff_base.clone(), cx);
assert_hunks(
diff.hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &buffer),
@@ -1469,12 +1459,7 @@ mod tests {
"
.unindent();
- let buffer = Buffer::new(
- ReplicaId::LOCAL,
- BufferId::new(1).unwrap(),
- buffer_text,
- cx.background_executor(),
- );
+ let buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), buffer_text);
let unstaged_diff = BufferDiffSnapshot::new_sync(buffer.clone(), index_text, cx);
let mut uncommitted_diff =
BufferDiffSnapshot::new_sync(buffer.clone(), head_text.clone(), cx);
@@ -1543,12 +1528,7 @@ mod tests {
"
.unindent();
- let buffer = Buffer::new(
- ReplicaId::LOCAL,
- BufferId::new(1).unwrap(),
- buffer_text,
- cx.background_executor(),
- );
+ let buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), buffer_text);
let diff = cx
.update(|cx| {
BufferDiffSnapshot::new_with_base_text(
@@ -1811,12 +1791,7 @@ mod tests {
for example in table {
let (buffer_text, ranges) = marked_text_ranges(&example.buffer_marked_text, false);
- let buffer = Buffer::new(
- ReplicaId::LOCAL,
- BufferId::new(1).unwrap(),
- buffer_text,
- cx.background_executor(),
- );
+ let buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), buffer_text);
let hunk_range =
buffer.anchor_before(ranges[0].start)..buffer.anchor_before(ranges[0].end);
@@ -1893,7 +1868,6 @@ mod tests {
ReplicaId::LOCAL,
BufferId::new(1).unwrap(),
buffer_text.clone(),
- cx.background_executor(),
);
let unstaged = BufferDiffSnapshot::new_sync(buffer.clone(), index_text, cx);
let uncommitted = BufferDiffSnapshot::new_sync(buffer.clone(), head_text.clone(), cx);
@@ -1967,12 +1941,7 @@ mod tests {
"
.unindent();
- let mut buffer = Buffer::new(
- ReplicaId::LOCAL,
- BufferId::new(1).unwrap(),
- buffer_text_1,
- cx.background_executor(),
- );
+ let mut buffer = Buffer::new(ReplicaId::LOCAL, BufferId::new(1).unwrap(), buffer_text_1);
let empty_diff = cx.update(|cx| BufferDiffSnapshot::empty(&buffer, cx));
let diff_1 = BufferDiffSnapshot::new_sync(buffer.clone(), base_text.clone(), cx);
@@ -1992,7 +1961,6 @@ mod tests {
NINE
"
.unindent(),
- cx.background_executor(),
);
let diff_2 = BufferDiffSnapshot::new_sync(buffer.clone(), base_text.clone(), cx);
assert_eq!(None, diff_2.inner.compare(&diff_1.inner, &buffer));
@@ -2010,7 +1978,6 @@ mod tests {
NINE
"
.unindent(),
- cx.background_executor(),
);
let diff_3 = BufferDiffSnapshot::new_sync(buffer.clone(), base_text.clone(), cx);
let range = diff_3.inner.compare(&diff_2.inner, &buffer).unwrap();
@@ -2028,7 +1995,6 @@ mod tests {
NINE
"
.unindent(),
- cx.background_executor(),
);
let diff_4 = BufferDiffSnapshot::new_sync(buffer.clone(), base_text.clone(), cx);
let range = diff_4.inner.compare(&diff_3.inner, &buffer).unwrap();
@@ -2047,7 +2013,6 @@ mod tests {
NINE
"
.unindent(),
- cx.background_executor(),
);
let diff_5 = BufferDiffSnapshot::new_sync(buffer.snapshot(), base_text.clone(), cx);
let range = diff_5.inner.compare(&diff_4.inner, &buffer).unwrap();
@@ -2066,7 +2031,6 @@ mod tests {
«nine»
"
.unindent(),
- cx.background_executor(),
);
let diff_6 = BufferDiffSnapshot::new_sync(buffer.snapshot(), base_text, cx);
let range = diff_6.inner.compare(&diff_5.inner, &buffer).unwrap();
@@ -2176,14 +2140,14 @@ mod tests {
let working_copy = gen_working_copy(rng, &head_text);
let working_copy = cx.new(|cx| {
language::Buffer::local_normalized(
- Rope::from_str(working_copy.as_str(), cx.background_executor()),
+ Rope::from(working_copy.as_str()),
text::LineEnding::default(),
cx,
)
});
let working_copy = working_copy.read_with(cx, |working_copy, _| working_copy.snapshot());
let mut index_text = if rng.random() {
- Rope::from_str(head_text.as_str(), cx.background_executor())
+ Rope::from(head_text.as_str())
} else {
working_copy.as_rope().clone()
};
diff --git a/crates/channel/src/channel_buffer.rs b/crates/channel/src/channel_buffer.rs
index 0e59ccedf5e8e0767eb9be56608eb433d63d1bf4..efa0850753887c2116ee7916727a870a3528b627 100644
--- a/crates/channel/src/channel_buffer.rs
+++ b/crates/channel/src/channel_buffer.rs
@@ -70,7 +70,6 @@ impl ChannelBuffer {
ReplicaId::new(response.replica_id as u16),
capability,
base_text,
- cx.background_executor(),
)
})?;
buffer.update(cx, |buffer, cx| buffer.apply_ops(operations, cx))?;
diff --git a/crates/collab/src/db/queries/buffers.rs b/crates/collab/src/db/queries/buffers.rs
index fb457abcd46cf32b4a34d87637011b307bbacf9d..6c4cd58d132bdeaaa791f4da8406e0e6d9052981 100644
--- a/crates/collab/src/db/queries/buffers.rs
+++ b/crates/collab/src/db/queries/buffers.rs
@@ -701,12 +701,12 @@ impl Database {
return Ok(());
}
- let mut text_buffer = text::Buffer::new_slow(
+ let mut text_buffer = text::Buffer::new(
clock::ReplicaId::LOCAL,
text::BufferId::new(1).unwrap(),
base_text,
);
- text_buffer.apply_ops(operations.into_iter().filter_map(operation_from_wire), None);
+ text_buffer.apply_ops(operations.into_iter().filter_map(operation_from_wire));
let base_text = text_buffer.text();
let epoch = buffer.epoch + 1;
diff --git a/crates/collab/src/db/tests/buffer_tests.rs b/crates/collab/src/db/tests/buffer_tests.rs
index 82310331ffc864d4bba942f3924dcc644427891b..4eae7a54cba4a906351f05e5945cff5691fd1126 100644
--- a/crates/collab/src/db/tests/buffer_tests.rs
+++ b/crates/collab/src/db/tests/buffer_tests.rs
@@ -74,21 +74,11 @@ async fn test_channel_buffers(db: &Arc) {
ReplicaId::new(0),
text::BufferId::new(1).unwrap(),
"".to_string(),
- &db.test_options.as_ref().unwrap().executor,
);
let operations = vec![
- buffer_a.edit(
- [(0..0, "hello world")],
- &db.test_options.as_ref().unwrap().executor,
- ),
- buffer_a.edit(
- [(5..5, ", cruel")],
- &db.test_options.as_ref().unwrap().executor,
- ),
- buffer_a.edit(
- [(0..5, "goodbye")],
- &db.test_options.as_ref().unwrap().executor,
- ),
+ buffer_a.edit([(0..0, "hello world")]),
+ buffer_a.edit([(5..5, ", cruel")]),
+ buffer_a.edit([(0..5, "goodbye")]),
buffer_a.undo().unwrap().1,
];
assert_eq!(buffer_a.text(), "hello, cruel world");
@@ -112,19 +102,15 @@ async fn test_channel_buffers(db: &Arc) {
ReplicaId::new(0),
text::BufferId::new(1).unwrap(),
buffer_response_b.base_text,
- &db.test_options.as_ref().unwrap().executor,
- );
- buffer_b.apply_ops(
- buffer_response_b.operations.into_iter().map(|operation| {
- let operation = proto::deserialize_operation(operation).unwrap();
- if let language::Operation::Buffer(operation) = operation {
- operation
- } else {
- unreachable!()
- }
- }),
- None,
);
+ buffer_b.apply_ops(buffer_response_b.operations.into_iter().map(|operation| {
+ let operation = proto::deserialize_operation(operation).unwrap();
+ if let language::Operation::Buffer(operation) = operation {
+ operation
+ } else {
+ unreachable!()
+ }
+ }));
assert_eq!(buffer_b.text(), "hello, cruel world");
@@ -261,7 +247,6 @@ async fn test_channel_buffers_last_operations(db: &Database) {
ReplicaId::new(res.replica_id as u16),
text::BufferId::new(1).unwrap(),
"".to_string(),
- &db.test_options.as_ref().unwrap().executor,
));
}
@@ -270,9 +255,9 @@ async fn test_channel_buffers_last_operations(db: &Database) {
user_id,
db,
vec![
- text_buffers[0].edit([(0..0, "a")], &db.test_options.as_ref().unwrap().executor),
- text_buffers[0].edit([(0..0, "b")], &db.test_options.as_ref().unwrap().executor),
- text_buffers[0].edit([(0..0, "c")], &db.test_options.as_ref().unwrap().executor),
+ text_buffers[0].edit([(0..0, "a")]),
+ text_buffers[0].edit([(0..0, "b")]),
+ text_buffers[0].edit([(0..0, "c")]),
],
)
.await;
@@ -282,9 +267,9 @@ async fn test_channel_buffers_last_operations(db: &Database) {
user_id,
db,
vec![
- text_buffers[1].edit([(0..0, "d")], &db.test_options.as_ref().unwrap().executor),
- text_buffers[1].edit([(1..1, "e")], &db.test_options.as_ref().unwrap().executor),
- text_buffers[1].edit([(2..2, "f")], &db.test_options.as_ref().unwrap().executor),
+ text_buffers[1].edit([(0..0, "d")]),
+ text_buffers[1].edit([(1..1, "e")]),
+ text_buffers[1].edit([(2..2, "f")]),
],
)
.await;
@@ -301,15 +286,14 @@ async fn test_channel_buffers_last_operations(db: &Database) {
replica_id,
text::BufferId::new(1).unwrap(),
"def".to_string(),
- &db.test_options.as_ref().unwrap().executor,
);
update_buffer(
buffers[1].channel_id,
user_id,
db,
vec![
- text_buffers[1].edit([(0..0, "g")], &db.test_options.as_ref().unwrap().executor),
- text_buffers[1].edit([(0..0, "h")], &db.test_options.as_ref().unwrap().executor),
+ text_buffers[1].edit([(0..0, "g")]),
+ text_buffers[1].edit([(0..0, "h")]),
],
)
.await;
@@ -318,7 +302,7 @@ async fn test_channel_buffers_last_operations(db: &Database) {
buffers[2].channel_id,
user_id,
db,
- vec![text_buffers[2].edit([(0..0, "i")], &db.test_options.as_ref().unwrap().executor)],
+ vec![text_buffers[2].edit([(0..0, "i")])],
)
.await;
diff --git a/crates/collab/src/tests/editor_tests.rs b/crates/collab/src/tests/editor_tests.rs
index 73fdd8da8890d62f7da39f944edfe333d2c983aa..bdc024aaca7242ab0fe261e3b673bf4d0efe23b1 100644
--- a/crates/collab/src/tests/editor_tests.rs
+++ b/crates/collab/src/tests/editor_tests.rs
@@ -39,6 +39,7 @@ use std::{
Arc,
atomic::{self, AtomicBool, AtomicUsize},
},
+ time::Duration,
};
use text::Point;
use util::{path, rel_path::rel_path, uri};
@@ -1817,14 +1818,7 @@ async fn test_mutual_editor_inlay_hint_cache_update(
settings.project.all_languages.defaults.inlay_hints =
Some(InlayHintSettingsContent {
enabled: Some(true),
- show_value_hints: Some(true),
- edit_debounce_ms: Some(0),
- scroll_debounce_ms: Some(0),
- show_type_hints: Some(true),
- show_parameter_hints: Some(false),
- show_other_hints: Some(true),
- show_background: Some(false),
- toggle_on_modifiers_press: None,
+ ..InlayHintSettingsContent::default()
})
});
});
@@ -1834,15 +1828,8 @@ async fn test_mutual_editor_inlay_hint_cache_update(
store.update_user_settings(cx, |settings| {
settings.project.all_languages.defaults.inlay_hints =
Some(InlayHintSettingsContent {
- show_value_hints: Some(true),
enabled: Some(true),
- edit_debounce_ms: Some(0),
- scroll_debounce_ms: Some(0),
- show_type_hints: Some(true),
- show_parameter_hints: Some(false),
- show_other_hints: Some(true),
- show_background: Some(false),
- toggle_on_modifiers_press: None,
+ ..InlayHintSettingsContent::default()
})
});
});
@@ -1935,6 +1922,7 @@ async fn test_mutual_editor_inlay_hint_cache_update(
});
let fake_language_server = fake_language_servers.next().await.unwrap();
let editor_a = file_a.await.unwrap().downcast::().unwrap();
+ executor.advance_clock(Duration::from_millis(100));
executor.run_until_parked();
let initial_edit = edits_made.load(atomic::Ordering::Acquire);
@@ -1955,6 +1943,7 @@ async fn test_mutual_editor_inlay_hint_cache_update(
.downcast::()
.unwrap();
+ executor.advance_clock(Duration::from_millis(100));
executor.run_until_parked();
editor_b.update(cx_b, |editor, cx| {
assert_eq!(
@@ -1973,6 +1962,7 @@ async fn test_mutual_editor_inlay_hint_cache_update(
});
cx_b.focus(&editor_b);
+ executor.advance_clock(Duration::from_secs(1));
executor.run_until_parked();
editor_a.update(cx_a, |editor, cx| {
assert_eq!(
@@ -1996,6 +1986,7 @@ async fn test_mutual_editor_inlay_hint_cache_update(
});
cx_a.focus(&editor_a);
+ executor.advance_clock(Duration::from_secs(1));
executor.run_until_parked();
editor_a.update(cx_a, |editor, cx| {
assert_eq!(
@@ -2017,6 +2008,7 @@ async fn test_mutual_editor_inlay_hint_cache_update(
.into_response()
.expect("inlay refresh request failed");
+ executor.advance_clock(Duration::from_secs(1));
executor.run_until_parked();
editor_a.update(cx_a, |editor, cx| {
assert_eq!(
diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs
index 37e6622b0343bca9ae6b9179c830071999bf51df..4fa32b6c9ba55e6962547510f52251f16fc9be81 100644
--- a/crates/collab/src/tests/integration_tests.rs
+++ b/crates/collab/src/tests/integration_tests.rs
@@ -3694,7 +3694,7 @@ async fn test_buffer_reloading(
assert_eq!(buf.line_ending(), LineEnding::Unix);
});
- let new_contents = Rope::from_str_small("d\ne\nf");
+ let new_contents = Rope::from("d\ne\nf");
client_a
.fs()
.save(
@@ -4479,7 +4479,7 @@ async fn test_reloading_buffer_manually(
.fs()
.save(
path!("/a/a.rs").as_ref(),
- &Rope::from_str_small("let seven = 7;"),
+ &Rope::from("let seven = 7;"),
LineEnding::Unix,
)
.await
diff --git a/crates/collab/src/tests/random_project_collaboration_tests.rs b/crates/collab/src/tests/random_project_collaboration_tests.rs
index 399f1a663fe72798a4269804955dcfd3678c5cca..7e9b84c0571ed6dff19702ce3532c45d56f6413f 100644
--- a/crates/collab/src/tests/random_project_collaboration_tests.rs
+++ b/crates/collab/src/tests/random_project_collaboration_tests.rs
@@ -27,7 +27,6 @@ use std::{
rc::Rc,
sync::Arc,
};
-use text::Rope;
use util::{
ResultExt, path,
paths::PathStyle,
@@ -939,11 +938,7 @@ impl RandomizedTest for ProjectCollaborationTest {
client
.fs()
- .save(
- &path,
- &Rope::from_str_small(content.as_str()),
- text::LineEnding::Unix,
- )
+ .save(&path, &content.as_str().into(), text::LineEnding::Unix)
.await
.unwrap();
}
diff --git a/crates/dap_adapters/src/dap_adapters.rs b/crates/dap_adapters/src/dap_adapters.rs
index d8a706ba414af2c9e0beb1cffe8357bcece1dc52..2ab9cabc198c4b036301cb92e1f544ae640b898d 100644
--- a/crates/dap_adapters/src/dap_adapters.rs
+++ b/crates/dap_adapters/src/dap_adapters.rs
@@ -42,61 +42,63 @@ pub fn init(cx: &mut App) {
}
#[cfg(test)]
-struct MockDelegate {
- worktree_root: PathBuf,
-}
+mod test_mocks {
+ use super::*;
-#[cfg(test)]
-impl MockDelegate {
- fn new() -> Arc {
- Arc::new(Self {
- worktree_root: PathBuf::from("/tmp/test"),
- })
+ pub(crate) struct MockDelegate {
+ worktree_root: PathBuf,
}
-}
-#[cfg(test)]
-#[async_trait::async_trait]
-impl adapters::DapDelegate for MockDelegate {
- fn worktree_id(&self) -> settings::WorktreeId {
- settings::WorktreeId::from_usize(0)
+ impl MockDelegate {
+ pub(crate) fn new() -> Arc {
+ Arc::new(Self {
+ worktree_root: PathBuf::from("/tmp/test"),
+ })
+ }
}
- fn worktree_root_path(&self) -> &std::path::Path {
- &self.worktree_root
- }
+ #[async_trait::async_trait]
+ impl adapters::DapDelegate for MockDelegate {
+ fn worktree_id(&self) -> settings::WorktreeId {
+ settings::WorktreeId::from_usize(0)
+ }
- fn http_client(&self) -> Arc {
- unimplemented!("Not needed for tests")
- }
+ fn worktree_root_path(&self) -> &std::path::Path {
+ &self.worktree_root
+ }
- fn node_runtime(&self) -> node_runtime::NodeRuntime {
- unimplemented!("Not needed for tests")
- }
+ fn http_client(&self) -> Arc {
+ unimplemented!("Not needed for tests")
+ }
- fn toolchain_store(&self) -> Arc {
- unimplemented!("Not needed for tests")
- }
+ fn node_runtime(&self) -> node_runtime::NodeRuntime {
+ unimplemented!("Not needed for tests")
+ }
- fn fs(&self) -> Arc {
- unimplemented!("Not needed for tests")
- }
+ fn toolchain_store(&self) -> Arc {
+ unimplemented!("Not needed for tests")
+ }
- fn output_to_console(&self, _msg: String) {}
+ fn fs(&self) -> Arc {
+ unimplemented!("Not needed for tests")
+ }
- async fn which(&self, _command: &std::ffi::OsStr) -> Option {
- None
- }
+ fn output_to_console(&self, _msg: String) {}
- async fn read_text_file(&self, _path: &util::rel_path::RelPath) -> Result {
- Ok(String::new())
- }
+ async fn which(&self, _command: &std::ffi::OsStr) -> Option {
+ None
+ }
- async fn shell_env(&self) -> collections::HashMap {
- collections::HashMap::default()
- }
+ async fn read_text_file(&self, _path: &util::rel_path::RelPath) -> Result {
+ Ok(String::new())
+ }
- fn is_headless(&self) -> bool {
- false
+ async fn shell_env(&self) -> collections::HashMap {
+ collections::HashMap::default()
+ }
+
+ fn is_headless(&self) -> bool {
+ false
+ }
}
}
diff --git a/crates/dap_adapters/src/python.rs b/crates/dap_adapters/src/python.rs
index e718f66c78099044baed837da0ddc7bfa96ffa1c..4d81e5ba851305ae3adc2ee0a6ab6a29f43edd62 100644
--- a/crates/dap_adapters/src/python.rs
+++ b/crates/dap_adapters/src/python.rs
@@ -824,29 +824,58 @@ impl DebugAdapter for PythonDebugAdapter {
.await;
}
- let base_path = config
- .config
- .get("cwd")
- .and_then(|cwd| {
- RelPath::new(
- cwd.as_str()
- .map(Path::new)?
- .strip_prefix(delegate.worktree_root_path())
- .ok()?,
- PathStyle::local(),
- )
- .ok()
+ let base_paths = ["cwd", "program", "module"]
+ .into_iter()
+ .filter_map(|key| {
+ config.config.get(key).and_then(|cwd| {
+ RelPath::new(
+ cwd.as_str()
+ .map(Path::new)?
+ .strip_prefix(delegate.worktree_root_path())
+ .ok()?,
+ PathStyle::local(),
+ )
+ .ok()
+ })
})
- .unwrap_or_else(|| RelPath::empty().into());
- let toolchain = delegate
- .toolchain_store()
- .active_toolchain(
- delegate.worktree_id(),
- base_path.into_arc(),
- language::LanguageName::new(Self::LANGUAGE_NAME),
- cx,
+ .chain(
+ // While Debugpy's wiki saids absolute paths are required, but it actually supports relative paths when cwd is passed in.
+ // (Which should always be the case because Zed defaults to the cwd worktree root)
+ // So we want to check that these relative paths find toolchains as well. Otherwise, they won't be checked
+ // because the strip prefix in the iteration above will return an error
+ config
+ .config
+ .get("cwd")
+ .map(|_| {
+ ["program", "module"].into_iter().filter_map(|key| {
+ config.config.get(key).and_then(|value| {
+ let path = Path::new(value.as_str()?);
+ RelPath::new(path, PathStyle::local()).ok()
+ })
+ })
+ })
+ .into_iter()
+ .flatten(),
)
- .await;
+ .chain([RelPath::empty().into()]);
+
+ let mut toolchain = None;
+
+ for base_path in base_paths {
+ if let Some(found_toolchain) = delegate
+ .toolchain_store()
+ .active_toolchain(
+ delegate.worktree_id(),
+ base_path.into_arc(),
+ language::LanguageName::new(Self::LANGUAGE_NAME),
+ cx,
+ )
+ .await
+ {
+ toolchain = Some(found_toolchain);
+ break;
+ }
+ }
self.fetch_debugpy_whl(toolchain.clone(), delegate)
.await
@@ -914,7 +943,7 @@ mod tests {
let result = adapter
.get_installed_binary(
- &MockDelegate::new(),
+ &test_mocks::MockDelegate::new(),
&task_def,
None,
None,
@@ -955,7 +984,7 @@ mod tests {
let result_host = adapter
.get_installed_binary(
- &MockDelegate::new(),
+ &test_mocks::MockDelegate::new(),
&task_def_host,
None,
None,
diff --git a/crates/debugger_ui/src/session/running/console.rs b/crates/debugger_ui/src/session/running/console.rs
index 2d01a325a2b0056bfbf42e519a79a4ec199c4a9d..e157d832b440b8016f152c88b376a9418ee3c843 100644
--- a/crates/debugger_ui/src/session/running/console.rs
+++ b/crates/debugger_ui/src/session/running/console.rs
@@ -6,7 +6,10 @@ use alacritty_terminal::vte::ansi;
use anyhow::Result;
use collections::HashMap;
use dap::{CompletionItem, CompletionItemType, OutputEvent};
-use editor::{Bias, CompletionProvider, Editor, EditorElement, EditorStyle, ExcerptId};
+use editor::{
+ Bias, CompletionProvider, Editor, EditorElement, EditorMode, EditorStyle, ExcerptId,
+ SizingBehavior,
+};
use fuzzy::StringMatchCandidate;
use gpui::{
Action as _, AppContext, Context, Corner, Entity, FocusHandle, Focusable, HighlightStyle, Hsla,
@@ -59,6 +62,11 @@ impl Console {
) -> Self {
let console = cx.new(|cx| {
let mut editor = Editor::multi_line(window, cx);
+ editor.set_mode(EditorMode::Full {
+ scale_ui_elements_with_buffer_font_size: true,
+ show_active_line_background: true,
+ sizing_behavior: SizingBehavior::ExcludeOverscrollMargin,
+ });
editor.move_to_end(&editor::actions::MoveToEnd, window, cx);
editor.set_read_only(true);
editor.disable_scrollbars_and_minimap(window, cx);
diff --git a/crates/diagnostics/Cargo.toml b/crates/diagnostics/Cargo.toml
index 5bb6892f0cea9500fd66671f8e8e86ab9a6d901a..0eccf44c357125e5e11fcdccda8280c22006c6fa 100644
--- a/crates/diagnostics/Cargo.toml
+++ b/crates/diagnostics/Cargo.toml
@@ -34,6 +34,7 @@ theme.workspace = true
ui.workspace = true
util.workspace = true
workspace.workspace = true
+itertools.workspace = true
[dev-dependencies]
client = { workspace = true, features = ["test-support"] }
diff --git a/crates/diagnostics/src/buffer_diagnostics.rs b/crates/diagnostics/src/buffer_diagnostics.rs
index 1205cef385fdd91af8e3f986b432b9fff4ad3ac6..8fe503a706027fb6ed2f0b9114450eb79c2aa027 100644
--- a/crates/diagnostics/src/buffer_diagnostics.rs
+++ b/crates/diagnostics/src/buffer_diagnostics.rs
@@ -1,5 +1,5 @@
use crate::{
- DIAGNOSTICS_UPDATE_DELAY, IncludeWarnings, ToggleWarnings, context_range_for_entry,
+ DIAGNOSTICS_UPDATE_DEBOUNCE, IncludeWarnings, ToggleWarnings, context_range_for_entry,
diagnostic_renderer::{DiagnosticBlock, DiagnosticRenderer},
toolbar_controls::DiagnosticsToolbarEditor,
};
@@ -283,7 +283,7 @@ impl BufferDiagnosticsEditor {
self.update_excerpts_task = Some(cx.spawn_in(window, async move |editor, cx| {
cx.background_executor()
- .timer(DIAGNOSTICS_UPDATE_DELAY)
+ .timer(DIAGNOSTICS_UPDATE_DEBOUNCE)
.await;
if let Some(buffer) = buffer {
@@ -938,10 +938,6 @@ impl DiagnosticsToolbarEditor for WeakEntity {
.unwrap_or(false)
}
- fn has_stale_excerpts(&self, _cx: &App) -> bool {
- false
- }
-
fn is_updating(&self, cx: &App) -> bool {
self.read_with(cx, |buffer_diagnostics_editor, cx| {
buffer_diagnostics_editor.update_excerpts_task.is_some()
diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs
index 5a43fd135391a5e3d97d5c65e6d3be826210f102..5506cdba9ae4aaa7fbf1246aaa7b07e653ad0efc 100644
--- a/crates/diagnostics/src/diagnostics.rs
+++ b/crates/diagnostics/src/diagnostics.rs
@@ -9,7 +9,7 @@ mod diagnostics_tests;
use anyhow::Result;
use buffer_diagnostics::BufferDiagnosticsEditor;
-use collections::{BTreeSet, HashMap};
+use collections::{BTreeSet, HashMap, HashSet};
use diagnostic_renderer::DiagnosticBlock;
use editor::{
Editor, EditorEvent, ExcerptRange, MultiBuffer, PathKey,
@@ -17,10 +17,11 @@ use editor::{
multibuffer_context_lines,
};
use gpui::{
- AnyElement, AnyView, App, AsyncApp, Context, Entity, EventEmitter, FocusHandle, Focusable,
- Global, InteractiveElement, IntoElement, ParentElement, Render, SharedString, Styled,
- Subscription, Task, WeakEntity, Window, actions, div,
+ AnyElement, AnyView, App, AsyncApp, Context, Entity, EventEmitter, FocusHandle, FocusOutEvent,
+ Focusable, Global, InteractiveElement, IntoElement, ParentElement, Render, SharedString,
+ Styled, Subscription, Task, WeakEntity, Window, actions, div,
};
+use itertools::Itertools as _;
use language::{
Bias, Buffer, BufferRow, BufferSnapshot, DiagnosticEntry, DiagnosticEntryRef, Point,
ToTreeSitterPoint,
@@ -32,7 +33,7 @@ use project::{
use settings::Settings;
use std::{
any::{Any, TypeId},
- cmp::{self, Ordering},
+ cmp,
ops::{Range, RangeInclusive},
sync::Arc,
time::Duration,
@@ -89,8 +90,8 @@ pub(crate) struct ProjectDiagnosticsEditor {
impl EventEmitter for ProjectDiagnosticsEditor {}
-const DIAGNOSTICS_UPDATE_DELAY: Duration = Duration::from_millis(50);
-const DIAGNOSTICS_SUMMARY_UPDATE_DELAY: Duration = Duration::from_millis(30);
+const DIAGNOSTICS_UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
+const DIAGNOSTICS_SUMMARY_UPDATE_DEBOUNCE: Duration = Duration::from_millis(30);
impl Render for ProjectDiagnosticsEditor {
fn render(&mut self, _: &mut Window, cx: &mut Context) -> impl IntoElement {
@@ -149,6 +150,12 @@ impl Render for ProjectDiagnosticsEditor {
}
}
+#[derive(PartialEq, Eq, Copy, Clone, Debug)]
+enum RetainExcerpts {
+ Yes,
+ No,
+}
+
impl ProjectDiagnosticsEditor {
pub fn register(
workspace: &mut Workspace,
@@ -165,14 +172,21 @@ impl ProjectDiagnosticsEditor {
window: &mut Window,
cx: &mut Context,
) -> Self {
- let project_event_subscription =
- cx.subscribe_in(&project_handle, window, |this, _project, event, window, cx| match event {
+ let project_event_subscription = cx.subscribe_in(
+ &project_handle,
+ window,
+ |this, _project, event, window, cx| match event {
project::Event::DiskBasedDiagnosticsStarted { .. } => {
cx.notify();
}
project::Event::DiskBasedDiagnosticsFinished { language_server_id } => {
log::debug!("disk based diagnostics finished for server {language_server_id}");
- this.update_stale_excerpts(window, cx);
+ this.close_diagnosticless_buffers(
+ window,
+ cx,
+ this.editor.focus_handle(cx).contains_focused(window, cx)
+ || this.focus_handle.contains_focused(window, cx),
+ );
}
project::Event::DiagnosticsUpdated {
language_server_id,
@@ -181,34 +195,39 @@ impl ProjectDiagnosticsEditor {
this.paths_to_update.extend(paths.clone());
this.diagnostic_summary_update = cx.spawn(async move |this, cx| {
cx.background_executor()
- .timer(DIAGNOSTICS_SUMMARY_UPDATE_DELAY)
+ .timer(DIAGNOSTICS_SUMMARY_UPDATE_DEBOUNCE)
.await;
this.update(cx, |this, cx| {
this.update_diagnostic_summary(cx);
})
.log_err();
});
- cx.emit(EditorEvent::TitleChanged);
- if this.editor.focus_handle(cx).contains_focused(window, cx) || this.focus_handle.contains_focused(window, cx) {
- log::debug!("diagnostics updated for server {language_server_id}, paths {paths:?}. recording change");
- } else {
- log::debug!("diagnostics updated for server {language_server_id}, paths {paths:?}. updating excerpts");
- this.update_stale_excerpts(window, cx);
- }
+ log::debug!(
+ "diagnostics updated for server {language_server_id}, \
+ paths {paths:?}. updating excerpts"
+ );
+ let focused = this.editor.focus_handle(cx).contains_focused(window, cx)
+ || this.focus_handle.contains_focused(window, cx);
+ this.update_stale_excerpts(
+ if focused {
+ RetainExcerpts::Yes
+ } else {
+ RetainExcerpts::No
+ },
+ window,
+ cx,
+ );
}
_ => {}
- });
+ },
+ );
let focus_handle = cx.focus_handle();
- cx.on_focus_in(&focus_handle, window, |this, window, cx| {
- this.focus_in(window, cx)
- })
- .detach();
- cx.on_focus_out(&focus_handle, window, |this, _event, window, cx| {
- this.focus_out(window, cx)
- })
- .detach();
+ cx.on_focus_in(&focus_handle, window, Self::focus_in)
+ .detach();
+ cx.on_focus_out(&focus_handle, window, Self::focus_out)
+ .detach();
let excerpts = cx.new(|cx| MultiBuffer::new(project_handle.read(cx).capability()));
let editor = cx.new(|cx| {
@@ -238,8 +257,11 @@ impl ProjectDiagnosticsEditor {
window.focus(&this.focus_handle);
}
}
- EditorEvent::Blurred => this.update_stale_excerpts(window, cx),
- EditorEvent::Saved => this.update_stale_excerpts(window, cx),
+ EditorEvent::Blurred => this.close_diagnosticless_buffers(window, cx, false),
+ EditorEvent::Saved => this.close_diagnosticless_buffers(window, cx, true),
+ EditorEvent::SelectionsChanged { .. } => {
+ this.close_diagnosticless_buffers(window, cx, true)
+ }
_ => {}
}
},
@@ -283,15 +305,67 @@ impl ProjectDiagnosticsEditor {
this
}
- fn update_stale_excerpts(&mut self, window: &mut Window, cx: &mut Context) {
- if self.update_excerpts_task.is_some() || self.multibuffer.read(cx).is_dirty(cx) {
+ /// Closes all excerpts of buffers that:
+ /// - have no diagnostics anymore
+ /// - are saved (not dirty)
+ /// - and, if `reatin_selections` is true, do not have selections within them
+ fn close_diagnosticless_buffers(
+ &mut self,
+ _window: &mut Window,
+ cx: &mut Context,
+ retain_selections: bool,
+ ) {
+ let buffer_ids = self.multibuffer.read(cx).all_buffer_ids();
+ let selected_buffers = self.editor.update(cx, |editor, cx| {
+ editor
+ .selections
+ .all_anchors(cx)
+ .iter()
+ .filter_map(|anchor| anchor.start.buffer_id)
+ .collect::>()
+ });
+ for buffer_id in buffer_ids {
+ if retain_selections && selected_buffers.contains(&buffer_id) {
+ continue;
+ }
+ let has_blocks = self
+ .blocks
+ .get(&buffer_id)
+ .is_none_or(|blocks| blocks.is_empty());
+ if !has_blocks {
+ continue;
+ }
+ let is_dirty = self
+ .multibuffer
+ .read(cx)
+ .buffer(buffer_id)
+ .is_some_and(|buffer| buffer.read(cx).is_dirty());
+ if !is_dirty {
+ continue;
+ }
+ self.multibuffer.update(cx, |b, cx| {
+ b.remove_excerpts_for_buffer(buffer_id, cx);
+ });
+ }
+ }
+
+ fn update_stale_excerpts(
+ &mut self,
+ mut retain_excerpts: RetainExcerpts,
+ window: &mut Window,
+ cx: &mut Context,
+ ) {
+ if self.update_excerpts_task.is_some() {
return;
}
+ if self.multibuffer.read(cx).is_dirty(cx) {
+ retain_excerpts = RetainExcerpts::Yes;
+ }
let project_handle = self.project.clone();
self.update_excerpts_task = Some(cx.spawn_in(window, async move |this, cx| {
cx.background_executor()
- .timer(DIAGNOSTICS_UPDATE_DELAY)
+ .timer(DIAGNOSTICS_UPDATE_DEBOUNCE)
.await;
loop {
let Some(path) = this.update(cx, |this, cx| {
@@ -312,7 +386,7 @@ impl ProjectDiagnosticsEditor {
.log_err()
{
this.update_in(cx, |this, window, cx| {
- this.update_excerpts(buffer, window, cx)
+ this.update_excerpts(buffer, retain_excerpts, window, cx)
})?
.await?;
}
@@ -378,10 +452,10 @@ impl ProjectDiagnosticsEditor {
}
}
- fn focus_out(&mut self, window: &mut Window, cx: &mut Context) {
+ fn focus_out(&mut self, _: FocusOutEvent, window: &mut Window, cx: &mut Context) {
if !self.focus_handle.is_focused(window) && !self.editor.focus_handle(cx).is_focused(window)
{
- self.update_stale_excerpts(window, cx);
+ self.close_diagnosticless_buffers(window, cx, false);
}
}
@@ -403,12 +477,13 @@ impl ProjectDiagnosticsEditor {
});
}
}
+ multibuffer.clear(cx);
});
self.paths_to_update = project_paths;
});
- self.update_stale_excerpts(window, cx);
+ self.update_stale_excerpts(RetainExcerpts::No, window, cx);
}
fn diagnostics_are_unchanged(
@@ -431,6 +506,7 @@ impl ProjectDiagnosticsEditor {
fn update_excerpts(
&mut self,
buffer: Entity,
+ retain_excerpts: RetainExcerpts,
window: &mut Window,
cx: &mut Context,
) -> Task> {
@@ -497,24 +573,27 @@ impl ProjectDiagnosticsEditor {
)
})?;
- for item in more {
- let i = blocks
- .binary_search_by(|probe| {
- probe
- .initial_range
- .start
- .cmp(&item.initial_range.start)
- .then(probe.initial_range.end.cmp(&item.initial_range.end))
- .then(Ordering::Greater)
- })
- .unwrap_or_else(|i| i);
- blocks.insert(i, item);
- }
+ blocks.extend(more);
}
- let mut excerpt_ranges: Vec> = Vec::new();
+ let mut excerpt_ranges: Vec> = match retain_excerpts {
+ RetainExcerpts::No => Vec::new(),
+ RetainExcerpts::Yes => this.update(cx, |this, cx| {
+ this.multibuffer.update(cx, |multi_buffer, cx| {
+ multi_buffer
+ .excerpts_for_buffer(buffer_id, cx)
+ .into_iter()
+ .map(|(_, range)| ExcerptRange {
+ context: range.context.to_point(&buffer_snapshot),
+ primary: range.primary.to_point(&buffer_snapshot),
+ })
+ .collect()
+ })
+ })?,
+ };
+ let mut result_blocks = vec![None; excerpt_ranges.len()];
let context_lines = cx.update(|_, cx| multibuffer_context_lines(cx))?;
- for b in blocks.iter() {
+ for b in blocks {
let excerpt_range = context_range_for_entry(
b.initial_range.clone(),
context_lines,
@@ -541,7 +620,8 @@ impl ProjectDiagnosticsEditor {
context: excerpt_range,
primary: b.initial_range.clone(),
},
- )
+ );
+ result_blocks.insert(i, Some(b));
}
this.update_in(cx, |this, window, cx| {
@@ -562,7 +642,7 @@ impl ProjectDiagnosticsEditor {
)
});
#[cfg(test)]
- let cloned_blocks = blocks.clone();
+ let cloned_blocks = result_blocks.clone();
if was_empty && let Some(anchor_range) = anchor_ranges.first() {
let range_to_select = anchor_range.start..anchor_range.start;
@@ -576,22 +656,20 @@ impl ProjectDiagnosticsEditor {
}
}
- let editor_blocks =
- anchor_ranges
- .into_iter()
- .zip(blocks.into_iter())
- .map(|(anchor, block)| {
- let editor = this.editor.downgrade();
- BlockProperties {
- placement: BlockPlacement::Near(anchor.start),
- height: Some(1),
- style: BlockStyle::Flex,
- render: Arc::new(move |bcx| {
- block.render_block(editor.clone(), bcx)
- }),
- priority: 1,
- }
- });
+ let editor_blocks = anchor_ranges
+ .into_iter()
+ .zip_eq(result_blocks.into_iter())
+ .filter_map(|(anchor, block)| {
+ let block = block?;
+ let editor = this.editor.downgrade();
+ Some(BlockProperties {
+ placement: BlockPlacement::Near(anchor.start),
+ height: Some(1),
+ style: BlockStyle::Flex,
+ render: Arc::new(move |bcx| block.render_block(editor.clone(), bcx)),
+ priority: 1,
+ })
+ });
let block_ids = this.editor.update(cx, |editor, cx| {
editor.display_map.update(cx, |display_map, cx| {
@@ -601,7 +679,9 @@ impl ProjectDiagnosticsEditor {
#[cfg(test)]
{
- for (block_id, block) in block_ids.iter().zip(cloned_blocks.iter()) {
+ for (block_id, block) in
+ block_ids.iter().zip(cloned_blocks.into_iter().flatten())
+ {
let markdown = block.markdown.clone();
editor::test::set_block_content_for_tests(
&this.editor,
@@ -626,6 +706,7 @@ impl ProjectDiagnosticsEditor {
fn update_diagnostic_summary(&mut self, cx: &mut Context) {
self.summary = self.project.read(cx).diagnostic_summary(false, cx);
+ cx.emit(EditorEvent::TitleChanged);
}
}
@@ -843,13 +924,6 @@ impl DiagnosticsToolbarEditor for WeakEntity {
.unwrap_or(false)
}
- fn has_stale_excerpts(&self, cx: &App) -> bool {
- self.read_with(cx, |project_diagnostics_editor, _cx| {
- !project_diagnostics_editor.paths_to_update.is_empty()
- })
- .unwrap_or(false)
- }
-
fn is_updating(&self, cx: &App) -> bool {
self.read_with(cx, |project_diagnostics_editor, cx| {
project_diagnostics_editor.update_excerpts_task.is_some()
@@ -1010,12 +1084,6 @@ async fn heuristic_syntactic_expand(
return;
}
}
-
- log::info!(
- "Expanding to ancestor started on {} node\
- exceeding row limit of {max_row_count}.",
- node.grammar_name()
- );
*ancestor_range = Some(None);
}
})
diff --git a/crates/diagnostics/src/diagnostics_tests.rs b/crates/diagnostics/src/diagnostics_tests.rs
index 824d4db6a58c06db5df4c04ac79ee1e509d55d4d..ad7c675fa82aaa95379a9e06dfc2561880d5da7f 100644
--- a/crates/diagnostics/src/diagnostics_tests.rs
+++ b/crates/diagnostics/src/diagnostics_tests.rs
@@ -119,7 +119,7 @@ async fn test_diagnostics(cx: &mut TestAppContext) {
let editor = diagnostics.update(cx, |diagnostics, _| diagnostics.editor.clone());
diagnostics
- .next_notification(DIAGNOSTICS_UPDATE_DELAY + Duration::from_millis(10), cx)
+ .next_notification(DIAGNOSTICS_UPDATE_DEBOUNCE + Duration::from_millis(10), cx)
.await;
pretty_assertions::assert_eq!(
@@ -190,7 +190,7 @@ async fn test_diagnostics(cx: &mut TestAppContext) {
});
diagnostics
- .next_notification(DIAGNOSTICS_UPDATE_DELAY + Duration::from_millis(10), cx)
+ .next_notification(DIAGNOSTICS_UPDATE_DEBOUNCE + Duration::from_millis(10), cx)
.await;
pretty_assertions::assert_eq!(
@@ -277,7 +277,7 @@ async fn test_diagnostics(cx: &mut TestAppContext) {
});
diagnostics
- .next_notification(DIAGNOSTICS_UPDATE_DELAY + Duration::from_millis(10), cx)
+ .next_notification(DIAGNOSTICS_UPDATE_DEBOUNCE + Duration::from_millis(10), cx)
.await;
pretty_assertions::assert_eq!(
@@ -391,7 +391,7 @@ async fn test_diagnostics_with_folds(cx: &mut TestAppContext) {
// Only the first language server's diagnostics are shown.
cx.executor()
- .advance_clock(DIAGNOSTICS_UPDATE_DELAY + Duration::from_millis(10));
+ .advance_clock(DIAGNOSTICS_UPDATE_DEBOUNCE + Duration::from_millis(10));
cx.executor().run_until_parked();
editor.update_in(cx, |editor, window, cx| {
editor.fold_ranges(vec![Point::new(0, 0)..Point::new(3, 0)], false, window, cx);
@@ -490,7 +490,7 @@ async fn test_diagnostics_multiple_servers(cx: &mut TestAppContext) {
// Only the first language server's diagnostics are shown.
cx.executor()
- .advance_clock(DIAGNOSTICS_UPDATE_DELAY + Duration::from_millis(10));
+ .advance_clock(DIAGNOSTICS_UPDATE_DEBOUNCE + Duration::from_millis(10));
cx.executor().run_until_parked();
pretty_assertions::assert_eq!(
@@ -530,7 +530,7 @@ async fn test_diagnostics_multiple_servers(cx: &mut TestAppContext) {
// Both language server's diagnostics are shown.
cx.executor()
- .advance_clock(DIAGNOSTICS_UPDATE_DELAY + Duration::from_millis(10));
+ .advance_clock(DIAGNOSTICS_UPDATE_DEBOUNCE + Duration::from_millis(10));
cx.executor().run_until_parked();
pretty_assertions::assert_eq!(
@@ -587,7 +587,7 @@ async fn test_diagnostics_multiple_servers(cx: &mut TestAppContext) {
// Only the first language server's diagnostics are updated.
cx.executor()
- .advance_clock(DIAGNOSTICS_UPDATE_DELAY + Duration::from_millis(10));
+ .advance_clock(DIAGNOSTICS_UPDATE_DEBOUNCE + Duration::from_millis(10));
cx.executor().run_until_parked();
pretty_assertions::assert_eq!(
@@ -629,7 +629,7 @@ async fn test_diagnostics_multiple_servers(cx: &mut TestAppContext) {
// Both language servers' diagnostics are updated.
cx.executor()
- .advance_clock(DIAGNOSTICS_UPDATE_DELAY + Duration::from_millis(10));
+ .advance_clock(DIAGNOSTICS_UPDATE_DEBOUNCE + Duration::from_millis(10));
cx.executor().run_until_parked();
pretty_assertions::assert_eq!(
@@ -760,7 +760,7 @@ async fn test_random_diagnostics_blocks(cx: &mut TestAppContext, mut rng: StdRng
.unwrap()
});
cx.executor()
- .advance_clock(DIAGNOSTICS_UPDATE_DELAY + Duration::from_millis(10));
+ .advance_clock(DIAGNOSTICS_UPDATE_DEBOUNCE + Duration::from_millis(10));
cx.run_until_parked();
}
@@ -769,7 +769,7 @@ async fn test_random_diagnostics_blocks(cx: &mut TestAppContext, mut rng: StdRng
log::info!("updating mutated diagnostics view");
mutated_diagnostics.update_in(cx, |diagnostics, window, cx| {
- diagnostics.update_stale_excerpts(window, cx)
+ diagnostics.update_stale_excerpts(RetainExcerpts::No, window, cx)
});
log::info!("constructing reference diagnostics view");
@@ -777,7 +777,7 @@ async fn test_random_diagnostics_blocks(cx: &mut TestAppContext, mut rng: StdRng
ProjectDiagnosticsEditor::new(true, project.clone(), workspace.downgrade(), window, cx)
});
cx.executor()
- .advance_clock(DIAGNOSTICS_UPDATE_DELAY + Duration::from_millis(10));
+ .advance_clock(DIAGNOSTICS_UPDATE_DEBOUNCE + Duration::from_millis(10));
cx.run_until_parked();
let mutated_excerpts =
@@ -789,7 +789,12 @@ async fn test_random_diagnostics_blocks(cx: &mut TestAppContext, mut rng: StdRng
// The mutated view may contain more than the reference view as
// we don't currently shrink excerpts when diagnostics were removed.
- let mut ref_iter = reference_excerpts.lines().filter(|line| *line != "§ -----");
+ let mut ref_iter = reference_excerpts.lines().filter(|line| {
+ // ignore $ ---- and $ .rs
+ !line.starts_with('§')
+ || line.starts_with("§ diagnostic")
+ || line.starts_with("§ related info")
+ });
let mut next_ref_line = ref_iter.next();
let mut skipped_block = false;
@@ -797,7 +802,12 @@ async fn test_random_diagnostics_blocks(cx: &mut TestAppContext, mut rng: StdRng
if let Some(ref_line) = next_ref_line {
if mut_line == ref_line {
next_ref_line = ref_iter.next();
- } else if mut_line.contains('§') && mut_line != "§ -----" {
+ } else if mut_line.contains('§')
+ // ignore $ ---- and $ .rs
+ && (!mut_line.starts_with('§')
+ || mut_line.starts_with("§ diagnostic")
+ || mut_line.starts_with("§ related info"))
+ {
skipped_block = true;
}
}
@@ -877,7 +887,7 @@ async fn test_random_diagnostics_with_inlays(cx: &mut TestAppContext, mut rng: S
vec![Inlay::edit_prediction(
post_inc(&mut next_inlay_id),
snapshot.buffer_snapshot().anchor_before(position),
- Rope::from_iter_small(["Test inlay ", "next_inlay_id"]),
+ Rope::from_iter(["Test inlay ", "next_inlay_id"]),
)],
cx,
);
@@ -949,7 +959,7 @@ async fn test_random_diagnostics_with_inlays(cx: &mut TestAppContext, mut rng: S
.unwrap()
});
cx.executor()
- .advance_clock(DIAGNOSTICS_UPDATE_DELAY + Duration::from_millis(10));
+ .advance_clock(DIAGNOSTICS_UPDATE_DEBOUNCE + Duration::from_millis(10));
cx.run_until_parked();
}
@@ -958,11 +968,11 @@ async fn test_random_diagnostics_with_inlays(cx: &mut TestAppContext, mut rng: S
log::info!("updating mutated diagnostics view");
mutated_diagnostics.update_in(cx, |diagnostics, window, cx| {
- diagnostics.update_stale_excerpts(window, cx)
+ diagnostics.update_stale_excerpts(RetainExcerpts::No, window, cx)
});
cx.executor()
- .advance_clock(DIAGNOSTICS_UPDATE_DELAY + Duration::from_millis(10));
+ .advance_clock(DIAGNOSTICS_UPDATE_DEBOUNCE + Duration::from_millis(10));
cx.run_until_parked();
}
@@ -1427,7 +1437,7 @@ async fn test_diagnostics_with_code(cx: &mut TestAppContext) {
let editor = diagnostics.update(cx, |diagnostics, _| diagnostics.editor.clone());
diagnostics
- .next_notification(DIAGNOSTICS_UPDATE_DELAY + Duration::from_millis(10), cx)
+ .next_notification(DIAGNOSTICS_UPDATE_DEBOUNCE + Duration::from_millis(10), cx)
.await;
// Verify that the diagnostic codes are displayed correctly
@@ -1704,7 +1714,7 @@ async fn test_buffer_diagnostics(cx: &mut TestAppContext) {
// wait a little bit to ensure that the buffer diagnostic's editor content
// is rendered.
cx.executor()
- .advance_clock(DIAGNOSTICS_UPDATE_DELAY + Duration::from_millis(10));
+ .advance_clock(DIAGNOSTICS_UPDATE_DEBOUNCE + Duration::from_millis(10));
pretty_assertions::assert_eq!(
editor_content_with_blocks(&editor, cx),
@@ -1837,7 +1847,7 @@ async fn test_buffer_diagnostics_without_warnings(cx: &mut TestAppContext) {
// wait a little bit to ensure that the buffer diagnostic's editor content
// is rendered.
cx.executor()
- .advance_clock(DIAGNOSTICS_UPDATE_DELAY + Duration::from_millis(10));
+ .advance_clock(DIAGNOSTICS_UPDATE_DEBOUNCE + Duration::from_millis(10));
pretty_assertions::assert_eq!(
editor_content_with_blocks(&editor, cx),
@@ -1971,7 +1981,7 @@ async fn test_buffer_diagnostics_multiple_servers(cx: &mut TestAppContext) {
// wait a little bit to ensure that the buffer diagnostic's editor content
// is rendered.
cx.executor()
- .advance_clock(DIAGNOSTICS_UPDATE_DELAY + Duration::from_millis(10));
+ .advance_clock(DIAGNOSTICS_UPDATE_DEBOUNCE + Duration::from_millis(10));
pretty_assertions::assert_eq!(
editor_content_with_blocks(&editor, cx),
@@ -2070,7 +2080,7 @@ fn random_lsp_diagnostic(
const ERROR_MARGIN: usize = 10;
let file_content = fs.read_file_sync(path).unwrap();
- let file_text = Rope::from_str_small(String::from_utf8_lossy(&file_content).as_ref());
+ let file_text = Rope::from(String::from_utf8_lossy(&file_content).as_ref());
let start = rng.random_range(0..file_text.len().saturating_add(ERROR_MARGIN));
let end = rng.random_range(start..file_text.len().saturating_add(ERROR_MARGIN));
diff --git a/crates/diagnostics/src/toolbar_controls.rs b/crates/diagnostics/src/toolbar_controls.rs
index b55fa5783dc96965a7d1ce7f52c5e4336b674ed2..2ba64d39dfd63fc246bf3dedf5974909c0d67a6f 100644
--- a/crates/diagnostics/src/toolbar_controls.rs
+++ b/crates/diagnostics/src/toolbar_controls.rs
@@ -16,9 +16,6 @@ pub(crate) trait DiagnosticsToolbarEditor: Send + Sync {
/// Toggles whether warning diagnostics should be displayed by the
/// diagnostics editor.
fn toggle_warnings(&self, window: &mut Window, cx: &mut App);
- /// Indicates whether any of the excerpts displayed by the diagnostics
- /// editor are stale.
- fn has_stale_excerpts(&self, cx: &App) -> bool;
/// Indicates whether the diagnostics editor is currently updating the
/// diagnostics.
fn is_updating(&self, cx: &App) -> bool;
@@ -37,14 +34,12 @@ pub(crate) trait DiagnosticsToolbarEditor: Send + Sync {
impl Render for ToolbarControls {
fn render(&mut self, _: &mut Window, cx: &mut Context) -> impl IntoElement {
- let mut has_stale_excerpts = false;
let mut include_warnings = false;
let mut is_updating = false;
match &self.editor {
Some(editor) => {
include_warnings = editor.include_warnings(cx);
- has_stale_excerpts = editor.has_stale_excerpts(cx);
is_updating = editor.is_updating(cx);
}
None => {}
@@ -86,7 +81,6 @@ impl Render for ToolbarControls {
IconButton::new("refresh-diagnostics", IconName::ArrowCircle)
.icon_color(Color::Info)
.shape(IconButtonShape::Square)
- .disabled(!has_stale_excerpts)
.tooltip(Tooltip::for_action_title(
"Refresh diagnostics",
&ToggleDiagnosticsRefresh,
diff --git a/crates/edit_prediction_button/src/edit_prediction_button.rs b/crates/edit_prediction_button/src/edit_prediction_button.rs
index 594c290730d5c734430e747ac6d09d6cbbbd4d0e..70c861ab1112630c2e3293cb54a4e96c6754b3bd 100644
--- a/crates/edit_prediction_button/src/edit_prediction_button.rs
+++ b/crates/edit_prediction_button/src/edit_prediction_button.rs
@@ -13,7 +13,7 @@ use gpui::{
};
use indoc::indoc;
use language::{
- EditPredictionsMode, File, Language, Rope,
+ EditPredictionsMode, File, Language,
language_settings::{self, AllLanguageSettings, EditPredictionProvider, all_language_settings},
};
use project::DisableAiSettings;
@@ -1056,11 +1056,8 @@ async fn open_disabled_globs_setting_in_editor(
) -> Result<()> {
let settings_editor = workspace
.update_in(cx, |_, window, cx| {
- create_and_open_local_file(paths::settings_file(), window, cx, |cx| {
- Rope::from_str(
- settings::initial_user_settings_content().as_ref(),
- cx.background_executor(),
- )
+ create_and_open_local_file(paths::settings_file(), window, cx, || {
+ settings::initial_user_settings_content().as_ref().into()
})
})?
.await?
diff --git a/crates/editor/src/code_context_menus.rs b/crates/editor/src/code_context_menus.rs
index 359c985ee9208a1a83e3458635df883c2cf991a8..b7f3d57870a9504b7e6f9f736a0951b9b4b733e5 100644
--- a/crates/editor/src/code_context_menus.rs
+++ b/crates/editor/src/code_context_menus.rs
@@ -28,10 +28,12 @@ use std::{
rc::Rc,
};
use task::ResolvedTask;
-use ui::{Color, IntoElement, ListItem, Pixels, Popover, Styled, prelude::*};
+use ui::{
+ Color, IntoElement, ListItem, Pixels, Popover, ScrollAxes, Scrollbars, Styled, WithScrollbar,
+ prelude::*,
+};
use util::ResultExt;
-use crate::CodeActionSource;
use crate::hover_popover::{hover_markdown_style, open_markdown_url};
use crate::{
CodeActionProvider, CompletionId, CompletionItemKind, CompletionProvider, DisplayRow, Editor,
@@ -39,7 +41,8 @@ use crate::{
actions::{ConfirmCodeAction, ConfirmCompletion},
split_words, styled_runs_for_code_label,
};
-use settings::SnippetSortOrder;
+use crate::{CodeActionSource, EditorSettings};
+use settings::{Settings, SnippetSortOrder};
pub const MENU_GAP: Pixels = px(4.);
pub const MENU_ASIDE_X_PADDING: Pixels = px(16.);
@@ -261,6 +264,20 @@ impl Drop for CompletionsMenu {
}
}
+struct CompletionMenuScrollBarSetting;
+
+impl ui::scrollbars::GlobalSetting for CompletionMenuScrollBarSetting {
+ fn get_value(_cx: &App) -> &Self {
+ &Self
+ }
+}
+
+impl ui::scrollbars::ScrollbarVisibility for CompletionMenuScrollBarSetting {
+ fn visibility(&self, cx: &App) -> ui::scrollbars::ShowScrollbar {
+ EditorSettings::get_global(cx).completion_menu_scrollbar
+ }
+}
+
impl CompletionsMenu {
pub fn new(
id: CompletionId,
@@ -898,7 +915,17 @@ impl CompletionsMenu {
}
});
- Popover::new().child(list).into_any_element()
+ Popover::new()
+ .child(
+ div().child(list).custom_scrollbars(
+ Scrollbars::for_settings::()
+ .show_along(ScrollAxes::Vertical)
+ .tracked_scroll_handle(self.scroll_handle.clone()),
+ window,
+ cx,
+ ),
+ )
+ .into_any_element()
}
fn render_aside(
diff --git a/crates/editor/src/display_map.rs b/crates/editor/src/display_map.rs
index a269d22d71a95eef1ca1485437863091e3505439..7a225d6019edf8f09b1758d62e8181917649cc2b 100644
--- a/crates/editor/src/display_map.rs
+++ b/crates/editor/src/display_map.rs
@@ -1569,7 +1569,6 @@ pub mod tests {
use lsp::LanguageServerId;
use project::Project;
use rand::{Rng, prelude::*};
- use rope::Rope;
use settings::{SettingsContent, SettingsStore};
use smol::stream::StreamExt;
use std::{env, sync::Arc};
@@ -2075,7 +2074,7 @@ pub mod tests {
vec![Inlay::edit_prediction(
0,
buffer_snapshot.anchor_after(0),
- Rope::from_str_small("\n"),
+ "\n",
)],
cx,
);
diff --git a/crates/editor/src/display_map/inlay_map.rs b/crates/editor/src/display_map/inlay_map.rs
index 3c7cedb6574d02bcf6b06075b8db79cc3a6080db..486676f1120bc2e9d85effd4c328a2b7a547e06b 100644
--- a/crates/editor/src/display_map/inlay_map.rs
+++ b/crates/editor/src/display_map/inlay_map.rs
@@ -700,20 +700,16 @@ impl InlayMap {
.collect::();
let next_inlay = if i % 2 == 0 {
- use rope::Rope;
-
Inlay::mock_hint(
post_inc(next_inlay_id),
snapshot.buffer.anchor_at(position, bias),
- Rope::from_str_small(&text),
+ &text,
)
} else {
- use rope::Rope;
-
Inlay::edit_prediction(
post_inc(next_inlay_id),
snapshot.buffer.anchor_at(position, bias),
- Rope::from_str_small(&text),
+ &text,
)
};
let inlay_id = next_inlay.id;
@@ -1305,7 +1301,7 @@ mod tests {
vec![Inlay::mock_hint(
post_inc(&mut next_inlay_id),
buffer.read(cx).snapshot(cx).anchor_after(3),
- Rope::from_str_small("|123|"),
+ "|123|",
)],
);
assert_eq!(inlay_snapshot.text(), "abc|123|defghi");
@@ -1382,12 +1378,12 @@ mod tests {
Inlay::mock_hint(
post_inc(&mut next_inlay_id),
buffer.read(cx).snapshot(cx).anchor_before(3),
- Rope::from_str_small("|123|"),
+ "|123|",
),
Inlay::edit_prediction(
post_inc(&mut next_inlay_id),
buffer.read(cx).snapshot(cx).anchor_after(3),
- Rope::from_str_small("|456|"),
+ "|456|",
),
],
);
@@ -1597,17 +1593,17 @@ mod tests {
Inlay::mock_hint(
post_inc(&mut next_inlay_id),
buffer.read(cx).snapshot(cx).anchor_before(0),
- Rope::from_str_small("|123|\n"),
+ "|123|\n",
),
Inlay::mock_hint(
post_inc(&mut next_inlay_id),
buffer.read(cx).snapshot(cx).anchor_before(4),
- Rope::from_str_small("|456|"),
+ "|456|",
),
Inlay::edit_prediction(
post_inc(&mut next_inlay_id),
buffer.read(cx).snapshot(cx).anchor_before(7),
- Rope::from_str_small("\n|567|\n"),
+ "\n|567|\n",
),
],
);
@@ -1681,14 +1677,9 @@ mod tests {
(offset, inlay.clone())
})
.collect::>();
- let mut expected_text =
- Rope::from_str(&buffer_snapshot.text(), cx.background_executor());
+ let mut expected_text = Rope::from(&buffer_snapshot.text());
for (offset, inlay) in inlays.iter().rev() {
- expected_text.replace(
- *offset..*offset,
- &inlay.text().to_string(),
- cx.background_executor(),
- );
+ expected_text.replace(*offset..*offset, &inlay.text().to_string());
}
assert_eq!(inlay_snapshot.text(), expected_text.to_string());
@@ -2076,7 +2067,7 @@ mod tests {
let inlay = Inlay {
id: InlayId::Hint(0),
position,
- content: InlayContent::Text(text::Rope::from_str(inlay_text, cx.background_executor())),
+ content: InlayContent::Text(text::Rope::from(inlay_text)),
};
let (inlay_snapshot, _) = inlay_map.splice(&[], vec![inlay]);
@@ -2190,10 +2181,7 @@ mod tests {
let inlay = Inlay {
id: InlayId::Hint(0),
position,
- content: InlayContent::Text(text::Rope::from_str(
- test_case.inlay_text,
- cx.background_executor(),
- )),
+ content: InlayContent::Text(text::Rope::from(test_case.inlay_text)),
};
let (inlay_snapshot, _) = inlay_map.splice(&[], vec![inlay]);
diff --git a/crates/editor/src/display_map/tab_map.rs b/crates/editor/src/display_map/tab_map.rs
index 084ced82b3aa311f90f905077e2d18dd831e0bd6..7a63723f53a49483eaa728373a5ae8530aa6f4d6 100644
--- a/crates/editor/src/display_map/tab_map.rs
+++ b/crates/editor/src/display_map/tab_map.rs
@@ -1042,7 +1042,7 @@ mod tests {
let (mut tab_map, _) = TabMap::new(fold_snapshot, tab_size);
let tabs_snapshot = tab_map.set_max_expansion_column(32);
- let text = text::Rope::from_str(tabs_snapshot.text().as_str(), cx.background_executor());
+ let text = text::Rope::from(tabs_snapshot.text().as_str());
log::info!(
"TabMap text (tab size: {}): {:?}",
tab_size,
diff --git a/crates/editor/src/display_map/wrap_map.rs b/crates/editor/src/display_map/wrap_map.rs
index 1f50ff28daff51e9e16da683053104ea4800977b..7371eb678538dbc12abe43bde4073ffd9d2bdb21 100644
--- a/crates/editor/src/display_map/wrap_map.rs
+++ b/crates/editor/src/display_map/wrap_map.rs
@@ -863,7 +863,7 @@ impl WrapSnapshot {
}
}
- let text = language::Rope::from_str_small(self.text().as_str());
+ let text = language::Rope::from(self.text().as_str());
let mut input_buffer_rows = self.tab_snapshot.rows(0);
let mut expected_buffer_rows = Vec::new();
let mut prev_tab_row = 0;
@@ -1413,10 +1413,9 @@ mod tests {
}
}
- let mut initial_text =
- Rope::from_str(initial_snapshot.text().as_str(), cx.background_executor());
+ let mut initial_text = Rope::from(initial_snapshot.text().as_str());
for (snapshot, patch) in edits {
- let snapshot_text = Rope::from_str(snapshot.text().as_str(), cx.background_executor());
+ let snapshot_text = Rope::from(snapshot.text().as_str());
for edit in &patch {
let old_start = initial_text.point_to_offset(Point::new(edit.new.start, 0));
let old_end = initial_text.point_to_offset(cmp::min(
@@ -1432,7 +1431,7 @@ mod tests {
.chunks_in_range(new_start..new_end)
.collect::();
- initial_text.replace(old_start..old_end, &new_text, cx.background_executor());
+ initial_text.replace(old_start..old_end, &new_text);
}
assert_eq!(initial_text.to_string(), snapshot_text.to_string());
}
diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs
index ed6b8ec2eca4dcb558bc832ac56b92af8791712c..50102a685f93abac91341539ef51445cb80c6403 100644
--- a/crates/editor/src/editor.rs
+++ b/crates/editor/src/editor.rs
@@ -452,6 +452,20 @@ pub enum SelectMode {
All,
}
+#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
+pub enum SizingBehavior {
+ /// The editor will layout itself using `size_full` and will include the vertical
+ /// scroll margin as requested by user settings.
+ #[default]
+ Default,
+ /// The editor will layout itself using `size_full`, but will not have any
+ /// vertical overscroll.
+ ExcludeOverscrollMargin,
+ /// The editor will request a vertical size according to its content and will be
+ /// layouted without a vertical scroll margin.
+ SizeByContent,
+}
+
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum EditorMode {
SingleLine,
@@ -464,8 +478,8 @@ pub enum EditorMode {
scale_ui_elements_with_buffer_font_size: bool,
/// When set to `true`, the editor will render a background for the active line.
show_active_line_background: bool,
- /// When set to `true`, the editor's height will be determined by its content.
- sized_by_content: bool,
+ /// Determines the sizing behavior for this editor
+ sizing_behavior: SizingBehavior,
},
Minimap {
parent: WeakEntity,
@@ -477,7 +491,7 @@ impl EditorMode {
Self::Full {
scale_ui_elements_with_buffer_font_size: true,
show_active_line_background: true,
- sized_by_content: false,
+ sizing_behavior: SizingBehavior::Default,
}
}
@@ -1832,9 +1846,15 @@ impl Editor {
project::Event::RefreshCodeLens => {
// we always query lens with actions, without storing them, always refreshing them
}
- project::Event::RefreshInlayHints(server_id) => {
+ project::Event::RefreshInlayHints {
+ server_id,
+ request_id,
+ } => {
editor.refresh_inlay_hints(
- InlayHintRefreshReason::RefreshRequested(*server_id),
+ InlayHintRefreshReason::RefreshRequested {
+ server_id: *server_id,
+ request_id: *request_id,
+ },
cx,
);
}
@@ -7852,7 +7872,7 @@ impl Editor {
let inlay = Inlay::edit_prediction(
post_inc(&mut self.next_inlay_id),
range.start,
- Rope::from_str_small(new_text.as_str()),
+ new_text.as_str(),
);
inlay_ids.push(inlay.id);
inlays.push(inlay);
diff --git a/crates/editor/src/editor_settings.rs b/crates/editor/src/editor_settings.rs
index dc67ab3ed6c8cfdbe88809e32d615789c01eef60..77c9558eaf4ea49df981b8eb32ee075d069da08f 100644
--- a/crates/editor/src/editor_settings.rs
+++ b/crates/editor/src/editor_settings.rs
@@ -55,6 +55,7 @@ pub struct EditorSettings {
pub drag_and_drop_selection: DragAndDropSelection,
pub lsp_document_colors: DocumentColorsRenderMode,
pub minimum_contrast_for_highlights: f32,
+ pub completion_menu_scrollbar: ShowScrollbar,
}
#[derive(Debug, Clone)]
pub struct Jupyter {
@@ -159,6 +160,7 @@ pub struct SearchSettings {
pub case_sensitive: bool,
pub include_ignored: bool,
pub regex: bool,
+ pub center_on_match: bool,
}
impl EditorSettings {
@@ -249,6 +251,7 @@ impl Settings for EditorSettings {
case_sensitive: search.case_sensitive.unwrap(),
include_ignored: search.include_ignored.unwrap(),
regex: search.regex.unwrap(),
+ center_on_match: search.center_on_match.unwrap(),
},
auto_signature_help: editor.auto_signature_help.unwrap(),
show_signature_help_after_edits: editor.show_signature_help_after_edits.unwrap(),
@@ -266,6 +269,7 @@ impl Settings for EditorSettings {
},
lsp_document_colors: editor.lsp_document_colors.unwrap(),
minimum_contrast_for_highlights: editor.minimum_contrast_for_highlights.unwrap().0,
+ completion_menu_scrollbar: editor.completion_menu_scrollbar.map(Into::into).unwrap(),
}
}
}
diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs
index 06fbd9d3381f70955049ddde1c7a395945d67c66..903ca3b9c1d947094f3b79419ae00c499ec9fd0c 100644
--- a/crates/editor/src/editor_tests.rs
+++ b/crates/editor/src/editor_tests.rs
@@ -14217,7 +14217,7 @@ async fn test_completion_in_multibuffer_with_replace_range(cx: &mut TestAppConte
EditorMode::Full {
scale_ui_elements_with_buffer_font_size: false,
show_active_line_background: false,
- sized_by_content: false,
+ sizing_behavior: SizingBehavior::Default,
},
multi_buffer.clone(),
Some(project.clone()),
diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs
index 7579441595c5d774e8d96439d0e03a21f3e624b8..761d71d43b24ddf54f8410f64c7357fd2fb6dca4 100644
--- a/crates/editor/src/element.rs
+++ b/crates/editor/src/element.rs
@@ -8,8 +8,8 @@ use crate::{
HandleInput, HoveredCursor, InlayHintRefreshReason, JumpData, LineDown, LineHighlight, LineUp,
MAX_LINE_LEN, MINIMAP_FONT_SIZE, MULTI_BUFFER_EXCERPT_HEADER_HEIGHT, OpenExcerpts, PageDown,
PageUp, PhantomBreakpointIndicator, Point, RowExt, RowRangeExt, SelectPhase,
- SelectedTextHighlight, Selection, SelectionDragState, SoftWrap, StickyHeaderExcerpt, ToPoint,
- ToggleFold, ToggleFoldAll,
+ SelectedTextHighlight, Selection, SelectionDragState, SizingBehavior, SoftWrap,
+ StickyHeaderExcerpt, ToPoint, ToggleFold, ToggleFoldAll,
code_context_menus::{CodeActionsMenu, MENU_ASIDE_MAX_WIDTH, MENU_ASIDE_MIN_WIDTH, MENU_GAP},
display_map::{
Block, BlockContext, BlockStyle, ChunkRendererId, DisplaySnapshot, EditorMargins,
@@ -8441,11 +8441,11 @@ impl Element for EditorElement {
window.request_layout(style, None, cx)
}
EditorMode::Full {
- sized_by_content, ..
+ sizing_behavior, ..
} => {
let mut style = Style::default();
style.size.width = relative(1.).into();
- if sized_by_content {
+ if sizing_behavior == SizingBehavior::SizeByContent {
let snapshot = editor.snapshot(window, cx);
let line_height =
self.style.text.line_height_in_pixels(window.rem_size());
@@ -8609,7 +8609,8 @@ impl Element for EditorElement {
EditorMode::SingleLine
| EditorMode::AutoHeight { .. }
| EditorMode::Full {
- sized_by_content: true,
+ sizing_behavior: SizingBehavior::ExcludeOverscrollMargin
+ | SizingBehavior::SizeByContent,
..
}
) {
diff --git a/crates/editor/src/git/blame.rs b/crates/editor/src/git/blame.rs
index 94bc67e684cd512942d42527d0adb802500ed49f..b36a57a7e47bf148fff4201ec87ac7c868658a04 100644
--- a/crates/editor/src/git/blame.rs
+++ b/crates/editor/src/git/blame.rs
@@ -1115,19 +1115,18 @@ mod tests {
let fs = FakeFs::new(cx.executor());
let buffer_initial_text_len = rng.random_range(5..15);
- let mut buffer_initial_text = Rope::from_str(
+ let mut buffer_initial_text = Rope::from(
RandomCharIter::new(&mut rng)
.take(buffer_initial_text_len)
.collect::()
.as_str(),
- cx.background_executor(),
);
let mut newline_ixs = (0..buffer_initial_text_len).choose_multiple(&mut rng, 5);
newline_ixs.sort_unstable();
for newline_ix in newline_ixs.into_iter().rev() {
let newline_ix = buffer_initial_text.clip_offset(newline_ix, Bias::Right);
- buffer_initial_text.replace(newline_ix..newline_ix, "\n", cx.background_executor());
+ buffer_initial_text.replace(newline_ix..newline_ix, "\n");
}
log::info!("initial buffer text: {:?}", buffer_initial_text);
diff --git a/crates/editor/src/inlays.rs b/crates/editor/src/inlays.rs
index 1d411fef5617c00ef4d34b521f2321ac9baac934..f07bf0b315161f0ce9cdf3ef7e2f6db6d60abfb5 100644
--- a/crates/editor/src/inlays.rs
+++ b/crates/editor/src/inlays.rs
@@ -59,10 +59,10 @@ impl Inlay {
pub fn hint(id: InlayId, position: Anchor, hint: &InlayHint) -> Self {
let mut text = hint.text();
if hint.padding_right && text.reversed_chars_at(text.len()).next() != Some(' ') {
- text.push_small(" ");
+ text.push(" ");
}
if hint.padding_left && text.chars_at(0).next() != Some(' ') {
- text.push_front_small(" ");
+ text.push_front(" ");
}
Self {
id,
@@ -72,11 +72,11 @@ impl Inlay {
}
#[cfg(any(test, feature = "test-support"))]
- pub fn mock_hint(id: usize, position: Anchor, text: Rope) -> Self {
+ pub fn mock_hint(id: usize, position: Anchor, text: impl Into) -> Self {
Self {
id: InlayId::Hint(id),
position,
- content: InlayContent::Text(text),
+ content: InlayContent::Text(text.into()),
}
}
@@ -88,19 +88,19 @@ impl Inlay {
}
}
- pub fn edit_prediction(id: usize, position: Anchor, text: Rope) -> Self {
+ pub fn edit_prediction>(id: usize, position: Anchor, text: T) -> Self {
Self {
id: InlayId::EditPrediction(id),
position,
- content: InlayContent::Text(text),
+ content: InlayContent::Text(text.into()),
}
}
- pub fn debugger(id: usize, position: Anchor, text: Rope) -> Self {
+ pub fn debugger>(id: usize, position: Anchor, text: T) -> Self {
Self {
id: InlayId::DebuggerValue(id),
position,
- content: InlayContent::Text(text),
+ content: InlayContent::Text(text.into()),
}
}
@@ -108,7 +108,7 @@ impl Inlay {
static COLOR_TEXT: OnceLock = OnceLock::new();
match &self.content {
InlayContent::Text(text) => text,
- InlayContent::Color(_) => COLOR_TEXT.get_or_init(|| Rope::from_str_small("◼")),
+ InlayContent::Color(_) => COLOR_TEXT.get_or_init(|| Rope::from("◼")),
}
}
diff --git a/crates/editor/src/inlays/inlay_hints.rs b/crates/editor/src/inlays/inlay_hints.rs
index 74fe9988763b976f315624b8e1ab36110e2137ee..4fd673a8d2f049da94f90adfcdfbd8cd3263d12d 100644
--- a/crates/editor/src/inlays/inlay_hints.rs
+++ b/crates/editor/src/inlays/inlay_hints.rs
@@ -1,5 +1,4 @@
use std::{
- collections::hash_map,
ops::{ControlFlow, Range},
time::Duration,
};
@@ -49,8 +48,8 @@ pub struct LspInlayHintData {
allowed_hint_kinds: HashSet