Compare commits
20 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
52a60e5115 | ||
![]() |
8b25b8172b | ||
![]() |
09845c0a3a | ||
![]() |
a6b9668355 | ||
![]() |
d5b6a4d710 | ||
![]() |
bf6f715961 | ||
![]() |
1934e5c23e | ||
![]() |
295da0757e | ||
![]() |
85261bb5cc | ||
![]() |
8c159d0fbd | ||
![]() |
25f3f88a34 | ||
![]() |
0c24950911 | ||
![]() |
900fe328c0 | ||
![]() |
863e39b774 | ||
![]() |
7d58eb200b | ||
![]() |
87c9f6a52e | ||
![]() |
059a409235 | ||
![]() |
5c450693fa | ||
![]() |
910507d7e5 | ||
![]() |
3d48f14248 |
50 changed files with 647 additions and 176 deletions
33
.github/actionlint.yml
vendored
33
.github/actionlint.yml
vendored
|
@ -5,26 +5,25 @@ self-hosted-runner:
|
||||||
# GitHub-hosted Runners
|
# GitHub-hosted Runners
|
||||||
- github-8vcpu-ubuntu-2404
|
- github-8vcpu-ubuntu-2404
|
||||||
- github-16vcpu-ubuntu-2404
|
- github-16vcpu-ubuntu-2404
|
||||||
|
- github-32vcpu-ubuntu-2404
|
||||||
|
- github-8vcpu-ubuntu-2204
|
||||||
|
- github-16vcpu-ubuntu-2204
|
||||||
|
- github-32vcpu-ubuntu-2204
|
||||||
|
- github-16vcpu-ubuntu-2204-arm
|
||||||
- windows-2025-16
|
- windows-2025-16
|
||||||
- windows-2025-32
|
- windows-2025-32
|
||||||
- windows-2025-64
|
- windows-2025-64
|
||||||
# Buildjet Ubuntu 20.04 - AMD x86_64
|
# Namespace Ubuntu 20.04 (Release builds)
|
||||||
- buildjet-2vcpu-ubuntu-2004
|
- namespace-profile-16x32-ubuntu-2004
|
||||||
- buildjet-4vcpu-ubuntu-2004
|
- namespace-profile-32x64-ubuntu-2004
|
||||||
- buildjet-8vcpu-ubuntu-2004
|
- namespace-profile-16x32-ubuntu-2004-arm
|
||||||
- buildjet-16vcpu-ubuntu-2004
|
- namespace-profile-32x64-ubuntu-2004-arm
|
||||||
- buildjet-32vcpu-ubuntu-2004
|
# Namespace Ubuntu 22.04 (Everything else)
|
||||||
# Buildjet Ubuntu 22.04 - AMD x86_64
|
- namespace-profile-2x4-ubuntu-2204
|
||||||
- buildjet-2vcpu-ubuntu-2204
|
- namespace-profile-4x8-ubuntu-2204
|
||||||
- buildjet-4vcpu-ubuntu-2204
|
- namespace-profile-8x16-ubuntu-2204
|
||||||
- buildjet-8vcpu-ubuntu-2204
|
- namespace-profile-16x32-ubuntu-2204
|
||||||
- buildjet-16vcpu-ubuntu-2204
|
- namespace-profile-32x64-ubuntu-2204
|
||||||
- buildjet-32vcpu-ubuntu-2204
|
|
||||||
# Buildjet Ubuntu 22.04 - Graviton aarch64
|
|
||||||
- buildjet-8vcpu-ubuntu-2204-arm
|
|
||||||
- buildjet-16vcpu-ubuntu-2204-arm
|
|
||||||
- buildjet-32vcpu-ubuntu-2204-arm
|
|
||||||
- buildjet-64vcpu-ubuntu-2204-arm
|
|
||||||
# Self Hosted Runners
|
# Self Hosted Runners
|
||||||
- self-mini-macos
|
- self-mini-macos
|
||||||
- self-32vcpu-windows-2022
|
- self-32vcpu-windows-2022
|
||||||
|
|
2
.github/actions/build_docs/action.yml
vendored
2
.github/actions/build_docs/action.yml
vendored
|
@ -13,7 +13,7 @@ runs:
|
||||||
uses: swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2
|
uses: swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2
|
||||||
with:
|
with:
|
||||||
save-if: ${{ github.ref == 'refs/heads/main' }}
|
save-if: ${{ github.ref == 'refs/heads/main' }}
|
||||||
cache-provider: "buildjet"
|
# cache-provider: "buildjet"
|
||||||
|
|
||||||
- name: Install Linux dependencies
|
- name: Install Linux dependencies
|
||||||
shell: bash -euxo pipefail {0}
|
shell: bash -euxo pipefail {0}
|
||||||
|
|
2
.github/workflows/bump_patch_version.yml
vendored
2
.github/workflows/bump_patch_version.yml
vendored
|
@ -16,7 +16,7 @@ jobs:
|
||||||
bump_patch_version:
|
bump_patch_version:
|
||||||
if: github.repository_owner == 'zed-industries'
|
if: github.repository_owner == 'zed-industries'
|
||||||
runs-on:
|
runs-on:
|
||||||
- buildjet-16vcpu-ubuntu-2204
|
- namespace-profile-16x32-ubuntu-2204
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||||
|
|
18
.github/workflows/ci.yml
vendored
18
.github/workflows/ci.yml
vendored
|
@ -136,7 +136,7 @@ jobs:
|
||||||
github.repository_owner == 'zed-industries' &&
|
github.repository_owner == 'zed-industries' &&
|
||||||
needs.job_spec.outputs.run_tests == 'true'
|
needs.job_spec.outputs.run_tests == 'true'
|
||||||
runs-on:
|
runs-on:
|
||||||
- buildjet-8vcpu-ubuntu-2204
|
- namespace-profile-8x16-ubuntu-2204
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||||
|
@ -167,7 +167,7 @@ jobs:
|
||||||
needs: [job_spec]
|
needs: [job_spec]
|
||||||
if: github.repository_owner == 'zed-industries'
|
if: github.repository_owner == 'zed-industries'
|
||||||
runs-on:
|
runs-on:
|
||||||
- buildjet-8vcpu-ubuntu-2204
|
- namespace-profile-4x8-ubuntu-2204
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||||
|
@ -220,7 +220,7 @@ jobs:
|
||||||
github.repository_owner == 'zed-industries' &&
|
github.repository_owner == 'zed-industries' &&
|
||||||
(needs.job_spec.outputs.run_tests == 'true' || needs.job_spec.outputs.run_docs == 'true')
|
(needs.job_spec.outputs.run_tests == 'true' || needs.job_spec.outputs.run_docs == 'true')
|
||||||
runs-on:
|
runs-on:
|
||||||
- buildjet-8vcpu-ubuntu-2204
|
- namespace-profile-8x16-ubuntu-2204
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||||
|
@ -327,7 +327,7 @@ jobs:
|
||||||
github.repository_owner == 'zed-industries' &&
|
github.repository_owner == 'zed-industries' &&
|
||||||
needs.job_spec.outputs.run_tests == 'true'
|
needs.job_spec.outputs.run_tests == 'true'
|
||||||
runs-on:
|
runs-on:
|
||||||
- buildjet-16vcpu-ubuntu-2204
|
- namespace-profile-16x32-ubuntu-2204
|
||||||
steps:
|
steps:
|
||||||
- name: Add Rust to the PATH
|
- name: Add Rust to the PATH
|
||||||
run: echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
run: echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
||||||
|
@ -341,7 +341,7 @@ jobs:
|
||||||
uses: swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2
|
uses: swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2
|
||||||
with:
|
with:
|
||||||
save-if: ${{ github.ref == 'refs/heads/main' }}
|
save-if: ${{ github.ref == 'refs/heads/main' }}
|
||||||
cache-provider: "buildjet"
|
# cache-provider: "buildjet"
|
||||||
|
|
||||||
- name: Install Linux dependencies
|
- name: Install Linux dependencies
|
||||||
run: ./script/linux
|
run: ./script/linux
|
||||||
|
@ -379,7 +379,7 @@ jobs:
|
||||||
github.repository_owner == 'zed-industries' &&
|
github.repository_owner == 'zed-industries' &&
|
||||||
needs.job_spec.outputs.run_tests == 'true'
|
needs.job_spec.outputs.run_tests == 'true'
|
||||||
runs-on:
|
runs-on:
|
||||||
- buildjet-8vcpu-ubuntu-2204
|
- namespace-profile-16x32-ubuntu-2204
|
||||||
steps:
|
steps:
|
||||||
- name: Add Rust to the PATH
|
- name: Add Rust to the PATH
|
||||||
run: echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
run: echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
||||||
|
@ -393,7 +393,7 @@ jobs:
|
||||||
uses: swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2
|
uses: swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2
|
||||||
with:
|
with:
|
||||||
save-if: ${{ github.ref == 'refs/heads/main' }}
|
save-if: ${{ github.ref == 'refs/heads/main' }}
|
||||||
cache-provider: "buildjet"
|
# cache-provider: "buildjet"
|
||||||
|
|
||||||
- name: Install Clang & Mold
|
- name: Install Clang & Mold
|
||||||
run: ./script/remote-server && ./script/install-mold 2.34.0
|
run: ./script/remote-server && ./script/install-mold 2.34.0
|
||||||
|
@ -596,7 +596,7 @@ jobs:
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
name: Linux x86_x64 release bundle
|
name: Linux x86_x64 release bundle
|
||||||
runs-on:
|
runs-on:
|
||||||
- buildjet-16vcpu-ubuntu-2004 # ubuntu 20.04 for minimal glibc
|
- namespace-profile-16x32-ubuntu-2004 # ubuntu 20.04 for minimal glibc
|
||||||
if: |
|
if: |
|
||||||
startsWith(github.ref, 'refs/tags/v')
|
startsWith(github.ref, 'refs/tags/v')
|
||||||
|| contains(github.event.pull_request.labels.*.name, 'run-bundling')
|
|| contains(github.event.pull_request.labels.*.name, 'run-bundling')
|
||||||
|
@ -649,7 +649,7 @@ jobs:
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
name: Linux arm64 release bundle
|
name: Linux arm64 release bundle
|
||||||
runs-on:
|
runs-on:
|
||||||
- buildjet-16vcpu-ubuntu-2204-arm
|
- namespace-profile-32x64-ubuntu-2004-arm # ubuntu 20.04 for minimal glibc
|
||||||
if: |
|
if: |
|
||||||
startsWith(github.ref, 'refs/tags/v')
|
startsWith(github.ref, 'refs/tags/v')
|
||||||
|| contains(github.event.pull_request.labels.*.name, 'run-bundling')
|
|| contains(github.event.pull_request.labels.*.name, 'run-bundling')
|
||||||
|
|
2
.github/workflows/deploy_cloudflare.yml
vendored
2
.github/workflows/deploy_cloudflare.yml
vendored
|
@ -9,7 +9,7 @@ jobs:
|
||||||
deploy-docs:
|
deploy-docs:
|
||||||
name: Deploy Docs
|
name: Deploy Docs
|
||||||
if: github.repository_owner == 'zed-industries'
|
if: github.repository_owner == 'zed-industries'
|
||||||
runs-on: buildjet-16vcpu-ubuntu-2204
|
runs-on: namespace-profile-16x32-ubuntu-2204
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
|
|
4
.github/workflows/deploy_collab.yml
vendored
4
.github/workflows/deploy_collab.yml
vendored
|
@ -61,7 +61,7 @@ jobs:
|
||||||
- style
|
- style
|
||||||
- tests
|
- tests
|
||||||
runs-on:
|
runs-on:
|
||||||
- buildjet-16vcpu-ubuntu-2204
|
- namespace-profile-16x32-ubuntu-2204
|
||||||
steps:
|
steps:
|
||||||
- name: Install doctl
|
- name: Install doctl
|
||||||
uses: digitalocean/action-doctl@v2
|
uses: digitalocean/action-doctl@v2
|
||||||
|
@ -94,7 +94,7 @@ jobs:
|
||||||
needs:
|
needs:
|
||||||
- publish
|
- publish
|
||||||
runs-on:
|
runs-on:
|
||||||
- buildjet-16vcpu-ubuntu-2204
|
- namespace-profile-16x32-ubuntu-2204
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
|
|
4
.github/workflows/eval.yml
vendored
4
.github/workflows/eval.yml
vendored
|
@ -32,7 +32,7 @@ jobs:
|
||||||
github.repository_owner == 'zed-industries' &&
|
github.repository_owner == 'zed-industries' &&
|
||||||
(github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'run-eval'))
|
(github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'run-eval'))
|
||||||
runs-on:
|
runs-on:
|
||||||
- buildjet-16vcpu-ubuntu-2204
|
- namespace-profile-16x32-ubuntu-2204
|
||||||
steps:
|
steps:
|
||||||
- name: Add Rust to the PATH
|
- name: Add Rust to the PATH
|
||||||
run: echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
run: echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
||||||
|
@ -46,7 +46,7 @@ jobs:
|
||||||
uses: swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2
|
uses: swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2
|
||||||
with:
|
with:
|
||||||
save-if: ${{ github.ref == 'refs/heads/main' }}
|
save-if: ${{ github.ref == 'refs/heads/main' }}
|
||||||
cache-provider: "buildjet"
|
# cache-provider: "buildjet"
|
||||||
|
|
||||||
- name: Install Linux dependencies
|
- name: Install Linux dependencies
|
||||||
run: ./script/linux
|
run: ./script/linux
|
||||||
|
|
2
.github/workflows/nix.yml
vendored
2
.github/workflows/nix.yml
vendored
|
@ -20,7 +20,7 @@ jobs:
|
||||||
matrix:
|
matrix:
|
||||||
system:
|
system:
|
||||||
- os: x86 Linux
|
- os: x86 Linux
|
||||||
runner: buildjet-16vcpu-ubuntu-2204
|
runner: namespace-profile-16x32-ubuntu-2204
|
||||||
install_nix: true
|
install_nix: true
|
||||||
- os: arm Mac
|
- os: arm Mac
|
||||||
runner: [macOS, ARM64, test]
|
runner: [macOS, ARM64, test]
|
||||||
|
|
2
.github/workflows/randomized_tests.yml
vendored
2
.github/workflows/randomized_tests.yml
vendored
|
@ -20,7 +20,7 @@ jobs:
|
||||||
name: Run randomized tests
|
name: Run randomized tests
|
||||||
if: github.repository_owner == 'zed-industries'
|
if: github.repository_owner == 'zed-industries'
|
||||||
runs-on:
|
runs-on:
|
||||||
- buildjet-16vcpu-ubuntu-2204
|
- namespace-profile-16x32-ubuntu-2204
|
||||||
steps:
|
steps:
|
||||||
- name: Install Node
|
- name: Install Node
|
||||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||||
|
|
4
.github/workflows/release_nightly.yml
vendored
4
.github/workflows/release_nightly.yml
vendored
|
@ -127,7 +127,7 @@ jobs:
|
||||||
name: Create a Linux *.tar.gz bundle for x86
|
name: Create a Linux *.tar.gz bundle for x86
|
||||||
if: github.repository_owner == 'zed-industries'
|
if: github.repository_owner == 'zed-industries'
|
||||||
runs-on:
|
runs-on:
|
||||||
- buildjet-16vcpu-ubuntu-2004
|
- namespace-profile-16x32-ubuntu-2004 # ubuntu 20.04 for minimal glibc
|
||||||
needs: tests
|
needs: tests
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
|
@ -167,7 +167,7 @@ jobs:
|
||||||
name: Create a Linux *.tar.gz bundle for ARM
|
name: Create a Linux *.tar.gz bundle for ARM
|
||||||
if: github.repository_owner == 'zed-industries'
|
if: github.repository_owner == 'zed-industries'
|
||||||
runs-on:
|
runs-on:
|
||||||
- buildjet-16vcpu-ubuntu-2204-arm
|
- namespace-profile-32x64-ubuntu-2004-arm # ubuntu 20.04 for minimal glibc
|
||||||
needs: tests
|
needs: tests
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
|
|
4
.github/workflows/unit_evals.yml
vendored
4
.github/workflows/unit_evals.yml
vendored
|
@ -23,7 +23,7 @@ jobs:
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
name: Run unit evals
|
name: Run unit evals
|
||||||
runs-on:
|
runs-on:
|
||||||
- buildjet-16vcpu-ubuntu-2204
|
- namespace-profile-16x32-ubuntu-2204
|
||||||
steps:
|
steps:
|
||||||
- name: Add Rust to the PATH
|
- name: Add Rust to the PATH
|
||||||
run: echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
run: echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
||||||
|
@ -37,7 +37,7 @@ jobs:
|
||||||
uses: swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2
|
uses: swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2
|
||||||
with:
|
with:
|
||||||
save-if: ${{ github.ref == 'refs/heads/main' }}
|
save-if: ${{ github.ref == 'refs/heads/main' }}
|
||||||
cache-provider: "buildjet"
|
# cache-provider: "buildjet"
|
||||||
|
|
||||||
- name: Install Linux dependencies
|
- name: Install Linux dependencies
|
||||||
run: ./script/linux
|
run: ./script/linux
|
||||||
|
|
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -4960,6 +4960,7 @@ dependencies = [
|
||||||
"theme",
|
"theme",
|
||||||
"time",
|
"time",
|
||||||
"tree-sitter-bash",
|
"tree-sitter-bash",
|
||||||
|
"tree-sitter-c",
|
||||||
"tree-sitter-html",
|
"tree-sitter-html",
|
||||||
"tree-sitter-python",
|
"tree-sitter-python",
|
||||||
"tree-sitter-rust",
|
"tree-sitter-rust",
|
||||||
|
@ -6362,7 +6363,6 @@ dependencies = [
|
||||||
"buffer_diff",
|
"buffer_diff",
|
||||||
"call",
|
"call",
|
||||||
"chrono",
|
"chrono",
|
||||||
"client",
|
|
||||||
"cloud_llm_client",
|
"cloud_llm_client",
|
||||||
"collections",
|
"collections",
|
||||||
"command_palette_hooks",
|
"command_palette_hooks",
|
||||||
|
@ -20193,7 +20193,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zed"
|
name = "zed"
|
||||||
version = "0.198.0"
|
version = "0.198.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"activity_indicator",
|
"activity_indicator",
|
||||||
"agent",
|
"agent",
|
||||||
|
|
|
@ -95,7 +95,7 @@
|
||||||
"ctrl-shift-r": ["pane::DeploySearch", { "replace_enabled": true }],
|
"ctrl-shift-r": ["pane::DeploySearch", { "replace_enabled": true }],
|
||||||
"alt-shift-f10": "task::Spawn",
|
"alt-shift-f10": "task::Spawn",
|
||||||
"ctrl-e": "file_finder::Toggle",
|
"ctrl-e": "file_finder::Toggle",
|
||||||
"ctrl-k": "git_panel::ToggleFocus", // bug: This should also focus commit editor
|
// "ctrl-k": "git_panel::ToggleFocus", // bug: This should also focus commit editor
|
||||||
"ctrl-shift-n": "file_finder::Toggle",
|
"ctrl-shift-n": "file_finder::Toggle",
|
||||||
"ctrl-shift-a": "command_palette::Toggle",
|
"ctrl-shift-a": "command_palette::Toggle",
|
||||||
"shift shift": "command_palette::Toggle",
|
"shift shift": "command_palette::Toggle",
|
||||||
|
@ -166,7 +166,7 @@
|
||||||
{ "context": "Diagnostics > Editor", "bindings": { "alt-6": "pane::CloseActiveItem" } },
|
{ "context": "Diagnostics > Editor", "bindings": { "alt-6": "pane::CloseActiveItem" } },
|
||||||
{ "context": "OutlinePanel", "bindings": { "alt-7": "workspace::CloseActiveDock" } },
|
{ "context": "OutlinePanel", "bindings": { "alt-7": "workspace::CloseActiveDock" } },
|
||||||
{
|
{
|
||||||
"context": "Dock || Workspace || Terminal || OutlinePanel || ProjectPanel || CollabPanel || (Editor && mode == auto_height)",
|
"context": "Dock || Workspace || OutlinePanel || ProjectPanel || CollabPanel || (Editor && mode == auto_height)",
|
||||||
"bindings": {
|
"bindings": {
|
||||||
"escape": "editor::ToggleFocus",
|
"escape": "editor::ToggleFocus",
|
||||||
"shift-escape": "workspace::CloseActiveDock"
|
"shift-escape": "workspace::CloseActiveDock"
|
||||||
|
|
|
@ -97,7 +97,7 @@
|
||||||
"cmd-shift-r": ["pane::DeploySearch", { "replace_enabled": true }],
|
"cmd-shift-r": ["pane::DeploySearch", { "replace_enabled": true }],
|
||||||
"ctrl-alt-r": "task::Spawn",
|
"ctrl-alt-r": "task::Spawn",
|
||||||
"cmd-e": "file_finder::Toggle",
|
"cmd-e": "file_finder::Toggle",
|
||||||
"cmd-k": "git_panel::ToggleFocus", // bug: This should also focus commit editor
|
// "cmd-k": "git_panel::ToggleFocus", // bug: This should also focus commit editor
|
||||||
"cmd-shift-o": "file_finder::Toggle",
|
"cmd-shift-o": "file_finder::Toggle",
|
||||||
"cmd-shift-a": "command_palette::Toggle",
|
"cmd-shift-a": "command_palette::Toggle",
|
||||||
"shift shift": "command_palette::Toggle",
|
"shift shift": "command_palette::Toggle",
|
||||||
|
@ -167,7 +167,7 @@
|
||||||
{ "context": "Diagnostics > Editor", "bindings": { "cmd-6": "pane::CloseActiveItem" } },
|
{ "context": "Diagnostics > Editor", "bindings": { "cmd-6": "pane::CloseActiveItem" } },
|
||||||
{ "context": "OutlinePanel", "bindings": { "cmd-7": "workspace::CloseActiveDock" } },
|
{ "context": "OutlinePanel", "bindings": { "cmd-7": "workspace::CloseActiveDock" } },
|
||||||
{
|
{
|
||||||
"context": "Dock || Workspace || Terminal || OutlinePanel || ProjectPanel || CollabPanel || (Editor && mode == auto_height)",
|
"context": "Dock || Workspace || OutlinePanel || ProjectPanel || CollabPanel || (Editor && mode == auto_height)",
|
||||||
"bindings": {
|
"bindings": {
|
||||||
"escape": "editor::ToggleFocus",
|
"escape": "editor::ToggleFocus",
|
||||||
"shift-escape": "workspace::CloseActiveDock"
|
"shift-escape": "workspace::CloseActiveDock"
|
||||||
|
|
|
@ -43,7 +43,7 @@ use anyhow::{Result, anyhow};
|
||||||
use assistant_context::{AssistantContext, ContextEvent, ContextSummary};
|
use assistant_context::{AssistantContext, ContextEvent, ContextSummary};
|
||||||
use assistant_slash_command::SlashCommandWorkingSet;
|
use assistant_slash_command::SlashCommandWorkingSet;
|
||||||
use assistant_tool::ToolWorkingSet;
|
use assistant_tool::ToolWorkingSet;
|
||||||
use client::{DisableAiSettings, UserStore, zed_urls};
|
use client::{UserStore, zed_urls};
|
||||||
use cloud_llm_client::{CompletionIntent, UsageLimit};
|
use cloud_llm_client::{CompletionIntent, UsageLimit};
|
||||||
use editor::{Anchor, AnchorRangeExt as _, Editor, EditorEvent, MultiBuffer};
|
use editor::{Anchor, AnchorRangeExt as _, Editor, EditorEvent, MultiBuffer};
|
||||||
use feature_flags::{self, FeatureFlagAppExt};
|
use feature_flags::{self, FeatureFlagAppExt};
|
||||||
|
@ -58,7 +58,7 @@ use language::LanguageRegistry;
|
||||||
use language_model::{
|
use language_model::{
|
||||||
ConfigurationError, ConfiguredModel, LanguageModelProviderTosView, LanguageModelRegistry,
|
ConfigurationError, ConfiguredModel, LanguageModelProviderTosView, LanguageModelRegistry,
|
||||||
};
|
};
|
||||||
use project::{Project, ProjectPath, Worktree};
|
use project::{DisableAiSettings, Project, ProjectPath, Worktree};
|
||||||
use prompt_store::{PromptBuilder, PromptStore, UserPromptId};
|
use prompt_store::{PromptBuilder, PromptStore, UserPromptId};
|
||||||
use proto::Plan;
|
use proto::Plan;
|
||||||
use rules_library::{RulesLibrary, open_rules_library};
|
use rules_library::{RulesLibrary, open_rules_library};
|
||||||
|
|
|
@ -31,7 +31,7 @@ use std::sync::Arc;
|
||||||
use agent::{Thread, ThreadId};
|
use agent::{Thread, ThreadId};
|
||||||
use agent_settings::{AgentProfileId, AgentSettings, LanguageModelSelection};
|
use agent_settings::{AgentProfileId, AgentSettings, LanguageModelSelection};
|
||||||
use assistant_slash_command::SlashCommandRegistry;
|
use assistant_slash_command::SlashCommandRegistry;
|
||||||
use client::{Client, DisableAiSettings};
|
use client::Client;
|
||||||
use command_palette_hooks::CommandPaletteFilter;
|
use command_palette_hooks::CommandPaletteFilter;
|
||||||
use feature_flags::FeatureFlagAppExt as _;
|
use feature_flags::FeatureFlagAppExt as _;
|
||||||
use fs::Fs;
|
use fs::Fs;
|
||||||
|
@ -40,6 +40,7 @@ use language::LanguageRegistry;
|
||||||
use language_model::{
|
use language_model::{
|
||||||
ConfiguredModel, LanguageModel, LanguageModelId, LanguageModelProviderId, LanguageModelRegistry,
|
ConfiguredModel, LanguageModel, LanguageModelId, LanguageModelProviderId, LanguageModelRegistry,
|
||||||
};
|
};
|
||||||
|
use project::DisableAiSettings;
|
||||||
use prompt_store::PromptBuilder;
|
use prompt_store::PromptBuilder;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
|
@ -16,7 +16,7 @@ use agent::{
|
||||||
};
|
};
|
||||||
use agent_settings::AgentSettings;
|
use agent_settings::AgentSettings;
|
||||||
use anyhow::{Context as _, Result};
|
use anyhow::{Context as _, Result};
|
||||||
use client::{DisableAiSettings, telemetry::Telemetry};
|
use client::telemetry::Telemetry;
|
||||||
use collections::{HashMap, HashSet, VecDeque, hash_map};
|
use collections::{HashMap, HashSet, VecDeque, hash_map};
|
||||||
use editor::SelectionEffects;
|
use editor::SelectionEffects;
|
||||||
use editor::{
|
use editor::{
|
||||||
|
@ -39,7 +39,7 @@ use language_model::{
|
||||||
};
|
};
|
||||||
use multi_buffer::MultiBufferRow;
|
use multi_buffer::MultiBufferRow;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use project::{CodeAction, LspAction, Project, ProjectTransaction};
|
use project::{CodeAction, DisableAiSettings, LspAction, Project, ProjectTransaction};
|
||||||
use prompt_store::{PromptBuilder, PromptStore};
|
use prompt_store::{PromptBuilder, PromptStore};
|
||||||
use settings::{Settings, SettingsStore};
|
use settings::{Settings, SettingsStore};
|
||||||
use telemetry_events::{AssistantEventData, AssistantKind, AssistantPhase};
|
use telemetry_events::{AssistantEventData, AssistantKind, AssistantPhase};
|
||||||
|
|
|
@ -36,11 +36,18 @@ pub enum AnthropicModelMode {
|
||||||
pub enum Model {
|
pub enum Model {
|
||||||
#[serde(rename = "claude-opus-4", alias = "claude-opus-4-latest")]
|
#[serde(rename = "claude-opus-4", alias = "claude-opus-4-latest")]
|
||||||
ClaudeOpus4,
|
ClaudeOpus4,
|
||||||
|
#[serde(rename = "claude-opus-4-1", alias = "claude-opus-4-1-latest")]
|
||||||
|
ClaudeOpus4_1,
|
||||||
#[serde(
|
#[serde(
|
||||||
rename = "claude-opus-4-thinking",
|
rename = "claude-opus-4-thinking",
|
||||||
alias = "claude-opus-4-thinking-latest"
|
alias = "claude-opus-4-thinking-latest"
|
||||||
)]
|
)]
|
||||||
ClaudeOpus4Thinking,
|
ClaudeOpus4Thinking,
|
||||||
|
#[serde(
|
||||||
|
rename = "claude-opus-4-1-thinking",
|
||||||
|
alias = "claude-opus-4-1-thinking-latest"
|
||||||
|
)]
|
||||||
|
ClaudeOpus4_1Thinking,
|
||||||
#[default]
|
#[default]
|
||||||
#[serde(rename = "claude-sonnet-4", alias = "claude-sonnet-4-latest")]
|
#[serde(rename = "claude-sonnet-4", alias = "claude-sonnet-4-latest")]
|
||||||
ClaudeSonnet4,
|
ClaudeSonnet4,
|
||||||
|
@ -91,10 +98,18 @@ impl Model {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_id(id: &str) -> Result<Self> {
|
pub fn from_id(id: &str) -> Result<Self> {
|
||||||
|
if id.starts_with("claude-opus-4-1-thinking") {
|
||||||
|
return Ok(Self::ClaudeOpus4_1Thinking);
|
||||||
|
}
|
||||||
|
|
||||||
if id.starts_with("claude-opus-4-thinking") {
|
if id.starts_with("claude-opus-4-thinking") {
|
||||||
return Ok(Self::ClaudeOpus4Thinking);
|
return Ok(Self::ClaudeOpus4Thinking);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if id.starts_with("claude-opus-4-1") {
|
||||||
|
return Ok(Self::ClaudeOpus4_1);
|
||||||
|
}
|
||||||
|
|
||||||
if id.starts_with("claude-opus-4") {
|
if id.starts_with("claude-opus-4") {
|
||||||
return Ok(Self::ClaudeOpus4);
|
return Ok(Self::ClaudeOpus4);
|
||||||
}
|
}
|
||||||
|
@ -141,7 +156,9 @@ impl Model {
|
||||||
pub fn id(&self) -> &str {
|
pub fn id(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
Self::ClaudeOpus4 => "claude-opus-4-latest",
|
Self::ClaudeOpus4 => "claude-opus-4-latest",
|
||||||
|
Self::ClaudeOpus4_1 => "claude-opus-4-1-latest",
|
||||||
Self::ClaudeOpus4Thinking => "claude-opus-4-thinking-latest",
|
Self::ClaudeOpus4Thinking => "claude-opus-4-thinking-latest",
|
||||||
|
Self::ClaudeOpus4_1Thinking => "claude-opus-4-1-thinking-latest",
|
||||||
Self::ClaudeSonnet4 => "claude-sonnet-4-latest",
|
Self::ClaudeSonnet4 => "claude-sonnet-4-latest",
|
||||||
Self::ClaudeSonnet4Thinking => "claude-sonnet-4-thinking-latest",
|
Self::ClaudeSonnet4Thinking => "claude-sonnet-4-thinking-latest",
|
||||||
Self::Claude3_5Sonnet => "claude-3-5-sonnet-latest",
|
Self::Claude3_5Sonnet => "claude-3-5-sonnet-latest",
|
||||||
|
@ -159,6 +176,7 @@ impl Model {
|
||||||
pub fn request_id(&self) -> &str {
|
pub fn request_id(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
Self::ClaudeOpus4 | Self::ClaudeOpus4Thinking => "claude-opus-4-20250514",
|
Self::ClaudeOpus4 | Self::ClaudeOpus4Thinking => "claude-opus-4-20250514",
|
||||||
|
Self::ClaudeOpus4_1 | Self::ClaudeOpus4_1Thinking => "claude-opus-4-1-20250805",
|
||||||
Self::ClaudeSonnet4 | Self::ClaudeSonnet4Thinking => "claude-sonnet-4-20250514",
|
Self::ClaudeSonnet4 | Self::ClaudeSonnet4Thinking => "claude-sonnet-4-20250514",
|
||||||
Self::Claude3_5Sonnet => "claude-3-5-sonnet-latest",
|
Self::Claude3_5Sonnet => "claude-3-5-sonnet-latest",
|
||||||
Self::Claude3_7Sonnet | Self::Claude3_7SonnetThinking => "claude-3-7-sonnet-latest",
|
Self::Claude3_7Sonnet | Self::Claude3_7SonnetThinking => "claude-3-7-sonnet-latest",
|
||||||
|
@ -173,7 +191,9 @@ impl Model {
|
||||||
pub fn display_name(&self) -> &str {
|
pub fn display_name(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
Self::ClaudeOpus4 => "Claude Opus 4",
|
Self::ClaudeOpus4 => "Claude Opus 4",
|
||||||
|
Self::ClaudeOpus4_1 => "Claude Opus 4.1",
|
||||||
Self::ClaudeOpus4Thinking => "Claude Opus 4 Thinking",
|
Self::ClaudeOpus4Thinking => "Claude Opus 4 Thinking",
|
||||||
|
Self::ClaudeOpus4_1Thinking => "Claude Opus 4.1 Thinking",
|
||||||
Self::ClaudeSonnet4 => "Claude Sonnet 4",
|
Self::ClaudeSonnet4 => "Claude Sonnet 4",
|
||||||
Self::ClaudeSonnet4Thinking => "Claude Sonnet 4 Thinking",
|
Self::ClaudeSonnet4Thinking => "Claude Sonnet 4 Thinking",
|
||||||
Self::Claude3_7Sonnet => "Claude 3.7 Sonnet",
|
Self::Claude3_7Sonnet => "Claude 3.7 Sonnet",
|
||||||
|
@ -192,7 +212,9 @@ impl Model {
|
||||||
pub fn cache_configuration(&self) -> Option<AnthropicModelCacheConfiguration> {
|
pub fn cache_configuration(&self) -> Option<AnthropicModelCacheConfiguration> {
|
||||||
match self {
|
match self {
|
||||||
Self::ClaudeOpus4
|
Self::ClaudeOpus4
|
||||||
|
| Self::ClaudeOpus4_1
|
||||||
| Self::ClaudeOpus4Thinking
|
| Self::ClaudeOpus4Thinking
|
||||||
|
| Self::ClaudeOpus4_1Thinking
|
||||||
| Self::ClaudeSonnet4
|
| Self::ClaudeSonnet4
|
||||||
| Self::ClaudeSonnet4Thinking
|
| Self::ClaudeSonnet4Thinking
|
||||||
| Self::Claude3_5Sonnet
|
| Self::Claude3_5Sonnet
|
||||||
|
@ -215,7 +237,9 @@ impl Model {
|
||||||
pub fn max_token_count(&self) -> u64 {
|
pub fn max_token_count(&self) -> u64 {
|
||||||
match self {
|
match self {
|
||||||
Self::ClaudeOpus4
|
Self::ClaudeOpus4
|
||||||
|
| Self::ClaudeOpus4_1
|
||||||
| Self::ClaudeOpus4Thinking
|
| Self::ClaudeOpus4Thinking
|
||||||
|
| Self::ClaudeOpus4_1Thinking
|
||||||
| Self::ClaudeSonnet4
|
| Self::ClaudeSonnet4
|
||||||
| Self::ClaudeSonnet4Thinking
|
| Self::ClaudeSonnet4Thinking
|
||||||
| Self::Claude3_5Sonnet
|
| Self::Claude3_5Sonnet
|
||||||
|
@ -232,7 +256,9 @@ impl Model {
|
||||||
pub fn max_output_tokens(&self) -> u64 {
|
pub fn max_output_tokens(&self) -> u64 {
|
||||||
match self {
|
match self {
|
||||||
Self::ClaudeOpus4
|
Self::ClaudeOpus4
|
||||||
|
| Self::ClaudeOpus4_1
|
||||||
| Self::ClaudeOpus4Thinking
|
| Self::ClaudeOpus4Thinking
|
||||||
|
| Self::ClaudeOpus4_1Thinking
|
||||||
| Self::ClaudeSonnet4
|
| Self::ClaudeSonnet4
|
||||||
| Self::ClaudeSonnet4Thinking
|
| Self::ClaudeSonnet4Thinking
|
||||||
| Self::Claude3_5Sonnet
|
| Self::Claude3_5Sonnet
|
||||||
|
@ -249,7 +275,9 @@ impl Model {
|
||||||
pub fn default_temperature(&self) -> f32 {
|
pub fn default_temperature(&self) -> f32 {
|
||||||
match self {
|
match self {
|
||||||
Self::ClaudeOpus4
|
Self::ClaudeOpus4
|
||||||
|
| Self::ClaudeOpus4_1
|
||||||
| Self::ClaudeOpus4Thinking
|
| Self::ClaudeOpus4Thinking
|
||||||
|
| Self::ClaudeOpus4_1Thinking
|
||||||
| Self::ClaudeSonnet4
|
| Self::ClaudeSonnet4
|
||||||
| Self::ClaudeSonnet4Thinking
|
| Self::ClaudeSonnet4Thinking
|
||||||
| Self::Claude3_5Sonnet
|
| Self::Claude3_5Sonnet
|
||||||
|
@ -269,6 +297,7 @@ impl Model {
|
||||||
pub fn mode(&self) -> AnthropicModelMode {
|
pub fn mode(&self) -> AnthropicModelMode {
|
||||||
match self {
|
match self {
|
||||||
Self::ClaudeOpus4
|
Self::ClaudeOpus4
|
||||||
|
| Self::ClaudeOpus4_1
|
||||||
| Self::ClaudeSonnet4
|
| Self::ClaudeSonnet4
|
||||||
| Self::Claude3_5Sonnet
|
| Self::Claude3_5Sonnet
|
||||||
| Self::Claude3_7Sonnet
|
| Self::Claude3_7Sonnet
|
||||||
|
@ -277,6 +306,7 @@ impl Model {
|
||||||
| Self::Claude3Sonnet
|
| Self::Claude3Sonnet
|
||||||
| Self::Claude3Haiku => AnthropicModelMode::Default,
|
| Self::Claude3Haiku => AnthropicModelMode::Default,
|
||||||
Self::ClaudeOpus4Thinking
|
Self::ClaudeOpus4Thinking
|
||||||
|
| Self::ClaudeOpus4_1Thinking
|
||||||
| Self::ClaudeSonnet4Thinking
|
| Self::ClaudeSonnet4Thinking
|
||||||
| Self::Claude3_7SonnetThinking => AnthropicModelMode::Thinking {
|
| Self::Claude3_7SonnetThinking => AnthropicModelMode::Thinking {
|
||||||
budget_tokens: Some(4_096),
|
budget_tokens: Some(4_096),
|
||||||
|
|
|
@ -630,6 +630,11 @@ impl ActionLog {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if tracked_buffer.unreviewed_edits.is_empty() {
|
||||||
|
if let TrackedBufferStatus::Created { .. } = &mut tracked_buffer.status {
|
||||||
|
tracked_buffer.status = TrackedBufferStatus::Modified;
|
||||||
|
}
|
||||||
|
}
|
||||||
tracked_buffer.schedule_diff_update(ChangeAuthor::User, cx);
|
tracked_buffer.schedule_diff_update(ChangeAuthor::User, cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -775,6 +780,9 @@ impl ActionLog {
|
||||||
.retain(|_buffer, tracked_buffer| match tracked_buffer.status {
|
.retain(|_buffer, tracked_buffer| match tracked_buffer.status {
|
||||||
TrackedBufferStatus::Deleted => false,
|
TrackedBufferStatus::Deleted => false,
|
||||||
_ => {
|
_ => {
|
||||||
|
if let TrackedBufferStatus::Created { .. } = &mut tracked_buffer.status {
|
||||||
|
tracked_buffer.status = TrackedBufferStatus::Modified;
|
||||||
|
}
|
||||||
tracked_buffer.unreviewed_edits.clear();
|
tracked_buffer.unreviewed_edits.clear();
|
||||||
tracked_buffer.diff_base = tracked_buffer.snapshot.as_rope().clone();
|
tracked_buffer.diff_base = tracked_buffer.snapshot.as_rope().clone();
|
||||||
tracked_buffer.schedule_diff_update(ChangeAuthor::User, cx);
|
tracked_buffer.schedule_diff_update(ChangeAuthor::User, cx);
|
||||||
|
@ -2075,6 +2083,134 @@ mod tests {
|
||||||
assert_eq!(content, "ai content\nuser added this line");
|
assert_eq!(content, "ai content\nuser added this line");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_reject_after_accepting_hunk_on_created_file(cx: &mut TestAppContext) {
|
||||||
|
init_test(cx);
|
||||||
|
|
||||||
|
let fs = FakeFs::new(cx.executor());
|
||||||
|
let project = Project::test(fs.clone(), [path!("/dir").as_ref()], cx).await;
|
||||||
|
let action_log = cx.new(|_| ActionLog::new(project.clone()));
|
||||||
|
|
||||||
|
let file_path = project
|
||||||
|
.read_with(cx, |project, cx| {
|
||||||
|
project.find_project_path("dir/new_file", cx)
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
let buffer = project
|
||||||
|
.update(cx, |project, cx| project.open_buffer(file_path.clone(), cx))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// AI creates file with initial content
|
||||||
|
cx.update(|cx| {
|
||||||
|
action_log.update(cx, |log, cx| log.buffer_created(buffer.clone(), cx));
|
||||||
|
buffer.update(cx, |buffer, cx| buffer.set_text("ai content v1", cx));
|
||||||
|
action_log.update(cx, |log, cx| log.buffer_edited(buffer.clone(), cx));
|
||||||
|
});
|
||||||
|
project
|
||||||
|
.update(cx, |project, cx| project.save_buffer(buffer.clone(), cx))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
cx.run_until_parked();
|
||||||
|
assert_ne!(unreviewed_hunks(&action_log, cx), vec![]);
|
||||||
|
|
||||||
|
// User accepts the single hunk
|
||||||
|
action_log.update(cx, |log, cx| {
|
||||||
|
log.keep_edits_in_range(buffer.clone(), Anchor::MIN..Anchor::MAX, cx)
|
||||||
|
});
|
||||||
|
cx.run_until_parked();
|
||||||
|
assert_eq!(unreviewed_hunks(&action_log, cx), vec![]);
|
||||||
|
assert!(fs.is_file(path!("/dir/new_file").as_ref()).await);
|
||||||
|
|
||||||
|
// AI modifies the file
|
||||||
|
cx.update(|cx| {
|
||||||
|
buffer.update(cx, |buffer, cx| buffer.set_text("ai content v2", cx));
|
||||||
|
action_log.update(cx, |log, cx| log.buffer_edited(buffer.clone(), cx));
|
||||||
|
});
|
||||||
|
project
|
||||||
|
.update(cx, |project, cx| project.save_buffer(buffer.clone(), cx))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
cx.run_until_parked();
|
||||||
|
assert_ne!(unreviewed_hunks(&action_log, cx), vec![]);
|
||||||
|
|
||||||
|
// User rejects the hunk
|
||||||
|
action_log
|
||||||
|
.update(cx, |log, cx| {
|
||||||
|
log.reject_edits_in_ranges(buffer.clone(), vec![Anchor::MIN..Anchor::MAX], cx)
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
cx.run_until_parked();
|
||||||
|
assert!(fs.is_file(path!("/dir/new_file").as_ref()).await,);
|
||||||
|
assert_eq!(
|
||||||
|
buffer.read_with(cx, |buffer, _| buffer.text()),
|
||||||
|
"ai content v1"
|
||||||
|
);
|
||||||
|
assert_eq!(unreviewed_hunks(&action_log, cx), vec![]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_reject_edits_on_previously_accepted_created_file(cx: &mut TestAppContext) {
|
||||||
|
init_test(cx);
|
||||||
|
|
||||||
|
let fs = FakeFs::new(cx.executor());
|
||||||
|
let project = Project::test(fs.clone(), [path!("/dir").as_ref()], cx).await;
|
||||||
|
let action_log = cx.new(|_| ActionLog::new(project.clone()));
|
||||||
|
|
||||||
|
let file_path = project
|
||||||
|
.read_with(cx, |project, cx| {
|
||||||
|
project.find_project_path("dir/new_file", cx)
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
let buffer = project
|
||||||
|
.update(cx, |project, cx| project.open_buffer(file_path.clone(), cx))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// AI creates file with initial content
|
||||||
|
cx.update(|cx| {
|
||||||
|
action_log.update(cx, |log, cx| log.buffer_created(buffer.clone(), cx));
|
||||||
|
buffer.update(cx, |buffer, cx| buffer.set_text("ai content v1", cx));
|
||||||
|
action_log.update(cx, |log, cx| log.buffer_edited(buffer.clone(), cx));
|
||||||
|
});
|
||||||
|
project
|
||||||
|
.update(cx, |project, cx| project.save_buffer(buffer.clone(), cx))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
cx.run_until_parked();
|
||||||
|
|
||||||
|
// User clicks "Accept All"
|
||||||
|
action_log.update(cx, |log, cx| log.keep_all_edits(cx));
|
||||||
|
cx.run_until_parked();
|
||||||
|
assert!(fs.is_file(path!("/dir/new_file").as_ref()).await);
|
||||||
|
assert_eq!(unreviewed_hunks(&action_log, cx), vec![]); // Hunks are cleared
|
||||||
|
|
||||||
|
// AI modifies file again
|
||||||
|
cx.update(|cx| {
|
||||||
|
buffer.update(cx, |buffer, cx| buffer.set_text("ai content v2", cx));
|
||||||
|
action_log.update(cx, |log, cx| log.buffer_edited(buffer.clone(), cx));
|
||||||
|
});
|
||||||
|
project
|
||||||
|
.update(cx, |project, cx| project.save_buffer(buffer.clone(), cx))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
cx.run_until_parked();
|
||||||
|
assert_ne!(unreviewed_hunks(&action_log, cx), vec![]);
|
||||||
|
|
||||||
|
// User clicks "Reject All"
|
||||||
|
action_log
|
||||||
|
.update(cx, |log, cx| log.reject_all_edits(cx))
|
||||||
|
.await;
|
||||||
|
cx.run_until_parked();
|
||||||
|
assert!(fs.is_file(path!("/dir/new_file").as_ref()).await);
|
||||||
|
assert_eq!(
|
||||||
|
buffer.read_with(cx, |buffer, _| buffer.text()),
|
||||||
|
"ai content v1"
|
||||||
|
);
|
||||||
|
assert_eq!(unreviewed_hunks(&action_log, cx), vec![]);
|
||||||
|
}
|
||||||
|
|
||||||
#[gpui::test(iterations = 100)]
|
#[gpui::test(iterations = 100)]
|
||||||
async fn test_random_diffs(mut rng: StdRng, cx: &mut TestAppContext) {
|
async fn test_random_diffs(mut rng: StdRng, cx: &mut TestAppContext) {
|
||||||
init_test(cx);
|
init_test(cx);
|
||||||
|
|
|
@ -32,11 +32,18 @@ pub enum Model {
|
||||||
ClaudeSonnet4Thinking,
|
ClaudeSonnet4Thinking,
|
||||||
#[serde(rename = "claude-opus-4", alias = "claude-opus-4-latest")]
|
#[serde(rename = "claude-opus-4", alias = "claude-opus-4-latest")]
|
||||||
ClaudeOpus4,
|
ClaudeOpus4,
|
||||||
|
#[serde(rename = "claude-opus-4-1", alias = "claude-opus-4-1-latest")]
|
||||||
|
ClaudeOpus4_1,
|
||||||
#[serde(
|
#[serde(
|
||||||
rename = "claude-opus-4-thinking",
|
rename = "claude-opus-4-thinking",
|
||||||
alias = "claude-opus-4-thinking-latest"
|
alias = "claude-opus-4-thinking-latest"
|
||||||
)]
|
)]
|
||||||
ClaudeOpus4Thinking,
|
ClaudeOpus4Thinking,
|
||||||
|
#[serde(
|
||||||
|
rename = "claude-opus-4-1-thinking",
|
||||||
|
alias = "claude-opus-4-1-thinking-latest"
|
||||||
|
)]
|
||||||
|
ClaudeOpus4_1Thinking,
|
||||||
#[serde(rename = "claude-3-5-sonnet-v2", alias = "claude-3-5-sonnet-latest")]
|
#[serde(rename = "claude-3-5-sonnet-v2", alias = "claude-3-5-sonnet-latest")]
|
||||||
Claude3_5SonnetV2,
|
Claude3_5SonnetV2,
|
||||||
#[serde(rename = "claude-3-7-sonnet", alias = "claude-3-7-sonnet-latest")]
|
#[serde(rename = "claude-3-7-sonnet", alias = "claude-3-7-sonnet-latest")]
|
||||||
|
@ -147,7 +154,9 @@ impl Model {
|
||||||
Model::ClaudeSonnet4 => "claude-4-sonnet",
|
Model::ClaudeSonnet4 => "claude-4-sonnet",
|
||||||
Model::ClaudeSonnet4Thinking => "claude-4-sonnet-thinking",
|
Model::ClaudeSonnet4Thinking => "claude-4-sonnet-thinking",
|
||||||
Model::ClaudeOpus4 => "claude-4-opus",
|
Model::ClaudeOpus4 => "claude-4-opus",
|
||||||
|
Model::ClaudeOpus4_1 => "claude-4-opus-1",
|
||||||
Model::ClaudeOpus4Thinking => "claude-4-opus-thinking",
|
Model::ClaudeOpus4Thinking => "claude-4-opus-thinking",
|
||||||
|
Model::ClaudeOpus4_1Thinking => "claude-4-opus-1-thinking",
|
||||||
Model::Claude3_5SonnetV2 => "claude-3-5-sonnet-v2",
|
Model::Claude3_5SonnetV2 => "claude-3-5-sonnet-v2",
|
||||||
Model::Claude3_5Sonnet => "claude-3-5-sonnet",
|
Model::Claude3_5Sonnet => "claude-3-5-sonnet",
|
||||||
Model::Claude3Opus => "claude-3-opus",
|
Model::Claude3Opus => "claude-3-opus",
|
||||||
|
@ -208,6 +217,9 @@ impl Model {
|
||||||
Model::ClaudeOpus4 | Model::ClaudeOpus4Thinking => {
|
Model::ClaudeOpus4 | Model::ClaudeOpus4Thinking => {
|
||||||
"anthropic.claude-opus-4-20250514-v1:0"
|
"anthropic.claude-opus-4-20250514-v1:0"
|
||||||
}
|
}
|
||||||
|
Model::ClaudeOpus4_1 | Model::ClaudeOpus4_1Thinking => {
|
||||||
|
"anthropic.claude-opus-4-1-20250805-v1:0"
|
||||||
|
}
|
||||||
Model::Claude3_5SonnetV2 => "anthropic.claude-3-5-sonnet-20241022-v2:0",
|
Model::Claude3_5SonnetV2 => "anthropic.claude-3-5-sonnet-20241022-v2:0",
|
||||||
Model::Claude3_5Sonnet => "anthropic.claude-3-5-sonnet-20240620-v1:0",
|
Model::Claude3_5Sonnet => "anthropic.claude-3-5-sonnet-20240620-v1:0",
|
||||||
Model::Claude3Opus => "anthropic.claude-3-opus-20240229-v1:0",
|
Model::Claude3Opus => "anthropic.claude-3-opus-20240229-v1:0",
|
||||||
|
@ -266,7 +278,9 @@ impl Model {
|
||||||
Self::ClaudeSonnet4 => "Claude Sonnet 4",
|
Self::ClaudeSonnet4 => "Claude Sonnet 4",
|
||||||
Self::ClaudeSonnet4Thinking => "Claude Sonnet 4 Thinking",
|
Self::ClaudeSonnet4Thinking => "Claude Sonnet 4 Thinking",
|
||||||
Self::ClaudeOpus4 => "Claude Opus 4",
|
Self::ClaudeOpus4 => "Claude Opus 4",
|
||||||
|
Self::ClaudeOpus4_1 => "Claude Opus 4.1",
|
||||||
Self::ClaudeOpus4Thinking => "Claude Opus 4 Thinking",
|
Self::ClaudeOpus4Thinking => "Claude Opus 4 Thinking",
|
||||||
|
Self::ClaudeOpus4_1Thinking => "Claude Opus 4.1 Thinking",
|
||||||
Self::Claude3_5SonnetV2 => "Claude 3.5 Sonnet v2",
|
Self::Claude3_5SonnetV2 => "Claude 3.5 Sonnet v2",
|
||||||
Self::Claude3_5Sonnet => "Claude 3.5 Sonnet",
|
Self::Claude3_5Sonnet => "Claude 3.5 Sonnet",
|
||||||
Self::Claude3Opus => "Claude 3 Opus",
|
Self::Claude3Opus => "Claude 3 Opus",
|
||||||
|
@ -330,8 +344,10 @@ impl Model {
|
||||||
| Self::Claude3_7Sonnet
|
| Self::Claude3_7Sonnet
|
||||||
| Self::ClaudeSonnet4
|
| Self::ClaudeSonnet4
|
||||||
| Self::ClaudeOpus4
|
| Self::ClaudeOpus4
|
||||||
|
| Self::ClaudeOpus4_1
|
||||||
| Self::ClaudeSonnet4Thinking
|
| Self::ClaudeSonnet4Thinking
|
||||||
| Self::ClaudeOpus4Thinking => 200_000,
|
| Self::ClaudeOpus4Thinking
|
||||||
|
| Self::ClaudeOpus4_1Thinking => 200_000,
|
||||||
Self::AmazonNovaPremier => 1_000_000,
|
Self::AmazonNovaPremier => 1_000_000,
|
||||||
Self::PalmyraWriterX5 => 1_000_000,
|
Self::PalmyraWriterX5 => 1_000_000,
|
||||||
Self::PalmyraWriterX4 => 128_000,
|
Self::PalmyraWriterX4 => 128_000,
|
||||||
|
@ -348,7 +364,9 @@ impl Model {
|
||||||
| Self::ClaudeSonnet4
|
| Self::ClaudeSonnet4
|
||||||
| Self::ClaudeSonnet4Thinking
|
| Self::ClaudeSonnet4Thinking
|
||||||
| Self::ClaudeOpus4
|
| Self::ClaudeOpus4
|
||||||
| Model::ClaudeOpus4Thinking => 128_000,
|
| Model::ClaudeOpus4Thinking
|
||||||
|
| Self::ClaudeOpus4_1
|
||||||
|
| Model::ClaudeOpus4_1Thinking => 128_000,
|
||||||
Self::Claude3_5SonnetV2 | Self::PalmyraWriterX4 | Self::PalmyraWriterX5 => 8_192,
|
Self::Claude3_5SonnetV2 | Self::PalmyraWriterX4 | Self::PalmyraWriterX5 => 8_192,
|
||||||
Self::Custom {
|
Self::Custom {
|
||||||
max_output_tokens, ..
|
max_output_tokens, ..
|
||||||
|
@ -366,6 +384,8 @@ impl Model {
|
||||||
| Self::Claude3_7Sonnet
|
| Self::Claude3_7Sonnet
|
||||||
| Self::ClaudeOpus4
|
| Self::ClaudeOpus4
|
||||||
| Self::ClaudeOpus4Thinking
|
| Self::ClaudeOpus4Thinking
|
||||||
|
| Self::ClaudeOpus4_1
|
||||||
|
| Self::ClaudeOpus4_1Thinking
|
||||||
| Self::ClaudeSonnet4
|
| Self::ClaudeSonnet4
|
||||||
| Self::ClaudeSonnet4Thinking => 1.0,
|
| Self::ClaudeSonnet4Thinking => 1.0,
|
||||||
Self::Custom {
|
Self::Custom {
|
||||||
|
@ -387,6 +407,8 @@ impl Model {
|
||||||
| Self::Claude3_7SonnetThinking
|
| Self::Claude3_7SonnetThinking
|
||||||
| Self::ClaudeOpus4
|
| Self::ClaudeOpus4
|
||||||
| Self::ClaudeOpus4Thinking
|
| Self::ClaudeOpus4Thinking
|
||||||
|
| Self::ClaudeOpus4_1
|
||||||
|
| Self::ClaudeOpus4_1Thinking
|
||||||
| Self::ClaudeSonnet4
|
| Self::ClaudeSonnet4
|
||||||
| Self::ClaudeSonnet4Thinking
|
| Self::ClaudeSonnet4Thinking
|
||||||
| Self::Claude3_5Haiku => true,
|
| Self::Claude3_5Haiku => true,
|
||||||
|
@ -420,7 +442,9 @@ impl Model {
|
||||||
| Self::ClaudeSonnet4
|
| Self::ClaudeSonnet4
|
||||||
| Self::ClaudeSonnet4Thinking
|
| Self::ClaudeSonnet4Thinking
|
||||||
| Self::ClaudeOpus4
|
| Self::ClaudeOpus4
|
||||||
| Self::ClaudeOpus4Thinking => true,
|
| Self::ClaudeOpus4Thinking
|
||||||
|
| Self::ClaudeOpus4_1
|
||||||
|
| Self::ClaudeOpus4_1Thinking => true,
|
||||||
|
|
||||||
// Custom models - check if they have cache configuration
|
// Custom models - check if they have cache configuration
|
||||||
Self::Custom {
|
Self::Custom {
|
||||||
|
@ -440,7 +464,9 @@ impl Model {
|
||||||
| Self::ClaudeSonnet4
|
| Self::ClaudeSonnet4
|
||||||
| Self::ClaudeSonnet4Thinking
|
| Self::ClaudeSonnet4Thinking
|
||||||
| Self::ClaudeOpus4
|
| Self::ClaudeOpus4
|
||||||
| Self::ClaudeOpus4Thinking => Some(BedrockModelCacheConfiguration {
|
| Self::ClaudeOpus4Thinking
|
||||||
|
| Self::ClaudeOpus4_1
|
||||||
|
| Self::ClaudeOpus4_1Thinking => Some(BedrockModelCacheConfiguration {
|
||||||
max_cache_anchors: 4,
|
max_cache_anchors: 4,
|
||||||
min_total_token: 1024,
|
min_total_token: 1024,
|
||||||
}),
|
}),
|
||||||
|
@ -467,9 +493,11 @@ impl Model {
|
||||||
Model::ClaudeSonnet4Thinking => BedrockModelMode::Thinking {
|
Model::ClaudeSonnet4Thinking => BedrockModelMode::Thinking {
|
||||||
budget_tokens: Some(4096),
|
budget_tokens: Some(4096),
|
||||||
},
|
},
|
||||||
Model::ClaudeOpus4Thinking => BedrockModelMode::Thinking {
|
Model::ClaudeOpus4Thinking | Model::ClaudeOpus4_1Thinking => {
|
||||||
budget_tokens: Some(4096),
|
BedrockModelMode::Thinking {
|
||||||
},
|
budget_tokens: Some(4096),
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => BedrockModelMode::Default,
|
_ => BedrockModelMode::Default,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -518,6 +546,8 @@ impl Model {
|
||||||
| Model::ClaudeSonnet4Thinking
|
| Model::ClaudeSonnet4Thinking
|
||||||
| Model::ClaudeOpus4
|
| Model::ClaudeOpus4
|
||||||
| Model::ClaudeOpus4Thinking
|
| Model::ClaudeOpus4Thinking
|
||||||
|
| Model::ClaudeOpus4_1
|
||||||
|
| Model::ClaudeOpus4_1Thinking
|
||||||
| Model::Claude3Haiku
|
| Model::Claude3Haiku
|
||||||
| Model::Claude3Opus
|
| Model::Claude3Opus
|
||||||
| Model::Claude3Sonnet
|
| Model::Claude3Sonnet
|
||||||
|
|
|
@ -151,7 +151,6 @@ impl Settings for ProxySettings {
|
||||||
|
|
||||||
pub fn init_settings(cx: &mut App) {
|
pub fn init_settings(cx: &mut App) {
|
||||||
TelemetrySettings::register(cx);
|
TelemetrySettings::register(cx);
|
||||||
DisableAiSettings::register(cx);
|
|
||||||
ClientSettings::register(cx);
|
ClientSettings::register(cx);
|
||||||
ProxySettings::register(cx);
|
ProxySettings::register(cx);
|
||||||
}
|
}
|
||||||
|
@ -549,33 +548,6 @@ impl settings::Settings for TelemetrySettings {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether to disable all AI features in Zed.
|
|
||||||
///
|
|
||||||
/// Default: false
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
pub struct DisableAiSettings {
|
|
||||||
pub disable_ai: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl settings::Settings for DisableAiSettings {
|
|
||||||
const KEY: Option<&'static str> = Some("disable_ai");
|
|
||||||
|
|
||||||
type FileContent = Option<bool>;
|
|
||||||
|
|
||||||
fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
|
|
||||||
Ok(Self {
|
|
||||||
disable_ai: sources
|
|
||||||
.user
|
|
||||||
.or(sources.server)
|
|
||||||
.copied()
|
|
||||||
.flatten()
|
|
||||||
.unwrap_or(sources.default.ok_or_else(Self::missing_default)?),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut Self::FileContent) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
clock: Arc<dyn SystemClock>,
|
clock: Arc<dyn SystemClock>,
|
||||||
|
|
|
@ -6,7 +6,6 @@ mod sign_in;
|
||||||
use crate::sign_in::initiate_sign_in_within_workspace;
|
use crate::sign_in::initiate_sign_in_within_workspace;
|
||||||
use ::fs::Fs;
|
use ::fs::Fs;
|
||||||
use anyhow::{Context as _, Result, anyhow};
|
use anyhow::{Context as _, Result, anyhow};
|
||||||
use client::DisableAiSettings;
|
|
||||||
use collections::{HashMap, HashSet};
|
use collections::{HashMap, HashSet};
|
||||||
use command_palette_hooks::CommandPaletteFilter;
|
use command_palette_hooks::CommandPaletteFilter;
|
||||||
use futures::{Future, FutureExt, TryFutureExt, channel::oneshot, future::Shared};
|
use futures::{Future, FutureExt, TryFutureExt, channel::oneshot, future::Shared};
|
||||||
|
@ -24,6 +23,7 @@ use language::{
|
||||||
use lsp::{LanguageServer, LanguageServerBinary, LanguageServerId, LanguageServerName};
|
use lsp::{LanguageServer, LanguageServerBinary, LanguageServerId, LanguageServerName};
|
||||||
use node_runtime::NodeRuntime;
|
use node_runtime::NodeRuntime;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
use project::DisableAiSettings;
|
||||||
use request::StatusNotification;
|
use request::StatusNotification;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
|
|
|
@ -295,7 +295,7 @@ mod tests {
|
||||||
request: dap_types::StartDebuggingRequestArgumentsRequest::Launch,
|
request: dap_types::StartDebuggingRequestArgumentsRequest::Launch,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Box::new(|_| panic!("Did not expect to hit this code path")),
|
Box::new(|_| {}),
|
||||||
&mut cx.to_async(),
|
&mut cx.to_async(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -883,6 +883,7 @@ impl FakeTransport {
|
||||||
break Err(anyhow!("exit in response to request"));
|
break Err(anyhow!("exit in response to request"));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let success = response.success;
|
||||||
let message =
|
let message =
|
||||||
serde_json::to_string(&Message::Response(response)).unwrap();
|
serde_json::to_string(&Message::Response(response)).unwrap();
|
||||||
|
|
||||||
|
@ -893,6 +894,25 @@ impl FakeTransport {
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
if request.command == dap_types::requests::Initialize::COMMAND
|
||||||
|
&& success
|
||||||
|
{
|
||||||
|
let message = serde_json::to_string(&Message::Event(Box::new(
|
||||||
|
dap_types::messages::Events::Initialized(Some(
|
||||||
|
Default::default(),
|
||||||
|
)),
|
||||||
|
)))
|
||||||
|
.unwrap();
|
||||||
|
writer
|
||||||
|
.write_all(
|
||||||
|
TransportDelegate::build_rpc_message(message)
|
||||||
|
.as_bytes(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
writer.flush().await.unwrap();
|
writer.flush().await.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ test-support = [
|
||||||
"theme/test-support",
|
"theme/test-support",
|
||||||
"util/test-support",
|
"util/test-support",
|
||||||
"workspace/test-support",
|
"workspace/test-support",
|
||||||
|
"tree-sitter-c",
|
||||||
"tree-sitter-rust",
|
"tree-sitter-rust",
|
||||||
"tree-sitter-typescript",
|
"tree-sitter-typescript",
|
||||||
"tree-sitter-html",
|
"tree-sitter-html",
|
||||||
|
@ -76,6 +77,7 @@ telemetry.workspace = true
|
||||||
text.workspace = true
|
text.workspace = true
|
||||||
time.workspace = true
|
time.workspace = true
|
||||||
theme.workspace = true
|
theme.workspace = true
|
||||||
|
tree-sitter-c = { workspace = true, optional = true }
|
||||||
tree-sitter-html = { workspace = true, optional = true }
|
tree-sitter-html = { workspace = true, optional = true }
|
||||||
tree-sitter-rust = { workspace = true, optional = true }
|
tree-sitter-rust = { workspace = true, optional = true }
|
||||||
tree-sitter-typescript = { workspace = true, optional = true }
|
tree-sitter-typescript = { workspace = true, optional = true }
|
||||||
|
@ -106,6 +108,7 @@ settings = { workspace = true, features = ["test-support"] }
|
||||||
tempfile.workspace = true
|
tempfile.workspace = true
|
||||||
text = { workspace = true, features = ["test-support"] }
|
text = { workspace = true, features = ["test-support"] }
|
||||||
theme = { workspace = true, features = ["test-support"] }
|
theme = { workspace = true, features = ["test-support"] }
|
||||||
|
tree-sitter-c.workspace = true
|
||||||
tree-sitter-html.workspace = true
|
tree-sitter-html.workspace = true
|
||||||
tree-sitter-rust.workspace = true
|
tree-sitter-rust.workspace = true
|
||||||
tree-sitter-typescript.workspace = true
|
tree-sitter-typescript.workspace = true
|
||||||
|
|
|
@ -56,7 +56,7 @@ use aho_corasick::AhoCorasick;
|
||||||
use anyhow::{Context as _, Result, anyhow};
|
use anyhow::{Context as _, Result, anyhow};
|
||||||
use blink_manager::BlinkManager;
|
use blink_manager::BlinkManager;
|
||||||
use buffer_diff::DiffHunkStatus;
|
use buffer_diff::DiffHunkStatus;
|
||||||
use client::{Collaborator, DisableAiSettings, ParticipantIndex};
|
use client::{Collaborator, ParticipantIndex};
|
||||||
use clock::{AGENT_REPLICA_ID, ReplicaId};
|
use clock::{AGENT_REPLICA_ID, ReplicaId};
|
||||||
use collections::{BTreeMap, HashMap, HashSet, VecDeque};
|
use collections::{BTreeMap, HashMap, HashSet, VecDeque};
|
||||||
use convert_case::{Case, Casing};
|
use convert_case::{Case, Casing};
|
||||||
|
@ -125,7 +125,7 @@ use markdown::Markdown;
|
||||||
use mouse_context_menu::MouseContextMenu;
|
use mouse_context_menu::MouseContextMenu;
|
||||||
use persistence::DB;
|
use persistence::DB;
|
||||||
use project::{
|
use project::{
|
||||||
BreakpointWithPosition, CompletionResponse, ProjectPath,
|
BreakpointWithPosition, CompletionResponse, DisableAiSettings, ProjectPath,
|
||||||
debugger::{
|
debugger::{
|
||||||
breakpoint_store::{
|
breakpoint_store::{
|
||||||
BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
|
BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
|
||||||
|
@ -1305,6 +1305,7 @@ impl Default for SelectionHistoryMode {
|
||||||
///
|
///
|
||||||
/// Similarly, you might want to disable scrolling if you don't want the viewport to
|
/// Similarly, you might want to disable scrolling if you don't want the viewport to
|
||||||
/// move.
|
/// move.
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct SelectionEffects {
|
pub struct SelectionEffects {
|
||||||
nav_history: Option<bool>,
|
nav_history: Option<bool>,
|
||||||
completions: bool,
|
completions: bool,
|
||||||
|
@ -2944,10 +2945,12 @@ impl Editor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let selection_anchors = self.selections.disjoint_anchors();
|
||||||
|
|
||||||
if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
|
if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
|
||||||
self.buffer.update(cx, |buffer, cx| {
|
self.buffer.update(cx, |buffer, cx| {
|
||||||
buffer.set_active_selections(
|
buffer.set_active_selections(
|
||||||
&self.selections.disjoint_anchors(),
|
&selection_anchors,
|
||||||
self.selections.line_mode,
|
self.selections.line_mode,
|
||||||
self.cursor_shape,
|
self.cursor_shape,
|
||||||
cx,
|
cx,
|
||||||
|
@ -2964,9 +2967,8 @@ impl Editor {
|
||||||
self.select_next_state = None;
|
self.select_next_state = None;
|
||||||
self.select_prev_state = None;
|
self.select_prev_state = None;
|
||||||
self.select_syntax_node_history.try_clear();
|
self.select_syntax_node_history.try_clear();
|
||||||
self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
|
self.invalidate_autoclose_regions(&selection_anchors, buffer);
|
||||||
self.snippet_stack
|
self.snippet_stack.invalidate(&selection_anchors, buffer);
|
||||||
.invalidate(&self.selections.disjoint_anchors(), buffer);
|
|
||||||
self.take_rename(false, window, cx);
|
self.take_rename(false, window, cx);
|
||||||
|
|
||||||
let newest_selection = self.selections.newest_anchor();
|
let newest_selection = self.selections.newest_anchor();
|
||||||
|
@ -4047,7 +4049,8 @@ impl Editor {
|
||||||
// then don't insert that closing bracket again; just move the selection
|
// then don't insert that closing bracket again; just move the selection
|
||||||
// past the closing bracket.
|
// past the closing bracket.
|
||||||
let should_skip = selection.end == region.range.end.to_point(&snapshot)
|
let should_skip = selection.end == region.range.end.to_point(&snapshot)
|
||||||
&& text.as_ref() == region.pair.end.as_str();
|
&& text.as_ref() == region.pair.end.as_str()
|
||||||
|
&& snapshot.contains_str_at(region.range.end, text.as_ref());
|
||||||
if should_skip {
|
if should_skip {
|
||||||
let anchor = snapshot.anchor_after(selection.end);
|
let anchor = snapshot.anchor_after(selection.end);
|
||||||
new_selections
|
new_selections
|
||||||
|
@ -4973,13 +4976,17 @@ impl Editor {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove any autoclose regions that no longer contain their selection.
|
/// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
|
||||||
fn invalidate_autoclose_regions(
|
fn invalidate_autoclose_regions(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut selections: &[Selection<Anchor>],
|
mut selections: &[Selection<Anchor>],
|
||||||
buffer: &MultiBufferSnapshot,
|
buffer: &MultiBufferSnapshot,
|
||||||
) {
|
) {
|
||||||
self.autoclose_regions.retain(|state| {
|
self.autoclose_regions.retain(|state| {
|
||||||
|
if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while let Some(selection) = selections.get(i) {
|
while let Some(selection) = selections.get(i) {
|
||||||
if selection.end.cmp(&state.range.start, buffer).is_lt() {
|
if selection.end.cmp(&state.range.start, buffer).is_lt() {
|
||||||
|
@ -5891,18 +5898,20 @@ impl Editor {
|
||||||
text: new_text[common_prefix_len..].into(),
|
text: new_text[common_prefix_len..].into(),
|
||||||
});
|
});
|
||||||
|
|
||||||
self.transact(window, cx, |this, window, cx| {
|
self.transact(window, cx, |editor, window, cx| {
|
||||||
if let Some(mut snippet) = snippet {
|
if let Some(mut snippet) = snippet {
|
||||||
snippet.text = new_text.to_string();
|
snippet.text = new_text.to_string();
|
||||||
this.insert_snippet(&ranges, snippet, window, cx).log_err();
|
editor
|
||||||
|
.insert_snippet(&ranges, snippet, window, cx)
|
||||||
|
.log_err();
|
||||||
} else {
|
} else {
|
||||||
this.buffer.update(cx, |buffer, cx| {
|
editor.buffer.update(cx, |multi_buffer, cx| {
|
||||||
let auto_indent = match completion.insert_text_mode {
|
let auto_indent = match completion.insert_text_mode {
|
||||||
Some(InsertTextMode::AS_IS) => None,
|
Some(InsertTextMode::AS_IS) => None,
|
||||||
_ => this.autoindent_mode.clone(),
|
_ => editor.autoindent_mode.clone(),
|
||||||
};
|
};
|
||||||
let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
|
let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
|
||||||
buffer.edit(edits, auto_indent, cx);
|
multi_buffer.edit(edits, auto_indent, cx);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
for (buffer, edits) in linked_edits {
|
for (buffer, edits) in linked_edits {
|
||||||
|
@ -5921,8 +5930,9 @@ impl Editor {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
this.refresh_inline_completion(true, false, window, cx);
|
editor.refresh_inline_completion(true, false, window, cx);
|
||||||
});
|
});
|
||||||
|
self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
|
||||||
|
|
||||||
let show_new_completions_on_confirm = completion
|
let show_new_completions_on_confirm = completion
|
||||||
.confirm
|
.confirm
|
||||||
|
@ -6993,6 +7003,10 @@ impl Editor {
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
|
if DisableAiSettings::get_global(cx).disable_ai {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let provider = self.edit_prediction_provider()?;
|
let provider = self.edit_prediction_provider()?;
|
||||||
let cursor = self.selections.newest_anchor().head();
|
let cursor = self.selections.newest_anchor().head();
|
||||||
let (buffer, cursor_buffer_position) =
|
let (buffer, cursor_buffer_position) =
|
||||||
|
@ -7050,6 +7064,7 @@ impl Editor {
|
||||||
pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
|
pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
|
||||||
if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
|
if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
|
||||||
self.edit_prediction_settings = EditPredictionSettings::Disabled;
|
self.edit_prediction_settings = EditPredictionSettings::Disabled;
|
||||||
|
self.discard_inline_completion(false, cx);
|
||||||
} else {
|
} else {
|
||||||
let selection = self.selections.newest_anchor();
|
let selection = self.selections.newest_anchor();
|
||||||
let cursor = selection.head();
|
let cursor = selection.head();
|
||||||
|
@ -7667,6 +7682,10 @@ impl Editor {
|
||||||
_window: &mut Window,
|
_window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
|
if DisableAiSettings::get_global(cx).disable_ai {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let selection = self.selections.newest_anchor();
|
let selection = self.selections.newest_anchor();
|
||||||
let cursor = selection.head();
|
let cursor = selection.head();
|
||||||
let multibuffer = self.buffer.read(cx).snapshot(cx);
|
let multibuffer = self.buffer.read(cx).snapshot(cx);
|
||||||
|
@ -9562,27 +9581,46 @@ impl Editor {
|
||||||
// Check whether the just-entered snippet ends with an auto-closable bracket.
|
// Check whether the just-entered snippet ends with an auto-closable bracket.
|
||||||
if self.autoclose_regions.is_empty() {
|
if self.autoclose_regions.is_empty() {
|
||||||
let snapshot = self.buffer.read(cx).snapshot(cx);
|
let snapshot = self.buffer.read(cx).snapshot(cx);
|
||||||
for selection in &mut self.selections.all::<Point>(cx) {
|
let mut all_selections = self.selections.all::<Point>(cx);
|
||||||
|
for selection in &mut all_selections {
|
||||||
let selection_head = selection.head();
|
let selection_head = selection.head();
|
||||||
let Some(scope) = snapshot.language_scope_at(selection_head) else {
|
let Some(scope) = snapshot.language_scope_at(selection_head) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut bracket_pair = None;
|
let mut bracket_pair = None;
|
||||||
let next_chars = snapshot.chars_at(selection_head).collect::<String>();
|
let max_lookup_length = scope
|
||||||
let prev_chars = snapshot
|
.brackets()
|
||||||
.reversed_chars_at(selection_head)
|
.map(|(pair, _)| {
|
||||||
.collect::<String>();
|
pair.start
|
||||||
for (pair, enabled) in scope.brackets() {
|
.as_str()
|
||||||
if enabled
|
.chars()
|
||||||
&& pair.close
|
.count()
|
||||||
&& prev_chars.starts_with(pair.start.as_str())
|
.max(pair.end.as_str().chars().count())
|
||||||
&& next_chars.starts_with(pair.end.as_str())
|
})
|
||||||
{
|
.max();
|
||||||
bracket_pair = Some(pair.clone());
|
if let Some(max_lookup_length) = max_lookup_length {
|
||||||
break;
|
let next_text = snapshot
|
||||||
|
.chars_at(selection_head)
|
||||||
|
.take(max_lookup_length)
|
||||||
|
.collect::<String>();
|
||||||
|
let prev_text = snapshot
|
||||||
|
.reversed_chars_at(selection_head)
|
||||||
|
.take(max_lookup_length)
|
||||||
|
.collect::<String>();
|
||||||
|
|
||||||
|
for (pair, enabled) in scope.brackets() {
|
||||||
|
if enabled
|
||||||
|
&& pair.close
|
||||||
|
&& prev_text.starts_with(pair.start.as_str())
|
||||||
|
&& next_text.starts_with(pair.end.as_str())
|
||||||
|
{
|
||||||
|
bracket_pair = Some(pair.clone());
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(pair) = bracket_pair {
|
if let Some(pair) = bracket_pair {
|
||||||
let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
|
let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
|
||||||
let autoclose_enabled =
|
let autoclose_enabled =
|
||||||
|
|
|
@ -13400,6 +13400,178 @@ async fn test_as_is_completions(cx: &mut TestAppContext) {
|
||||||
cx.assert_editor_state("fn a() {}\n unsafeˇ");
|
cx.assert_editor_state("fn a() {}\n unsafeˇ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_panic_during_c_completions(cx: &mut TestAppContext) {
|
||||||
|
init_test(cx, |_| {});
|
||||||
|
let language =
|
||||||
|
Arc::try_unwrap(languages::language("c", tree_sitter_c::LANGUAGE.into())).unwrap();
|
||||||
|
let mut cx = EditorLspTestContext::new(
|
||||||
|
language,
|
||||||
|
lsp::ServerCapabilities {
|
||||||
|
completion_provider: Some(lsp::CompletionOptions {
|
||||||
|
..lsp::CompletionOptions::default()
|
||||||
|
}),
|
||||||
|
..lsp::ServerCapabilities::default()
|
||||||
|
},
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
cx.set_state(
|
||||||
|
"#ifndef BAR_H
|
||||||
|
#define BAR_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
int fn_branch(bool do_branch1, bool do_branch2);
|
||||||
|
|
||||||
|
#endif // BAR_H
|
||||||
|
ˇ",
|
||||||
|
);
|
||||||
|
cx.executor().run_until_parked();
|
||||||
|
cx.update_editor(|editor, window, cx| {
|
||||||
|
editor.handle_input("#", window, cx);
|
||||||
|
});
|
||||||
|
cx.executor().run_until_parked();
|
||||||
|
cx.update_editor(|editor, window, cx| {
|
||||||
|
editor.handle_input("i", window, cx);
|
||||||
|
});
|
||||||
|
cx.executor().run_until_parked();
|
||||||
|
cx.update_editor(|editor, window, cx| {
|
||||||
|
editor.handle_input("n", window, cx);
|
||||||
|
});
|
||||||
|
cx.executor().run_until_parked();
|
||||||
|
cx.assert_editor_state(
|
||||||
|
"#ifndef BAR_H
|
||||||
|
#define BAR_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
int fn_branch(bool do_branch1, bool do_branch2);
|
||||||
|
|
||||||
|
#endif // BAR_H
|
||||||
|
#inˇ",
|
||||||
|
);
|
||||||
|
|
||||||
|
cx.lsp
|
||||||
|
.set_request_handler::<lsp::request::Completion, _, _>(move |_, _| async move {
|
||||||
|
Ok(Some(lsp::CompletionResponse::List(lsp::CompletionList {
|
||||||
|
is_incomplete: false,
|
||||||
|
item_defaults: None,
|
||||||
|
items: vec![lsp::CompletionItem {
|
||||||
|
kind: Some(lsp::CompletionItemKind::SNIPPET),
|
||||||
|
label_details: Some(lsp::CompletionItemLabelDetails {
|
||||||
|
detail: Some("header".to_string()),
|
||||||
|
description: None,
|
||||||
|
}),
|
||||||
|
label: " include".to_string(),
|
||||||
|
text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
|
||||||
|
range: lsp::Range {
|
||||||
|
start: lsp::Position {
|
||||||
|
line: 8,
|
||||||
|
character: 1,
|
||||||
|
},
|
||||||
|
end: lsp::Position {
|
||||||
|
line: 8,
|
||||||
|
character: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
new_text: "include \"$0\"".to_string(),
|
||||||
|
})),
|
||||||
|
sort_text: Some("40b67681include".to_string()),
|
||||||
|
insert_text_format: Some(lsp::InsertTextFormat::SNIPPET),
|
||||||
|
filter_text: Some("include".to_string()),
|
||||||
|
insert_text: Some("include \"$0\"".to_string()),
|
||||||
|
..lsp::CompletionItem::default()
|
||||||
|
}],
|
||||||
|
})))
|
||||||
|
});
|
||||||
|
cx.update_editor(|editor, window, cx| {
|
||||||
|
editor.show_completions(&ShowCompletions { trigger: None }, window, cx);
|
||||||
|
});
|
||||||
|
cx.executor().run_until_parked();
|
||||||
|
cx.update_editor(|editor, window, cx| {
|
||||||
|
editor.confirm_completion(&ConfirmCompletion::default(), window, cx)
|
||||||
|
});
|
||||||
|
cx.executor().run_until_parked();
|
||||||
|
cx.assert_editor_state(
|
||||||
|
"#ifndef BAR_H
|
||||||
|
#define BAR_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
int fn_branch(bool do_branch1, bool do_branch2);
|
||||||
|
|
||||||
|
#endif // BAR_H
|
||||||
|
#include \"ˇ\"",
|
||||||
|
);
|
||||||
|
|
||||||
|
cx.lsp
|
||||||
|
.set_request_handler::<lsp::request::Completion, _, _>(move |_, _| async move {
|
||||||
|
Ok(Some(lsp::CompletionResponse::List(lsp::CompletionList {
|
||||||
|
is_incomplete: true,
|
||||||
|
item_defaults: None,
|
||||||
|
items: vec![lsp::CompletionItem {
|
||||||
|
kind: Some(lsp::CompletionItemKind::FILE),
|
||||||
|
label: "AGL/".to_string(),
|
||||||
|
text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
|
||||||
|
range: lsp::Range {
|
||||||
|
start: lsp::Position {
|
||||||
|
line: 8,
|
||||||
|
character: 10,
|
||||||
|
},
|
||||||
|
end: lsp::Position {
|
||||||
|
line: 8,
|
||||||
|
character: 11,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
new_text: "AGL/".to_string(),
|
||||||
|
})),
|
||||||
|
sort_text: Some("40b67681AGL/".to_string()),
|
||||||
|
insert_text_format: Some(lsp::InsertTextFormat::PLAIN_TEXT),
|
||||||
|
filter_text: Some("AGL/".to_string()),
|
||||||
|
insert_text: Some("AGL/".to_string()),
|
||||||
|
..lsp::CompletionItem::default()
|
||||||
|
}],
|
||||||
|
})))
|
||||||
|
});
|
||||||
|
cx.update_editor(|editor, window, cx| {
|
||||||
|
editor.show_completions(&ShowCompletions { trigger: None }, window, cx);
|
||||||
|
});
|
||||||
|
cx.executor().run_until_parked();
|
||||||
|
cx.update_editor(|editor, window, cx| {
|
||||||
|
editor.confirm_completion(&ConfirmCompletion::default(), window, cx)
|
||||||
|
});
|
||||||
|
cx.executor().run_until_parked();
|
||||||
|
cx.assert_editor_state(
|
||||||
|
r##"#ifndef BAR_H
|
||||||
|
#define BAR_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
int fn_branch(bool do_branch1, bool do_branch2);
|
||||||
|
|
||||||
|
#endif // BAR_H
|
||||||
|
#include "AGL/ˇ"##,
|
||||||
|
);
|
||||||
|
|
||||||
|
cx.update_editor(|editor, window, cx| {
|
||||||
|
editor.handle_input("\"", window, cx);
|
||||||
|
});
|
||||||
|
cx.executor().run_until_parked();
|
||||||
|
cx.assert_editor_state(
|
||||||
|
r##"#ifndef BAR_H
|
||||||
|
#define BAR_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
int fn_branch(bool do_branch1, bool do_branch2);
|
||||||
|
|
||||||
|
#endif // BAR_H
|
||||||
|
#include "AGL/"ˇ"##,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_no_duplicated_completion_requests(cx: &mut TestAppContext) {
|
async fn test_no_duplicated_completion_requests(cx: &mut TestAppContext) {
|
||||||
init_test(cx, |_| {});
|
init_test(cx, |_| {});
|
||||||
|
|
|
@ -23,7 +23,6 @@ askpass.workspace = true
|
||||||
buffer_diff.workspace = true
|
buffer_diff.workspace = true
|
||||||
call.workspace = true
|
call.workspace = true
|
||||||
chrono.workspace = true
|
chrono.workspace = true
|
||||||
client.workspace = true
|
|
||||||
cloud_llm_client.workspace = true
|
cloud_llm_client.workspace = true
|
||||||
collections.workspace = true
|
collections.workspace = true
|
||||||
command_palette_hooks.workspace = true
|
command_palette_hooks.workspace = true
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use crate::branch_picker::{self, BranchList};
|
use crate::branch_picker::{self, BranchList};
|
||||||
use crate::git_panel::{GitPanel, commit_message_editor};
|
use crate::git_panel::{GitPanel, commit_message_editor};
|
||||||
use client::DisableAiSettings;
|
|
||||||
use git::repository::CommitOptions;
|
use git::repository::CommitOptions;
|
||||||
use git::{Amend, Commit, GenerateCommitMessage, Signoff};
|
use git::{Amend, Commit, GenerateCommitMessage, Signoff};
|
||||||
use panel::{panel_button, panel_editor_style};
|
use panel::{panel_button, panel_editor_style};
|
||||||
|
use project::DisableAiSettings;
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
use ui::{
|
use ui::{
|
||||||
ContextMenu, KeybindingHint, PopoverMenu, PopoverMenuHandle, SplitButton, Tooltip, prelude::*,
|
ContextMenu, KeybindingHint, PopoverMenu, PopoverMenuHandle, SplitButton, Tooltip, prelude::*,
|
||||||
|
|
|
@ -12,7 +12,6 @@ use crate::{
|
||||||
use agent_settings::AgentSettings;
|
use agent_settings::AgentSettings;
|
||||||
use anyhow::Context as _;
|
use anyhow::Context as _;
|
||||||
use askpass::AskPassDelegate;
|
use askpass::AskPassDelegate;
|
||||||
use client::DisableAiSettings;
|
|
||||||
use db::kvp::KEY_VALUE_STORE;
|
use db::kvp::KEY_VALUE_STORE;
|
||||||
use editor::{
|
use editor::{
|
||||||
Editor, EditorElement, EditorMode, EditorSettings, MultiBuffer, ShowScrollbar,
|
Editor, EditorElement, EditorMode, EditorSettings, MultiBuffer, ShowScrollbar,
|
||||||
|
@ -51,10 +50,9 @@ use panel::{
|
||||||
PanelHeader, panel_button, panel_editor_container, panel_editor_style, panel_filled_button,
|
PanelHeader, panel_button, panel_editor_container, panel_editor_style, panel_filled_button,
|
||||||
panel_icon_button,
|
panel_icon_button,
|
||||||
};
|
};
|
||||||
use project::git_store::{RepositoryEvent, RepositoryId};
|
|
||||||
use project::{
|
use project::{
|
||||||
Fs, Project, ProjectPath,
|
DisableAiSettings, Fs, Project, ProjectPath,
|
||||||
git_store::{GitStoreEvent, Repository},
|
git_store::{GitStoreEvent, Repository, RepositoryEvent, RepositoryId},
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use settings::{Settings, SettingsStore};
|
use settings::{Settings, SettingsStore};
|
||||||
|
@ -5115,7 +5113,6 @@ mod tests {
|
||||||
language::init(cx);
|
language::init(cx);
|
||||||
editor::init(cx);
|
editor::init(cx);
|
||||||
Project::init_settings(cx);
|
Project::init_settings(cx);
|
||||||
client::DisableAiSettings::register(cx);
|
|
||||||
crate::init(cx);
|
crate::init(cx);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -606,7 +606,7 @@ impl BladeRenderer {
|
||||||
xy_position: v.xy_position,
|
xy_position: v.xy_position,
|
||||||
st_position: v.st_position,
|
st_position: v.st_position,
|
||||||
color: path.color,
|
color: path.color,
|
||||||
bounds: path.bounds.intersect(&path.content_mask.bounds),
|
bounds: path.clipped_bounds(),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
let vertex_buf = unsafe { self.instance_belt.alloc_typed(&vertices, &self.gpu) };
|
let vertex_buf = unsafe { self.instance_belt.alloc_typed(&vertices, &self.gpu) };
|
||||||
|
@ -735,13 +735,13 @@ impl BladeRenderer {
|
||||||
paths
|
paths
|
||||||
.iter()
|
.iter()
|
||||||
.map(|path| PathSprite {
|
.map(|path| PathSprite {
|
||||||
bounds: path.bounds,
|
bounds: path.clipped_bounds(),
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
let mut bounds = first_path.bounds;
|
let mut bounds = first_path.clipped_bounds();
|
||||||
for path in paths.iter().skip(1) {
|
for path in paths.iter().skip(1) {
|
||||||
bounds = bounds.union(&path.bounds);
|
bounds = bounds.union(&path.clipped_bounds());
|
||||||
}
|
}
|
||||||
vec![PathSprite { bounds }]
|
vec![PathSprite { bounds }]
|
||||||
};
|
};
|
||||||
|
|
|
@ -1004,12 +1004,13 @@ impl X11Client {
|
||||||
let mut keystroke = crate::Keystroke::from_xkb(&state.xkb, modifiers, code);
|
let mut keystroke = crate::Keystroke::from_xkb(&state.xkb, modifiers, code);
|
||||||
let keysym = state.xkb.key_get_one_sym(code);
|
let keysym = state.xkb.key_get_one_sym(code);
|
||||||
|
|
||||||
// should be called after key_get_one_sym
|
|
||||||
state.xkb.update_key(code, xkbc::KeyDirection::Down);
|
|
||||||
|
|
||||||
if keysym.is_modifier_key() {
|
if keysym.is_modifier_key() {
|
||||||
return Some(());
|
return Some(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// should be called after key_get_one_sym
|
||||||
|
state.xkb.update_key(code, xkbc::KeyDirection::Down);
|
||||||
|
|
||||||
if let Some(mut compose_state) = state.compose_state.take() {
|
if let Some(mut compose_state) = state.compose_state.take() {
|
||||||
compose_state.feed(keysym);
|
compose_state.feed(keysym);
|
||||||
match compose_state.status() {
|
match compose_state.status() {
|
||||||
|
@ -1067,12 +1068,13 @@ impl X11Client {
|
||||||
let keystroke = crate::Keystroke::from_xkb(&state.xkb, modifiers, code);
|
let keystroke = crate::Keystroke::from_xkb(&state.xkb, modifiers, code);
|
||||||
let keysym = state.xkb.key_get_one_sym(code);
|
let keysym = state.xkb.key_get_one_sym(code);
|
||||||
|
|
||||||
// should be called after key_get_one_sym
|
|
||||||
state.xkb.update_key(code, xkbc::KeyDirection::Up);
|
|
||||||
|
|
||||||
if keysym.is_modifier_key() {
|
if keysym.is_modifier_key() {
|
||||||
return Some(());
|
return Some(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// should be called after key_get_one_sym
|
||||||
|
state.xkb.update_key(code, xkbc::KeyDirection::Up);
|
||||||
|
|
||||||
keystroke
|
keystroke
|
||||||
};
|
};
|
||||||
drop(state);
|
drop(state);
|
||||||
|
|
|
@ -791,13 +791,13 @@ impl MetalRenderer {
|
||||||
sprites = paths
|
sprites = paths
|
||||||
.iter()
|
.iter()
|
||||||
.map(|path| PathSprite {
|
.map(|path| PathSprite {
|
||||||
bounds: path.bounds,
|
bounds: path.clipped_bounds(),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
} else {
|
} else {
|
||||||
let mut bounds = first_path.bounds;
|
let mut bounds = first_path.clipped_bounds();
|
||||||
for path in paths.iter().skip(1) {
|
for path in paths.iter().skip(1) {
|
||||||
bounds = bounds.union(&path.bounds);
|
bounds = bounds.union(&path.clipped_bounds());
|
||||||
}
|
}
|
||||||
sprites = vec![PathSprite { bounds }];
|
sprites = vec![PathSprite { bounds }];
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,12 @@ use crate::{
|
||||||
AtlasTextureId, AtlasTile, Background, Bounds, ContentMask, Corners, Edges, Hsla, Pixels,
|
AtlasTextureId, AtlasTile, Background, Bounds, ContentMask, Corners, Edges, Hsla, Pixels,
|
||||||
Point, Radians, ScaledPixels, Size, bounds_tree::BoundsTree, point,
|
Point, Radians, ScaledPixels, Size, bounds_tree::BoundsTree, point,
|
||||||
};
|
};
|
||||||
use std::{fmt::Debug, iter::Peekable, ops::Range, slice};
|
use std::{
|
||||||
|
fmt::Debug,
|
||||||
|
iter::Peekable,
|
||||||
|
ops::{Add, Range, Sub},
|
||||||
|
slice,
|
||||||
|
};
|
||||||
|
|
||||||
#[allow(non_camel_case_types, unused)]
|
#[allow(non_camel_case_types, unused)]
|
||||||
pub(crate) type PathVertex_ScaledPixels = PathVertex<ScaledPixels>;
|
pub(crate) type PathVertex_ScaledPixels = PathVertex<ScaledPixels>;
|
||||||
|
@ -793,6 +798,16 @@ impl Path<Pixels> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> Path<T>
|
||||||
|
where
|
||||||
|
T: Clone + Debug + Default + PartialEq + PartialOrd + Add<T, Output = T> + Sub<Output = T>,
|
||||||
|
{
|
||||||
|
#[allow(unused)]
|
||||||
|
pub(crate) fn clipped_bounds(&self) -> Bounds<T> {
|
||||||
|
self.bounds.intersect(&self.content_mask.bounds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Path<ScaledPixels>> for Primitive {
|
impl From<Path<ScaledPixels>> for Primitive {
|
||||||
fn from(path: Path<ScaledPixels>) -> Self {
|
fn from(path: Path<ScaledPixels>) -> Self {
|
||||||
Primitive::Path(path)
|
Primitive::Path(path)
|
||||||
|
|
|
@ -25,6 +25,7 @@ indoc.workspace = true
|
||||||
inline_completion.workspace = true
|
inline_completion.workspace = true
|
||||||
language.workspace = true
|
language.workspace = true
|
||||||
paths.workspace = true
|
paths.workspace = true
|
||||||
|
project.workspace = true
|
||||||
regex.workspace = true
|
regex.workspace = true
|
||||||
settings.workspace = true
|
settings.workspace = true
|
||||||
supermaven.workspace = true
|
supermaven.workspace = true
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use client::{DisableAiSettings, UserStore, zed_urls};
|
use client::{UserStore, zed_urls};
|
||||||
use cloud_llm_client::UsageLimit;
|
use cloud_llm_client::UsageLimit;
|
||||||
use copilot::{Copilot, Status};
|
use copilot::{Copilot, Status};
|
||||||
use editor::{
|
use editor::{
|
||||||
|
@ -19,6 +19,7 @@ use language::{
|
||||||
EditPredictionsMode, File, Language,
|
EditPredictionsMode, File, Language,
|
||||||
language_settings::{self, AllLanguageSettings, EditPredictionProvider, all_language_settings},
|
language_settings::{self, AllLanguageSettings, EditPredictionProvider, all_language_settings},
|
||||||
};
|
};
|
||||||
|
use project::DisableAiSettings;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use settings::{Settings, SettingsStore, update_settings_file};
|
use settings::{Settings, SettingsStore, update_settings_file};
|
||||||
use std::{
|
use std::{
|
||||||
|
|
|
@ -674,6 +674,10 @@ pub fn count_open_ai_tokens(
|
||||||
| Model::O3
|
| Model::O3
|
||||||
| Model::O3Mini
|
| Model::O3Mini
|
||||||
| Model::O4Mini => tiktoken_rs::num_tokens_from_messages(model.id(), &messages),
|
| Model::O4Mini => tiktoken_rs::num_tokens_from_messages(model.id(), &messages),
|
||||||
|
// GPT-5 models don't have tiktoken support yet; fall back on gpt-4o tokenizer
|
||||||
|
Model::Five | Model::FiveMini | Model::FiveNano => {
|
||||||
|
tiktoken_rs::num_tokens_from_messages("gpt-4o", &messages)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.map(|tokens| tokens as u64)
|
.map(|tokens| tokens as u64)
|
||||||
})
|
})
|
||||||
|
|
|
@ -167,10 +167,10 @@ impl Anchor {
|
||||||
if *self == Anchor::min() || *self == Anchor::max() {
|
if *self == Anchor::min() || *self == Anchor::max() {
|
||||||
true
|
true
|
||||||
} else if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) {
|
} else if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) {
|
||||||
excerpt.contains(self)
|
(self.text_anchor == excerpt.range.context.start
|
||||||
&& (self.text_anchor == excerpt.range.context.start
|
|| self.text_anchor == excerpt.range.context.end
|
||||||
|| self.text_anchor == excerpt.range.context.end
|
|| self.text_anchor.is_valid(&excerpt.buffer))
|
||||||
|| self.text_anchor.is_valid(&excerpt.buffer))
|
&& excerpt.contains(self)
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,12 @@ pub enum Model {
|
||||||
O3,
|
O3,
|
||||||
#[serde(rename = "o4-mini")]
|
#[serde(rename = "o4-mini")]
|
||||||
O4Mini,
|
O4Mini,
|
||||||
|
#[serde(rename = "gpt-5")]
|
||||||
|
Five,
|
||||||
|
#[serde(rename = "gpt-5-mini")]
|
||||||
|
FiveMini,
|
||||||
|
#[serde(rename = "gpt-5-nano")]
|
||||||
|
FiveNano,
|
||||||
|
|
||||||
#[serde(rename = "custom")]
|
#[serde(rename = "custom")]
|
||||||
Custom {
|
Custom {
|
||||||
|
@ -105,6 +111,9 @@ impl Model {
|
||||||
"o3-mini" => Ok(Self::O3Mini),
|
"o3-mini" => Ok(Self::O3Mini),
|
||||||
"o3" => Ok(Self::O3),
|
"o3" => Ok(Self::O3),
|
||||||
"o4-mini" => Ok(Self::O4Mini),
|
"o4-mini" => Ok(Self::O4Mini),
|
||||||
|
"gpt-5" => Ok(Self::Five),
|
||||||
|
"gpt-5-mini" => Ok(Self::FiveMini),
|
||||||
|
"gpt-5-nano" => Ok(Self::FiveNano),
|
||||||
invalid_id => anyhow::bail!("invalid model id '{invalid_id}'"),
|
invalid_id => anyhow::bail!("invalid model id '{invalid_id}'"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,6 +132,9 @@ impl Model {
|
||||||
Self::O3Mini => "o3-mini",
|
Self::O3Mini => "o3-mini",
|
||||||
Self::O3 => "o3",
|
Self::O3 => "o3",
|
||||||
Self::O4Mini => "o4-mini",
|
Self::O4Mini => "o4-mini",
|
||||||
|
Self::Five => "gpt-5",
|
||||||
|
Self::FiveMini => "gpt-5-mini",
|
||||||
|
Self::FiveNano => "gpt-5-nano",
|
||||||
Self::Custom { name, .. } => name,
|
Self::Custom { name, .. } => name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,6 +153,9 @@ impl Model {
|
||||||
Self::O3Mini => "o3-mini",
|
Self::O3Mini => "o3-mini",
|
||||||
Self::O3 => "o3",
|
Self::O3 => "o3",
|
||||||
Self::O4Mini => "o4-mini",
|
Self::O4Mini => "o4-mini",
|
||||||
|
Self::Five => "gpt-5",
|
||||||
|
Self::FiveMini => "gpt-5-mini",
|
||||||
|
Self::FiveNano => "gpt-5-nano",
|
||||||
Self::Custom {
|
Self::Custom {
|
||||||
name, display_name, ..
|
name, display_name, ..
|
||||||
} => display_name.as_ref().unwrap_or(name),
|
} => display_name.as_ref().unwrap_or(name),
|
||||||
|
@ -161,6 +176,9 @@ impl Model {
|
||||||
Self::O3Mini => 200_000,
|
Self::O3Mini => 200_000,
|
||||||
Self::O3 => 200_000,
|
Self::O3 => 200_000,
|
||||||
Self::O4Mini => 200_000,
|
Self::O4Mini => 200_000,
|
||||||
|
Self::Five => 272_000,
|
||||||
|
Self::FiveMini => 272_000,
|
||||||
|
Self::FiveNano => 272_000,
|
||||||
Self::Custom { max_tokens, .. } => *max_tokens,
|
Self::Custom { max_tokens, .. } => *max_tokens,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,6 +200,9 @@ impl Model {
|
||||||
Self::O3Mini => Some(100_000),
|
Self::O3Mini => Some(100_000),
|
||||||
Self::O3 => Some(100_000),
|
Self::O3 => Some(100_000),
|
||||||
Self::O4Mini => Some(100_000),
|
Self::O4Mini => Some(100_000),
|
||||||
|
Self::Five => Some(128_000),
|
||||||
|
Self::FiveMini => Some(128_000),
|
||||||
|
Self::FiveNano => Some(128_000),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,7 +218,10 @@ impl Model {
|
||||||
| Self::FourOmniMini
|
| Self::FourOmniMini
|
||||||
| Self::FourPointOne
|
| Self::FourPointOne
|
||||||
| Self::FourPointOneMini
|
| Self::FourPointOneMini
|
||||||
| Self::FourPointOneNano => true,
|
| Self::FourPointOneNano
|
||||||
|
| Self::Five
|
||||||
|
| Self::FiveMini
|
||||||
|
| Self::FiveNano => true,
|
||||||
Self::O1 | Self::O3 | Self::O3Mini | Self::O4Mini | Model::Custom { .. } => false,
|
Self::O1 | Self::O3 | Self::O3Mini | Self::O4Mini | Model::Custom { .. } => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{path::Path, sync::Arc};
|
use std::{path::Path, sync::Arc};
|
||||||
|
|
||||||
use dap::client::DebugAdapterClient;
|
use dap::client::DebugAdapterClient;
|
||||||
use gpui::{App, AppContext, Subscription};
|
use gpui::{App, Subscription};
|
||||||
|
|
||||||
use super::session::{Session, SessionStateEvent};
|
use super::session::{Session, SessionStateEvent};
|
||||||
|
|
||||||
|
@ -19,14 +19,6 @@ pub fn intercept_debug_sessions<T: Fn(&Arc<DebugAdapterClient>) + 'static>(
|
||||||
let client = session.adapter_client().unwrap();
|
let client = session.adapter_client().unwrap();
|
||||||
register_default_handlers(session, &client, cx);
|
register_default_handlers(session, &client, cx);
|
||||||
configure(&client);
|
configure(&client);
|
||||||
cx.background_spawn(async move {
|
|
||||||
client
|
|
||||||
.fake_event(dap::messages::Events::Initialized(
|
|
||||||
Some(Default::default()),
|
|
||||||
))
|
|
||||||
.await
|
|
||||||
})
|
|
||||||
.detach();
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
|
|
|
@ -2269,7 +2269,7 @@ impl LspCommand for GetCompletions {
|
||||||
// the range based on the syntax tree.
|
// the range based on the syntax tree.
|
||||||
None => {
|
None => {
|
||||||
if self.position != clipped_position {
|
if self.position != clipped_position {
|
||||||
log::info!("completion out of expected range");
|
log::info!("completion out of expected range ");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2483,7 +2483,9 @@ pub(crate) fn parse_completion_text_edit(
|
||||||
let start = snapshot.clip_point_utf16(range.start, Bias::Left);
|
let start = snapshot.clip_point_utf16(range.start, Bias::Left);
|
||||||
let end = snapshot.clip_point_utf16(range.end, Bias::Left);
|
let end = snapshot.clip_point_utf16(range.end, Bias::Left);
|
||||||
if start != range.start.0 || end != range.end.0 {
|
if start != range.start.0 || end != range.end.0 {
|
||||||
log::info!("completion out of expected range");
|
log::info!(
|
||||||
|
"completion out of expected range, start: {start:?}, end: {end:?}, range: {range:?}"
|
||||||
|
);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
snapshot.anchor_before(start)..snapshot.anchor_after(end)
|
snapshot.anchor_before(start)..snapshot.anchor_after(end)
|
||||||
|
|
|
@ -97,7 +97,7 @@ use rpc::{
|
||||||
};
|
};
|
||||||
use search::{SearchInputKind, SearchQuery, SearchResult};
|
use search::{SearchInputKind, SearchQuery, SearchResult};
|
||||||
use search_history::SearchHistory;
|
use search_history::SearchHistory;
|
||||||
use settings::{InvalidSettingsError, Settings, SettingsLocation, SettingsStore};
|
use settings::{InvalidSettingsError, Settings, SettingsLocation, SettingsSources, SettingsStore};
|
||||||
use smol::channel::Receiver;
|
use smol::channel::Receiver;
|
||||||
use snippet::Snippet;
|
use snippet::Snippet;
|
||||||
use snippet_provider::SnippetProvider;
|
use snippet_provider::SnippetProvider;
|
||||||
|
@ -942,10 +942,38 @@ pub enum PulledDiagnostics {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether to disable all AI features in Zed.
|
||||||
|
///
|
||||||
|
/// Default: false
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct DisableAiSettings {
|
||||||
|
pub disable_ai: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl settings::Settings for DisableAiSettings {
|
||||||
|
const KEY: Option<&'static str> = Some("disable_ai");
|
||||||
|
|
||||||
|
type FileContent = Option<bool>;
|
||||||
|
|
||||||
|
fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
|
||||||
|
Ok(Self {
|
||||||
|
disable_ai: sources
|
||||||
|
.user
|
||||||
|
.or(sources.server)
|
||||||
|
.copied()
|
||||||
|
.flatten()
|
||||||
|
.unwrap_or(sources.default.ok_or_else(Self::missing_default)?),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut Self::FileContent) {}
|
||||||
|
}
|
||||||
|
|
||||||
impl Project {
|
impl Project {
|
||||||
pub fn init_settings(cx: &mut App) {
|
pub fn init_settings(cx: &mut App) {
|
||||||
WorktreeSettings::register(cx);
|
WorktreeSettings::register(cx);
|
||||||
ProjectSettings::register(cx);
|
ProjectSettings::register(cx);
|
||||||
|
DisableAiSettings::register(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(client: &Arc<Client>, cx: &mut App) {
|
pub fn init(client: &Arc<Client>, cx: &mut App) {
|
||||||
|
|
|
@ -99,7 +99,9 @@ impl Anchor {
|
||||||
} else if self.buffer_id != Some(buffer.remote_id) {
|
} else if self.buffer_id != Some(buffer.remote_id) {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
let fragment_id = buffer.fragment_id_for_anchor(self);
|
let Some(fragment_id) = buffer.try_fragment_id_for_anchor(self) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
let mut fragment_cursor = buffer.fragments.cursor::<(Option<&Locator>, usize)>(&None);
|
let mut fragment_cursor = buffer.fragments.cursor::<(Option<&Locator>, usize)>(&None);
|
||||||
fragment_cursor.seek(&Some(fragment_id), Bias::Left);
|
fragment_cursor.seek(&Some(fragment_id), Bias::Left);
|
||||||
fragment_cursor
|
fragment_cursor
|
||||||
|
|
|
@ -2330,10 +2330,19 @@ impl BufferSnapshot {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fragment_id_for_anchor(&self, anchor: &Anchor) -> &Locator {
|
fn fragment_id_for_anchor(&self, anchor: &Anchor) -> &Locator {
|
||||||
|
self.try_fragment_id_for_anchor(anchor).unwrap_or_else(|| {
|
||||||
|
panic!(
|
||||||
|
"invalid anchor {:?}. buffer id: {}, version: {:?}",
|
||||||
|
anchor, self.remote_id, self.version,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_fragment_id_for_anchor(&self, anchor: &Anchor) -> Option<&Locator> {
|
||||||
if *anchor == Anchor::MIN {
|
if *anchor == Anchor::MIN {
|
||||||
Locator::min_ref()
|
Some(Locator::min_ref())
|
||||||
} else if *anchor == Anchor::MAX {
|
} else if *anchor == Anchor::MAX {
|
||||||
Locator::max_ref()
|
Some(Locator::max_ref())
|
||||||
} else {
|
} else {
|
||||||
let anchor_key = InsertionFragmentKey {
|
let anchor_key = InsertionFragmentKey {
|
||||||
timestamp: anchor.timestamp,
|
timestamp: anchor.timestamp,
|
||||||
|
@ -2354,20 +2363,12 @@ impl BufferSnapshot {
|
||||||
insertion_cursor.prev();
|
insertion_cursor.prev();
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(insertion) = insertion_cursor.item().filter(|insertion| {
|
insertion_cursor
|
||||||
if cfg!(debug_assertions) {
|
.item()
|
||||||
insertion.timestamp == anchor.timestamp
|
.filter(|insertion| {
|
||||||
} else {
|
!cfg!(debug_assertions) || insertion.timestamp == anchor.timestamp
|
||||||
true
|
})
|
||||||
}
|
.map(|insertion| &insertion.fragment_id)
|
||||||
}) else {
|
|
||||||
panic!(
|
|
||||||
"invalid anchor {:?}. buffer id: {}, version: {:?}",
|
|
||||||
anchor, self.remote_id, self.version
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
&insertion.fragment_id
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
use client::{DisableAiSettings, TelemetrySettings, telemetry::Telemetry};
|
use client::{TelemetrySettings, telemetry::Telemetry};
|
||||||
use db::kvp::KEY_VALUE_STORE;
|
use db::kvp::KEY_VALUE_STORE;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
Action, App, Context, Entity, EventEmitter, FocusHandle, Focusable, InteractiveElement,
|
Action, App, Context, Entity, EventEmitter, FocusHandle, Focusable, InteractiveElement,
|
||||||
ParentElement, Render, Styled, Subscription, Task, WeakEntity, Window, actions, svg,
|
ParentElement, Render, Styled, Subscription, Task, WeakEntity, Window, actions, svg,
|
||||||
};
|
};
|
||||||
use language::language_settings::{EditPredictionProvider, all_language_settings};
|
use language::language_settings::{EditPredictionProvider, all_language_settings};
|
||||||
|
use project::DisableAiSettings;
|
||||||
use settings::{Settings, SettingsStore};
|
use settings::{Settings, SettingsStore};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use ui::{CheckboxWithLabel, ElevationIndex, Tooltip, prelude::*};
|
use ui::{CheckboxWithLabel, ElevationIndex, Tooltip, prelude::*};
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
description = "The fast, collaborative code editor."
|
description = "The fast, collaborative code editor."
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
name = "zed"
|
name = "zed"
|
||||||
version = "0.198.0"
|
version = "0.198.3"
|
||||||
publish.workspace = true
|
publish.workspace = true
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
authors = ["Zed Team <hi@zed.dev>"]
|
authors = ["Zed Team <hi@zed.dev>"]
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
dev
|
stable
|
|
@ -1,9 +1,10 @@
|
||||||
use client::{Client, DisableAiSettings, UserStore};
|
use client::{Client, UserStore};
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use copilot::{Copilot, CopilotCompletionProvider};
|
use copilot::{Copilot, CopilotCompletionProvider};
|
||||||
use editor::Editor;
|
use editor::Editor;
|
||||||
use gpui::{AnyWindowHandle, App, AppContext as _, Context, Entity, WeakEntity};
|
use gpui::{AnyWindowHandle, App, AppContext as _, Context, Entity, WeakEntity};
|
||||||
use language::language_settings::{EditPredictionProvider, all_language_settings};
|
use language::language_settings::{EditPredictionProvider, all_language_settings};
|
||||||
|
use project::DisableAiSettings;
|
||||||
use settings::{Settings as _, SettingsStore};
|
use settings::{Settings as _, SettingsStore};
|
||||||
use smol::stream::StreamExt;
|
use smol::stream::StreamExt;
|
||||||
use std::{cell::RefCell, rc::Rc, sync::Arc};
|
use std::{cell::RefCell, rc::Rc, sync::Arc};
|
||||||
|
|
|
@ -2,7 +2,6 @@ mod preview;
|
||||||
mod repl_menu;
|
mod repl_menu;
|
||||||
|
|
||||||
use agent_settings::AgentSettings;
|
use agent_settings::AgentSettings;
|
||||||
use client::DisableAiSettings;
|
|
||||||
use editor::actions::{
|
use editor::actions::{
|
||||||
AddSelectionAbove, AddSelectionBelow, CodeActionSource, DuplicateLineDown, GoToDiagnostic,
|
AddSelectionAbove, AddSelectionBelow, CodeActionSource, DuplicateLineDown, GoToDiagnostic,
|
||||||
GoToHunk, GoToPreviousDiagnostic, GoToPreviousHunk, MoveLineDown, MoveLineUp, SelectAll,
|
GoToHunk, GoToPreviousDiagnostic, GoToPreviousHunk, MoveLineDown, MoveLineUp, SelectAll,
|
||||||
|
@ -16,6 +15,7 @@ use gpui::{
|
||||||
FocusHandle, Focusable, InteractiveElement, ParentElement, Render, Styled, Subscription,
|
FocusHandle, Focusable, InteractiveElement, ParentElement, Render, Styled, Subscription,
|
||||||
WeakEntity, Window, anchored, deferred, point,
|
WeakEntity, Window, anchored, deferred, point,
|
||||||
};
|
};
|
||||||
|
use project::DisableAiSettings;
|
||||||
use project::project_settings::DiagnosticSeverity;
|
use project::project_settings::DiagnosticSeverity;
|
||||||
use search::{BufferSearchBar, buffer_search};
|
use search::{BufferSearchBar, buffer_search};
|
||||||
use settings::{Settings, SettingsStore};
|
use settings::{Settings, SettingsStore};
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use std::any::{Any, TypeId};
|
use std::any::{Any, TypeId};
|
||||||
|
|
||||||
use client::DisableAiSettings;
|
|
||||||
use command_palette_hooks::CommandPaletteFilter;
|
use command_palette_hooks::CommandPaletteFilter;
|
||||||
use feature_flags::{FeatureFlagAppExt as _, PredictEditsRateCompletionsFeatureFlag};
|
use feature_flags::{FeatureFlagAppExt as _, PredictEditsRateCompletionsFeatureFlag};
|
||||||
use gpui::actions;
|
use gpui::actions;
|
||||||
use language::language_settings::{AllLanguageSettings, EditPredictionProvider};
|
use language::language_settings::{AllLanguageSettings, EditPredictionProvider};
|
||||||
|
use project::DisableAiSettings;
|
||||||
use settings::{Settings, SettingsStore, update_settings_file};
|
use settings::{Settings, SettingsStore, update_settings_file};
|
||||||
use ui::App;
|
use ui::App;
|
||||||
use workspace::Workspace;
|
use workspace::Workspace;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue