Compare commits

..

2 Commits

Author SHA1 Message Date
Peter Tripp
044594da78 Merge branch 'main' into faster_arm_linux 2025-08-20 15:25:38 -04:00
Peter Tripp
1b8ca17dad ci: Larger Linux ARM runners 2025-08-20 12:15:48 -04:00
1477 changed files with 90151 additions and 242641 deletions

View File

@@ -10,15 +10,3 @@
# Here, we opted to use `[target.'cfg(all())']` instead of `[build]` because `[target.'**']` is guaranteed to be cumulative.
[target.'cfg(all())']
rustflags = ["-D", "warnings"]
# Use Mold on Linux, because it's faster than GNU ld and LLD.
#
# We no longer set this in the default `config.toml` so that developers can opt in to Wild, which
# is faster than Mold, in their own ~/.cargo/config.toml.
[target.x86_64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=mold"]
[target.aarch64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=mold"]

View File

@@ -4,9 +4,14 @@ rustflags = ["-C", "symbol-mangling-version=v0", "--cfg", "tokio_unstable"]
[alias]
xtask = "run --package xtask --"
perf-test = ["test", "--profile", "release-fast", "--lib", "--bins", "--tests", "--all-features", "--config", "target.'cfg(true)'.runner='cargo run -p perf --release'", "--config", "target.'cfg(true)'.rustflags=[\"--cfg\", \"perf_enabled\"]"]
# Keep similar flags here to share some ccache
perf-compare = ["run", "--profile", "release-fast", "-p", "perf", "--config", "target.'cfg(true)'.rustflags=[\"--cfg\", \"perf_enabled\"]", "--", "compare"]
[target.x86_64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=mold"]
[target.aarch64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=mold"]
[target.'cfg(target_os = "windows")']
rustflags = [
@@ -14,6 +19,8 @@ rustflags = [
"windows_slim_errors", # This cfg will reduce the size of `windows::core::Error` from 16 bytes to 4 bytes
"-C",
"target-feature=+crt-static", # This fixes the linking issue when compiling livekit on Windows
"-C",
"link-arg=-fuse-ld=lld",
]
[env]

View File

@@ -24,9 +24,9 @@ workspace-members = [
third-party = [
{ name = "reqwest", version = "0.11.27" },
# build of remote_server should not include scap / its x11 dependency
{ name = "zed-scap", git = "https://github.com/zed-industries/scap", rev = "4afea48c3b002197176fb19cd0f9b180dd36eaac", version = "0.0.8-zed" },
{ name = "scap", git = "https://github.com/zed-industries/scap", rev = "808aa5c45b41e8f44729d02e38fd00a2fe2722e7" },
# build of remote_server should not need to include on libalsa through rodio
{ name = "rodio", git = "https://github.com/RustAudio/rodio" },
{ name = "rodio" },
]
[final-excludes]
@@ -37,6 +37,9 @@ workspace-members = [
"zed_glsl",
"zed_html",
"zed_proto",
"zed_ruff",
"slash_commands_example",
"zed_snippets",
"zed_test_extension",
"zed_toml",
]

3
.gitattributes vendored
View File

@@ -1,5 +1,2 @@
# Prevent GitHub from displaying comments within JSON files as errors.
*.json linguist-language=JSON-with-Comments
# Ensure the WSL script always has LF line endings, even on Windows
crates/zed/resources/windows/zed.sh text eol=lf

View File

@@ -1,35 +0,0 @@
name: Bug Report (Windows)
description: Zed Windows Related Bugs
type: "Bug"
labels: ["windows"]
title: "Windows: <a short description of the Windows bug>"
body:
- type: textarea
attributes:
label: Summary
description: Describe the bug with a one-line summary, and provide detailed reproduction steps
value: |
<!-- Please insert a one-line summary of the issue below -->
SUMMARY_SENTENCE_HERE
### Description
<!-- Describe with sufficient detail to reproduce from a clean Zed install. -->
Steps to trigger the problem:
1.
2.
3.
**Expected Behavior**:
**Actual Behavior**:
validations:
required: true
- type: textarea
id: environment
attributes:
label: Zed Version and System Specs
description: 'Open Zed, and in the command palette select "zed: copy system specs into clipboard"'
placeholder: |
Output of "zed: copy system specs into clipboard"
validations:
required: true

View File

@@ -1,8 +1,8 @@
name: Bug Report (Windows Beta)
description: Zed Windows Beta Related Bugs
name: Bug Report (Windows Alpha)
description: Zed Windows Alpha Related Bugs
type: "Bug"
labels: ["windows"]
title: "Windows Beta: <a short description of the Windows bug>"
title: "Windows Alpha: <a short description of the Windows bug>"
body:
- type: textarea
attributes:

View File

@@ -14,7 +14,7 @@ body:
### Description
<!-- Describe with sufficient detail to reproduce from a clean Zed install.
- Any code must be sufficient to reproduce (include context!)
- Include code as text, not just as a screenshot.
- Code must as text, not just as a screenshot.
- Issues with insufficient detail may be summarily closed.
-->

View File

@@ -19,27 +19,15 @@ self-hosted-runner:
- namespace-profile-16x32-ubuntu-2004-arm
- namespace-profile-32x64-ubuntu-2004-arm
# Namespace Ubuntu 22.04 (Everything else)
- namespace-profile-2x4-ubuntu-2204
- namespace-profile-4x8-ubuntu-2204
- namespace-profile-8x16-ubuntu-2204
- namespace-profile-16x32-ubuntu-2204
- namespace-profile-32x64-ubuntu-2204
# Namespace Ubuntu 24.04 (like ubuntu-latest)
- namespace-profile-2x4-ubuntu-2404
# Namespace Limited Preview
- namespace-profile-8x16-ubuntu-2004-arm-m4
- namespace-profile-8x32-ubuntu-2004-arm-m4
- namespace-profile-12x32-ubuntu-2004-arm-m4
# Self Hosted Runners
- self-mini-macos
- self-32vcpu-windows-2022
# Disable shellcheck because it doesn't like powershell
# This should have been triggered with initial rollout of actionlint
# but https://github.com/zed-industries/zed/pull/36693
# somehow caused actionlint to actually check those windows jobs
# where previously they were being skipped. Likely caused by an
# unknown bug in actionlint where parsing of `runs-on: [ ]`
# breaks something else. (yuck)
paths:
.github/workflows/{ci,release_nightly}.yml:
ignore:
- "shellcheck"

View File

@@ -20,4 +20,4 @@ runs:
- name: Run tests
shell: bash -euxo pipefail {0}
run: cargo nextest run --workspace --no-fail-fast --failure-output immediate-final
run: cargo nextest run --workspace --no-fail-fast

View File

@@ -20,8 +20,167 @@ runs:
with:
node-version: "18"
- name: Configure crash dumps
shell: powershell
run: |
# Record the start time for this CI run
$runStartTime = Get-Date
$runStartTimeStr = $runStartTime.ToString("yyyy-MM-dd HH:mm:ss")
Write-Host "CI run started at: $runStartTimeStr"
# Save the timestamp for later use
echo "CI_RUN_START_TIME=$($runStartTime.Ticks)" >> $env:GITHUB_ENV
# Create crash dump directory in workspace (non-persistent)
$dumpPath = "$env:GITHUB_WORKSPACE\crash_dumps"
New-Item -ItemType Directory -Force -Path $dumpPath | Out-Null
Write-Host "Setting up crash dump detection..."
Write-Host "Workspace dump path: $dumpPath"
# Note: We're NOT modifying registry on stateful runners
# Instead, we'll check default Windows crash locations after tests
- name: Run tests
shell: powershell
working-directory: ${{ inputs.working-directory }}
run: |
cargo nextest run --workspace --no-fail-fast --failure-output immediate-final
$env:RUST_BACKTRACE = "full"
# Enable Windows debugging features
$env:_NT_SYMBOL_PATH = "srv*https://msdl.microsoft.com/download/symbols"
# .NET crash dump environment variables (ephemeral)
$env:COMPlus_DbgEnableMiniDump = "1"
$env:COMPlus_DbgMiniDumpType = "4"
$env:COMPlus_CreateDumpDiagnostics = "1"
cargo nextest run --workspace --no-fail-fast
- name: Analyze crash dumps
if: always()
shell: powershell
run: |
Write-Host "Checking for crash dumps..."
# Get the CI run start time from the environment
$runStartTime = [DateTime]::new([long]$env:CI_RUN_START_TIME)
Write-Host "Only analyzing dumps created after: $($runStartTime.ToString('yyyy-MM-dd HH:mm:ss'))"
# Check all possible crash dump locations
$searchPaths = @(
"$env:GITHUB_WORKSPACE\crash_dumps",
"$env:LOCALAPPDATA\CrashDumps",
"$env:TEMP",
"$env:GITHUB_WORKSPACE",
"$env:USERPROFILE\AppData\Local\CrashDumps",
"C:\Windows\System32\config\systemprofile\AppData\Local\CrashDumps"
)
$dumps = @()
foreach ($path in $searchPaths) {
if (Test-Path $path) {
Write-Host "Searching in: $path"
$found = Get-ChildItem "$path\*.dmp" -ErrorAction SilentlyContinue | Where-Object {
$_.CreationTime -gt $runStartTime
}
if ($found) {
$dumps += $found
Write-Host " Found $($found.Count) dump(s) from this CI run"
}
}
}
if ($dumps) {
Write-Host "Found $($dumps.Count) crash dump(s)"
# Install debugging tools if not present
$cdbPath = "C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\cdb.exe"
if (-not (Test-Path $cdbPath)) {
Write-Host "Installing Windows Debugging Tools..."
$url = "https://go.microsoft.com/fwlink/?linkid=2237387"
Invoke-WebRequest -Uri $url -OutFile winsdksetup.exe
Start-Process -Wait winsdksetup.exe -ArgumentList "/features OptionId.WindowsDesktopDebuggers /quiet"
}
foreach ($dump in $dumps) {
Write-Host "`n=================================="
Write-Host "Analyzing crash dump: $($dump.Name)"
Write-Host "Size: $([math]::Round($dump.Length / 1MB, 2)) MB"
Write-Host "Time: $($dump.CreationTime)"
Write-Host "=================================="
# Set symbol path
$env:_NT_SYMBOL_PATH = "srv*C:\symbols*https://msdl.microsoft.com/download/symbols"
# Run analysis
$analysisOutput = & $cdbPath -z $dump.FullName -c "!analyze -v; ~*k; lm; q" 2>&1 | Out-String
# Extract key information
if ($analysisOutput -match "ExceptionCode:\s*([\w]+)") {
Write-Host "Exception Code: $($Matches[1])"
if ($Matches[1] -eq "c0000005") {
Write-Host "Exception Type: ACCESS VIOLATION"
}
}
if ($analysisOutput -match "EXCEPTION_RECORD:\s*(.+)") {
Write-Host "Exception Record: $($Matches[1])"
}
if ($analysisOutput -match "FAULTING_IP:\s*\n(.+)") {
Write-Host "Faulting Instruction: $($Matches[1])"
}
# Save full analysis
$analysisFile = "$($dump.FullName).analysis.txt"
$analysisOutput | Out-File -FilePath $analysisFile
Write-Host "`nFull analysis saved to: $analysisFile"
# Print stack trace section
Write-Host "`n--- Stack Trace Preview ---"
$stackSection = $analysisOutput -split "STACK_TEXT:" | Select-Object -Last 1
$stackLines = $stackSection -split "`n" | Select-Object -First 20
$stackLines | ForEach-Object { Write-Host $_ }
Write-Host "--- End Stack Trace Preview ---"
}
Write-Host "`n⚠ Crash dumps detected! Download the 'crash-dumps' artifact for detailed analysis."
# Copy dumps to workspace for artifact upload
$artifactPath = "$env:GITHUB_WORKSPACE\crash_dumps_collected"
New-Item -ItemType Directory -Force -Path $artifactPath | Out-Null
foreach ($dump in $dumps) {
$destName = "$($dump.Directory.Name)_$($dump.Name)"
Copy-Item $dump.FullName -Destination "$artifactPath\$destName"
if (Test-Path "$($dump.FullName).analysis.txt") {
Copy-Item "$($dump.FullName).analysis.txt" -Destination "$artifactPath\$destName.analysis.txt"
}
}
Write-Host "Copied $($dumps.Count) dump(s) to artifact directory"
} else {
Write-Host "No crash dumps from this CI run found"
}
- name: Upload crash dumps
if: always()
uses: actions/upload-artifact@v4
with:
name: crash-dumps-${{ github.run_id }}-${{ github.run_attempt }}
path: |
crash_dumps_collected/*.dmp
crash_dumps_collected/*.txt
if-no-files-found: ignore
retention-days: 7
- name: Check test results
shell: powershell
working-directory: ${{ inputs.working-directory }}
run: |
# Re-check test results to fail the job if tests failed
if ($LASTEXITCODE -ne 0) {
Write-Host "Tests failed with exit code: $LASTEXITCODE"
exit $LASTEXITCODE
}

View File

@@ -8,7 +8,7 @@ on:
jobs:
update-collab-staging-tag:
if: github.repository_owner == 'zed-industries'
runs-on: namespace-profile-2x4-ubuntu-2404
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4

View File

@@ -37,7 +37,7 @@ jobs:
run_nix: ${{ steps.filter.outputs.run_nix }}
run_actionlint: ${{ steps.filter.outputs.run_actionlint }}
runs-on:
- namespace-profile-2x4-ubuntu-2404
- ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
@@ -81,7 +81,6 @@ jobs:
echo "run_license=false" >> "$GITHUB_OUTPUT"
echo "$CHANGED_FILES" | grep -qP '^(nix/|flake\.|Cargo\.|rust-toolchain.toml|\.cargo/config.toml)' && \
echo "$GITHUB_REF_NAME" | grep -qvP '^v[0-9]+\.[0-9]+\.[0-9x](-pre)?$' && \
echo "run_nix=true" >> "$GITHUB_OUTPUT" || \
echo "run_nix=false" >> "$GITHUB_OUTPUT"
@@ -238,7 +237,7 @@ jobs:
uses: ./.github/actions/build_docs
actionlint:
runs-on: namespace-profile-2x4-ubuntu-2404
runs-on: ubuntu-latest
if: github.repository_owner == 'zed-industries' && needs.job_spec.outputs.run_actionlint == 'true'
needs: [job_spec]
steps:
@@ -373,46 +372,6 @@ jobs:
if: always()
run: rm -rf ./../.cargo
doctests:
# Nextest currently doesn't support doctests, so run them separately and in parallel.
timeout-minutes: 60
name: (Linux) Run doctests
needs: [job_spec]
if: |
github.repository_owner == 'zed-industries' &&
needs.job_spec.outputs.run_tests == 'true'
runs-on:
- namespace-profile-16x32-ubuntu-2204
steps:
- name: Add Rust to the PATH
run: echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
- name: Checkout repo
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
clean: false
- name: Cache dependencies
uses: swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2
with:
save-if: ${{ github.ref == 'refs/heads/main' }}
# cache-provider: "buildjet"
- name: Install Linux dependencies
run: ./script/linux
- name: Configure CI
run: |
mkdir -p ./../.cargo
cp ./.cargo/ci-config.toml ./../.cargo/config.toml
- name: Run doctests
run: cargo test --workspace --doc --no-fail-fast
- name: Clean CI config file
if: always()
run: rm -rf ./../.cargo
build_remote_server:
timeout-minutes: 60
name: (Linux) Build Remote Server
@@ -459,7 +418,7 @@ jobs:
if: |
github.repository_owner == 'zed-industries' &&
needs.job_spec.outputs.run_tests == 'true'
runs-on: [self-32vcpu-windows-2022]
runs-on: [self-hosted, Windows, X64]
steps:
- name: Environment Setup
run: |
@@ -499,7 +458,7 @@ jobs:
tests_pass:
name: Tests Pass
runs-on: namespace-profile-2x4-ubuntu-2404
runs-on: ubuntu-latest
needs:
- job_spec
- style
@@ -701,7 +660,7 @@ jobs:
timeout-minutes: 60
name: Linux arm64 release bundle
runs-on:
- namespace-profile-8x32-ubuntu-2004-arm-m4 # ubuntu 20.04 for minimal glibc
- namespace-profile-12x32-ubuntu-2004-arm-m4 # ubuntu 20.04 for minimal glibc
if: |
startsWith(github.ref, 'refs/tags/v')
|| contains(github.event.pull_request.labels.*.name, 'run-bundling')
@@ -825,10 +784,9 @@ jobs:
bundle-windows-x64:
timeout-minutes: 120
name: Create a Windows installer
runs-on: [self-32vcpu-windows-2022]
if: |
( startsWith(github.ref, 'refs/tags/v')
|| contains(github.event.pull_request.labels.*.name, 'run-bundling') )
runs-on: [self-hosted, Windows, X64]
if: contains(github.event.pull_request.labels.*.name, 'run-bundling')
# if: (startsWith(github.ref, 'refs/tags/v') || contains(github.event.pull_request.labels.*.name, 'run-bundling'))
needs: [windows_tests]
env:
AZURE_TENANT_ID: ${{ secrets.AZURE_SIGNING_TENANT_ID }}
@@ -866,12 +824,13 @@ jobs:
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
if: contains(github.event.pull_request.labels.*.name, 'run-bundling')
with:
name: Zed_${{ github.event.pull_request.head.sha || github.sha }}-x86_64.exe
name: ZedEditorUserSetup-x64-${{ github.event.pull_request.head.sha || github.sha }}.exe
path: ${{ env.SETUP_PATH }}
- name: Upload Artifacts to release
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
if: ${{ !(contains(github.event.pull_request.labels.*.name, 'run-bundling')) }}
# Re-enable when we are ready to publish windows preview releases
if: ${{ !(contains(github.event.pull_request.labels.*.name, 'run-bundling')) && env.RELEASE_CHANNEL == 'preview' }} # upload only preview
with:
draft: true
prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}

View File

@@ -1,48 +0,0 @@
name: Community Champion Auto Labeler
on:
issues:
types: [opened]
pull_request_target:
types: [opened]
jobs:
label_community_champion:
if: github.repository_owner == 'zed-industries'
runs-on: ubuntu-latest
steps:
- name: Check if author is a community champion and apply label
uses: actions/github-script@v7
with:
script: |
const communityChampionBody = `${{ secrets.COMMUNITY_CHAMPIONS }}`;
const communityChampions = communityChampionBody
.split('\n')
.map(handle => handle.trim().toLowerCase());
let author;
if (context.eventName === 'issues') {
author = context.payload.issue.user.login;
} else if (context.eventName === 'pull_request_target') {
author = context.payload.pull_request.user.login;
}
if (!author || !communityChampions.includes(author.toLowerCase())) {
return;
}
const issueNumber = context.payload.issue?.number || context.payload.pull_request?.number;
try {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
labels: ['community champion']
});
console.log(`Applied 'community champion' label to #${issueNumber} by ${author}`);
} catch (error) {
console.error(`Failed to apply label: ${error.message}`);
}

View File

@@ -1,6 +1,3 @@
# IF YOU UPDATE THE NAME OF ANY GITHUB SECRET, YOU MUST CHERRY PICK THE COMMIT
# TO BOTH STABLE AND PREVIEW CHANNELS
name: Release Actions
on:
@@ -16,9 +13,9 @@ jobs:
id: get-release-url
run: |
if [ "${{ github.event.release.prerelease }}" == "true" ]; then
URL="https://zed.dev/releases/preview"
URL="https://zed.dev/releases/preview/latest"
else
URL="https://zed.dev/releases/stable"
URL="https://zed.dev/releases/stable/latest"
fi
echo "URL=$URL" >> "$GITHUB_OUTPUT"
@@ -35,11 +32,11 @@ jobs:
- name: Discord Webhook Action
uses: tsickert/discord-webhook@c840d45a03a323fbc3f7507ac7769dbd91bfb164 # v5.3.0
with:
webhook-url: ${{ secrets.DISCORD_WEBHOOK_RELEASE_NOTES }}
webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
content: ${{ steps.get-content.outputs.string }}
send_release_notes_email:
if: false && github.repository_owner == 'zed-industries' && !github.event.release.prerelease
if: github.repository_owner == 'zed-industries' && !github.event.release.prerelease
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4

View File

@@ -1,57 +0,0 @@
name: Congratsbot
on:
push:
branches: [main]
jobs:
check-author:
if: ${{ github.repository_owner == 'zed-industries' }}
runs-on: ubuntu-latest
outputs:
should_congratulate: ${{ steps.check.outputs.should_congratulate }}
steps:
- name: Get PR info and check if author is external
id: check
uses: actions/github-script@v7
with:
github-token: ${{ secrets.CONGRATSBOT_GITHUB_TOKEN }}
script: |
const { data: prs } = await github.rest.repos.listPullRequestsAssociatedWithCommit({
owner: context.repo.owner,
repo: context.repo.repo,
commit_sha: context.sha
});
if (prs.length === 0) {
core.setOutput('should_congratulate', 'false');
return;
}
const mergedPR = prs.find(pr => pr.merged_at !== null) || prs[0];
const prAuthor = mergedPR.user.login;
try {
await github.rest.teams.getMembershipForUserInOrg({
org: 'zed-industries',
team_slug: 'staff',
username: prAuthor
});
core.setOutput('should_congratulate', 'false');
} catch (error) {
if (error.status === 404) {
core.setOutput('should_congratulate', 'true');
} else {
console.error(`Error checking team membership: ${error.message}`);
core.setOutput('should_congratulate', 'false');
}
}
congrats:
needs: check-author
if: needs.check-author.outputs.should_congratulate == 'true'
uses: withastro/automation/.github/workflows/congratsbot.yml@main
with:
EMOJIS: 🎉,🎊,🧑‍🚀,🥳,🙌,🚀,🦀,🔥,🚢
secrets:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK_CONGRATS }}

View File

@@ -12,7 +12,7 @@ on:
jobs:
danger:
if: github.repository_owner == 'zed-industries'
runs-on: namespace-profile-2x4-ubuntu-2404
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4

View File

@@ -1,36 +0,0 @@
name: Good First Issue Notifier
on:
issues:
types: [labeled]
jobs:
handle-good-first-issue:
if: github.event.label.name == 'good first issue' && github.repository_owner == 'zed-industries'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Prepare Discord message
id: prepare-message
env:
ISSUE_TITLE: ${{ github.event.issue.title }}
ISSUE_NUMBER: ${{ github.event.issue.number }}
ISSUE_URL: ${{ github.event.issue.html_url }}
ISSUE_AUTHOR: ${{ github.event.issue.user.login }}
run: |
MESSAGE="[${ISSUE_TITLE} (#${ISSUE_NUMBER})](<${ISSUE_URL}>)"
{
echo "message<<EOF"
echo "$MESSAGE"
echo "EOF"
} >> "$GITHUB_OUTPUT"
- name: Discord Webhook Action
uses: tsickert/discord-webhook@c840d45a03a323fbc3f7507ac7769dbd91bfb164 # v5.3.0
with:
webhook-url: ${{ secrets.DISCORD_WEBHOOK_GOOD_FIRST_ISSUE }}
content: ${{ steps.prepare-message.outputs.message }}

33
.github/workflows/issue_response.yml vendored Normal file
View File

@@ -0,0 +1,33 @@
name: Issue Response
on:
schedule:
- cron: "0 12 * * 2"
workflow_dispatch:
jobs:
issue-response:
if: github.repository_owner == 'zed-industries'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
with:
version: 9
- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: "20"
cache: "pnpm"
cache-dependency-path: "script/issue_response/pnpm-lock.yaml"
- run: pnpm install --dir script/issue_response
- name: Run Issue Response
run: pnpm run --dir script/issue_response start
env:
ISSUE_RESPONSE_GITHUB_TOKEN: ${{ secrets.ISSUE_RESPONSE_GITHUB_TOKEN }}
SLACK_ISSUE_RESPONSE_WEBHOOK_URL: ${{ secrets.SLACK_ISSUE_RESPONSE_WEBHOOK_URL }}

View File

@@ -59,7 +59,7 @@ jobs:
timeout-minutes: 60
name: Run tests on Windows
if: github.repository_owner == 'zed-industries'
runs-on: [self-32vcpu-windows-2022]
runs-on: [self-hosted, Windows, X64]
steps:
- name: Checkout repo
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
@@ -168,7 +168,7 @@ jobs:
name: Create a Linux *.tar.gz bundle for ARM
if: github.repository_owner == 'zed-industries'
runs-on:
- namespace-profile-8x32-ubuntu-2004-arm-m4 # ubuntu 20.04 for minimal glibc
- namespace-profile-12x32-ubuntu-2004-arm-m4 # ubuntu 20.04 for minimal glibc
needs: tests
steps:
- name: Checkout repo
@@ -206,6 +206,9 @@ jobs:
runs-on: github-8vcpu-ubuntu-2404
needs: tests
name: Build Zed on FreeBSD
# env:
# MYTOKEN : ${{ secrets.MYTOKEN }}
# MYTOKEN2: "value2"
steps:
- uses: actions/checkout@v4
- name: Build FreeBSD remote-server
@@ -240,6 +243,7 @@ jobs:
bundle-nix:
name: Build and cache Nix package
if: false
needs: tests
secrets: inherit
uses: ./.github/workflows/nix.yml
@@ -248,7 +252,7 @@ jobs:
timeout-minutes: 60
name: Create a Windows installer
if: github.repository_owner == 'zed-industries'
runs-on: [self-32vcpu-windows-2022]
runs-on: [self-hosted, Windows, X64]
needs: windows-tests
env:
AZURE_TENANT_ID: ${{ secrets.AZURE_SIGNING_TENANT_ID }}
@@ -290,7 +294,7 @@ jobs:
update-nightly-tag:
name: Update nightly tag
if: github.repository_owner == 'zed-industries'
runs-on: namespace-profile-2x4-ubuntu-2404
runs-on: ubuntu-latest
needs:
- bundle-mac
- bundle-linux-x86

View File

@@ -12,7 +12,7 @@ jobs:
shellcheck:
name: "ShellCheck Scripts"
if: github.repository_owner == 'zed-industries'
runs-on: namespace-profile-2x4-ubuntu-2404
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4

1
.gitignore vendored
View File

@@ -20,7 +20,6 @@
.venv
.vscode
.wrangler
.perf-runs
/assets/*licenses.*
/crates/collab/seed.json
/crates/theme/schemas/theme.json

15
.rules
View File

@@ -12,19 +12,6 @@
- Example: avoid `let _ = client.request(...).await?;` - use `client.request(...).await?;` instead
* When implementing async operations that may fail, ensure errors propagate to the UI layer so users get meaningful feedback.
* Never create files with `mod.rs` paths - prefer `src/some_module.rs` instead of `src/some_module/mod.rs`.
* When creating new crates, prefer specifying the library root path in `Cargo.toml` using `[lib] path = "...rs"` instead of the default `lib.rs`, to maintain consistent and descriptive naming (e.g., `gpui.rs` or `main.rs`).
* Avoid creative additions unless explicitly requested
* Use full words for variable names (no abbreviations like "q" for "queue")
* Use variable shadowing to scope clones in async contexts for clarity, minimizing the lifetime of borrowed references.
Example:
```rust
executor.spawn({
let task_ran = task_ran.clone();
async move {
*task_ran.borrow_mut() = true;
}
});
```
# GPUI
@@ -59,7 +46,7 @@ Trying to update an entity while it's already being updated must be avoided as t
When `read_with`, `update`, or `update_in` are used with an async context, the closure's return value is wrapped in an `anyhow::Result`.
`WeakEntity<T>` is a weak handle. It has `read_with`, `update`, and `update_in` methods that work the same, but always return an `anyhow::Result` so that they can fail if the entity no longer exists. This can be useful to avoid memory leaks - if entities have mutually recursive handles to each other they will never be dropped.
`WeakEntity<T>` is a weak handle. It has `read_with`, `update`, and `update_in` methods that work the same, but always return an `anyhow::Result` so that they can fail if the entity no longer exists. This can be useful to avoid memory leaks - if entities have mutually recursive handles to eachother they will never be dropped.
## Concurrency

View File

@@ -1,76 +1,54 @@
# Contributing to Zed
Thank you for helping us make Zed better!
Thanks for your interest in contributing to Zed, the collaborative platform that is also a code editor!
All activity in Zed forums is subject to our [Code of
Conduct](https://zed.dev/code-of-conduct). Additionally, contributors must sign
our [Contributor License Agreement](https://zed.dev/cla) before their
contributions can be merged.
All activity in Zed forums is subject to our [Code of Conduct](https://zed.dev/code-of-conduct). Additionally, contributors must sign our [Contributor License Agreement](https://zed.dev/cla) before their contributions can be merged.
## Contribution ideas
Zed is a large project with a number of priorities. We spend most of
our time working on what we believe the product needs, but we also love working
with the community to improve the product in ways we haven't thought of (or had time to get to yet!)
If you're looking for ideas about what to work on, check out:
In particular we love PRs that are:
- Fixes to existing bugs and issues.
- Small enhancements to existing features, particularly to make them work for more people.
- Small extra features, like keybindings or actions you miss from other editors or extensions.
- Work towards shipping larger features on our roadmap.
If you're looking for concrete ideas:
- Our [top-ranking issues](https://github.com/zed-industries/zed/issues/5393) based on votes by the community.
- Our [public roadmap](https://zed.dev/roadmap) contains a rough outline of our near-term priorities for Zed.
- Our [top-ranking issues](https://github.com/zed-industries/zed/issues/5393) based on votes by the community.
## Sending changes
For adding themes or support for a new language to Zed, check out our [docs on developing extensions](https://zed.dev/docs/extensions/developing-extensions).
The Zed culture values working code and synchronous conversations over long
discussion threads.
## Proposing changes
The best way to get us to take a look at a proposed change is to send a pull
request. We will get back to you (though this sometimes takes longer than we'd
like, sorry).
The best way to propose a change is to [start a discussion on our GitHub repository](https://github.com/zed-industries/zed/discussions).
Although we will take a look, we tend to only merge about half the PRs that are
submitted. If you'd like your PR to have the best chance of being merged:
First, write a short **problem statement**, which _clearly_ and _briefly_ describes the problem you want to solve independently from any specific solution. It doesn't need to be long or formal, but it's difficult to consider a solution in absence of a clear understanding of the problem.
- Include a clear description of what you're solving, and why it's important to you.
- Include tests.
- If it changes the UI, attach screenshots or screen recordings.
Next, write a short **solution proposal**. How can the problem (or set of problems) you have stated above be addressed? What are the pros and cons of your approach? Again, keep it brief and informal. This isn't a specification, but rather a starting point for a conversation.
The internal advice for reviewers is as follows:
By effectively engaging with the Zed team and community early in your process, we're better positioned to give you feedback and understand your pull request once you open it. If the first thing we see from you is a big changeset, we're much less likely to respond to it in a timely manner.
- If the fix/feature is obviously great, and the code is great. Hit merge.
- If the fix/feature is obviously great, and the code is nearly great. Send PR comments, or offer to pair to get things perfect.
- If the fix/feature is not obviously great, or the code needs rewriting from scratch. Close the PR with a thank you and some explanation.
## Pair programming
If you need more feedback from us: the best way is to be responsive to
Github comments, or to offer up time to pair with us.
We plan to set aside time each week to pair program with contributors on promising pull requests in Zed. This will be an experiment. We tend to prefer pairing over async code review on our team, and we'd like to see how well it works in an open source setting. If we're finding it difficult to get on the same page with async review, we may ask you to pair with us if you're open to it. The closer a contribution is to the goals outlined in our roadmap, the more likely we'll be to spend time pairing on it.
If you are making a larger change, or need advice on how to finish the change
you're making, please open the PR early. We would love to help you get
things right, and it's often easier to see how to solve a problem before the
diff gets too big.
## Tips to improve the chances of your PR getting reviewed and merged
## Things we will (probably) not merge
- Discuss your plans ahead of time with the team
- Small, focused, incremental pull requests are much easier to review
- Spend time explaining your changes in the pull request body
- Add test coverage and documentation
- Choose tasks that align with our roadmap
- Pair with us and watch us code to learn the codebase
- Low effort PRs, such as those that just re-arrange syntax, won't be merged without a compelling justification
Although there are few hard and fast rules, typically we don't merge:
## File icons
- Anything that can be provided by an extension. For example a new language, or theme. For adding themes or support for a new language to Zed, check out our [docs on developing extensions](https://zed.dev/docs/extensions/developing-extensions).
- New file icons. Zed's default icon theme consists of icons that are hand-designed to fit together in a cohesive manner, please don't submit PRs with off-the-shelf SVGs.
- Giant refactorings.
- Non-trivial changes with no tests.
- Stylistic code changes that do not alter any app logic. Reducing allocations, removing `.unwrap()`s, fixing typos is great; making code "more readable" — maybe not so much.
- Features where (in our subjective opinion) the extra complexity isn't worth it for the number of people who will benefit.
- Anything that seems completely AI generated.
Zed's default icon theme consists of icons that are hand-designed to fit together in a cohesive manner.
We do not accept PRs for file icons that are just an off-the-shelf SVG taken from somewhere else.
### Adding new icons to the Zed icon theme
If you would like to add a new icon to the Zed icon theme, [open a Discussion](https://github.com/zed-industries/zed/discussions/new?category=ux-and-design) and we can work with you on getting an icon designed and added to Zed.
## Bird's-eye view of Zed
We suggest you keep the [Zed glossary](docs/src/development/glossary.md) at your side when starting out. It lists and explains some of the structures and terms you will see throughout the codebase.
Zed is made up of several smaller crates - let's go over those you're most likely to interact with:
- [`gpui`](/crates/gpui) is a GPU-accelerated UI framework which provides all of the building blocks for Zed. **We recommend familiarizing yourself with the root level GPUI documentation.**

4454
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,6 @@
[workspace]
resolver = "2"
members = [
"crates/acp_tools",
"crates/acp_thread",
"crates/action_log",
"crates/activity_indicator",
@@ -35,7 +34,6 @@ members = [
"crates/cloud_api_client",
"crates/cloud_api_types",
"crates/cloud_llm_client",
"crates/cloud_zeta2_prompt",
"crates/collab",
"crates/collab_ui",
"crates/collections",
@@ -53,13 +51,8 @@ members = [
"crates/debugger_tools",
"crates/debugger_ui",
"crates/deepseek",
"crates/denoise",
"crates/diagnostics",
"crates/docs_preprocessor",
"crates/edit_prediction",
"crates/edit_prediction_button",
"crates/edit_prediction_context",
"crates/zeta2_tools",
"crates/editor",
"crates/eval",
"crates/explorer_command_injector",
@@ -88,20 +81,20 @@ members = [
"crates/http_client_tls",
"crates/icons",
"crates/image_viewer",
"crates/edit_prediction",
"crates/edit_prediction_button",
"crates/inspector_ui",
"crates/install_cli",
"crates/jj",
"crates/jj_ui",
"crates/journal",
"crates/json_schema_store",
"crates/keymap_editor",
"crates/language",
"crates/language_extension",
"crates/language_model",
"crates/language_models",
"crates/language_onboarding",
"crates/language_selector",
"crates/language_tools",
"crates/languages",
"crates/line_ending_selector",
"crates/livekit_api",
"crates/livekit_client",
"crates/lmstudio",
@@ -136,7 +129,6 @@ members = [
"crates/refineable",
"crates/refineable/derive_refineable",
"crates/release_channel",
"crates/scheduler",
"crates/remote",
"crates/remote_server",
"crates/repl",
@@ -147,10 +139,10 @@ members = [
"crates/rules_library",
"crates/schema_generator",
"crates/search",
"crates/semantic_index",
"crates/semantic_version",
"crates/session",
"crates/settings",
"crates/settings_macros",
"crates/settings_profile_selector",
"crates/settings_ui",
"crates/snippet",
@@ -164,9 +156,7 @@ members = [
"crates/sum_tree",
"crates/supermaven",
"crates/supermaven_api",
"crates/codestral",
"crates/svg_preview",
"crates/system_specs",
"crates/tab_switcher",
"crates/task",
"crates/tasks_ui",
@@ -199,9 +189,7 @@ members = [
"crates/x_ai",
"crates/zed",
"crates/zed_actions",
"crates/zed_env_vars",
"crates/zeta",
"crates/zeta2",
"crates/zeta_cli",
"crates/zlog",
"crates/zlog_settings",
@@ -213,14 +201,16 @@ members = [
"extensions/glsl",
"extensions/html",
"extensions/proto",
"extensions/ruff",
"extensions/slash-commands-example",
"extensions/snippets",
"extensions/test-extension",
"extensions/toml",
#
# Tooling
#
"tooling/perf",
"tooling/workspace-hack",
"tooling/xtask",
]
@@ -236,7 +226,6 @@ edition = "2024"
# Workspace member crates
#
acp_tools = { path = "crates/acp_tools" }
acp_thread = { path = "crates/acp_thread" }
action_log = { path = "crates/action_log" }
agent = { path = "crates/agent" }
@@ -271,10 +260,9 @@ clock = { path = "crates/clock" }
cloud_api_client = { path = "crates/cloud_api_client" }
cloud_api_types = { path = "crates/cloud_api_types" }
cloud_llm_client = { path = "crates/cloud_llm_client" }
cloud_zeta2_prompt = { path = "crates/cloud_zeta2_prompt" }
collab = { path = "crates/collab" }
collab_ui = { path = "crates/collab_ui" }
collections = { path = "crates/collections", package = "zed-collections", version = "0.1.0" }
collections = { path = "crates/collections" }
command_palette = { path = "crates/command_palette" }
command_palette_hooks = { path = "crates/command_palette_hooks" }
component = { path = "crates/component" }
@@ -282,7 +270,6 @@ context_server = { path = "crates/context_server" }
copilot = { path = "crates/copilot" }
crashes = { path = "crates/crashes" }
credentials_provider = { path = "crates/credentials_provider" }
crossbeam = "0.8.4"
dap = { path = "crates/dap" }
dap_adapters = { path = "crates/dap_adapters" }
db = { path = "crates/db" }
@@ -290,7 +277,6 @@ debug_adapter_extension = { path = "crates/debug_adapter_extension" }
debugger_tools = { path = "crates/debugger_tools" }
debugger_ui = { path = "crates/debugger_ui" }
deepseek = { path = "crates/deepseek" }
derive_refineable = { path = "crates/refineable/derive_refineable", package = "zed-derive-refineable", version = "0.1.0" }
diagnostics = { path = "crates/diagnostics" }
editor = { path = "crates/editor" }
extension = { path = "crates/extension" }
@@ -308,32 +294,30 @@ git_hosting_providers = { path = "crates/git_hosting_providers" }
git_ui = { path = "crates/git_ui" }
go_to_line = { path = "crates/go_to_line" }
google_ai = { path = "crates/google_ai" }
gpui = { path = "crates/gpui", default-features = false }
gpui_macros = { path = "crates/gpui_macros", package = "gpui-macros", version = "0.1.0" }
gpui = { path = "crates/gpui", default-features = false, features = [
"http_client",
] }
gpui_macros = { path = "crates/gpui_macros" }
gpui_tokio = { path = "crates/gpui_tokio" }
html_to_markdown = { path = "crates/html_to_markdown" }
http_client = { path = "crates/http_client", package = "zed-http-client", version = "0.1.0" }
http_client = { path = "crates/http_client" }
http_client_tls = { path = "crates/http_client_tls" }
icons = { path = "crates/icons" }
image_viewer = { path = "crates/image_viewer" }
edit_prediction = { path = "crates/edit_prediction" }
edit_prediction_button = { path = "crates/edit_prediction_button" }
edit_prediction_context = { path = "crates/edit_prediction_context" }
zeta2_tools = { path = "crates/zeta2_tools" }
inspector_ui = { path = "crates/inspector_ui" }
install_cli = { path = "crates/install_cli" }
jj = { path = "crates/jj" }
jj_ui = { path = "crates/jj_ui" }
journal = { path = "crates/journal" }
json_schema_store = { path = "crates/json_schema_store" }
keymap_editor = { path = "crates/keymap_editor" }
language = { path = "crates/language" }
language_extension = { path = "crates/language_extension" }
language_model = { path = "crates/language_model" }
language_models = { path = "crates/language_models" }
language_onboarding = { path = "crates/language_onboarding" }
language_selector = { path = "crates/language_selector" }
language_tools = { path = "crates/language_tools" }
languages = { path = "crates/languages" }
line_ending_selector = { path = "crates/line_ending_selector" }
livekit_api = { path = "crates/livekit_api" }
livekit_client = { path = "crates/livekit_client" }
lmstudio = { path = "crates/lmstudio" }
@@ -341,7 +325,7 @@ lsp = { path = "crates/lsp" }
markdown = { path = "crates/markdown" }
markdown_preview = { path = "crates/markdown_preview" }
svg_preview = { path = "crates/svg_preview" }
media = { path = "crates/media", package = "zed-media", version = "0.1.0" }
media = { path = "crates/media" }
menu = { path = "crates/menu" }
migrator = { path = "crates/migrator" }
mistral = { path = "crates/mistral" }
@@ -358,7 +342,6 @@ outline = { path = "crates/outline" }
outline_panel = { path = "crates/outline_panel" }
panel = { path = "crates/panel" }
paths = { path = "crates/paths" }
perf = { path = "tooling/perf", package = "zed-perf", version = "0.1.0" }
picker = { path = "crates/picker" }
plugin = { path = "crates/plugin" }
plugin_macros = { path = "crates/plugin_macros" }
@@ -370,23 +353,22 @@ project_symbols = { path = "crates/project_symbols" }
prompt_store = { path = "crates/prompt_store" }
proto = { path = "crates/proto" }
recent_projects = { path = "crates/recent_projects" }
refineable = { path = "crates/refineable", package = "zed-refineable", version = "0.1.0" }
refineable = { path = "crates/refineable" }
release_channel = { path = "crates/release_channel" }
scheduler = { path = "crates/scheduler" }
remote = { path = "crates/remote" }
remote_server = { path = "crates/remote_server" }
repl = { path = "crates/repl" }
reqwest_client = { path = "crates/reqwest_client" }
rich_text = { path = "crates/rich_text" }
rodio = { git = "https://github.com/RustAudio/rodio" }
rodio = { version = "0.21.1", default-features = false }
rope = { path = "crates/rope" }
rpc = { path = "crates/rpc" }
rules_library = { path = "crates/rules_library" }
search = { path = "crates/search" }
semantic_version = { path = "crates/semantic_version", package = "zed-semantic-version", version = "0.1.0" }
semantic_index = { path = "crates/semantic_index" }
semantic_version = { path = "crates/semantic_version" }
session = { path = "crates/session" }
settings = { path = "crates/settings" }
settings_macros = { path = "crates/settings_macros" }
settings_ui = { path = "crates/settings_ui" }
snippet = { path = "crates/snippet" }
snippet_provider = { path = "crates/snippet_provider" }
@@ -396,11 +378,9 @@ sqlez_macros = { path = "crates/sqlez_macros" }
story = { path = "crates/story" }
storybook = { path = "crates/storybook" }
streaming_diff = { path = "crates/streaming_diff" }
sum_tree = { path = "crates/sum_tree", package = "zed-sum-tree", version = "0.1.0" }
sum_tree = { path = "crates/sum_tree" }
supermaven = { path = "crates/supermaven" }
supermaven_api = { path = "crates/supermaven_api" }
codestral = { path = "crates/codestral" }
system_specs = { path = "crates/system_specs" }
tab_switcher = { path = "crates/tab_switcher" }
task = { path = "crates/task" }
tasks_ui = { path = "crates/tasks_ui" }
@@ -420,8 +400,8 @@ ui = { path = "crates/ui" }
ui_input = { path = "crates/ui_input" }
ui_macros = { path = "crates/ui_macros" }
ui_prompt = { path = "crates/ui_prompt" }
util = { path = "crates/util", package = "zed-util", version = "0.1.0" }
util_macros = { path = "crates/util_macros", package = "zed-util-macros", version = "0.1.0" }
util = { path = "crates/util" }
util_macros = { path = "crates/util_macros" }
vercel = { path = "crates/vercel" }
vim = { path = "crates/vim" }
vim_mode_setting = { path = "crates/vim_mode_setting" }
@@ -434,9 +414,7 @@ worktree = { path = "crates/worktree" }
x_ai = { path = "crates/x_ai" }
zed = { path = "crates/zed" }
zed_actions = { path = "crates/zed_actions" }
zed_env_vars = { path = "crates/zed_env_vars" }
zeta = { path = "crates/zeta" }
zeta2 = { path = "crates/zeta2" }
zlog = { path = "crates/zlog" }
zlog_settings = { path = "crates/zlog_settings" }
@@ -444,9 +422,10 @@ zlog_settings = { path = "crates/zlog_settings" }
# External crates
#
agent-client-protocol = { version = "0.4.3", features = ["unstable"] }
agentic-coding-protocol = "0.0.10"
agent-client-protocol = "0.0.28"
aho-corasick = "1.1"
alacritty_terminal = "0.25.1-rc1"
alacritty_terminal = { git = "https://github.com/zed-industries/alacritty.git", branch = "add-hush-login-flag" }
any_vec = "0.14"
anyhow = "1.0.86"
arrayvec = { version = "0.7.4", features = ["serde"] }
@@ -458,7 +437,6 @@ async-fs = "2.1"
async-pipe = { git = "https://github.com/zed-industries/async-pipe-rs", rev = "82d00a04211cf4e1236029aa03e6b6ce2a74c553" }
async-recursion = "1.0.0"
async-tar = "0.5.0"
async-task = "4.7"
async-trait = "0.1"
async-tungstenite = "0.29.1"
async_zip = { version = "0.0.17", features = ["deflate", "deflate64"] }
@@ -471,17 +449,15 @@ aws-sdk-bedrockruntime = { version = "1.80.0", features = [
] }
aws-smithy-runtime-api = { version = "1.7.4", features = ["http-1x", "client"] }
aws-smithy-types = { version = "1.3.0", features = ["http-body-1-x"] }
backtrace = "0.3"
base64 = "0.22"
bincode = "1.2.1"
bitflags = "2.6.0"
blade-graphics = { version = "0.7.0" }
blade-macros = { version = "0.3.0" }
blade-util = { version = "0.3.0" }
blade-graphics = { git = "https://github.com/kvark/blade", rev = "e0ec4e720957edd51b945b64dd85605ea54bcfe5" }
blade-macros = { git = "https://github.com/kvark/blade", rev = "e0ec4e720957edd51b945b64dd85605ea54bcfe5" }
blade-util = { git = "https://github.com/kvark/blade", rev = "e0ec4e720957edd51b945b64dd85605ea54bcfe5" }
blake3 = "1.5.3"
bytes = "1.0"
cargo_metadata = "0.19"
cargo_toml = "0.21"
cfg-if = "1.0.3"
chrono = { version = "0.4", features = ["serde"] }
ciborium = "0.2"
circular-buffer = "1.0"
@@ -514,11 +490,9 @@ futures-lite = "1.13"
git2 = { version = "0.20.1", default-features = false }
globset = "0.4"
handlebars = "4.3"
hashbrown = "0.15.3"
heck = "0.5"
heed = { version = "0.21.0", features = ["read-txn-no-tls"] }
hex = "0.4.3"
human_bytes = "0.4.1"
html5ever = "0.27.0"
http = "1.1"
http-body = "1.0"
@@ -530,6 +504,7 @@ indexmap = { version = "2.7.0", features = ["serde"] }
indoc = "2"
inventory = "0.3.19"
itertools = "0.14.0"
jj-lib = { git = "https://github.com/jj-vcs/jj", rev = "e18eb8e05efaa153fad5ef46576af145bba1807f" }
json_dotpath = "1.1"
jsonschema = "0.30.0"
jsonwebtoken = "9.3"
@@ -539,7 +514,7 @@ libc = "0.2"
libsqlite3-sys = { version = "0.30.1", features = ["bundled"] }
linkify = "0.10.0"
log = { version = "0.4.16", features = ["kv_unstable_serde", "serde"] }
lsp-types = { git = "https://github.com/zed-industries/lsp-types", rev = "0874f8742fe55b4dc94308c1e3c0069710d8eeaf" }
lsp-types = { git = "https://github.com/zed-industries/lsp-types", rev = "39f629bdd03d59abd786ed9fc27e8bca02c0c0ec" }
mach2 = "0.5"
markup5ever_rcdom = "0.3.0"
metal = "0.29"
@@ -550,40 +525,13 @@ nanoid = "0.4"
nbformat = { git = "https://github.com/ConradIrwin/runtimed", rev = "7130c804216b6914355d15d0b91ea91f6babd734" }
nix = "0.29"
num-format = "0.4.4"
num-traits = "0.2"
objc = "0.2"
objc2-foundation = { version = "0.3", default-features = false, features = [
"NSArray",
"NSAttributedString",
"NSBundle",
"NSCoder",
"NSData",
"NSDate",
"NSDictionary",
"NSEnumerator",
"NSError",
"NSGeometry",
"NSNotification",
"NSNull",
"NSObjCRuntime",
"NSObject",
"NSProcessInfo",
"NSRange",
"NSRunLoop",
"NSString",
"NSURL",
"NSUndoManager",
"NSValue",
"objc2-core-foundation",
"std"
] }
open = "5.0.0"
ordered-float = "2.1.1"
palette = { version = "0.7.5", default-features = false, features = ["std"] }
parking_lot = "0.12.1"
partial-json-fixer = "0.5.3"
parse_int = "0.9"
pciid-parser = "0.8.0"
pathdiff = "0.2"
pet = { git = "https://github.com/microsoft/python-environment-tools.git", rev = "845945b830297a50de0e24020b980a65e4820559" }
pet-conda = { git = "https://github.com/microsoft/python-environment-tools.git", rev = "845945b830297a50de0e24020b980a65e4820559" }
@@ -592,7 +540,6 @@ pet-fs = { git = "https://github.com/microsoft/python-environment-tools.git", re
pet-pixi = { git = "https://github.com/microsoft/python-environment-tools.git", rev = "845945b830297a50de0e24020b980a65e4820559" }
pet-poetry = { git = "https://github.com/microsoft/python-environment-tools.git", rev = "845945b830297a50de0e24020b980a65e4820559" }
pet-reporter = { git = "https://github.com/microsoft/python-environment-tools.git", rev = "845945b830297a50de0e24020b980a65e4820559" }
pet-virtualenv = { git = "https://github.com/microsoft/python-environment-tools.git", rev = "845945b830297a50de0e24020b980a65e4820559" }
portable-pty = "0.9.0"
postage = { version = "0.5", features = ["futures-traits"] }
pretty_assertions = { version = "1.3.0", features = ["unstable"] }
@@ -603,12 +550,11 @@ prost-build = "0.9"
prost-types = "0.9"
pulldown-cmark = { version = "0.12.0", default-features = false }
quote = "1.0.9"
rand = "0.9"
rand = "0.8.5"
rayon = "1.8"
ref-cast = "1.0.24"
regex = "1.5"
# WARNING: If you change this, you must also publish a new version of zed-reqwest to crates.io
reqwest = { git = "https://github.com/zed-industries/reqwest.git", rev = "c15662463bda39148ba154100dd44d3fba5873a4", default-features = false, features = [
reqwest = { git = "https://github.com/zed-industries/reqwest.git", rev = "951c770a32f1998d6e999cef3e59e0013e6c4415", default-features = false, features = [
"charset",
"http2",
"macos-system-configuration",
@@ -616,34 +562,32 @@ reqwest = { git = "https://github.com/zed-industries/reqwest.git", rev = "c15662
"rustls-tls-native-roots",
"socks",
"stream",
], package = "zed-reqwest", version = "0.12.15-zed" }
] }
rsa = "0.9.6"
runtimelib = { git = "https://github.com/ConradIrwin/runtimed", rev = "7130c804216b6914355d15d0b91ea91f6babd734", default-features = false, features = [
"async-dispatcher-runtime",
] }
rust-embed = { version = "8.4", features = ["include-exclude"] }
rustc-demangle = "0.1.23"
rustc-hash = "2.1.0"
rustls = { version = "0.23.26" }
rustls-platform-verifier = "0.5.0"
# WARNING: If you change this, you must also publish a new version of zed-scap to crates.io
scap = { git = "https://github.com/zed-industries/scap", rev = "4afea48c3b002197176fb19cd0f9b180dd36eaac", default-features = false, package = "zed-scap", version = "0.0.8-zed" }
scap = { git = "https://github.com/zed-industries/scap", rev = "808aa5c45b41e8f44729d02e38fd00a2fe2722e7", default-features = false }
schemars = { version = "1.0", features = ["indexmap2"] }
semver = "1.0"
serde = { version = "1.0.221", features = ["derive", "rc"] }
serde_json = { version = "1.0.144", features = ["preserve_order", "raw_value"] }
serde = { version = "1.0", features = ["derive", "rc"] }
serde_derive = { version = "1.0", features = ["deserialize_in_place"] }
serde_json = { version = "1.0", features = ["preserve_order", "raw_value"] }
serde_json_lenient = { version = "0.2", features = [
"preserve_order",
"raw_value",
] }
serde_path_to_error = "0.1.17"
serde_repr = "0.1"
serde_urlencoded = "0.7"
serde_with = "3.4.0"
sha2 = "0.10"
shellexpand = "2.1.0"
shlex = "1.3.0"
simplelog = "0.12.2"
slotmap = "1.0.6"
smallvec = { version = "1.6", features = ["union"] }
smol = "2.0"
sqlformat = "0.2"
@@ -652,9 +596,9 @@ streaming-iterator = "0.1"
strsim = "0.11"
strum = { version = "0.27.0", features = ["derive"] }
subtle = "2.5.0"
syn = { version = "2.0.101", features = ["full", "extra-traits", "visit-mut"] }
syn = { version = "2.0.101", features = ["full", "extra-traits"] }
sys-locale = "0.3.1"
sysinfo = "0.37.0"
sysinfo = "0.31.0"
take-until = "0.2.0"
tempfile = "3.20.0"
thiserror = "2.0.12"
@@ -670,12 +614,11 @@ tiny_http = "0.8"
tokio = { version = "1" }
tokio-tungstenite = { version = "0.26", features = ["__rustls-tls"] }
toml = "0.8"
toml_edit = { version = "0.22", default-features = false, features = ["display", "parse", "serde"] }
tower-http = "0.4.4"
tree-sitter = { version = "0.25.10", features = ["wasm"] }
tree-sitter = { version = "0.25.6", features = ["wasm"] }
tree-sitter-bash = "0.25.0"
tree-sitter-c = "0.23"
tree-sitter-cpp = { git = "https://github.com/tree-sitter/tree-sitter-cpp", rev = "5cb9b693cfd7bfacab1d9ff4acac1a4150700609" }
tree-sitter-cpp = "0.23"
tree-sitter-css = "0.23"
tree-sitter-diff = "0.1.0"
tree-sitter-elixir = "0.3"
@@ -689,11 +632,11 @@ tree-sitter-html = "0.23"
tree-sitter-jsdoc = "0.23"
tree-sitter-json = "0.24"
tree-sitter-md = { git = "https://github.com/tree-sitter-grammars/tree-sitter-markdown", rev = "9a23c1a96c0513d8fc6520972beedd419a973539" }
tree-sitter-python = "0.25"
tree-sitter-python = { git = "https://github.com/zed-industries/tree-sitter-python", rev = "218fcbf3fda3d029225f3dec005cb497d111b35e" }
tree-sitter-regex = "0.24"
tree-sitter-ruby = "0.23"
tree-sitter-rust = "0.24"
tree-sitter-typescript = { git = "https://github.com/zed-industries/tree-sitter-typescript", rev = "e2c53597d6a5d9cf7bbe8dccde576fe1e46c5899" } # https://github.com/tree-sitter/tree-sitter-typescript/pull/347
tree-sitter-typescript = "0.23"
tree-sitter-yaml = { git = "https://github.com/zed-industries/tree-sitter-yaml", rev = "baff0b51c64ef6a1fb1f8390f3ad6015b83ec13a" }
unicase = "2.6"
unicode-script = "0.5.7"
@@ -720,7 +663,6 @@ windows-core = "0.61"
wit-component = "0.221"
workspace-hack = "0.1.0"
yawc = "0.2.5"
zeroize = "1.8"
zstd = "0.11"
[workspace.dependencies.windows]
@@ -743,11 +685,9 @@ features = [
"Win32_Graphics_Dxgi_Common",
"Win32_Graphics_Gdi",
"Win32_Graphics_Imaging",
"Win32_Graphics_Hlsl",
"Win32_Networking_WinSock",
"Win32_Security",
"Win32_Security_Credentials",
"Win32_Security_Cryptography",
"Win32_Storage_FileSystem",
"Win32_System_Com",
"Win32_System_Com_StructuredStorage",
@@ -805,7 +745,7 @@ wasmtime = { opt-level = 3 }
activity_indicator = { codegen-units = 1 }
assets = { codegen-units = 1 }
breadcrumbs = { codegen-units = 1 }
zed-collections = { codegen-units = 1 }
collections = { codegen-units = 1 }
command_palette = { codegen-units = 1 }
command_palette_hooks = { codegen-units = 1 }
extension_cli = { codegen-units = 1 }
@@ -816,7 +756,6 @@ image_viewer = { codegen-units = 1 }
edit_prediction_button = { codegen-units = 1 }
install_cli = { codegen-units = 1 }
journal = { codegen-units = 1 }
json_schema_store = { codegen-units = 1 }
lmstudio = { codegen-units = 1 }
menu = { codegen-units = 1 }
notifications = { codegen-units = 1 }
@@ -825,11 +764,11 @@ outline = { codegen-units = 1 }
paths = { codegen-units = 1 }
prettier = { codegen-units = 1 }
project_symbols = { codegen-units = 1 }
zed-refineable = { codegen-units = 1 }
refineable = { codegen-units = 1 }
release_channel = { codegen-units = 1 }
reqwest_client = { codegen-units = 1 }
rich_text = { codegen-units = 1 }
zed-semantic-version = { codegen-units = 1 }
semantic_version = { codegen-units = 1 }
session = { codegen-units = 1 }
snippet = { codegen-units = 1 }
snippets_ui = { codegen-units = 1 }
@@ -863,34 +802,148 @@ unexpected_cfgs = { level = "allow" }
dbg_macro = "deny"
todo = "deny"
# This is not a style lint, see https://github.com/rust-lang/rust-clippy/pull/15454
# Remove when the lint gets promoted to `suspicious`.
declare_interior_mutable_const = "deny"
redundant_clone = "deny"
disallowed_methods = "deny"
# We currently do not restrict any style rules
# as it slows down shipping code to Zed.
#
# Running ./script/clippy can take several minutes, and so it's
# common to skip that step and let CI do it. Any unexpected failures
# (which also take minutes to discover) thus require switching back
# to an old branch, manual fixing, and re-pushing.
#
# In the future we could improve this by either making sure
# Zed can surface clippy errors in diagnostics (in addition to the
# rust-analyzer errors), or by having CI fix style nits automatically.
style = { level = "allow", priority = -1 }
# Individual rules that have violations in the codebase:
type_complexity = "allow"
let_underscore_future = "allow"
# Motivation: We use `vec![a..b]` a lot when dealing with ranges in text, so
# warning on this rule produces a lot of noise.
single_range_in_vec_init = "allow"
redundant_clone = "warn"
declare_interior_mutable_const = "deny"
# These are all of the rules that currently have violations in the Zed
# codebase.
#
# We'll want to drive this list down by either:
# 1. fixing violations of the rule and begin enforcing it
# 2. deciding we want to allow the rule permanently, at which point
# we should codify that separately above.
#
# This list shouldn't be added to; it should only get shorter.
# =============================================================================
# There are a bunch of rules currently failing in the `style` group, so
# allow all of those, for now.
style = { level = "allow", priority = -1 }
# Temporary list of style lints that we've fixed so far.
# Progress is being tracked in #36577
blocks_in_conditions = "warn"
bool_assert_comparison = "warn"
borrow_interior_mutable_const = "warn"
box_default = "warn"
builtin_type_shadow = "warn"
bytes_nth = "warn"
chars_next_cmp = "warn"
cmp_null = "warn"
collapsible_else_if = "warn"
collapsible_if = "warn"
comparison_to_empty = "warn"
default_instead_of_iter_empty = "warn"
disallowed_macros = "warn"
disallowed_methods = "warn"
disallowed_names = "warn"
disallowed_types = "warn"
doc_lazy_continuation = "warn"
doc_overindented_list_items = "warn"
duplicate_underscore_argument = "warn"
err_expect = "warn"
fn_to_numeric_cast = "warn"
fn_to_numeric_cast_with_truncation = "warn"
for_kv_map = "warn"
implicit_saturating_add = "warn"
implicit_saturating_sub = "warn"
inconsistent_digit_grouping = "warn"
infallible_destructuring_match = "warn"
inherent_to_string = "warn"
init_numbered_fields = "warn"
into_iter_on_ref = "warn"
io_other_error = "warn"
items_after_test_module = "warn"
iter_cloned_collect = "warn"
iter_next_slice = "warn"
iter_nth = "warn"
iter_nth_zero = "warn"
iter_skip_next = "warn"
just_underscores_and_digits = "warn"
len_zero = "warn"
let_and_return = "warn"
main_recursion = "warn"
manual_bits = "warn"
manual_dangling_ptr = "warn"
manual_is_ascii_check = "warn"
manual_is_finite = "warn"
manual_is_infinite = "warn"
manual_map = "warn"
manual_next_back = "warn"
manual_non_exhaustive = "warn"
manual_ok_or = "warn"
manual_pattern_char_comparison = "warn"
manual_rotate = "warn"
manual_slice_fill = "warn"
manual_while_let_some = "warn"
map_clone = "warn"
map_collect_result_unit = "warn"
match_like_matches_macro = "warn"
match_overlapping_arm = "warn"
mem_replace_option_with_none = "warn"
mem_replace_option_with_some = "warn"
missing_enforced_import_renames = "warn"
missing_safety_doc = "warn"
mixed_attributes_style = "warn"
mixed_case_hex_literals = "warn"
module_inception = "warn"
must_use_unit = "warn"
mut_mutex_lock = "warn"
needless_borrow = "warn"
needless_doctest_main = "warn"
needless_else = "warn"
needless_parens_on_range_literals = "warn"
needless_pub_self = "warn"
needless_return = "warn"
needless_return_with_question_mark = "warn"
non_minimal_cfg = "warn"
ok_expect = "warn"
owned_cow = "warn"
print_literal = "warn"
print_with_newline = "warn"
println_empty_string = "warn"
ptr_eq = "warn"
question_mark = "warn"
redundant_closure = "warn"
redundant_field_names = "warn"
redundant_pattern_matching = "warn"
redundant_static_lifetimes = "warn"
result_map_or_into_option = "warn"
self_named_constructors = "warn"
single_match = "warn"
tabs_in_doc_comments = "warn"
to_digit_is_some = "warn"
toplevel_ref_arg = "warn"
unnecessary_fold = "warn"
unnecessary_map_or = "warn"
unnecessary_mut_passed = "warn"
unnecessary_owned_empty_strings = "warn"
unneeded_struct_pattern = "warn"
unsafe_removed_from_name = "warn"
unused_unit = "warn"
unusual_byte_groupings = "warn"
while_let_on_iterator = "warn"
write_literal = "warn"
write_with_newline = "warn"
writeln_empty_string = "warn"
wrong_self_convention = "warn"
zero_ptr = "warn"
# Individual rules that have violations in the codebase:
type_complexity = "allow"
# We often return trait objects from `new` functions.
new_ret_no_self = { level = "allow" }
# We have a few `next` functions that differ in lifetimes
# compared to Iterator::next. Yet, clippy complains about those.
should_implement_trait = { level = "allow" }
let_underscore_future = "allow"
# It doesn't make sense to implement `Default` unilaterally.
new_without_default = "allow"
# in Rust it can be very tedious to reduce argument count without
# running afoul of the borrow checker.
too_many_arguments = "allow"
@@ -898,8 +951,9 @@ too_many_arguments = "allow"
# We often have large enum variants yet we rarely actually bother with splitting them up.
large_enum_variant = "allow"
# Boolean expressions can be hard to read, requiring only the minimal form gets in the way
nonminimal_bool = "allow"
# `enum_variant_names` fires for all enums, even when they derive serde traits.
# Adhering to this lint would be a breaking change.
enum_variant_names = "allow"
[workspace.metadata.cargo-machete]
ignored = [

2
Cross.toml Normal file
View File

@@ -0,0 +1,2 @@
[build]
dockerfile = "Dockerfile-cross"

View File

@@ -1,6 +1,6 @@
# syntax = docker/dockerfile:1.2
FROM rust:1.90-bookworm as builder
FROM rust:1.89-bookworm as builder
WORKDIR app
COPY . .

17
Dockerfile-cross Normal file
View File

@@ -0,0 +1,17 @@
# syntax=docker/dockerfile:1
ARG CROSS_BASE_IMAGE
FROM ${CROSS_BASE_IMAGE}
WORKDIR /app
ARG TZ=Etc/UTC \
LANG=C.UTF-8 \
LC_ALL=C.UTF-8 \
DEBIAN_FRONTEND=noninteractive
ENV CARGO_TERM_COLOR=always
COPY script/install-mold script/
RUN ./script/install-mold "2.34.0"
COPY script/remote-server script/
RUN ./script/remote-server
COPY . .

View File

@@ -1 +0,0 @@
.rules

View File

@@ -1,2 +0,0 @@
postgrest_llm: postgrest crates/collab/postgrest_llm.conf
website: cd ../zed.dev; npm run dev -- --port=3000

View File

@@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.37288 4.48506L7.43539 10.6638C7.43539 10.9365 7.54373 11.1981 7.73655 11.3909C7.92938 11.5837 8.19092 11.6921 8.46362 11.6921C8.73632 11.6921 8.99785 11.5837 9.19068 11.3909C9.38351 11.1981 9.49184 10.9366 9.49184 10.6638L9.42933 4.48506C9.42933 3.93975 9.2127 3.41678 8.82711 3.03119C8.44152 2.6456 7.91855 2.42898 7.37324 2.42898C6.82794 2.42898 6.30496 2.6456 5.91937 3.03119C5.53378 3.41678 5.31716 3.93975 5.31716 4.48506L5.37968 10.6384C5.37636 11.0455 5.45368 11.4492 5.60718 11.8263C5.76067 12.2034 5.98731 12.5463 6.27401 12.8354C6.56071 13.1244 6.9018 13.3538 7.27761 13.5104C7.65341 13.667 8.0565 13.7476 8.46362 13.7476C8.87073 13.7476 9.27382 13.667 9.64963 13.5104C10.0254 13.3538 10.3665 13.1244 10.6532 12.8354C10.9399 12.5463 11.1666 12.2034 11.3201 11.8263C11.4736 11.4492 11.5509 11.0455 11.5476 10.6384L11.485 4.48506" stroke="black" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -1,4 +1 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12.486 6.2H7.24795C6.66895 6.2 6.19995 6.669 6.19995 7.248V12.486C6.19995 13.064 6.66895 13.533 7.24795 13.533H12.486C13.064 13.533 13.533 13.064 13.533 12.486V7.248C13.533 6.669 13.064 6.2 12.486 6.2Z" stroke="black" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3.91712 10.203C3.63951 10.2022 3.37351 10.0915 3.1773 9.89511C2.98109 9.69872 2.87064 9.43261 2.87012 9.155V3.917C2.87091 3.63956 2.98147 3.37371 3.17765 3.17753C3.37383 2.98135 3.63968 2.87079 3.91712 2.87H9.15512C9.43273 2.87053 9.69883 2.98097 9.89523 3.17718C10.0916 3.37339 10.2023 3.63939 10.2031 3.917" stroke="black" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="none"><path stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.2" d="M12.286 6H7.048C6.469 6 6 6.469 6 7.048v5.238c0 .578.469 1.047 1.048 1.047h5.238c.578 0 1.047-.469 1.047-1.047V7.048c0-.579-.469-1.048-1.047-1.048Z"/><path stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.2" d="M3.714 10a1.05 1.05 0 0 1-1.047-1.048V3.714a1.05 1.05 0 0 1 1.047-1.047h5.238A1.05 1.05 0 0 1 10 3.714"/></svg>

Before

Width:  |  Height:  |  Size: 802 B

After

Width:  |  Height:  |  Size: 515 B

View File

@@ -1,3 +1,9 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.2806 4.66818L8.26042 1.76982C8.09921 1.67673 7.9003 1.67673 7.73909 1.76982L2.71918 4.66818C2.58367 4.74642 2.5 4.89112 2.5 5.04785V10.8924C2.5 11.0489 2.58367 11.1938 2.71918 11.2721L7.73934 14.1704C7.90054 14.2635 8.09946 14.2635 8.26066 14.1704L13.2808 11.2721C13.4163 11.1938 13.5 11.0491 13.5 10.8924V5.04785C13.5 4.89136 13.4163 4.74642 13.2808 4.66818H13.2806ZM12.9653 5.28212L8.11901 13.676C8.08626 13.7326 7.99977 13.7095 7.99977 13.6439V8.14771C7.99977 8.03788 7.94107 7.9363 7.84586 7.88115L3.08613 5.13317C3.02957 5.10041 3.05266 5.0139 3.11818 5.0139H12.8106C12.9483 5.0139 13.0343 5.1631 12.9655 5.28236H12.9653V5.28212Z" fill="#C4CAD4"/>
<path opacity="0.6" d="M3.5 11V5.5L8.5 8L3.5 11Z" fill="black"/>
<path opacity="0.4" d="M8.5 14L3.5 11L8.5 8V14Z" fill="black"/>
<path opacity="0.6" d="M8.5 5.5H3.5L8.5 2.5L8.5 5.5Z" fill="black"/>
<path opacity="0.8" d="M8.5 5.5V2.5L13.5 5.5H8.5Z" fill="black"/>
<path opacity="0.2" d="M13.5 11L8.5 14L11 9.5L13.5 11Z" fill="black"/>
<path opacity="0.5" d="M13.5 11L11 9.5L13.5 5V11Z" fill="black"/>
<path d="M3.5 11V5L8.5 2.11325L13.5 5V11L8.5 13.8868L3.5 11Z" stroke="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 769 B

After

Width:  |  Height:  |  Size: 583 B

View File

@@ -1,11 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_3010_383)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.71141 7.06133C3.76141 6.47267 3.78341 5.88133 3.81608 5.29133C4.10416 0.190201 11.896 0.190202 12.1841 5.29133C12.2174 5.898 12.2441 6.50333 12.3067 7.10733C12.6951 7.94202 14.3637 11.6214 13.4134 12.006C13.1894 12.096 12.8041 11.7227 12.3694 11.052C12.207 11.9614 11.7273 12.8132 11.0587 13.4467C11.7441 13.68 12.3334 13.998 12.3334 14.3333C12.3334 14.9176 3.66675 14.9257 3.66675 14.3333C3.66675 13.998 4.25608 13.68 4.94141 13.4467C4.26191 12.803 3.82279 11.9657 3.62408 11.056C3.19075 11.724 2.80608 12.096 2.58341 12.006C1.626 11.6185 3.31478 7.90684 3.71141 7.06133Z" stroke="#7B7B7B" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6.11822 6.6L7.68822 7.89C7.85822 8.03 8.12822 8.03 8.29822 7.89L9.86822 6.6C10.1382 6.38 9.94822 6 9.56822 6H6.42822C6.04822 6 5.85822 6.38 6.12822 6.6H6.11822Z" fill="#7B7B7B"/>
</g>
<defs>
<clipPath id="clip0_3010_383">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-list-filter-icon lucide-list-filter"><path d="M3 6h18"/><path d="M7 12h10"/><path d="M10 18h4"/></svg>

Before

Width:  |  Height:  |  Size: 305 B

View File

@@ -1,3 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.66699 8H10.667M2.66699 4H13.333M2.66699 12H7.99999" stroke="black" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13.333 10H8M13.333 6H2.66701" stroke="black" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 251 B

After

Width:  |  Height:  |  Size: 227 B

View File

@@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.1645 4.45825L5.20344 9.52074C4.98225 9.74193 4.85798 10.0419 4.85798 10.3548C4.85798 10.6676 4.98225 10.9676 5.20344 11.1888C5.42464 11.41 5.72464 11.5342 6.03746 11.5342C6.35028 11.5342 6.65028 11.41 6.87148 11.1888L11.8326 6.12629C12.2749 5.68397 12.5234 5.08407 12.5234 4.45854C12.5234 3.83302 12.2749 3.23311 11.8326 2.7908C11.3902 2.34849 10.7903 2.1 10.1648 2.1C9.53928 2.1 8.93938 2.34849 8.49707 2.7908L3.55663 7.83265C3.22373 8.16017 2.95897 8.55037 2.77762 8.98072C2.59628 9.41108 2.50193 9.87308 2.50003 10.3401C2.49813 10.8071 2.58871 11.2698 2.76654 11.7017C2.94438 12.1335 3.20595 12.5258 3.53618 12.856C3.8664 13.1863 4.25873 13.4478 4.69055 13.6257C5.12237 13.8035 5.58513 13.8941 6.05213 13.8922C6.51913 13.8903 6.98114 13.7959 7.41149 13.6146C7.84185 13.4332 8.23204 13.1685 8.55957 12.8356L13.5 7.79373" stroke="#C4CAD4" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -1,6 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.5 5.50621L10.5941 3.41227C10.8585 3.14798 11.217 2.99953 11.5908 2.99957C11.9646 2.99962 12.3231 3.14816 12.5874 3.41252C12.8517 3.67688 13.0001 4.03541 13.0001 4.40922C13.0001 4.78304 12.8515 5.14152 12.5872 5.40582L10.493 7.5" stroke="black" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5.50789 8.5L3.92098 10.0869C3.80488 10.2027 3.71903 10.3452 3.67097 10.5019L3.01047 12.678C2.99754 12.7212 2.99657 12.7672 3.00764 12.8109C3.01872 12.8547 3.04143 12.8946 3.07337 12.9265C3.1053 12.9584 3.14528 12.981 3.18905 12.992C3.23282 13.003 3.27875 13.002 3.32197 12.989L5.49849 12.329C5.65508 12.2813 5.79758 12.196 5.91349 12.0805L7.49184 10.5019" stroke="black" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9 5L11 7" stroke="black" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3 3L13 13" stroke="black" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,4 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 12.375H13" stroke="black" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3 11.125L6.75003 7.375L3 3.62497" stroke="black" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 336 B

View File

@@ -1,3 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.9526 10.2625C10.0833 9.62316 9.9526 9.60566 10.9315 8.47946C11.5008 7.82461 11.9105 7.07306 11.9105 6.242C11.9105 5.22472 11.4979 4.2491 10.7637 3.52978C10.0294 2.81046 9.03338 2.40634 7.99491 2.40634C6.95644 2.40634 5.96051 2.81046 5.22619 3.52978C4.49189 4.2491 4.07935 5.22472 4.07935 6.242C4.07935 6.88128 4.20987 7.64842 5.05825 8.47946C6.03714 9.62442 5.90666 9.62316 6.03718 10.2625M9.9526 10.2625V12.3893C9.9526 13.0544 9.40223 13.5937 8.72319 13.5937H7.26665C6.58761 13.5937 6.03714 13.0544 6.03714 12.3893L6.03718 10.2625M9.9526 10.2625H7.99491H6.03718" stroke="black" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9.95231 10.2159C10.0803 9.58974 9.95231 9.57261 10.9111 8.46959C11.4686 7.82822 11.8699 7.09214 11.8699 6.27818C11.8699 5.28184 11.4658 4.32631 10.7467 3.62179C10.0275 2.91728 9.05201 2.52148 8.03492 2.52148C7.01782 2.52148 6.04239 2.91728 5.32319 3.62179C4.604 4.32631 4.19995 5.28184 4.19995 6.27818C4.19995 6.9043 4.32779 7.65565 5.1587 8.46959C6.11744 9.59098 5.98965 9.58974 6.11748 10.2159M9.95231 10.2159V12.2989C9.95231 12.9504 9.41327 13.4786 8.7482 13.4786H7.32165C6.65658 13.4786 6.11744 12.9504 6.11744 12.2989L6.11748 10.2159M9.95231 10.2159H8.03492H6.11748" stroke="black" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 762 B

After

Width:  |  Height:  |  Size: 768 B

View File

@@ -1,27 +1,27 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11 8.75V10.5C8.93097 10.5 8.06903 10.5 6 10.5V10L11 6V5.5H6V7.25" stroke="black" stroke-width="1.5"/>
<path d="M11 8.75V10.5C8.93097 10.5 8.06903 10.5 6 10.5V10L11 6V5.5H6V7.25" stroke="black" stroke-width="1.2"/>
<path d="M2 8.5C2.27614 8.5 2.5 8.27614 2.5 8C2.5 7.72386 2.27614 7.5 2 7.5C1.72386 7.5 1.5 7.72386 1.5 8C1.5 8.27614 1.72386 8.5 2 8.5Z" fill="black"/>
<path opacity="0.6" d="M2.99976 6.33002C3.2759 6.33002 3.49976 6.10616 3.49976 5.83002C3.49976 5.55387 3.2759 5.33002 2.99976 5.33002C2.72361 5.33002 2.49976 5.55387 2.49976 5.83002C2.49976 6.10616 2.72361 6.33002 2.99976 6.33002Z" fill="black"/>
<path opacity="0.6" d="M2.99976 10.66C3.2759 10.66 3.49976 10.4361 3.49976 10.16C3.49976 9.88383 3.2759 9.65997 2.99976 9.65997C2.72361 9.65997 2.49976 9.88383 2.49976 10.16C2.49976 10.4361 2.72361 10.66 2.99976 10.66Z" fill="black"/>
<path d="M2.99976 6.33002C3.2759 6.33002 3.49976 6.10616 3.49976 5.83002C3.49976 5.55387 3.2759 5.33002 2.99976 5.33002C2.72361 5.33002 2.49976 5.55387 2.49976 5.83002C2.49976 6.10616 2.72361 6.33002 2.99976 6.33002Z" fill="black"/>
<path d="M2.99976 10.66C3.2759 10.66 3.49976 10.4361 3.49976 10.16C3.49976 9.88383 3.2759 9.65997 2.99976 9.65997C2.72361 9.65997 2.49976 9.88383 2.49976 10.16C2.49976 10.4361 2.72361 10.66 2.99976 10.66Z" fill="black"/>
<path d="M15 8.5C15.2761 8.5 15.5 8.27614 15.5 8C15.5 7.72386 15.2761 7.5 15 7.5C14.7239 7.5 14.5 7.72386 14.5 8C14.5 8.27614 14.7239 8.5 15 8.5Z" fill="black"/>
<path opacity="0.6" d="M14 6.33002C14.2761 6.33002 14.5 6.10616 14.5 5.83002C14.5 5.55387 14.2761 5.33002 14 5.33002C13.7239 5.33002 13.5 5.55387 13.5 5.83002C13.5 6.10616 13.7239 6.33002 14 6.33002Z" fill="black"/>
<path opacity="0.6" d="M14 10.66C14.2761 10.66 14.5 10.4361 14.5 10.16C14.5 9.88383 14.2761 9.65997 14 9.65997C13.7239 9.65997 13.5 9.88383 13.5 10.16C13.5 10.4361 13.7239 10.66 14 10.66Z" fill="black"/>
<path d="M14 6.33002C14.2761 6.33002 14.5 6.10616 14.5 5.83002C14.5 5.55387 14.2761 5.33002 14 5.33002C13.7239 5.33002 13.5 5.55387 13.5 5.83002C13.5 6.10616 13.7239 6.33002 14 6.33002Z" fill="black"/>
<path d="M14 10.66C14.2761 10.66 14.5 10.4361 14.5 10.16C14.5 9.88383 14.2761 9.65997 14 9.65997C13.7239 9.65997 13.5 9.88383 13.5 10.16C13.5 10.4361 13.7239 10.66 14 10.66Z" fill="black"/>
<path d="M8.49219 2C8.76833 2 8.99219 1.77614 8.99219 1.5C8.99219 1.22386 8.76833 1 8.49219 1C8.21605 1 7.99219 1.22386 7.99219 1.5C7.99219 1.77614 8.21605 2 8.49219 2Z" fill="black"/>
<path opacity="0.6" d="M6 3C6.27614 3 6.5 2.77614 6.5 2.5C6.5 2.22386 6.27614 2 6 2C5.72386 2 5.5 2.22386 5.5 2.5C5.5 2.77614 5.72386 3 6 3Z" fill="black"/>
<path d="M6 3C6.27614 3 6.5 2.77614 6.5 2.5C6.5 2.22386 6.27614 2 6 2C5.72386 2 5.5 2.22386 5.5 2.5C5.5 2.77614 5.72386 3 6 3Z" fill="black"/>
<path d="M4 4C4.27614 4 4.5 3.77614 4.5 3.5C4.5 3.22386 4.27614 3 4 3C3.72386 3 3.5 3.22386 3.5 3.5C3.5 3.77614 3.72386 4 4 4Z" fill="black"/>
<path d="M3.99976 13C4.2759 13 4.49976 12.7761 4.49976 12.5C4.49976 12.2239 4.2759 12 3.99976 12C3.72361 12 3.49976 12.2239 3.49976 12.5C3.49976 12.7761 3.72361 13 3.99976 13Z" fill="black"/>
<path opacity="0.2" d="M2 12.5C2.27614 12.5 2.5 12.2761 2.5 12C2.5 11.7239 2.27614 11.5 2 11.5C1.72386 11.5 1.5 11.7239 1.5 12C1.5 12.2761 1.72386 12.5 2 12.5Z" fill="black"/>
<path opacity="0.2" d="M2 4.5C2.27614 4.5 2.5 4.27614 2.5 4C2.5 3.72386 2.27614 3.5 2 3.5C1.72386 3.5 1.5 3.72386 1.5 4C1.5 4.27614 1.72386 4.5 2 4.5Z" fill="black"/>
<path opacity="0.2" d="M15 12.5C15.2761 12.5 15.5 12.2761 15.5 12C15.5 11.7239 15.2761 11.5 15 11.5C14.7239 11.5 14.5 11.7239 14.5 12C14.5 12.2761 14.7239 12.5 15 12.5Z" fill="black"/>
<path opacity="0.2" d="M15 4.5C15.2761 4.5 15.5 4.27614 15.5 4C15.5 3.72386 15.2761 3.5 15 3.5C14.7239 3.5 14.5 3.72386 14.5 4C14.5 4.27614 14.7239 4.5 15 4.5Z" fill="black"/>
<path opacity="0.5" d="M3.99976 15C4.2759 15 4.49976 14.7761 4.49976 14.5C4.49976 14.2239 4.2759 14 3.99976 14C3.72361 14 3.49976 14.2239 3.49976 14.5C3.49976 14.7761 3.72361 15 3.99976 15Z" fill="black"/>
<path opacity="0.5" d="M4 2C4.27614 2 4.5 1.77614 4.5 1.5C4.5 1.22386 4.27614 1 4 1C3.72386 1 3.5 1.22386 3.5 1.5C3.5 1.77614 3.72386 2 4 2Z" fill="black"/>
<path opacity="0.5" d="M13 15C13.2761 15 13.5 14.7761 13.5 14.5C13.5 14.2239 13.2761 14 13 14C12.7239 14 12.5 14.2239 12.5 14.5C12.5 14.7761 12.7239 15 13 15Z" fill="black"/>
<path opacity="0.5" d="M13 2C13.2761 2 13.5 1.77614 13.5 1.5C13.5 1.22386 13.2761 1 13 1C12.7239 1 12.5 1.22386 12.5 1.5C12.5 1.77614 12.7239 2 13 2Z" fill="black"/>
<path d="M2 12.5C2.27614 12.5 2.5 12.2761 2.5 12C2.5 11.7239 2.27614 11.5 2 11.5C1.72386 11.5 1.5 11.7239 1.5 12C1.5 12.2761 1.72386 12.5 2 12.5Z" fill="black"/>
<path d="M2 4.5C2.27614 4.5 2.5 4.27614 2.5 4C2.5 3.72386 2.27614 3.5 2 3.5C1.72386 3.5 1.5 3.72386 1.5 4C1.5 4.27614 1.72386 4.5 2 4.5Z" fill="black"/>
<path d="M15 12.5C15.2761 12.5 15.5 12.2761 15.5 12C15.5 11.7239 15.2761 11.5 15 11.5C14.7239 11.5 14.5 11.7239 14.5 12C14.5 12.2761 14.7239 12.5 15 12.5Z" fill="black"/>
<path d="M15 4.5C15.2761 4.5 15.5 4.27614 15.5 4C15.5 3.72386 15.2761 3.5 15 3.5C14.7239 3.5 14.5 3.72386 14.5 4C14.5 4.27614 14.7239 4.5 15 4.5Z" fill="black"/>
<path d="M3.99976 15C4.2759 15 4.49976 14.7761 4.49976 14.5C4.49976 14.2239 4.2759 14 3.99976 14C3.72361 14 3.49976 14.2239 3.49976 14.5C3.49976 14.7761 3.72361 15 3.99976 15Z" fill="black"/>
<path d="M4 2C4.27614 2 4.5 1.77614 4.5 1.5C4.5 1.22386 4.27614 1 4 1C3.72386 1 3.5 1.22386 3.5 1.5C3.5 1.77614 3.72386 2 4 2Z" fill="black"/>
<path d="M13 15C13.2761 15 13.5 14.7761 13.5 14.5C13.5 14.2239 13.2761 14 13 14C12.7239 14 12.5 14.2239 12.5 14.5C12.5 14.7761 12.7239 15 13 15Z" fill="black"/>
<path d="M13 2C13.2761 2 13.5 1.77614 13.5 1.5C13.5 1.22386 13.2761 1 13 1C12.7239 1 12.5 1.22386 12.5 1.5C12.5 1.77614 12.7239 2 13 2Z" fill="black"/>
<path d="M13 4C13.2761 4 13.5 3.77614 13.5 3.5C13.5 3.22386 13.2761 3 13 3C12.7239 3 12.5 3.22386 12.5 3.5C12.5 3.77614 12.7239 4 13 4Z" fill="black"/>
<path d="M13 13C13.2761 13 13.5 12.7761 13.5 12.5C13.5 12.2239 13.2761 12 13 12C12.7239 12 12.5 12.2239 12.5 12.5C12.5 12.7761 12.7239 13 13 13Z" fill="black"/>
<path opacity="0.6" d="M11 3C11.2761 3 11.5 2.77614 11.5 2.5C11.5 2.22386 11.2761 2 11 2C10.7239 2 10.5 2.22386 10.5 2.5C10.5 2.77614 10.7239 3 11 3Z" fill="black"/>
<path d="M11 3C11.2761 3 11.5 2.77614 11.5 2.5C11.5 2.22386 11.2761 2 11 2C10.7239 2 10.5 2.22386 10.5 2.5C10.5 2.77614 10.7239 3 11 3Z" fill="black"/>
<path d="M8.5 15C8.77614 15 9 14.7761 9 14.5C9 14.2239 8.77614 14 8.5 14C8.22386 14 8 14.2239 8 14.5C8 14.7761 8.22386 15 8.5 15Z" fill="black"/>
<path opacity="0.6" d="M6 14C6.27614 14 6.5 13.7761 6.5 13.5C6.5 13.2239 6.27614 13 6 13C5.72386 13 5.5 13.2239 5.5 13.5C5.5 13.7761 5.72386 14 6 14Z" fill="black"/>
<path opacity="0.6" d="M11 14C11.2761 14 11.5 13.7761 11.5 13.5C11.5 13.2239 11.2761 13 11 13C10.7239 13 10.5 13.2239 10.5 13.5C10.5 13.7761 10.7239 14 11 14Z" fill="black"/>
<path d="M6 14C6.27614 14 6.5 13.7761 6.5 13.5C6.5 13.2239 6.27614 13 6 13C5.72386 13 5.5 13.2239 5.5 13.5C5.5 13.7761 5.72386 14 6 14Z" fill="black"/>
<path d="M11 14C11.2761 14 11.5 13.7761 11.5 13.5C11.5 13.2239 11.2761 13 11 13C10.7239 13 10.5 13.2239 10.5 13.5C10.5 13.7761 10.7239 14 11 14Z" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -1,5 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 2.93652L6.9243 6.20697C6.86924 6.37435 6.77565 6.52646 6.65105 6.65105C6.52646 6.77565 6.37435 6.86924 6.20697 6.9243L2.93652 8L6.20697 9.0757C6.37435 9.13076 6.52646 9.22435 6.65105 9.34895C6.77565 9.47354 6.86924 9.62565 6.9243 9.79306L8 13.0635L9.0757 9.79306C9.13076 9.62565 9.22435 9.47354 9.34895 9.34895C9.47354 9.22435 9.62565 9.13076 9.79306 9.0757L13.0635 8L9.79306 6.9243C9.62565 6.86924 9.47354 6.77565 9.34895 6.65105C9.22435 6.52646 9.13076 6.37435 9.0757 6.20697L8 2.93652Z" fill="black" fill-opacity="0.15" stroke="black" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3.33334 2V4.66666M2 3.33334H4.66666" stroke="black" stroke-opacity="0.75" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12.6665 11.3333V14M11.3333 12.6666H13.9999" stroke="black" stroke-opacity="0.75" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3.33334 2V4.66666M2 3.33334H4.66666" stroke="black" stroke-opacity="0.75" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12.6665 11.3333V14M11.3333 12.6666H13.9999" stroke="black" stroke-opacity="0.75" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 176 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="160" height="61" fill="none"><g clip-path="url(#a)"><path fill="#000" d="M130.75.385c5.428 0 10.297 2.81 13.011 7.511l14.214 24.618-.013-.005c2.599 4.504 2.707 9.932.28 14.513-2.618 4.944-7.862 8.015-13.679 8.015h-31.811c-.452 0-.873-.242-1.103-.637a1.268 1.268 0 0 1 0-1.274l3.919-6.78c.223-.394.65-.636 1.102-.636h28.288a5.622 5.622 0 0 0 4.925-2.849 5.615 5.615 0 0 0 0-5.69l-14.214-24.617a5.621 5.621 0 0 0-4.925-2.848 5.621 5.621 0 0 0-4.925 2.848l-14.214 24.618a6.267 6.267 0 0 0-.319.643.998.998 0 0 1-.069.14L101.724 54.4l-.823 1.313-2.529 4.39a1.27 1.27 0 0 1-1.103.636h-7.83c-.452 0-.873-.242-1.102-.637-.23-.394-.23-.879 0-1.274l2.188-3.791H66.803c-3.32 0-6.454-1.122-8.818-3.167a17.141 17.141 0 0 1-3.394-3.96 1.261 1.261 0 0 1-.091-.137L34.2 12.573a5.622 5.622 0 0 0-4.925-2.849 5.621 5.621 0 0 0-4.924 2.85L10.137 37.19a5.615 5.615 0 0 0 0 5.69 5.63 5.63 0 0 0 4.925 2.841h29.862a1.276 1.276 0 0 1 1.102 1.912l-3.912 6.778a1.27 1.27 0 0 1-1.102.638H14.495c-3.32 0-6.454-1.128-8.817-3.173-5.906-5.104-7.36-12.883-3.62-19.363L16.267 7.89C18.872 3.385 23.517.583 28.697.39c.184-.006.356-.006.534-.006 5.378 0 10.45 3.007 13.246 7.85l12.986 22.372L68.58 7.891C71.186 3.385 75.83.582 81.01.39c.185-.006.358-.006.536-.006 4.453 0 8.71 2.039 11.672 5.588.337.407.388.98.127 1.446l-3.765 6.6a1.268 1.268 0 0 1-2.205.006l-.847-1.465a5.623 5.623 0 0 0-4.926-2.848 5.622 5.622 0 0 0-4.924 2.848L62.464 37.18a5.614 5.614 0 0 0 0 5.689 5.628 5.628 0 0 0 4.925 2.842H95.91L117.76 7.87c2.714-4.683 7.575-7.486 12.99-7.486Z"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 .385h160v60.36H0z"/></clipPath></defs></svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -1,46 +0,0 @@
<svg width="257" height="47" viewBox="0 0 257 47" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_100_26)">
<path d="M119.922 24.4481L109.212 5.8996C107.081 2.20815 103.26 0 98.9973 0C94.7394 0 90.9279 2.19855 88.7918 5.8804L66.6239 44.2734C66.3646 44.7198 66.3646 45.2671 66.6239 45.7135C66.8831 46.1599 67.3583 46.4336 67.8719 46.4336H73.7715C74.2852 46.4336 74.7604 46.1599 75.0196 45.7135L76.9302 42.4013L77.5158 41.4652C77.5158 41.4652 77.535 41.4364 77.5398 41.422L84.6923 29.0324C84.7211 28.9844 84.7499 28.9316 84.7691 28.874C84.8363 28.7203 84.9035 28.5763 84.9851 28.4419L95.6946 9.89347C96.3811 8.70299 97.6148 7.98774 98.9925 7.98774C100.37 7.98774 101.604 8.69819 102.29 9.89347L113 28.4419C113.686 29.6324 113.691 31.0581 113 32.2486C112.313 33.4391 111.08 34.1543 109.702 34.1543H102.232C101.718 34.1543 101.243 34.4279 100.984 34.8744L98.0318 39.9819C97.7726 40.4283 97.7726 40.9756 98.0318 41.422C98.291 41.8684 98.7662 42.1421 99.2799 42.1421H109.404C113.965 42.1421 118.079 39.7275 120.133 35.844C122.039 32.2438 121.957 27.9859 119.912 24.4433L119.922 24.4481Z" fill="white"/>
<path d="M82.8564 34.1538H104.17L103.872 42.1416H79.9042C79.3905 42.1416 78.9153 41.8679 78.6561 41.4215C78.3969 40.9751 78.3969 40.4278 78.6561 39.9814L81.6083 34.8739C81.8675 34.4274 82.3427 34.1538 82.8564 34.1538Z" fill="url(#paint0_linear_100_26)"/>
<path d="M43.7123 25.1535C43.7123 24.9039 43.6451 24.659 43.5155 24.443L32.8972 6.14897C30.7131 2.36152 26.7288 -0.000244141 22.5093 -0.000244141C22.3701 -0.000244141 22.2309 -0.000244141 22.0869 0.00935651C18.0162 0.158167 14.368 2.36152 12.323 5.89936L1.61829 24.4478C-1.31951 29.5314 -0.181833 35.6374 4.44568 39.6361C6.31301 41.2538 8.78518 42.1418 11.4062 42.1418H31.3851C31.8987 42.1418 32.374 41.8682 32.6332 41.4218L35.5806 36.3142C35.8398 35.8678 35.8398 35.3206 35.5806 34.8741C35.3214 34.4277 34.8461 34.1541 34.3325 34.1541H11.8334C10.4557 34.1541 9.22201 33.4436 8.53556 32.2532C7.84431 31.0627 7.84431 29.6418 8.53556 28.4465L19.2451 9.89803C19.9315 8.70755 21.1652 7.9923 22.5429 7.9923C23.9206 7.9923 25.1495 8.70275 25.8407 9.89803L41.1346 36.4198C41.461 36.9863 42.1282 37.2599 42.7619 37.0919C43.3955 36.9191 43.8276 36.343 43.8228 35.6902L43.7171 25.1583L43.7123 25.1535Z" fill="url(#paint1_linear_100_26)"/>
<path d="M4.44544 39.6362C-0.182077 35.6376 -1.31975 29.5315 1.61805 24.448L8.53532 28.4467C7.84407 29.6419 7.84407 31.0628 8.53532 32.2533C9.22176 33.4438 10.4554 34.1543 11.8331 34.1543H34.3323C34.8459 34.1543 35.3211 34.4279 35.5804 34.8743C35.8396 35.3207 35.8396 35.868 35.5804 36.3144L32.633 41.422C32.3737 41.8684 31.8985 42.142 31.3849 42.142H11.4059C8.78493 42.142 6.31276 41.2539 4.44544 39.6362Z" fill="white"/>
<path d="M74.6308 34.8696C74.3716 34.4231 73.8964 34.1495 73.3827 34.1495H51.2532C49.8755 34.1495 48.6418 33.4391 47.9554 32.2486C47.2642 31.0581 47.2642 29.6372 47.9554 28.4419L58.6649 9.89347C59.3514 8.70299 60.5851 7.98774 61.9628 7.98774C63.3404 7.98774 64.5693 8.69819 65.2606 9.89347L65.899 10.9975C66.1582 11.444 66.6335 11.7176 67.1471 11.7176C67.6607 11.7176 68.1408 11.4392 68.3952 10.9927L71.2322 6.01961C71.5298 5.49637 71.4722 4.84353 71.0882 4.3827C68.7648 1.59851 65.4238 0 61.9291 0C61.7899 0 61.6507 0 61.5067 0.00960065C57.436 0.158411 53.7878 2.36176 51.7429 5.8996L41.0333 24.4481C38.0955 29.5316 39.2332 35.6376 43.8607 39.6363C45.728 41.254 48.2002 42.1421 50.8212 42.1421H70.4257C70.9394 42.1421 71.4146 41.8684 71.6738 41.422L74.626 36.3145C74.8852 35.868 74.8852 35.3208 74.626 34.8744L74.6308 34.8696Z" fill="url(#paint2_linear_100_26)"/>
</g>
<path d="M132.976 15.5649V14.6449C133.383 14.6449 133.695 14.5359 133.911 14.3178C134.128 14.0998 134.311 13.8067 134.461 13.4388C134.61 13.0571 134.773 12.6346 134.949 12.1712L139.057 0.865676H139.871L144.325 12.3348C144.434 12.5937 144.556 12.9481 144.692 13.3979C144.827 13.834 144.888 14.2088 144.875 14.5223C145.105 14.495 145.329 14.4814 145.546 14.4814C145.776 14.4678 145.993 14.4541 146.197 14.4405V15.5649H141.254V14.6654C141.729 14.6518 142.041 14.5495 142.19 14.3587C142.352 14.1543 142.413 13.909 142.373 13.6227C142.346 13.3365 142.278 13.0503 142.169 12.7641L141.559 11.1081L136.576 11.2308L135.986 13.0094C135.905 13.282 135.817 13.541 135.722 13.7863C135.627 14.0316 135.532 14.2701 135.437 14.5018C135.681 14.4746 135.939 14.461 136.21 14.461C136.495 14.4473 136.745 14.4337 136.962 14.4201V15.5649H132.976ZM136.942 10.1268H141.213L139.932 6.67178C139.769 6.22201 139.613 5.77906 139.464 5.34292C139.315 4.89315 139.179 4.46382 139.057 4.05494H139.037C138.929 4.39568 138.807 4.77048 138.671 5.17937C138.535 5.58825 138.379 6.0312 138.203 6.50823L136.942 10.1268Z" fill="white"/>
<path d="M151.397 21.1053C150.204 21.1053 149.241 20.969 148.509 20.6964C147.791 20.4374 147.268 20.0967 146.943 19.6742C146.631 19.2653 146.475 18.8292 146.475 18.3658C146.475 17.9978 146.557 17.657 146.719 17.3436C146.896 17.0301 147.126 16.7507 147.411 16.5054C147.696 16.2737 148.014 16.0897 148.367 15.9534C147.892 15.8034 147.533 15.5922 147.289 15.3196C147.045 15.0334 146.923 14.6858 146.923 14.277C146.923 13.8408 147.092 13.4115 147.431 12.989C147.784 12.5665 148.285 12.2803 148.936 12.1303C148.326 11.8577 147.838 11.4625 147.472 10.9446C147.106 10.4267 146.916 9.81334 146.902 9.10462C146.889 8.28686 147.092 7.57132 147.513 6.95799C147.946 6.34467 148.496 5.86765 149.16 5.52691C149.838 5.18618 150.543 5.01581 151.275 5.01581C151.696 5.01581 152.13 5.07714 152.577 5.19981C153.025 5.30884 153.431 5.48603 153.798 5.73135C153.947 5.3361 154.143 4.97492 154.387 4.64782C154.631 4.32072 154.916 4.06176 155.242 3.87095C155.581 3.68014 155.933 3.58473 156.299 3.58473C156.693 3.58473 156.991 3.68695 157.194 3.89139C157.398 4.09583 157.499 4.36842 157.499 4.70915C157.499 4.81819 157.465 4.95448 157.398 5.11803C157.343 5.26796 157.242 5.39743 157.093 5.50647C156.943 5.6155 156.74 5.67002 156.482 5.67002C156.265 5.67002 156.069 5.60187 155.893 5.46558C155.73 5.31566 155.628 5.13848 155.587 4.93404C155.303 4.98855 155.065 5.15892 154.876 5.44514C154.699 5.71772 154.584 5.99713 154.53 6.28334C154.882 6.59682 155.154 6.97162 155.343 7.40776C155.547 7.83027 155.648 8.28686 155.648 8.77751C155.648 9.55439 155.438 10.2427 155.018 10.8424C154.611 11.4421 154.076 11.9123 153.411 12.253C152.747 12.5937 152.028 12.7641 151.255 12.7641C151.025 12.7641 150.808 12.7505 150.604 12.7232C150.401 12.6823 150.177 12.6619 149.933 12.6619C149.499 12.6619 149.14 12.7641 148.855 12.9685C148.584 13.173 148.482 13.4183 148.55 13.7045C148.618 14.0044 148.902 14.202 149.404 14.2974C149.906 14.3928 150.631 14.461 151.581 14.5018C152.625 14.5427 153.52 14.6722 154.265 14.8903C155.025 15.0947 155.608 15.415 156.015 15.8511C156.435 16.2873 156.645 16.8802 156.645 17.6298C156.645 18.1886 156.489 18.6861 156.177 19.1222C155.879 19.5583 155.472 19.9195 154.957 20.2057C154.455 20.5056 153.892 20.7305 153.269 20.8804C152.645 21.0303 152.021 21.1053 151.397 21.1053ZM151.581 20.1035C152.679 20.1035 153.526 19.8991 154.123 19.4902C154.733 19.0813 155.038 18.6179 155.038 18.1C155.038 17.6638 154.889 17.3231 154.591 17.0778C154.292 16.8461 153.872 16.6757 153.33 16.5667C152.801 16.4713 152.177 16.4168 151.458 16.4031C151.106 16.3759 150.747 16.3554 150.38 16.3418C150.014 16.3282 149.675 16.2941 149.363 16.2396C149.052 16.4577 148.808 16.7234 148.631 17.0369C148.469 17.3504 148.38 17.6775 148.367 18.0182C148.367 18.6452 148.658 19.1494 149.241 19.5311C149.825 19.9127 150.604 20.1035 151.581 20.1035ZM151.316 11.8032C151.777 11.8032 152.157 11.6874 152.455 11.4557C152.767 11.2104 152.998 10.8901 153.147 10.4948C153.309 10.0859 153.391 9.64298 153.391 9.16595C153.391 8.60715 153.309 8.08242 153.147 7.59176C152.984 7.1011 152.747 6.70585 152.435 6.40601C152.123 6.10616 151.723 5.95624 151.235 5.95624C150.57 5.95624 150.055 6.22201 149.689 6.75356C149.323 7.2851 149.14 7.92568 149.14 8.67529C149.14 9.27499 149.221 9.81334 149.384 10.2904C149.56 10.7538 149.811 11.1218 150.136 11.3943C150.462 11.6669 150.855 11.8032 151.316 11.8032Z" fill="white"/>
<path d="M162.5 15.892C161.551 15.892 160.696 15.674 159.937 15.2378C159.191 14.7881 158.601 14.1611 158.168 13.357C157.734 12.5392 157.517 11.5783 157.517 10.4744C157.517 9.52031 157.727 8.62759 158.147 7.7962C158.581 6.96481 159.185 6.29697 159.957 5.79269C160.73 5.27477 161.625 5.01581 162.642 5.01581C163.212 5.01581 163.747 5.1044 164.249 5.28159C164.764 5.45877 165.219 5.73817 165.612 6.11979C166.019 6.48778 166.337 6.97162 166.568 7.57132C166.798 8.15738 166.914 8.87292 166.914 9.71794L159.917 9.8406C159.917 10.7674 160.018 11.592 160.222 12.3143C160.439 13.0367 160.785 13.5955 161.259 13.9907C161.734 14.386 162.351 14.5836 163.11 14.5836C163.476 14.5836 163.863 14.5223 164.27 14.3996C164.69 14.2633 165.083 14.0725 165.449 13.8272C165.829 13.5819 166.148 13.2888 166.405 12.9481L167.036 13.5001C166.629 14.1134 166.161 14.5972 165.632 14.9516C165.103 15.2923 164.561 15.5309 164.005 15.6672C163.463 15.8171 162.961 15.892 162.5 15.892ZM159.998 8.77751H164.697C164.697 8.2596 164.622 7.7962 164.473 7.38732C164.337 6.96481 164.12 6.63089 163.822 6.38556C163.524 6.14023 163.144 6.01757 162.683 6.01757C161.964 6.01757 161.374 6.24927 160.913 6.71267C160.452 7.16244 160.147 7.85072 159.998 8.77751Z" fill="white"/>
<path d="M168.419 15.5649V14.7063C168.826 14.7063 169.111 14.6109 169.273 14.4201C169.436 14.2293 169.531 13.9635 169.558 13.6227C169.599 13.282 169.619 12.8868 169.619 12.437L169.64 8.18464C169.64 7.96657 169.64 7.73487 169.64 7.48954C169.653 7.23058 169.68 6.97844 169.721 6.73311C169.477 6.74674 169.226 6.76037 168.968 6.774C168.724 6.774 168.494 6.78081 168.277 6.79444V5.71091C168.887 5.71091 169.362 5.68365 169.701 5.62913C170.053 5.56099 170.318 5.48603 170.494 5.40425C170.684 5.32247 170.826 5.23388 170.921 5.13848H171.653C171.667 5.26114 171.673 5.37699 171.673 5.48603C171.687 5.59506 171.694 5.71091 171.694 5.83357C171.707 5.95624 171.721 6.11298 171.735 6.30379C172.033 6.05846 172.358 5.84039 172.711 5.64958C173.063 5.45877 173.429 5.30884 173.809 5.19981C174.202 5.07714 174.575 5.01581 174.928 5.01581C176.135 5.01581 177.003 5.38381 177.531 6.11979C178.074 6.85578 178.345 8.00745 178.345 9.57483V13.0299C178.345 13.2752 178.338 13.5273 178.325 13.7863C178.311 14.0316 178.291 14.2838 178.264 14.5427C178.481 14.5291 178.697 14.5223 178.914 14.5223C179.145 14.5087 179.355 14.495 179.545 14.4814V15.5649H175.009V14.7063C175.416 14.7063 175.701 14.6109 175.863 14.4201C176.026 14.2293 176.121 13.9635 176.148 13.6227C176.189 13.282 176.209 12.8868 176.209 12.437V9.57483C176.196 8.49811 176.019 7.68717 175.68 7.14199C175.355 6.59682 174.826 6.33105 174.094 6.34467C173.66 6.34467 173.233 6.45371 172.813 6.67178C172.392 6.88985 172.04 7.15562 171.755 7.4691C171.755 7.60539 171.755 7.75531 171.755 7.91886C171.755 8.06879 171.755 8.22552 171.755 8.38908V13.0299C171.755 13.2752 171.748 13.5273 171.735 13.7863C171.721 14.0316 171.701 14.2838 171.673 14.5427C171.89 14.5291 172.107 14.5223 172.324 14.5223C172.555 14.5087 172.765 14.495 172.955 14.4814V15.5649H168.419Z" fill="white"/>
<path d="M184.495 15.892C184.156 15.892 183.81 15.8443 183.458 15.7489C183.119 15.6671 182.807 15.4968 182.522 15.2378C182.237 14.9652 182.014 14.5768 181.851 14.0725C181.688 13.5682 181.607 12.9004 181.607 12.069L181.648 6.48778H180.142V5.34292C180.509 5.32929 180.881 5.19299 181.261 4.93404C181.641 4.67508 181.973 4.32753 182.258 3.89139C182.543 3.45525 182.739 2.98504 182.848 2.48075H183.804V5.34292H186.936V6.40601L183.804 6.4469L183.763 11.9054C183.763 12.4234 183.804 12.8799 183.885 13.2752C183.98 13.6568 184.129 13.9567 184.332 14.1747C184.549 14.3792 184.841 14.4814 185.207 14.4814C185.519 14.4814 185.838 14.386 186.163 14.1952C186.502 14.0044 186.821 13.6909 187.119 13.2548L187.811 13.8681C187.485 14.3451 187.16 14.7199 186.834 14.9925C186.509 15.2651 186.197 15.4627 185.899 15.5854C185.6 15.7217 185.329 15.8034 185.085 15.8307C184.841 15.8716 184.644 15.892 184.495 15.892Z" fill="white"/>
<path d="M188.83 21.1053L187.508 20.2671L199.224 0.0683594L200.708 1.00878L188.83 21.1053Z" fill="white"/>
<path d="M212.664 5.81313C212.515 4.58649 212.095 3.64606 211.403 2.99185C210.712 2.32402 209.81 1.98328 208.698 1.96965C207.993 1.96965 207.342 2.12639 206.745 2.43987C206.149 2.75334 205.633 3.19629 205.199 3.76873C204.766 4.32753 204.427 4.99537 204.182 5.77224C203.952 6.53549 203.837 7.37369 203.837 8.28686C203.837 9.52713 204.054 10.6311 204.488 11.5988C204.921 12.5528 205.518 13.2956 206.277 13.8272C207.05 14.3587 207.925 14.6245 208.901 14.6245C209.769 14.6245 210.623 14.4201 211.464 14.0112C212.318 13.5887 213.023 12.9958 213.579 12.2326L214.251 12.805C213.64 13.65 212.99 14.2974 212.298 14.7472C211.606 15.1969 210.915 15.4968 210.223 15.6467C209.545 15.8103 208.928 15.892 208.372 15.892C207.355 15.892 206.42 15.708 205.566 15.34C204.711 14.9721 203.972 14.461 203.349 13.8067C202.738 13.1389 202.264 12.3688 201.925 11.4966C201.599 10.6107 201.437 9.65661 201.437 8.63441C201.437 7.68035 201.586 6.74674 201.884 5.83357C202.182 4.92041 202.623 4.09583 203.206 3.35985C203.789 2.61023 204.521 2.01736 205.403 1.58122C206.298 1.14508 207.335 0.927008 208.515 0.927008C209.206 0.927008 209.878 1.02241 210.528 1.21322C211.193 1.40404 211.83 1.69707 212.44 2.09232L212.339 1.07012H213.6V5.81313H212.664Z" fill="white"/>
<path d="M215.152 14.7063C215.559 14.7063 215.844 14.6109 216.006 14.4201C216.169 14.2293 216.264 13.9635 216.291 13.6227C216.332 13.282 216.352 12.8868 216.352 12.437V3.19629C216.352 2.9646 216.352 2.7329 216.352 2.5012C216.366 2.25587 216.386 1.99691 216.413 1.72432C216.183 1.73795 215.938 1.75158 215.681 1.76521C215.423 1.76521 215.193 1.77203 214.989 1.78566V0.702123C215.599 0.702123 216.081 0.674865 216.433 0.620348C216.799 0.552201 217.077 0.477239 217.267 0.395463C217.471 0.313687 217.62 0.225096 217.715 0.129691H218.488V13.0299C218.488 13.2752 218.481 13.5273 218.467 13.7863C218.454 14.0316 218.433 14.2838 218.406 14.5427C218.623 14.5291 218.84 14.5223 219.057 14.5223C219.288 14.5087 219.498 14.495 219.688 14.4814V15.5649H215.152V14.7063Z" fill="white"/>
<path d="M220.993 14.7063C221.399 14.7063 221.684 14.6109 221.847 14.4201C222.01 14.2293 222.105 13.9635 222.132 13.6227C222.172 13.282 222.193 12.8868 222.193 12.437V8.20508C222.193 7.97338 222.199 7.74168 222.213 7.50998C222.227 7.26466 222.247 7.0057 222.274 6.73311C222.044 6.74674 221.799 6.76037 221.542 6.774C221.284 6.774 221.047 6.78081 220.83 6.79444V5.71091C221.44 5.71091 221.921 5.68365 222.274 5.62913C222.64 5.56099 222.918 5.48603 223.108 5.40425C223.311 5.32247 223.461 5.23388 223.555 5.13848H224.328V13.0299C224.328 13.2752 224.322 13.5273 224.308 13.7863C224.294 14.0316 224.274 14.2838 224.247 14.5427C224.464 14.5291 224.681 14.5223 224.898 14.5223C225.128 14.5087 225.339 14.495 225.528 14.4814V15.5649H220.993V14.7063ZM223.149 3.25763C222.796 3.25763 222.498 3.12815 222.254 2.86919C222.01 2.5966 221.888 2.2695 221.888 1.88788C221.888 1.50626 222.016 1.18597 222.274 0.927008C222.532 0.654421 222.823 0.518127 223.149 0.518127C223.501 0.518127 223.793 0.654421 224.023 0.927008C224.267 1.18597 224.389 1.50626 224.389 1.88788C224.389 2.2695 224.267 2.5966 224.023 2.86919C223.793 3.12815 223.501 3.25763 223.149 3.25763Z" fill="white"/>
<path d="M231.689 15.892C230.74 15.892 229.886 15.674 229.126 15.2378C228.381 14.7881 227.791 14.1611 227.357 13.357C226.923 12.5392 226.706 11.5783 226.706 10.4744C226.706 9.52031 226.916 8.62759 227.337 7.7962C227.771 6.96481 228.374 6.29697 229.147 5.79269C229.92 5.27477 230.815 5.01581 231.832 5.01581C232.401 5.01581 232.937 5.1044 233.439 5.28159C233.954 5.45877 234.408 5.73817 234.801 6.11979C235.208 6.48778 235.527 6.97162 235.757 7.57132C235.988 8.15738 236.103 8.87292 236.103 9.71794L229.106 9.8406C229.106 10.7674 229.208 11.592 229.411 12.3143C229.628 13.0367 229.974 13.5955 230.449 13.9907C230.923 14.386 231.54 14.5836 232.299 14.5836C232.666 14.5836 233.052 14.5223 233.459 14.3996C233.879 14.2633 234.272 14.0725 234.639 13.8272C235.018 13.5819 235.337 13.2888 235.595 12.9481L236.225 13.5001C235.818 14.1134 235.35 14.5972 234.822 14.9516C234.293 15.2923 233.75 15.5309 233.194 15.6672C232.652 15.8171 232.15 15.892 231.689 15.892ZM229.188 8.77751H233.886C233.886 8.2596 233.811 7.7962 233.662 7.38732C233.527 6.96481 233.31 6.63089 233.011 6.38556C232.713 6.14023 232.333 6.01757 231.872 6.01757C231.154 6.01757 230.564 6.24927 230.103 6.71267C229.642 7.16244 229.337 7.85072 229.188 8.77751Z" fill="white"/>
<path d="M237.608 15.5649V14.7063C238.015 14.7063 238.3 14.6109 238.463 14.4201C238.625 14.2293 238.72 13.9635 238.748 13.6227C238.788 13.282 238.809 12.8868 238.809 12.437L238.829 8.18464C238.829 7.96657 238.829 7.73487 238.829 7.48954C238.842 7.23058 238.87 6.97844 238.91 6.73311C238.666 6.74674 238.415 6.76037 238.158 6.774C237.914 6.774 237.683 6.78081 237.466 6.79444V5.71091C238.076 5.71091 238.551 5.68365 238.89 5.62913C239.242 5.56099 239.507 5.48603 239.683 5.40425C239.873 5.32247 240.015 5.23388 240.11 5.13848H240.842C240.856 5.26114 240.863 5.37699 240.863 5.48603C240.876 5.59506 240.883 5.71091 240.883 5.83357C240.897 5.95624 240.91 6.11298 240.924 6.30379C241.222 6.05846 241.548 5.84039 241.9 5.64958C242.253 5.45877 242.619 5.30884 242.999 5.19981C243.392 5.07714 243.765 5.01581 244.117 5.01581C245.324 5.01581 246.192 5.38381 246.721 6.11979C247.263 6.85578 247.534 8.00745 247.534 9.57483V13.0299C247.534 13.2752 247.528 13.5273 247.514 13.7863C247.5 14.0316 247.48 14.2838 247.453 14.5427C247.67 14.5291 247.887 14.5223 248.104 14.5223C248.334 14.5087 248.544 14.495 248.734 14.4814V15.5649H244.199V14.7063C244.605 14.7063 244.89 14.6109 245.053 14.4201C245.216 14.2293 245.31 13.9635 245.338 13.6227C245.378 13.282 245.399 12.8868 245.399 12.437V9.57483C245.385 8.49811 245.209 7.68717 244.87 7.14199C244.544 6.59682 244.016 6.33105 243.283 6.34467C242.849 6.34467 242.422 6.45371 242.002 6.67178C241.582 6.88985 241.229 7.15562 240.944 7.4691C240.944 7.60539 240.944 7.75531 240.944 7.91886C240.944 8.06879 240.944 8.22552 240.944 8.38908V13.0299C240.944 13.2752 240.937 13.5273 240.924 13.7863C240.91 14.0316 240.89 14.2838 240.863 14.5427C241.08 14.5291 241.297 14.5223 241.514 14.5223C241.744 14.5087 241.954 14.495 242.144 14.4814V15.5649H237.608Z" fill="white"/>
<path d="M253.685 15.892C253.346 15.892 253 15.8443 252.647 15.7489C252.308 15.6671 251.996 15.4968 251.712 15.2378C251.427 14.9652 251.203 14.5768 251.04 14.0725C250.878 13.5682 250.796 12.9004 250.796 12.069L250.837 6.48778H249.332V5.34292C249.698 5.32929 250.071 5.19299 250.451 4.93404C250.83 4.67508 251.162 4.32753 251.447 3.89139C251.732 3.45525 251.929 2.98504 252.037 2.48075H252.993V5.34292H256.125V6.40601L252.993 6.4469L252.952 11.9054C252.952 12.4234 252.993 12.8799 253.074 13.2752C253.169 13.6568 253.318 13.9567 253.522 14.1747C253.739 14.3792 254.03 14.4814 254.396 14.4814C254.708 14.4814 255.027 14.386 255.352 14.1952C255.691 14.0044 256.01 13.6909 256.308 13.2548L257 13.8681C256.674 14.3451 256.349 14.7199 256.024 14.9925C255.698 15.2651 255.386 15.4627 255.088 15.5854C254.79 15.7217 254.518 15.8034 254.274 15.8307C254.03 15.8716 253.834 15.892 253.685 15.892Z" fill="white"/>
<path d="M134.115 40.8445C134.562 40.8173 134.881 40.7219 135.071 40.5583C135.274 40.3948 135.403 40.1494 135.457 39.8223C135.512 39.4952 135.539 39.0795 135.539 38.5752V30.0705C135.539 29.7707 135.545 29.4845 135.559 29.2119C135.573 28.9257 135.586 28.6803 135.6 28.4759C135.369 28.4895 135.118 28.5032 134.847 28.5168C134.576 28.5304 134.332 28.544 134.115 28.5577V27.4333C134.915 27.4196 135.728 27.4128 136.556 27.4128C137.383 27.3992 138.223 27.3924 139.078 27.3924C140.352 27.3924 141.43 27.5491 142.312 27.8626C143.207 28.1624 143.892 28.6258 144.366 29.2528C144.854 29.8661 145.105 30.643 145.119 31.5834C145.132 32.1149 145.037 32.6669 144.834 33.2394C144.631 33.7982 144.285 34.3229 143.797 34.8135C143.308 35.2906 142.644 35.679 141.803 35.9789C140.976 36.2787 139.932 36.4286 138.671 36.4286C138.535 36.4423 138.379 36.4491 138.203 36.4491C138.04 36.4491 137.871 36.4423 137.695 36.4286V39.0046C137.695 39.3726 137.688 39.7065 137.674 40.0063C137.674 40.2925 137.661 40.5242 137.634 40.7014C137.823 40.6878 138.027 40.6742 138.244 40.6605C138.461 40.6469 138.671 40.6401 138.874 40.6401C139.091 40.6265 139.288 40.6128 139.464 40.5992V41.7441H134.115V40.8445ZM137.695 35.3451C137.925 35.3724 138.122 35.3928 138.285 35.4064C138.461 35.4064 138.664 35.4064 138.895 35.4064C139.654 35.4064 140.325 35.2633 140.908 34.9771C141.491 34.6909 141.946 34.2752 142.271 33.73C142.597 33.1848 142.759 32.5375 142.759 31.7878C142.759 31.1336 142.658 30.5885 142.454 30.1523C142.264 29.7025 141.993 29.355 141.641 29.1097C141.302 28.8507 140.908 28.6667 140.461 28.5577C140.013 28.4486 139.539 28.3941 139.037 28.3941C138.63 28.3941 138.332 28.4759 138.142 28.6395C137.952 28.803 137.83 29.0415 137.776 29.355C137.722 29.6685 137.695 30.0705 137.695 30.5612V35.3451Z" fill="white"/>
<path d="M146.262 40.8854C146.668 40.8854 146.953 40.79 147.116 40.5992C147.278 40.4084 147.373 40.1426 147.401 39.8019C147.441 39.4612 147.462 39.0659 147.462 38.6161V34.3638C147.462 34.1457 147.462 33.914 147.462 33.6687C147.475 33.4097 147.502 33.1576 147.543 32.9123C147.312 32.9259 147.068 32.9395 146.811 32.9531C146.553 32.9531 146.316 32.96 146.099 32.9736V31.8901H146.79C147.36 31.8901 147.794 31.8287 148.092 31.7061C148.39 31.5834 148.607 31.4539 148.743 31.3176H149.475C149.502 31.5084 149.523 31.7742 149.536 32.1149C149.55 32.4557 149.563 32.8373 149.577 33.2598C149.835 32.8782 150.133 32.5374 150.472 32.2376C150.811 31.9241 151.177 31.672 151.57 31.4812C151.977 31.2904 152.397 31.195 152.831 31.195C153.252 31.195 153.611 31.3108 153.909 31.5425C154.221 31.7606 154.377 32.1218 154.377 32.626C154.377 32.7623 154.336 32.9191 154.255 33.0963C154.187 33.2734 154.065 33.4302 153.889 33.5665C153.726 33.6891 153.502 33.7505 153.218 33.7505C152.933 33.7368 152.682 33.6278 152.465 33.4234C152.262 33.2189 152.167 32.9395 152.18 32.5852C151.855 32.5852 151.53 32.6874 151.204 32.8918C150.879 33.0826 150.574 33.3416 150.289 33.6687C150.018 33.9958 149.787 34.3502 149.597 34.7318V39.209C149.597 39.4543 149.59 39.7065 149.577 39.9654C149.577 40.2108 149.557 40.4629 149.516 40.7219C149.733 40.7082 149.957 40.7014 150.187 40.7014C150.418 40.6878 150.628 40.6742 150.818 40.6605V41.7441H146.262V40.8854Z" fill="white"/>
<path d="M160.08 42.0712C159.117 42.0712 158.249 41.8531 157.477 41.417C156.704 40.9808 156.087 40.3743 155.626 39.5975C155.178 38.8069 154.954 37.9006 154.954 36.8784C154.954 35.7744 155.178 34.7999 155.626 33.9549C156.087 33.0963 156.704 32.4216 157.477 31.9309C158.249 31.4403 159.11 31.195 160.06 31.195C161.022 31.195 161.89 31.4198 162.663 31.8696C163.436 32.3058 164.046 32.9191 164.494 33.7096C164.955 34.4864 165.185 35.386 165.185 36.4082C165.185 37.4849 164.962 38.4526 164.514 39.3112C164.067 40.1699 163.456 40.8445 162.683 41.3352C161.924 41.8259 161.056 42.0712 160.08 42.0712ZM160.222 41.049C160.873 41.0353 161.382 40.8309 161.748 40.4357C162.128 40.0404 162.399 39.5361 162.561 38.9228C162.724 38.2959 162.806 37.6485 162.806 36.9806C162.806 36.3946 162.751 35.8221 162.643 35.2633C162.548 34.6909 162.392 34.173 162.175 33.7096C161.958 33.2462 161.673 32.8782 161.321 32.6056C160.968 32.3194 160.541 32.1831 160.039 32.1967C159.402 32.1967 158.88 32.3943 158.473 32.7896C158.08 33.1848 157.788 33.6959 157.599 34.3229C157.422 34.9362 157.334 35.5904 157.334 36.2855C157.334 37.0897 157.436 37.8529 157.639 38.5752C157.843 39.2976 158.154 39.8905 158.575 40.3539C159.009 40.8173 159.558 41.049 160.222 41.049Z" fill="white"/>
<path d="M170.516 42.0712C170.177 42.0712 169.832 42.0235 169.479 41.9281C169.14 41.8463 168.828 41.6759 168.543 41.417C168.259 41.1444 168.035 40.7559 167.872 40.2517C167.709 39.7474 167.628 39.0795 167.628 38.2481L167.669 32.6669H166.164V31.5221C166.53 31.5084 166.903 31.3721 167.282 31.1132C167.662 30.8542 167.994 30.5067 168.279 30.0705C168.564 29.6344 168.76 29.1642 168.869 28.6599H169.825V31.5221H172.957V32.5852L169.825 32.626L169.784 38.0846C169.784 38.6025 169.825 39.0591 169.906 39.4543C170.001 39.836 170.15 40.1358 170.354 40.3539C170.571 40.5583 170.862 40.6605 171.228 40.6605C171.54 40.6605 171.859 40.5651 172.184 40.3743C172.523 40.1835 172.842 39.87 173.14 39.4339L173.832 40.0472C173.506 40.5243 173.181 40.8991 172.855 41.1716C172.53 41.4442 172.218 41.6419 171.92 41.7645C171.621 41.9008 171.35 41.9826 171.106 42.0098C170.862 42.0507 170.666 42.0712 170.516 42.0712Z" fill="white"/>
<path d="M179.516 42.0712C178.554 42.0712 177.686 41.8531 176.913 41.417C176.14 40.9808 175.523 40.3743 175.062 39.5975C174.615 38.8069 174.391 37.9006 174.391 36.8784C174.391 35.7744 174.615 34.7999 175.062 33.9549C175.523 33.0963 176.14 32.4216 176.913 31.9309C177.686 31.4403 178.547 31.195 179.496 31.195C180.459 31.195 181.327 31.4198 182.1 31.8696C182.872 32.3058 183.483 32.9191 183.93 33.7096C184.391 34.4864 184.622 35.386 184.622 36.4082C184.622 37.4849 184.398 38.4526 183.95 39.3112C183.503 40.1699 182.893 40.8445 182.12 41.3352C181.361 41.8259 180.493 42.0712 179.516 42.0712ZM179.659 41.049C180.31 41.0353 180.818 40.8309 181.184 40.4357C181.564 40.0404 181.835 39.5361 181.998 38.9228C182.161 38.2959 182.242 37.6485 182.242 36.9806C182.242 36.3946 182.188 35.8221 182.079 35.2633C181.984 34.6909 181.828 34.173 181.611 33.7096C181.394 33.2462 181.11 32.8782 180.757 32.6056C180.405 32.3194 179.977 32.1831 179.476 32.1967C178.838 32.1967 178.316 32.3943 177.91 32.7896C177.516 33.1848 177.225 33.6959 177.035 34.3229C176.859 34.9362 176.771 35.5904 176.771 36.2855C176.771 37.0897 176.872 37.8529 177.076 38.5752C177.279 39.2976 177.591 39.8905 178.011 40.3539C178.445 40.8173 178.994 41.049 179.659 41.049Z" fill="white"/>
<path d="M190.97 42.0712C190.061 42.0712 189.227 41.8667 188.468 41.4579C187.709 41.0354 187.098 40.4357 186.637 39.6588C186.19 38.8819 185.966 37.9415 185.966 36.8375C185.966 36.1015 186.095 35.3996 186.353 34.7318C186.61 34.0503 186.97 33.4438 187.431 32.9123C187.905 32.3807 188.461 31.965 189.098 31.6652C189.749 31.3517 190.468 31.195 191.254 31.195C192.055 31.195 192.739 31.3176 193.309 31.563C193.878 31.8083 194.312 32.1286 194.611 32.5238C194.922 32.9191 195.078 33.3484 195.078 33.8118C195.078 34.1389 194.983 34.4251 194.794 34.6704C194.604 34.9158 194.333 35.0384 193.98 35.0384C193.587 35.0521 193.309 34.9362 193.146 34.6909C192.983 34.4319 192.902 34.1934 192.902 33.9753C192.902 33.8527 192.922 33.7164 192.963 33.5665C193.004 33.4029 193.078 33.2598 193.187 33.1371C193.078 32.8509 192.902 32.6397 192.658 32.5034C192.414 32.3671 192.163 32.2785 191.905 32.2376C191.648 32.1967 191.431 32.1763 191.254 32.1763C190.427 32.1899 189.729 32.5511 189.159 33.2598C188.604 33.9549 188.326 34.9635 188.326 36.2855C188.326 37.1305 188.448 37.887 188.692 38.5548C188.949 39.2226 189.322 39.7542 189.81 40.1494C190.299 40.5447 190.882 40.7491 191.56 40.7628C192.17 40.7628 192.76 40.606 193.329 40.2926C193.899 39.9654 194.36 39.5566 194.712 39.0659L195.363 39.6383C194.97 40.2517 194.516 40.7355 194 41.0899C193.499 41.4442 192.983 41.6964 192.455 41.8463C191.939 41.9962 191.444 42.0712 190.97 42.0712Z" fill="white"/>
<path d="M201.555 42.0712C200.592 42.0712 199.724 41.8531 198.951 41.417C198.178 40.9808 197.561 40.3743 197.1 39.5975C196.653 38.8069 196.429 37.9006 196.429 36.8784C196.429 35.7744 196.653 34.7999 197.1 33.9549C197.561 33.0963 198.178 32.4216 198.951 31.9309C199.724 31.4403 200.585 31.195 201.534 31.195C202.497 31.195 203.365 31.4198 204.138 31.8696C204.911 32.3058 205.521 32.9191 205.969 33.7096C206.43 34.4864 206.66 35.386 206.66 36.4082C206.66 37.4849 206.436 38.4526 205.989 39.3112C205.541 40.1699 204.931 40.8445 204.158 41.3352C203.399 41.8259 202.531 42.0712 201.555 42.0712ZM201.697 41.049C202.348 41.0353 202.857 40.8309 203.223 40.4357C203.602 40.0404 203.874 39.5361 204.036 38.9228C204.199 38.2959 204.28 37.6485 204.28 36.9806C204.28 36.3946 204.226 35.8221 204.118 35.2633C204.023 34.6909 203.867 34.173 203.65 33.7096C203.433 33.2462 203.148 32.8782 202.796 32.6056C202.443 32.3194 202.016 32.1831 201.514 32.1967C200.877 32.1967 200.355 32.3943 199.948 32.7896C199.555 33.1848 199.263 33.6959 199.073 34.3229C198.897 34.9362 198.809 35.5904 198.809 36.2855C198.809 37.0897 198.911 37.8529 199.114 38.5752C199.317 39.2976 199.629 39.8905 200.05 40.3539C200.484 40.8173 201.033 41.049 201.697 41.049Z" fill="white"/>
<path d="M207.842 40.8854C208.249 40.8854 208.534 40.79 208.697 40.5992C208.859 40.4084 208.954 40.1426 208.981 39.8019C209.022 39.4612 209.042 39.0659 209.042 38.6161V29.3754C209.042 29.1437 209.042 28.912 209.042 28.6803C209.056 28.435 209.076 28.1761 209.103 27.9035C208.873 27.9171 208.629 27.9307 208.371 27.9444C208.114 27.9444 207.883 27.9512 207.68 27.9648V26.8813C208.29 26.8813 208.771 26.854 209.124 26.7995C209.49 26.7313 209.768 26.6564 209.958 26.5746C210.161 26.4928 210.31 26.4042 210.405 26.3088H211.178V39.209C211.178 39.4543 211.171 39.7065 211.158 39.9654C211.144 40.2108 211.124 40.4629 211.097 40.7219C211.314 40.7082 211.531 40.7014 211.748 40.7014C211.978 40.6878 212.188 40.6742 212.378 40.6605V41.7441H207.842V40.8854Z" fill="white"/>
<defs>
<linearGradient id="paint0_linear_100_26" x1="99.1169" y1="38.1477" x2="82.6837" y2="38.1477" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint1_linear_100_26" x1="33.8049" y1="16.9269" x2="38.7165" y2="26.9811" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint2_linear_100_26" x1="55.0065" y1="30.3095" x2="68.2066" y2="40.7142" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<clipPath id="clip0_100_26">
<rect width="121.515" height="46.4384" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 29 KiB

View File

@@ -31,7 +31,6 @@
"ctrl--": ["zed::DecreaseBufferFontSize", { "persist": false }],
"ctrl-0": ["zed::ResetBufferFontSize", { "persist": false }],
"ctrl-,": "zed::OpenSettings",
"ctrl-alt-,": "zed::OpenSettingsFile",
"ctrl-q": "zed::Quit",
"f4": "debugger::Start",
"shift-f5": "debugger::Stop",
@@ -42,7 +41,7 @@
"shift-f11": "debugger::StepOut",
"f11": "zed::ToggleFullScreen",
"ctrl-alt-z": "edit_prediction::RateCompletions",
"ctrl-alt-shift-i": "edit_prediction::ToggleMenu",
"ctrl-shift-i": "edit_prediction::ToggleMenu",
"ctrl-alt-l": "lsp_tool::ToggleMenu"
}
},
@@ -65,8 +64,8 @@
"ctrl-k": "editor::CutToEndOfLine",
"ctrl-k ctrl-q": "editor::Rewrap",
"ctrl-k q": "editor::Rewrap",
"ctrl-backspace": ["editor::DeleteToPreviousWordStart", { "ignore_newlines": false, "ignore_brackets": false }],
"ctrl-delete": ["editor::DeleteToNextWordEnd", { "ignore_newlines": false, "ignore_brackets": false }],
"ctrl-backspace": "editor::DeleteToPreviousWordStart",
"ctrl-delete": "editor::DeleteToNextWordEnd",
"cut": "editor::Cut",
"shift-delete": "editor::Cut",
"ctrl-x": "editor::Cut",
@@ -122,7 +121,7 @@
"alt-g m": "git::OpenModifiedFiles",
"menu": "editor::OpenContextMenu",
"shift-f10": "editor::OpenContextMenu",
"ctrl-alt-shift-e": "editor::ToggleEditPrediction",
"ctrl-shift-e": "editor::ToggleEditPrediction",
"f9": "editor::ToggleBreakpoint",
"shift-f9": "editor::EditLogBreakpoint"
}
@@ -132,14 +131,14 @@
"bindings": {
"shift-enter": "editor::Newline",
"enter": "editor::Newline",
"ctrl-enter": "editor::NewlineBelow",
"ctrl-shift-enter": "editor::NewlineAbove",
"ctrl-enter": "editor::NewlineAbove",
"ctrl-shift-enter": "editor::NewlineBelow",
"ctrl-k ctrl-z": "editor::ToggleSoftWrap",
"ctrl-k z": "editor::ToggleSoftWrap",
"find": "buffer_search::Deploy",
"ctrl-f": "buffer_search::Deploy",
"ctrl-h": "buffer_search::DeployReplace",
"ctrl->": "agent::QuoteSelection",
"ctrl->": "assistant::QuoteSelection",
"ctrl-<": "assistant::InsertIntoEditor",
"ctrl-alt-e": "editor::SelectEnclosingSymbol",
"ctrl-shift-backspace": "editor::GoToPreviousChange",
@@ -172,7 +171,6 @@
"context": "Markdown",
"bindings": {
"copy": "markdown::Copy",
"ctrl-insert": "markdown::Copy",
"ctrl-c": "markdown::Copy"
}
},
@@ -243,15 +241,12 @@
"ctrl-shift-i": "agent::ToggleOptionsMenu",
"ctrl-alt-shift-n": "agent::ToggleNewThreadMenu",
"shift-alt-escape": "agent::ExpandMessageEditor",
"ctrl->": "agent::QuoteSelection",
"ctrl->": "assistant::QuoteSelection",
"ctrl-alt-e": "agent::RemoveAllContext",
"ctrl-shift-e": "project_panel::ToggleFocus",
"ctrl-shift-enter": "agent::ContinueThread",
"super-ctrl-b": "agent::ToggleBurnMode",
"alt-enter": "agent::ContinueWithBurnMode",
"ctrl-y": "agent::AllowOnce",
"ctrl-alt-y": "agent::AllowAlways",
"ctrl-alt-z": "agent::RejectOnce"
"alt-enter": "agent::ContinueWithBurnMode"
}
},
{
@@ -264,7 +259,6 @@
"context": "AgentPanel > Markdown",
"bindings": {
"copy": "markdown::CopyAsMarkdown",
"ctrl-insert": "markdown::CopyAsMarkdown",
"ctrl-c": "markdown::CopyAsMarkdown"
}
},
@@ -332,12 +326,6 @@
"enter": "agent::AcceptSuggestedContext"
}
},
{
"context": "AcpThread > ModeSelector",
"bindings": {
"ctrl-enter": "menu::Confirm"
}
},
{
"context": "AcpThread > Editor && !use_modifier_to_send",
"use_key_equivalents": true,
@@ -355,8 +343,7 @@
"ctrl-enter": "agent::Chat",
"shift-ctrl-r": "agent::OpenAgentDiff",
"ctrl-shift-y": "agent::KeepAll",
"ctrl-shift-n": "agent::RejectAll",
"shift-tab": "agent::CycleModeSelector"
"ctrl-shift-n": "agent::RejectAll"
}
},
{
@@ -370,8 +357,7 @@
"bindings": {
"new": "rules_library::NewRule",
"ctrl-n": "rules_library::NewRule",
"ctrl-shift-s": "rules_library::ToggleDefaultRule",
"ctrl-w": "workspace::CloseWindow"
"ctrl-shift-s": "rules_library::ToggleDefaultRule"
}
},
{
@@ -464,8 +450,8 @@
"ctrl-k ctrl-w": "workspace::CloseAllItemsAndPanes",
"back": "pane::GoBack",
"ctrl-alt--": "pane::GoBack",
"forward": "pane::GoForward",
"ctrl-alt-_": "pane::GoForward",
"forward": "pane::GoForward",
"ctrl-alt-g": "search::SelectNextMatch",
"f3": "search::SelectNextMatch",
"ctrl-alt-shift-g": "search::SelectPreviousMatch",
@@ -498,8 +484,8 @@
"alt-down": "editor::MoveLineDown",
"ctrl-alt-shift-up": "editor::DuplicateLineUp",
"ctrl-alt-shift-down": "editor::DuplicateLineDown",
"alt-shift-right": "editor::SelectLargerSyntaxNode", // Expand selection
"alt-shift-left": "editor::SelectSmallerSyntaxNode", // Shrink selection
"alt-shift-right": "editor::SelectLargerSyntaxNode", // Expand Selection
"alt-shift-left": "editor::SelectSmallerSyntaxNode", // Shrink Selection
"ctrl-shift-l": "editor::SelectAllMatches", // Select all occurrences of current selection
"ctrl-f2": "editor::SelectAllMatches", // Select all occurrences of current word
"ctrl-d": ["editor::SelectNext", { "replace_newest": false }], // editor.action.addSelectionToNextFindMatch / find_under_expand
@@ -527,15 +513,15 @@
"ctrl-k ctrl-l": "editor::ToggleFold",
"ctrl-k ctrl-[": "editor::FoldRecursive",
"ctrl-k ctrl-]": "editor::UnfoldRecursive",
"ctrl-k ctrl-1": "editor::FoldAtLevel_1",
"ctrl-k ctrl-2": "editor::FoldAtLevel_2",
"ctrl-k ctrl-3": "editor::FoldAtLevel_3",
"ctrl-k ctrl-4": "editor::FoldAtLevel_4",
"ctrl-k ctrl-5": "editor::FoldAtLevel_5",
"ctrl-k ctrl-6": "editor::FoldAtLevel_6",
"ctrl-k ctrl-7": "editor::FoldAtLevel_7",
"ctrl-k ctrl-8": "editor::FoldAtLevel_8",
"ctrl-k ctrl-9": "editor::FoldAtLevel_9",
"ctrl-k ctrl-1": ["editor::FoldAtLevel", 1],
"ctrl-k ctrl-2": ["editor::FoldAtLevel", 2],
"ctrl-k ctrl-3": ["editor::FoldAtLevel", 3],
"ctrl-k ctrl-4": ["editor::FoldAtLevel", 4],
"ctrl-k ctrl-5": ["editor::FoldAtLevel", 5],
"ctrl-k ctrl-6": ["editor::FoldAtLevel", 6],
"ctrl-k ctrl-7": ["editor::FoldAtLevel", 7],
"ctrl-k ctrl-8": ["editor::FoldAtLevel", 8],
"ctrl-k ctrl-9": ["editor::FoldAtLevel", 9],
"ctrl-k ctrl-0": "editor::FoldAll",
"ctrl-k ctrl-j": "editor::UnfoldAll",
"ctrl-space": "editor::ShowCompletions",
@@ -595,7 +581,7 @@
"ctrl-n": "workspace::NewFile",
"shift-new": "workspace::NewWindow",
"ctrl-shift-n": "workspace::NewWindow",
"ctrl-`": "terminal_panel::Toggle",
"ctrl-`": "terminal_panel::ToggleFocus",
"f10": ["app_menu::OpenApplicationMenu", "Zed"],
"alt-1": ["workspace::ActivatePane", 0],
"alt-2": ["workspace::ActivatePane", 1],
@@ -621,7 +607,7 @@
"ctrl-shift-f": "pane::DeploySearch",
"ctrl-shift-h": ["pane::DeploySearch", { "replace_enabled": true }],
"ctrl-shift-t": "pane::ReopenClosedItem",
"ctrl-k ctrl-s": "zed::OpenKeymap",
"ctrl-k ctrl-s": "zed::OpenKeymapEditor",
"ctrl-k ctrl-t": "theme_selector::Toggle",
"ctrl-alt-super-p": "settings_profile_selector::Toggle",
"ctrl-t": "project_symbols::Toggle",
@@ -640,7 +626,6 @@
"alt-save": "workspace::SaveAll",
"ctrl-alt-s": "workspace::SaveAll",
"ctrl-k m": "language_selector::Toggle",
"ctrl-k ctrl-m": "toolchain::AddToolchain",
"escape": "workspace::Unfollow",
"ctrl-k ctrl-left": "workspace::ActivatePaneLeft",
"ctrl-k ctrl-right": "workspace::ActivatePaneRight",
@@ -651,9 +636,7 @@
"ctrl-k shift-up": "workspace::SwapPaneUp",
"ctrl-k shift-down": "workspace::SwapPaneDown",
"ctrl-shift-x": "zed::Extensions",
// All task parameters are captured and unchanged between reruns by default.
// Use the `"reevaluate_context"` parameter to control this.
"ctrl-shift-r": ["task::Rerun", { "reevaluate_context": false }],
"ctrl-shift-r": "task::Rerun",
"ctrl-alt-r": "task::Rerun",
"alt-t": "task::Rerun",
"alt-shift-t": "task::Spawn",
@@ -873,7 +856,7 @@
"ctrl-backspace": ["project_panel::Delete", { "skip_prompt": false }],
"ctrl-delete": ["project_panel::Delete", { "skip_prompt": false }],
"alt-ctrl-r": "project_panel::RevealInFileManager",
"ctrl-shift-enter": "workspace::OpenWithSystem",
"ctrl-shift-enter": "project_panel::OpenWithSystem",
"alt-d": "project_panel::CompareMarkedFiles",
"shift-find": "project_panel::NewSearchInDirectory",
"ctrl-alt-shift-f": "project_panel::NewSearchInDirectory",
@@ -1043,13 +1026,6 @@
"tab": "channel_modal::ToggleMode"
}
},
{
"context": "ToolchainSelector",
"use_key_equivalents": true,
"bindings": {
"ctrl-shift-a": "toolchain::AddToolchain"
}
},
{
"context": "FileFinder || (FileFinder > Picker > Editor)",
"bindings": {
@@ -1077,12 +1053,6 @@
"ctrl-backspace": "tab_switcher::CloseSelectedItem"
}
},
{
"context": "StashList || (StashList > Picker > Editor)",
"bindings": {
"ctrl-shift-backspace": "stash_picker::DropStashItem"
}
},
{
"context": "Terminal",
"bindings": {
@@ -1142,13 +1112,6 @@
"ctrl-enter": "menu::Confirm"
}
},
{
"context": "ContextServerToolsModal",
"use_key_equivalents": true,
"bindings": {
"escape": "menu::Cancel"
}
},
{
"context": "OnboardingAiConfigurationModal",
"use_key_equivalents": true,
@@ -1229,55 +1192,12 @@
"context": "Onboarding",
"use_key_equivalents": true,
"bindings": {
"ctrl-enter": "onboarding::Finish",
"alt-shift-l": "onboarding::SignIn",
"ctrl-1": "onboarding::ActivateBasicsPage",
"ctrl-2": "onboarding::ActivateEditingPage",
"ctrl-3": "onboarding::ActivateAISetupPage",
"ctrl-escape": "onboarding::Finish",
"alt-tab": "onboarding::SignIn",
"alt-shift-a": "onboarding::OpenAccount"
}
},
{
"context": "InvalidBuffer",
"use_key_equivalents": true,
"bindings": {
"ctrl-shift-enter": "workspace::OpenWithSystem"
}
},
{
"context": "SettingsWindow",
"use_key_equivalents": true,
"bindings": {
"ctrl-w": "workspace::CloseWindow",
"escape": "workspace::CloseWindow",
"ctrl-m": "settings_editor::Minimize",
"ctrl-f": "search::FocusSearch",
"left": "settings_editor::ToggleFocusNav",
"ctrl-shift-e": "settings_editor::ToggleFocusNav",
// todo(settings_ui): cut this down based on the max files and overflow UI
"ctrl-1": ["settings_editor::FocusFile", 0],
"ctrl-2": ["settings_editor::FocusFile", 1],
"ctrl-3": ["settings_editor::FocusFile", 2],
"ctrl-4": ["settings_editor::FocusFile", 3],
"ctrl-5": ["settings_editor::FocusFile", 4],
"ctrl-6": ["settings_editor::FocusFile", 5],
"ctrl-7": ["settings_editor::FocusFile", 6],
"ctrl-8": ["settings_editor::FocusFile", 7],
"ctrl-9": ["settings_editor::FocusFile", 8],
"ctrl-0": ["settings_editor::FocusFile", 9],
"ctrl-pageup": "settings_editor::FocusPreviousFile",
"ctrl-pagedown": "settings_editor::FocusNextFile"
}
},
{
"context": "SettingsWindow > NavigationMenu",
"use_key_equivalents": true,
"bindings": {
"up": "settings_editor::FocusPreviousNavEntry",
"down": "settings_editor::FocusNextNavEntry",
"right": "settings_editor::ExpandNavEntry",
"left": "settings_editor::CollapseNavEntry",
"pageup": "settings_editor::FocusPreviousRootNavEntry",
"pagedown": "settings_editor::FocusNextRootNavEntry",
"home": "settings_editor::FocusFirstNavEntry",
"end": "settings_editor::FocusLastNavEntry"
}
}
]

View File

@@ -40,7 +40,6 @@
"cmd--": ["zed::DecreaseBufferFontSize", { "persist": false }],
"cmd-0": ["zed::ResetBufferFontSize", { "persist": false }],
"cmd-,": "zed::OpenSettings",
"cmd-alt-,": "zed::OpenSettingsFile",
"cmd-q": "zed::Quit",
"cmd-h": "zed::Hide",
"alt-cmd-h": "zed::HideOthers",
@@ -71,9 +70,9 @@
"cmd-k q": "editor::Rewrap",
"cmd-backspace": "editor::DeleteToBeginningOfLine",
"cmd-delete": "editor::DeleteToEndOfLine",
"alt-backspace": ["editor::DeleteToPreviousWordStart", { "ignore_newlines": false, "ignore_brackets": false }],
"ctrl-w": ["editor::DeleteToPreviousWordStart", { "ignore_newlines": false, "ignore_brackets": false }],
"alt-delete": ["editor::DeleteToNextWordEnd", { "ignore_newlines": false, "ignore_brackets": false }],
"alt-backspace": "editor::DeleteToPreviousWordStart",
"ctrl-w": "editor::DeleteToPreviousWordStart",
"alt-delete": "editor::DeleteToNextWordEnd",
"cmd-x": "editor::Cut",
"cmd-c": "editor::Copy",
"cmd-v": "editor::Paste",
@@ -163,7 +162,7 @@
"cmd-alt-f": "buffer_search::DeployReplace",
"cmd-alt-l": ["buffer_search::Deploy", { "selection_search_enabled": true }],
"cmd-e": ["buffer_search::Deploy", { "focus": false }],
"cmd->": "agent::QuoteSelection",
"cmd->": "assistant::QuoteSelection",
"cmd-<": "assistant::InsertIntoEditor",
"cmd-alt-e": "editor::SelectEnclosingSymbol",
"alt-enter": "editor::OpenSelectionsInMultibuffer"
@@ -219,7 +218,7 @@
}
},
{
"context": "Editor && !agent_diff && !AgentPanel",
"context": "Editor && !agent_diff",
"use_key_equivalents": true,
"bindings": {
"cmd-alt-z": "git::Restore",
@@ -282,15 +281,12 @@
"cmd-shift-i": "agent::ToggleOptionsMenu",
"cmd-alt-shift-n": "agent::ToggleNewThreadMenu",
"shift-alt-escape": "agent::ExpandMessageEditor",
"cmd->": "agent::QuoteSelection",
"cmd->": "assistant::QuoteSelection",
"cmd-alt-e": "agent::RemoveAllContext",
"cmd-shift-e": "project_panel::ToggleFocus",
"cmd-ctrl-b": "agent::ToggleBurnMode",
"cmd-shift-enter": "agent::ContinueThread",
"alt-enter": "agent::ContinueWithBurnMode",
"cmd-y": "agent::AllowOnce",
"cmd-alt-y": "agent::AllowAlways",
"cmd-alt-z": "agent::RejectOnce"
"alt-enter": "agent::ContinueWithBurnMode"
}
},
{
@@ -382,12 +378,6 @@
"ctrl--": "pane::GoBack"
}
},
{
"context": "AcpThread > ModeSelector",
"bindings": {
"cmd-enter": "menu::Confirm"
}
},
{
"context": "AcpThread > Editor && !use_modifier_to_send",
"use_key_equivalents": true,
@@ -395,8 +385,7 @@
"enter": "agent::Chat",
"shift-ctrl-r": "agent::OpenAgentDiff",
"cmd-shift-y": "agent::KeepAll",
"cmd-shift-n": "agent::RejectAll",
"shift-tab": "agent::CycleModeSelector"
"cmd-shift-n": "agent::RejectAll"
}
},
{
@@ -406,8 +395,7 @@
"cmd-enter": "agent::Chat",
"shift-ctrl-r": "agent::OpenAgentDiff",
"cmd-shift-y": "agent::KeepAll",
"cmd-shift-n": "agent::RejectAll",
"shift-tab": "agent::CycleModeSelector"
"cmd-shift-n": "agent::RejectAll"
}
},
{
@@ -548,12 +536,8 @@
"alt-down": "editor::MoveLineDown",
"alt-shift-up": "editor::DuplicateLineUp",
"alt-shift-down": "editor::DuplicateLineDown",
"cmd-ctrl-left": "editor::SelectSmallerSyntaxNode", // Shrink selection
"cmd-ctrl-right": "editor::SelectLargerSyntaxNode", // Expand selection
"cmd-ctrl-up": "editor::SelectPreviousSyntaxNode", // Move selection up
"ctrl-shift-right": "editor::SelectLargerSyntaxNode", // Expand selection (VSCode version)
"ctrl-shift-left": "editor::SelectSmallerSyntaxNode", // Shrink selection (VSCode version)
"cmd-ctrl-down": "editor::SelectNextSyntaxNode", // Move selection down
"ctrl-shift-right": "editor::SelectLargerSyntaxNode", // Expand Selection
"ctrl-shift-left": "editor::SelectSmallerSyntaxNode", // Shrink Selection
"cmd-d": ["editor::SelectNext", { "replace_newest": false }], // editor.action.addSelectionToNextFindMatch / find_under_expand
"cmd-shift-l": "editor::SelectAllMatches", // Select all occurrences of current selection
"cmd-f2": "editor::SelectAllMatches", // Select all occurrences of current word
@@ -582,15 +566,15 @@
"cmd-k cmd-l": "editor::ToggleFold",
"cmd-k cmd-[": "editor::FoldRecursive",
"cmd-k cmd-]": "editor::UnfoldRecursive",
"cmd-k cmd-1": "editor::FoldAtLevel_1",
"cmd-k cmd-2": "editor::FoldAtLevel_2",
"cmd-k cmd-3": "editor::FoldAtLevel_3",
"cmd-k cmd-4": "editor::FoldAtLevel_4",
"cmd-k cmd-5": "editor::FoldAtLevel_5",
"cmd-k cmd-6": "editor::FoldAtLevel_6",
"cmd-k cmd-7": "editor::FoldAtLevel_7",
"cmd-k cmd-8": "editor::FoldAtLevel_8",
"cmd-k cmd-9": "editor::FoldAtLevel_9",
"cmd-k cmd-1": ["editor::FoldAtLevel", 1],
"cmd-k cmd-2": ["editor::FoldAtLevel", 2],
"cmd-k cmd-3": ["editor::FoldAtLevel", 3],
"cmd-k cmd-4": ["editor::FoldAtLevel", 4],
"cmd-k cmd-5": ["editor::FoldAtLevel", 5],
"cmd-k cmd-6": ["editor::FoldAtLevel", 6],
"cmd-k cmd-7": ["editor::FoldAtLevel", 7],
"cmd-k cmd-8": ["editor::FoldAtLevel", 8],
"cmd-k cmd-9": ["editor::FoldAtLevel", 9],
"cmd-k cmd-0": "editor::FoldAll",
"cmd-k cmd-j": "editor::UnfoldAll",
// Using `ctrl-space` / `ctrl-shift-space` in Zed requires disabling the macOS global shortcut.
@@ -665,7 +649,7 @@
"alt-shift-enter": "toast::RunAction",
"cmd-shift-s": "workspace::SaveAs",
"cmd-shift-n": "workspace::NewWindow",
"ctrl-`": "terminal_panel::Toggle",
"ctrl-`": "terminal_panel::ToggleFocus",
"cmd-1": ["workspace::ActivatePane", 0],
"cmd-2": ["workspace::ActivatePane", 1],
"cmd-3": ["workspace::ActivatePane", 2],
@@ -690,7 +674,7 @@
"cmd-shift-f": "pane::DeploySearch",
"cmd-shift-h": ["pane::DeploySearch", { "replace_enabled": true }],
"cmd-shift-t": "pane::ReopenClosedItem",
"cmd-k cmd-s": "zed::OpenKeymap",
"cmd-k cmd-s": "zed::OpenKeymapEditor",
"cmd-k cmd-t": "theme_selector::Toggle",
"ctrl-alt-cmd-p": "settings_profile_selector::Toggle",
"cmd-t": "project_symbols::Toggle",
@@ -706,7 +690,6 @@
"cmd-?": "agent::ToggleFocus",
"cmd-alt-s": "workspace::SaveAll",
"cmd-k m": "language_selector::Toggle",
"cmd-k cmd-m": "toolchain::AddToolchain",
"escape": "workspace::Unfollow",
"cmd-k cmd-left": "workspace::ActivatePaneLeft",
"cmd-k cmd-right": "workspace::ActivatePaneRight",
@@ -727,9 +710,7 @@
"bindings": {
"cmd-n": "workspace::NewFile",
"cmd-shift-r": "task::Spawn",
// All task parameters are captured and unchanged between reruns by default.
// Use the `"reevaluate_context"` parameter to control this.
"cmd-alt-r": ["task::Rerun", { "reevaluate_context": false }],
"cmd-alt-r": "task::Rerun",
"ctrl-alt-shift-r": ["task::Spawn", { "reveal_target": "center" }]
// also possible to spawn tasks by name:
// "foo-bar": ["task::Spawn", { "task_name": "MyTask", "reveal_target": "dock" }]
@@ -934,7 +915,7 @@
"cmd-backspace": ["project_panel::Trash", { "skip_prompt": true }],
"cmd-delete": ["project_panel::Delete", { "skip_prompt": false }],
"alt-cmd-r": "project_panel::RevealInFileManager",
"ctrl-shift-enter": "workspace::OpenWithSystem",
"ctrl-shift-enter": "project_panel::OpenWithSystem",
"alt-d": "project_panel::CompareMarkedFiles",
"cmd-alt-backspace": ["project_panel::Delete", { "skip_prompt": false }],
"cmd-alt-shift-f": "project_panel::NewSearchInDirectory",
@@ -1113,13 +1094,6 @@
"tab": "channel_modal::ToggleMode"
}
},
{
"context": "ToolchainSelector",
"use_key_equivalents": true,
"bindings": {
"cmd-shift-a": "toolchain::AddToolchain"
}
},
{
"context": "FileFinder || (FileFinder > Picker > Editor)",
"use_key_equivalents": true,
@@ -1149,13 +1123,6 @@
"ctrl-backspace": "tab_switcher::CloseSelectedItem"
}
},
{
"context": "StashList || (StashList > Picker > Editor)",
"use_key_equivalents": true,
"bindings": {
"ctrl-shift-backspace": "stash_picker::DropStashItem"
}
},
{
"context": "Terminal",
"use_key_equivalents": true,
@@ -1247,13 +1214,6 @@
"cmd-enter": "menu::Confirm"
}
},
{
"context": "ContextServerToolsModal",
"use_key_equivalents": true,
"bindings": {
"escape": "menu::Cancel"
}
},
{
"context": "OnboardingAiConfigurationModal",
"use_key_equivalents": true,
@@ -1334,55 +1294,12 @@
"context": "Onboarding",
"use_key_equivalents": true,
"bindings": {
"cmd-enter": "onboarding::Finish",
"cmd-1": "onboarding::ActivateBasicsPage",
"cmd-2": "onboarding::ActivateEditingPage",
"cmd-3": "onboarding::ActivateAISetupPage",
"cmd-escape": "onboarding::Finish",
"alt-tab": "onboarding::SignIn",
"alt-shift-a": "onboarding::OpenAccount"
}
},
{
"context": "InvalidBuffer",
"use_key_equivalents": true,
"bindings": {
"ctrl-shift-enter": "workspace::OpenWithSystem"
}
},
{
"context": "SettingsWindow",
"use_key_equivalents": true,
"bindings": {
"cmd-w": "workspace::CloseWindow",
"escape": "workspace::CloseWindow",
"cmd-m": "settings_editor::Minimize",
"cmd-f": "search::FocusSearch",
"left": "settings_editor::ToggleFocusNav",
"cmd-shift-e": "settings_editor::ToggleFocusNav",
// todo(settings_ui): cut this down based on the max files and overflow UI
"ctrl-1": ["settings_editor::FocusFile", 0],
"ctrl-2": ["settings_editor::FocusFile", 1],
"ctrl-3": ["settings_editor::FocusFile", 2],
"ctrl-4": ["settings_editor::FocusFile", 3],
"ctrl-5": ["settings_editor::FocusFile", 4],
"ctrl-6": ["settings_editor::FocusFile", 5],
"ctrl-7": ["settings_editor::FocusFile", 6],
"ctrl-8": ["settings_editor::FocusFile", 7],
"ctrl-9": ["settings_editor::FocusFile", 8],
"ctrl-0": ["settings_editor::FocusFile", 9],
"cmd-{": "settings_editor::FocusPreviousFile",
"cmd-}": "settings_editor::FocusNextFile"
}
},
{
"context": "SettingsWindow > NavigationMenu",
"use_key_equivalents": true,
"bindings": {
"up": "settings_editor::FocusPreviousNavEntry",
"down": "settings_editor::FocusNextNavEntry",
"right": "settings_editor::ExpandNavEntry",
"left": "settings_editor::CollapseNavEntry",
"pageup": "settings_editor::FocusPreviousRootNavEntry",
"pagedown": "settings_editor::FocusNextRootNavEntry",
"home": "settings_editor::FocusFirstNavEntry",
"end": "settings_editor::FocusLastNavEntry"
}
}
]

File diff suppressed because it is too large Load Diff

View File

@@ -17,8 +17,8 @@
"bindings": {
"ctrl-i": "agent::ToggleFocus",
"ctrl-shift-i": "agent::ToggleFocus",
"ctrl-shift-l": "agent::QuoteSelection", // In cursor uses "Ask" mode
"ctrl-l": "agent::QuoteSelection", // In cursor uses "Agent" mode
"ctrl-shift-l": "assistant::QuoteSelection", // In cursor uses "Ask" mode
"ctrl-l": "assistant::QuoteSelection", // In cursor uses "Agent" mode
"ctrl-k": "assistant::InlineAssist",
"ctrl-shift-k": "assistant::InsertIntoEditor"
}

View File

@@ -38,11 +38,10 @@
"alt-;": ["editor::ToggleComments", { "advance_downwards": false }],
"ctrl-x ctrl-;": "editor::ToggleComments",
"alt-.": "editor::GoToDefinition", // xref-find-definitions
"alt-?": "editor::FindAllReferences", // xref-find-references
"alt-,": "pane::GoBack", // xref-pop-marker-stack
"ctrl-x h": "editor::SelectAll", // mark-whole-buffer
"ctrl-d": "editor::Delete", // delete-char
"alt-d": ["editor::DeleteToNextWordEnd", { "ignore_newlines": false, "ignore_brackets": false }], // kill-word
"alt-d": "editor::DeleteToNextWordEnd", // kill-word
"ctrl-k": "editor::KillRingCut", // kill-line
"ctrl-w": "editor::Cut", // kill-region
"alt-w": "editor::Copy", // kill-ring-save

View File

@@ -1,7 +1,7 @@
[
{
"bindings": {
"ctrl-alt-s": "zed::OpenSettingsFile",
"ctrl-alt-s": "zed::OpenSettings",
"ctrl-{": "pane::ActivatePreviousItem",
"ctrl-}": "pane::ActivateNextItem",
"shift-escape": null, // Unmap workspace::zoom
@@ -125,7 +125,7 @@
{
"context": "Workspace || Editor",
"bindings": {
"alt-f12": "terminal_panel::Toggle",
"alt-f12": "terminal_panel::ToggleFocus",
"ctrl-shift-k": "git::Push"
}
},

View File

@@ -50,8 +50,8 @@
"ctrl-k ctrl-u": "editor::ConvertToUpperCase",
"ctrl-k ctrl-l": "editor::ConvertToLowerCase",
"shift-alt-m": "markdown::OpenPreviewToTheSide",
"ctrl-backspace": ["editor::DeleteToPreviousWordStart", { "ignore_newlines": false, "ignore_brackets": false }],
"ctrl-delete": ["editor::DeleteToNextWordEnd", { "ignore_newlines": false, "ignore_brackets": false }],
"ctrl-backspace": "editor::DeleteToPreviousWordStart",
"ctrl-delete": "editor::DeleteToNextWordEnd",
"alt-right": "editor::MoveToNextSubwordEnd",
"alt-left": "editor::MoveToPreviousSubwordStart",
"alt-shift-right": "editor::SelectToNextSubwordEnd",

View File

@@ -17,8 +17,8 @@
"bindings": {
"cmd-i": "agent::ToggleFocus",
"cmd-shift-i": "agent::ToggleFocus",
"cmd-shift-l": "agent::QuoteSelection", // In cursor uses "Ask" mode
"cmd-l": "agent::QuoteSelection", // In cursor uses "Agent" mode
"cmd-shift-l": "assistant::QuoteSelection", // In cursor uses "Ask" mode
"cmd-l": "assistant::QuoteSelection", // In cursor uses "Agent" mode
"cmd-k": "assistant::InlineAssist",
"cmd-shift-k": "assistant::InsertIntoEditor"
}

View File

@@ -4,7 +4,6 @@
// from the command palette.
[
{
"context": "!GitPanel",
"bindings": {
"ctrl-g": "menu::Cancel"
}
@@ -39,11 +38,10 @@
"alt-;": ["editor::ToggleComments", { "advance_downwards": false }],
"ctrl-x ctrl-;": "editor::ToggleComments",
"alt-.": "editor::GoToDefinition", // xref-find-definitions
"alt-?": "editor::FindAllReferences", // xref-find-references
"alt-,": "pane::GoBack", // xref-pop-marker-stack
"ctrl-x h": "editor::SelectAll", // mark-whole-buffer
"ctrl-d": "editor::Delete", // delete-char
"alt-d": ["editor::DeleteToNextWordEnd", { "ignore_newlines": false, "ignore_brackets": false }], // kill-word
"alt-d": "editor::DeleteToNextWordEnd", // kill-word
"ctrl-k": "editor::KillRingCut", // kill-line
"ctrl-w": "editor::Cut", // kill-region
"alt-w": "editor::Copy", // kill-ring-save

View File

@@ -127,7 +127,7 @@
{
"context": "Workspace || Editor",
"bindings": {
"alt-f12": "terminal_panel::Toggle",
"alt-f12": "terminal_panel::ToggleFocus",
"cmd-shift-k": "git::Push"
}
},

View File

@@ -52,8 +52,8 @@
"cmd-k cmd-l": "editor::ConvertToLowerCase",
"cmd-shift-j": "editor::JoinLines",
"shift-alt-m": "markdown::OpenPreviewToTheSide",
"ctrl-backspace": ["editor::DeleteToPreviousWordStart", { "ignore_newlines": false, "ignore_brackets": false }],
"ctrl-delete": ["editor::DeleteToNextWordEnd", { "ignore_newlines": false, "ignore_brackets": false }],
"ctrl-backspace": "editor::DeleteToPreviousWordStart",
"ctrl-delete": "editor::DeleteToNextWordEnd",
"ctrl-right": "editor::MoveToNextSubwordEnd",
"ctrl-left": "editor::MoveToPreviousSubwordStart",
"ctrl-shift-right": "editor::SelectToNextSubwordEnd",

View File

@@ -21,10 +21,10 @@
{
"context": "Editor",
"bindings": {
"alt-backspace": ["editor::DeleteToPreviousWordStart", { "ignore_newlines": false, "ignore_brackets": false }],
"alt-shift-backspace": ["editor::DeleteToNextWordEnd", { "ignore_newlines": false, "ignore_brackets": false }],
"alt-delete": ["editor::DeleteToNextWordEnd", { "ignore_newlines": false, "ignore_brackets": false }],
"alt-shift-delete": ["editor::DeleteToNextWordEnd", { "ignore_newlines": false, "ignore_brackets": false }],
"alt-backspace": "editor::DeleteToPreviousWordStart",
"alt-shift-backspace": "editor::DeleteToNextWordEnd",
"alt-delete": "editor::DeleteToNextWordEnd",
"alt-shift-delete": "editor::DeleteToNextWordEnd",
"ctrl-backspace": "editor::DeleteToPreviousSubwordStart",
"ctrl-delete": "editor::DeleteToNextSubwordEnd",
"alt-left": ["editor::MoveToPreviousWordStart", { "stop_at_soft_wraps": true }],

View File

@@ -32,6 +32,34 @@
"(": "vim::SentenceBackward",
")": "vim::SentenceForward",
"|": "vim::GoToColumn",
"] ]": "vim::NextSectionStart",
"] [": "vim::NextSectionEnd",
"[ [": "vim::PreviousSectionStart",
"[ ]": "vim::PreviousSectionEnd",
"] m": "vim::NextMethodStart",
"] shift-m": "vim::NextMethodEnd",
"[ m": "vim::PreviousMethodStart",
"[ shift-m": "vim::PreviousMethodEnd",
"[ *": "vim::PreviousComment",
"[ /": "vim::PreviousComment",
"] *": "vim::NextComment",
"] /": "vim::NextComment",
"[ -": "vim::PreviousLesserIndent",
"[ +": "vim::PreviousGreaterIndent",
"[ =": "vim::PreviousSameIndent",
"] -": "vim::NextLesserIndent",
"] +": "vim::NextGreaterIndent",
"] =": "vim::NextSameIndent",
"] b": "pane::ActivateNextItem",
"[ b": "pane::ActivatePreviousItem",
"] shift-b": "pane::ActivateLastItem",
"[ shift-b": ["pane::ActivateItem", 0],
"] space": "vim::InsertEmptyLineBelow",
"[ space": "vim::InsertEmptyLineAbove",
"[ e": "editor::MoveLineUp",
"] e": "editor::MoveLineDown",
"[ f": "workspace::FollowNextCollaborator",
"] f": "workspace::FollowNextCollaborator",
// Word motions
"w": "vim::NextWordStart",
@@ -55,6 +83,10 @@
"n": "vim::MoveToNextMatch",
"shift-n": "vim::MoveToPreviousMatch",
"%": "vim::Matching",
"] }": ["vim::UnmatchedForward", { "char": "}" }],
"[ {": ["vim::UnmatchedBackward", { "char": "{" }],
"] )": ["vim::UnmatchedForward", { "char": ")" }],
"[ (": ["vim::UnmatchedBackward", { "char": "(" }],
"f": ["vim::PushFindForward", { "before": false, "multiline": false }],
"t": ["vim::PushFindForward", { "before": true, "multiline": false }],
"shift-f": ["vim::PushFindBackward", { "after": false, "multiline": false }],
@@ -95,8 +127,8 @@
"g g": "vim::StartOfDocument",
"g h": "editor::Hover",
"g B": "editor::BlameHover",
"g t": "vim::GoToTab",
"g shift-t": "vim::GoToPreviousTab",
"g t": "pane::ActivateNextItem",
"g shift-t": "pane::ActivatePreviousItem",
"g d": "editor::GoToDefinition",
"g shift-d": "editor::GoToDeclaration",
"g y": "editor::GoToTypeDefinition",
@@ -187,46 +219,6 @@
".": "vim::Repeat"
}
},
{
"context": "vim_mode == normal || vim_mode == visual || vim_mode == operator",
"bindings": {
"] ]": "vim::NextSectionStart",
"] [": "vim::NextSectionEnd",
"[ [": "vim::PreviousSectionStart",
"[ ]": "vim::PreviousSectionEnd",
"] m": "vim::NextMethodStart",
"] shift-m": "vim::NextMethodEnd",
"[ m": "vim::PreviousMethodStart",
"[ shift-m": "vim::PreviousMethodEnd",
"[ *": "vim::PreviousComment",
"[ /": "vim::PreviousComment",
"] *": "vim::NextComment",
"] /": "vim::NextComment",
"[ -": "vim::PreviousLesserIndent",
"[ +": "vim::PreviousGreaterIndent",
"[ =": "vim::PreviousSameIndent",
"] -": "vim::NextLesserIndent",
"] +": "vim::NextGreaterIndent",
"] =": "vim::NextSameIndent",
"] b": "pane::ActivateNextItem",
"[ b": "pane::ActivatePreviousItem",
"] shift-b": "pane::ActivateLastItem",
"[ shift-b": ["pane::ActivateItem", 0],
"] space": "vim::InsertEmptyLineBelow",
"[ space": "vim::InsertEmptyLineAbove",
"[ e": "editor::MoveLineUp",
"] e": "editor::MoveLineDown",
"[ f": "workspace::FollowNextCollaborator",
"] f": "workspace::FollowNextCollaborator",
"] }": ["vim::UnmatchedForward", { "char": "}" }],
"[ {": ["vim::UnmatchedBackward", { "char": "{" }],
"] )": ["vim::UnmatchedForward", { "char": ")" }],
"[ (": ["vim::UnmatchedBackward", { "char": "(" }],
// tree-sitter related commands
"[ x": "vim::SelectLargerSyntaxNode",
"] x": "vim::SelectSmallerSyntaxNode"
}
},
{
"context": "vim_mode == normal",
"bindings": {
@@ -240,7 +232,6 @@
"delete": "vim::DeleteRight",
"g shift-j": "vim::JoinLinesNoWhitespace",
"y": "vim::PushYank",
"shift-y": "vim::YankLine",
"x": "vim::DeleteRight",
"shift-x": "vim::DeleteLeft",
"ctrl-a": "vim::Increment",
@@ -258,6 +249,9 @@
"g w": "vim::PushRewrap",
"g q": "vim::PushRewrap",
"insert": "vim::InsertBefore",
// tree-sitter related commands
"[ x": "vim::SelectLargerSyntaxNode",
"] x": "vim::SelectSmallerSyntaxNode",
"] d": "editor::GoToDiagnostic",
"[ d": "editor::GoToPreviousDiagnostic",
"] c": "editor::GoToHunk",
@@ -323,28 +317,10 @@
"g w": "vim::Rewrap",
"g ?": "vim::ConvertToRot13",
// "g ?": "vim::ConvertToRot47",
"\"": "vim::PushRegister"
}
},
{
"context": "vim_mode == helix_select",
"bindings": {
"v": "vim::NormalBefore",
";": "vim::HelixCollapseSelection",
"~": "vim::ChangeCase",
"ctrl-a": "vim::Increment",
"ctrl-x": "vim::Decrement",
"shift-j": "vim::JoinLines",
"i": "vim::InsertBefore",
"a": "vim::InsertAfter",
"p": "vim::Paste",
"u": "vim::Undo",
"r": "vim::PushReplace",
"s": "vim::Substitute",
"ctrl-pageup": "pane::ActivatePreviousItem",
"ctrl-pagedown": "pane::ActivateNextItem",
".": "vim::Repeat",
"alt-.": "vim::RepeatFind"
"\"": "vim::PushRegister",
// tree-sitter related commands
"[ x": "editor::SelectLargerSyntaxNode",
"] x": "editor::SelectSmallerSyntaxNode"
}
},
{
@@ -361,7 +337,7 @@
"ctrl-x ctrl-z": "editor::Cancel",
"ctrl-x ctrl-e": "vim::LineDown",
"ctrl-x ctrl-y": "vim::LineUp",
"ctrl-w": ["editor::DeleteToPreviousWordStart", { "ignore_newlines": false, "ignore_brackets": false }],
"ctrl-w": "editor::DeleteToPreviousWordStart",
"ctrl-u": "editor::DeleteToBeginningOfLine",
"ctrl-t": "vim::Indent",
"ctrl-d": "vim::Outdent",
@@ -378,15 +354,6 @@
"ctrl-s": "editor::ShowSignatureHelp"
}
},
{
"context": "showing_completions",
"bindings": {
"ctrl-d": "vim::ScrollDown",
"ctrl-u": "vim::ScrollUp",
"ctrl-e": "vim::LineDown",
"ctrl-y": "vim::LineUp"
}
},
{
"context": "(vim_mode == normal || vim_mode == helix_normal) && !menu",
"bindings": {
@@ -418,25 +385,14 @@
"bindings": {
"i": "vim::HelixInsert",
"a": "vim::HelixAppend",
"ctrl-[": "editor::Cancel"
}
},
{
"context": "(vim_mode == helix_normal || vim_mode == helix_select) && !menu",
"bindings": {
"ctrl-[": "editor::Cancel",
";": "vim::HelixCollapseSelection",
":": "command_palette::Toggle",
"m": "vim::PushHelixMatch",
"s": "vim::HelixSelectRegex",
"]": ["vim::PushHelixNext", { "around": true }],
"[": ["vim::PushHelixPrevious", { "around": true }],
"left": "vim::WrappingLeft",
"right": "vim::WrappingRight",
"h": "vim::WrappingLeft",
"l": "vim::WrappingRight",
"y": "vim::HelixYank",
"p": "vim::HelixPaste",
"shift-p": ["vim::HelixPaste", { "before": true }],
"alt-;": "vim::OtherEnd",
"ctrl-r": "vim::Redo",
"f": ["vim::PushFindForward", { "before": false, "multiline": true }],
@@ -446,13 +402,21 @@
">": "vim::Indent",
"<": "vim::Outdent",
"=": "vim::AutoIndent",
"`": "vim::ConvertToLowerCase",
"alt-`": "vim::ConvertToUpperCase",
"g u": "vim::PushLowercase",
"g shift-u": "vim::PushUppercase",
"g ~": "vim::PushOppositeCase",
"g q": "vim::PushRewrap",
"g w": "vim::PushRewrap",
"insert": "vim::InsertBefore",
"alt-.": "vim::RepeatFind",
"alt-s": ["editor::SplitSelectionIntoLines", { "keep_selections": true }],
// tree-sitter related commands
"[ x": "editor::SelectLargerSyntaxNode",
"] x": "editor::SelectSmallerSyntaxNode",
"] d": "editor::GoToDiagnostic",
"[ d": "editor::GoToPreviousDiagnostic",
"] c": "editor::GoToHunk",
"[ c": "editor::GoToPreviousHunk",
// Goto mode
"g n": "pane::ActivateNextItem",
"g p": "pane::ActivatePreviousItem",
@@ -464,14 +428,12 @@
"g h": "vim::StartOfLine",
"g s": "vim::FirstNonWhitespace", // "g s" default behavior is "space s"
"g e": "vim::EndOfDocument",
"g .": "vim::HelixGotoLastModification", // go to last modification
"g r": "editor::FindAllReferences", // zed specific
"g t": "vim::WindowTop",
"g c": "vim::WindowMiddle",
"g b": "vim::WindowBottom",
"shift-r": "editor::Paste",
"x": "vim::HelixSelectLine",
"x": "editor::SelectLine",
"shift-x": "editor::SelectLine",
"%": "editor::SelectAll",
// Window mode
@@ -496,6 +458,9 @@
"space c": "editor::ToggleComments",
"space y": "editor::Copy",
"space p": "editor::Paste",
// Match mode
"m m": "vim::Matching",
"m i w": ["workspace::SendKeystrokes", "v i w"],
"shift-u": "editor::Redo",
"ctrl-c": "editor::ToggleComments",
"d": "vim::HelixDelete",
@@ -564,7 +529,7 @@
}
},
{
"context": "vim_operator == a || vim_operator == i || vim_operator == cs || vim_operator == helix_next || vim_operator == helix_previous",
"context": "vim_operator == a || vim_operator == i || vim_operator == cs",
"bindings": {
"w": "vim::Word",
"shift-w": ["vim::Word", { "ignore_punctuation": true }],
@@ -580,18 +545,18 @@
// "q": "vim::AnyQuotes",
"q": "vim::MiniQuotes",
"|": "vim::VerticalBars",
"(": ["vim::Parentheses", { "opening": true }],
"(": "vim::Parentheses",
")": "vim::Parentheses",
"b": "vim::Parentheses",
// "b": "vim::AnyBrackets",
// "b": "vim::MiniBrackets",
"[": ["vim::SquareBrackets", { "opening": true }],
"[": "vim::SquareBrackets",
"]": "vim::SquareBrackets",
"r": "vim::SquareBrackets",
"{": ["vim::CurlyBrackets", { "opening": true }],
"{": "vim::CurlyBrackets",
"}": "vim::CurlyBrackets",
"shift-b": "vim::CurlyBrackets",
"<": ["vim::AngleBrackets", { "opening": true }],
"<": "vim::AngleBrackets",
">": "vim::AngleBrackets",
"a": "vim::Argument",
"i": "vim::IndentObj",
@@ -601,48 +566,6 @@
"e": "vim::EntireFile"
}
},
{
"context": "vim_operator == helix_m",
"bindings": {
"m": "vim::Matching"
}
},
{
"context": "vim_operator == helix_next",
"bindings": {
"z": "vim::NextSectionStart",
"shift-z": "vim::NextSectionEnd",
"*": "vim::NextComment",
"/": "vim::NextComment",
"-": "vim::NextLesserIndent",
"+": "vim::NextGreaterIndent",
"=": "vim::NextSameIndent",
"b": "pane::ActivateNextItem",
"shift-b": "pane::ActivateLastItem",
"x": "editor::SelectSmallerSyntaxNode",
"d": "editor::GoToDiagnostic",
"c": "editor::GoToHunk",
"space": "vim::InsertEmptyLineBelow"
}
},
{
"context": "vim_operator == helix_previous",
"bindings": {
"z": "vim::PreviousSectionStart",
"shift-z": "vim::PreviousSectionEnd",
"*": "vim::PreviousComment",
"/": "vim::PreviousComment",
"-": "vim::PreviousLesserIndent",
"+": "vim::PreviousGreaterIndent",
"=": "vim::PreviousSameIndent",
"b": "pane::ActivatePreviousItem",
"shift-b": ["pane::ActivateItem", 0],
"x": "editor::SelectLargerSyntaxNode",
"d": "editor::GoToPreviousDiagnostic",
"c": "editor::GoToPreviousHunk",
"space": "vim::InsertEmptyLineAbove"
}
},
{
"context": "vim_operator == c",
"bindings": {
@@ -884,21 +807,19 @@
"/": "project_panel::NewSearchInDirectory",
"d": "project_panel::NewDirectory",
"enter": "project_panel::OpenPermanent",
"escape": "vim::ToggleProjectPanelFocus",
"escape": "project_panel::ToggleFocus",
"h": "project_panel::CollapseSelectedEntry",
"j": "vim::MenuSelectNext",
"k": "vim::MenuSelectPrevious",
"down": "vim::MenuSelectNext",
"up": "vim::MenuSelectPrevious",
"j": "menu::SelectNext",
"k": "menu::SelectPrevious",
"l": "project_panel::ExpandSelectedEntry",
"o": "project_panel::OpenPermanent",
"shift-d": "project_panel::Delete",
"shift-r": "project_panel::Rename",
"t": "project_panel::OpenPermanent",
"v": "project_panel::OpenSplitVertical",
"o": "project_panel::OpenSplitHorizontal",
"v": "project_panel::OpenPermanent",
"p": "project_panel::Open",
"x": "project_panel::RevealInFileManager",
"s": "workspace::OpenWithSystem",
"s": "project_panel::OpenWithSystem",
"z d": "project_panel::CompareMarkedFiles",
"] c": "project_panel::SelectNextGitEntry",
"[ c": "project_panel::SelectPrevGitEntry",
@@ -908,22 +829,7 @@
"{": "project_panel::SelectPrevDirectory",
"shift-g": "menu::SelectLast",
"g g": "menu::SelectFirst",
"-": "project_panel::SelectParent",
"ctrl-u": "project_panel::ScrollUp",
"ctrl-d": "project_panel::ScrollDown",
"z t": "project_panel::ScrollCursorTop",
"z z": "project_panel::ScrollCursorCenter",
"z b": "project_panel::ScrollCursorBottom",
"0": ["vim::Number", 0],
"1": ["vim::Number", 1],
"2": ["vim::Number", 2],
"3": ["vim::Number", 3],
"4": ["vim::Number", 4],
"5": ["vim::Number", 5],
"6": ["vim::Number", 6],
"7": ["vim::Number", 7],
"8": ["vim::Number", 8],
"9": ["vim::Number", 9]
"-": "project_panel::SelectParent"
}
},
{

View File

@@ -172,7 +172,7 @@ The user has specified the following rules that should be applied:
Rules title: {{title}}
{{/if}}
``````
{{contents}}
{{contents}}}
``````
{{/each}}
{{/if}}

View File

@@ -29,9 +29,7 @@ Generate {{content_type}} based on the following prompt:
Match the indentation in the original file in the inserted {{content_type}}, don't include any indentation on blank lines.
Return ONLY the {{content_type}} to insert. Do NOT include any XML tags like <document>, <insert_here>, or any surrounding markup from the input.
Respond with a code block containing the {{content_type}} to insert. Replace \{{INSERTED_CODE}} with your actual {{content_type}}:
Immediately start with the following format with no remarks:
```
\{{INSERTED_CODE}}
@@ -68,9 +66,7 @@ Only make changes that are necessary to fulfill the prompt, leave everything els
Start at the indentation level in the original file in the rewritten {{content_type}}. Don't stop until you've rewritten the entire section, even if you have no more changes to make, always write out the whole section with no unnecessary elisions.
Return ONLY the rewritten {{content_type}}. Do NOT include any XML tags like <document>, <rewrite_this>, or any surrounding markup from the input.
Respond with a code block containing the rewritten {{content_type}}. Replace \{{REWRITTEN_CODE}} with your actual rewritten {{content_type}}:
Immediately start with the following format with no remarks:
```
\{{REWRITTEN_CODE}}

View File

@@ -1,8 +1,4 @@
{
"$schema": "zed://schemas/settings",
/// The displayed name of this project. If not set or empty, the root directory name
/// will be displayed.
"project_name": "",
// The name of the Zed theme to use for the UI.
//
// `mode` is one of:
@@ -75,10 +71,8 @@
"ui_font_weight": 400,
// The default font size for text in the UI
"ui_font_size": 16,
// The default font size for agent responses in the agent panel. Falls back to the UI font size if unset.
"agent_ui_font_size": null,
// The default font size for user messages in the agent panel.
"agent_buffer_font_size": 12,
// The default font size for text in the agent panel. Falls back to the UI font size if unset.
"agent_font_size": null,
// How much to fade out unused code.
"unnecessary_code_fade": 0.3,
// Active pane styling settings.
@@ -120,7 +114,6 @@
// Whether to enable vim modes and key bindings.
"vim_mode": false,
// Whether to enable helix mode and key bindings.
// Enabling this mode will automatically enable vim mode.
"helix_mode": false,
// Whether to show the informational hover box when moving the mouse
// over symbols in the editor.
@@ -169,12 +162,6 @@
// 2. Always quit the application
// "on_last_window_closed": "quit_app",
"on_last_window_closed": "platform_default",
// Whether to show padding for zoomed panels.
// When enabled, zoomed center panels (e.g. code editor) will have padding all around,
// while zoomed bottom/left/right panels will have padding to the top/right/left (respectively).
//
// Default: true
"zoomed_padding": true,
// Whether to use the system provided dialogs for Open and Save As.
// When set to false, Zed will use the built-in keyboard-first pickers.
"use_system_path_prompts": true,
@@ -195,8 +182,8 @@
// 4. A box drawn around the following character
// "hollow"
//
// Default: "bar"
"cursor_shape": "bar",
// Default: not set, defaults to "bar"
"cursor_shape": null,
// Determines when the mouse cursor should be hidden in an editor or input box.
//
// 1. Never hide the mouse cursor:
@@ -230,25 +217,9 @@
"current_line_highlight": "all",
// Whether to highlight all occurrences of the selected text in an editor.
"selection_highlight": true,
// Whether the text selection should have rounded corners.
"rounded_selection": true,
// The debounce delay before querying highlights from the language
// server based on the current cursor location.
"lsp_highlight_debounce": 75,
// The minimum APCA perceptual contrast between foreground and background colors.
// APCA (Accessible Perceptual Contrast Algorithm) is more accurate than WCAG 2.x,
// especially for dark mode. Values range from 0 to 106.
//
// Based on APCA Readability Criterion (ARC) Bronze Simple Mode:
// https://readtech.org/ARC/tests/bronze-simple-mode/
// - 0: No contrast adjustment
// - 45: Minimum for large fluent text (36px+)
// - 60: Minimum for other content text
// - 75: Minimum for body text
// - 90: Preferred for body text
//
// This only affects text drawn over highlight backgrounds in the editor.
"minimum_contrast_for_highlights": 45,
// Whether to pop the completions menu while typing in an editor without
// explicitly requesting it.
"show_completions_on_input": true,
@@ -289,8 +260,8 @@
// - "warning"
// - "info"
// - "hint"
// - "all" — allow all diagnostics (default)
"diagnostics_max_severity": "all",
// - null — allow all diagnostics (default)
"diagnostics_max_severity": null,
// Whether to show wrap guides (vertical rulers) in the editor.
// Setting this to true will show a guide at the 'preferred_line_length' value
// if 'soft_wrap' is set to 'preferred_line_length', and will show any
@@ -302,8 +273,6 @@
"redact_private_values": false,
// The default number of lines to expand excerpts in the multibuffer by.
"expand_excerpt_lines": 5,
// The default number of context lines shown in multibuffer excerpts.
"excerpt_context_lines": 2,
// Globs to match against file paths to determine if a file is private.
"private_files": ["**/.env*", "**/*.pem", "**/*.key", "**/*.cert", "**/*.crt", "**/secrets.yml"],
// Whether to use additional LSP queries to format (and amend) the code after
@@ -317,7 +286,7 @@
// bracket, brace, single or double quote characters.
// For example, when you select text and type (, Zed will surround the text with ().
"use_auto_surround": true,
// Whether indentation should be adjusted based on the context whilst typing.
/// Whether indentation should be adjusted based on the context whilst typing.
"auto_indent": true,
// Whether indentation of pasted content should be adjusted based on the context.
"auto_indent_on_paste": true,
@@ -368,11 +337,6 @@
// - It is adjacent to an edge (start or end)
// - It is adjacent to a whitespace (left or right)
"show_whitespaces": "selection",
// Visible characters used to render whitespace when show_whitespaces is enabled.
"whitespace_map": {
"space": "•",
"tab": "→"
},
// Settings related to calls in Zed
"calls": {
// Join calls with the microphone live by default
@@ -393,8 +357,6 @@
// Whether to show code action buttons in the editor toolbar.
"code_actions": false
},
// Whether to allow windows to tab together based on the users tabbing preference (macOS only).
"use_system_window_tabs": false,
// Titlebar related settings
"title_bar": {
// Whether to show the branch icon beside branch switcher in the titlebar.
@@ -412,39 +374,6 @@
// Whether to show the menus in the titlebar.
"show_menus": false
},
"audio": {
// Opt into the new audio system.
"experimental.rodio_audio": false,
// Requires 'rodio_audio: true'
//
// Automatically increase or decrease you microphone's volume. This affects how
// loud you sound to others.
//
// Recommended: off (default)
// Microphones are too quite in zed, until everyone is on experimental
// audio and has auto speaker volume on this will make you very loud
// compared to other speakers.
"experimental.auto_microphone_volume": false,
// Requires 'rodio_audio: true'
//
// Automatically increate or decrease the volume of other call members.
// This only affects how things sound for you.
"experimental.auto_speaker_volume": true,
// Requires 'rodio_audio: true'
//
// Remove background noises. Works great for typing, cars, dogs, AC. Does
// not work well on music.
"experimental.denoise": true,
// Requires 'rodio_audio: true'
//
// Use audio parameters compatible with the previous versions of
// experimental audio and non-experimental audio. When this is false you
// will sound strange to anyone not on the latest experimental audio. In
// the future we will migrate by setting this to false
//
// You need to rejoin a call for this setting to apply
"experimental.legacy_audio_compatible": true
},
// Scrollbar related settings
"scrollbar": {
// When to show the scrollbar in the editor.
@@ -625,7 +554,6 @@
// Toggle certain types of hints on and off, all switched on by default.
"show_type_hints": true,
"show_parameter_hints": true,
"show_value_hints": true,
// Corresponds to null/None LSP hint type value.
"show_other_hints": true,
// Whether to show a background for inlay hints.
@@ -719,12 +647,8 @@
// "never"
"show": "always"
},
// Whether to enable drag-and-drop operations in the project panel.
"drag_and_drop": true,
// Whether to hide the root entry when only one folder is open in the window.
"hide_root": false,
// Whether to hide the hidden entries in the project panel.
"hide_hidden": false
"hide_root": false
},
"outline_panel": {
// Whether to show the outline panel button in the status bar
@@ -788,6 +712,16 @@
// Default width of the collaboration panel.
"default_width": 240
},
"chat_panel": {
// When to show the chat panel button in the status bar.
// Can be 'never', 'always', or 'when_in_call',
// or a boolean (interpreted as 'never'/'always').
"button": "when_in_call",
// Where to dock the chat panel. Can be 'left' or 'right'.
"dock": "right",
// Default width of the chat panel.
"default_width": 240
},
"git_panel": {
// Whether to show the git panel button in the status bar.
"button": true,
@@ -836,7 +770,7 @@
"agent": {
// Whether the agent is enabled.
"enabled": true,
// What completion mode to start new threads in, if available. Can be 'normal' or 'burn'.
/// What completion mode to start new threads in, if available. Can be 'normal' or 'burn'.
"preferred_completion_mode": "normal",
// Whether to show the agent panel button in the status bar.
"button": true,
@@ -846,8 +780,6 @@
"default_width": 640,
// Default height when the agent panel is docked to the bottom.
"default_height": 320,
// The view to use by default (thread, or text_thread)
"default_view": "thread",
// The default model to use when creating new threads.
"default_model": {
// The provider to use.
@@ -878,9 +810,6 @@
// }
],
// When enabled, the agent can run potentially destructive actions without asking for your confirmation.
//
// Note: This setting has no effect on external agents that support permission modes, such as Claude Code.
// You can set `agent_servers.claude.default_mode` to `bypassPermissions` to skip all permission requests.
"always_allow_tool_actions": false,
// When enabled, the agent will stream edits.
"stream_edits": false,
@@ -949,22 +878,22 @@
// Default: false
"play_sound_when_agent_done": false,
// Whether to have edit cards in the agent panel expanded, showing a preview of the full diff.
//
// Default: true
/// Whether to have edit cards in the agent panel expanded, showing a preview of the full diff.
///
/// Default: true
"expand_edit_card": true,
// Whether to have terminal cards in the agent panel expanded, showing the whole command output.
//
// Default: true
"expand_terminal_card": true,
// Whether to always use cmd-enter (or ctrl-enter on Linux or Windows) to send messages in the agent panel.
//
// Default: false
"use_modifier_to_send": false,
// Minimum number of lines to display in the agent message editor.
//
// Default: 4
"message_editor_min_lines": 4
/// Whether to have terminal cards in the agent panel expanded, showing the whole command output.
///
/// Default: true
"expand_terminal_card": true
},
// The settings for slash commands.
"slash_commands": {
// Settings for the `/project` slash command.
"project": {
// Whether `/project` is enabled.
"enabled": false
}
},
// Whether the screen sharing icon is shown in the os status bar.
"show_call_status_icon": true,
@@ -977,7 +906,6 @@
//
// This is typically customized on a per-language basis.
"language_servers": ["..."],
// When to automatically save edited buffers. This setting can
// take four values.
//
@@ -1006,7 +934,7 @@
// Show git status colors in the editor tabs.
"git_status": false,
// Position of the close button on the editor tabs.
// One of: ["right", "left"]
// One of: ["right", "left", "hidden"]
"close_position": "right",
// Whether to show the file icon for a tab.
"file_icons": false,
@@ -1104,7 +1032,7 @@
// Removes any lines containing only whitespace at the end of the file and
// ensures just one newline at the end.
"ensure_final_newline_on_save": true,
// Whether or not to perform a buffer format before saving: [on, off]
// Whether or not to perform a buffer format before saving: [on, off, prettier, language_server]
// Keep in mind, if the autosave with delay is enabled, format_on_save will be ignored
"format_on_save": "on",
// How to perform a buffer format. This setting can take 4 values:
@@ -1205,6 +1133,11 @@
// The minimum severity of the diagnostics to show inline.
// Inherits editor's diagnostics' max severity settings when `null`.
"max_severity": null
},
"cargo": {
// When enabled, Zed disables rust-analyzer's check on save and starts to query
// Cargo diagnostics separately.
"fetch_cargo_diagnostics": false
}
},
// Files or globs of files that will be excluded by Zed entirely. They will be skipped during file
@@ -1234,10 +1167,6 @@
// 2. Hide the gutter
// "git_gutter": "hide"
"git_gutter": "tracked_files",
/// Sets the debounce threshold (in milliseconds) after which changes are reflected in the git gutter.
///
/// Default: 0
"gutter_debounce": 0,
// Control whether the git blame information is shown inline,
// in the currently focused line.
"inline_blame": {
@@ -1253,13 +1182,6 @@
// The minimum column number to show the inline blame information at
"min_column": 0
},
"blame": {
"show_avatar": true
},
// Control which information is shown in the branch picker.
"branch_picker": {
"show_author_name": true
},
// How git hunks are displayed visually in the editor.
// This setting can take two values:
//
@@ -1314,15 +1236,6 @@
// "proxy": "",
// "proxy_no_verify": false
// },
"copilot": {
"enterprise_uri": null,
"proxy": null,
"proxy_no_verify": null
},
"codestral": {
"model": null,
"max_tokens": null
},
// Whether edit predictions are enabled when editing text threads.
// This setting has no effect if globally disabled.
"enabled_in_text_threads": true
@@ -1339,8 +1252,6 @@
},
// Status bar-related settings.
"status_bar": {
// Whether to show the status bar.
"experimental.show": true,
// Whether to show the active language button in the status bar.
"active_language_button": true,
// Whether to show the cursor position button in the status bar.
@@ -1407,8 +1318,8 @@
// 4. A box drawn around the following character
// "hollow"
//
// Default: "block"
"cursor_shape": "block",
// Default: not set, defaults to "block"
"cursor_shape": null,
// Set whether Alternate Scroll mode (code: ?1007) is active by default.
// Alternate Scroll mode converts mouse scroll events into up / down key
// presses when in the alternate screen (e.g. when running applications
@@ -1430,8 +1341,8 @@
// Whether or not selecting text in the terminal will automatically
// copy to the system clipboard.
"copy_on_select": false,
// Whether to keep the text selection after copying it to the clipboard.
"keep_selection_on_copy": true,
// Whether to keep the text selection after copying it to the clipboard
"keep_selection_on_copy": false,
// Whether to show the terminal button in the status bar
"button": true,
// Any key-value pairs added to this list will be added to the terminal's
@@ -1450,7 +1361,7 @@
// "line_height": {
// "custom": 2
// },
"line_height": "standard",
"line_height": "comfortable",
// Activate the python virtual environment, if one is found, in the
// terminal's working directory (as resolved by the working_directory
// setting). Set this to "off" to disable this behavior.
@@ -1470,7 +1381,7 @@
//
// The shell running in the terminal needs to be configured to emit the title.
// Example: `echo -e "\e]2;New Title\007";`
"breadcrumbs": false
"breadcrumbs": true
},
// Scrollbar-related settings
"scrollbar": {
@@ -1521,6 +1432,7 @@
// A value of 45 preserves colorful themes while ensuring legibility.
"minimum_contrast": 45
},
"code_actions_on_format": {},
// Settings related to running tasks.
"tasks": {
"variables": {},
@@ -1549,7 +1461,7 @@
// }
//
"file_types": {
"JSONC": ["**/.zed/**/*.json", "**/zed/**/*.json", "**/Zed/**/*.json", "**/.vscode/**/*.json", "tsconfig*.json"],
"JSONC": ["**/.zed/**/*.json", "**/zed/**/*.json", "**/Zed/**/*.json", "**/.vscode/**/*.json"],
"Shell Script": [".env.*"]
},
// Settings for which version of Node.js and NPM to use when installing
@@ -1575,14 +1487,6 @@
"auto_install_extensions": {
"html": true
},
// The capabilities granted to extensions.
//
// This list can be customized to restrict what extensions are able to do.
"granted_extension_capabilities": [
{ "kind": "process:exec", "command": "*", "args": ["**"] },
{ "kind": "download_file", "host": "*", "path": ["**"] },
{ "kind": "npm:install", "package": "*" }
],
// Controls how completions are processed for this language.
"completions": {
// Controls how words are completed.
@@ -1599,11 +1503,6 @@
//
// Default: fallback
"words": "fallback",
// Minimum number of characters required to automatically trigger word-based completions.
// Before that value, it's still possible to trigger the words-based completion manually with the corresponding editor command.
//
// Default: 3
"words_min_length": 3,
// Whether to fetch LSP completions or not.
//
// Default: true
@@ -1676,7 +1575,7 @@
"ensure_final_newline_on_save": false
},
"Elixir": {
"language_servers": ["elixir-ls", "!expert", "!next-ls", "!lexical", "..."]
"language_servers": ["elixir-ls", "!next-ls", "!lexical", "..."]
},
"Elm": {
"tab_size": 4
@@ -1690,7 +1589,9 @@
"preferred_line_length": 72
},
"Go": {
"formatter": [{ "code_action": "source.organizeImports" }, { "language_server": {} }],
"code_actions_on_format": {
"source.organizeImports": true
},
"debuggers": ["Delve"]
},
"GraphQL": {
@@ -1699,7 +1600,7 @@
}
},
"HEEX": {
"language_servers": ["elixir-ls", "!expert", "!next-ls", "!lexical", "..."]
"language_servers": ["elixir-ls", "!next-ls", "!lexical", "..."]
},
"HTML": {
"prettier": {
@@ -1728,9 +1629,6 @@
"allowed": true
}
},
"Kotlin": {
"language_servers": ["kotlin-language-server", "!kotlin-lsp", "..."]
},
"LaTeX": {
"formatter": "language_server",
"language_servers": ["texlab", "..."],
@@ -1744,6 +1642,9 @@
"use_on_type_format": false,
"allow_rewrap": "anywhere",
"soft_wrap": "editor_width",
"completions": {
"words": "disabled"
},
"prettier": {
"allowed": true
}
@@ -1757,14 +1658,12 @@
}
},
"Plain Text": {
"completions": {
"words": "disabled"
},
"allow_rewrap": "anywhere"
},
"Python": {
"formatter": {
"language_server": {
"name": "ruff"
}
},
"debuggers": ["Debugpy"]
},
"Ruby": {
@@ -1835,7 +1734,6 @@
"anthropic": {
"api_url": "https://api.anthropic.com"
},
"bedrock": {},
"google": {
"api_url": "https://generativelanguage.googleapis.com"
},
@@ -1853,45 +1751,31 @@
"api_url": "http://localhost:1234/api/v0"
},
"deepseek": {
"api_url": "https://api.deepseek.com/v1"
"api_url": "https://api.deepseek.com"
},
"mistral": {
"api_url": "https://api.mistral.ai/v1"
},
"vercel": {
"api_url": "https://api.v0.dev/v1"
},
"x_ai": {
"api_url": "https://api.x.ai/v1"
},
"zed.dev": {}
},
"session": {
// Whether or not to restore unsaved buffers on restart.
//
// If this is true, user won't be prompted whether to save/discard
// dirty files when closing the application.
//
// Default: true
"restore_unsaved_buffers": true
}
},
// Zed's Prettier integration settings.
// Allows to enable/disable formatting with Prettier
// and configure default Prettier, used when no project-level Prettier installation is found.
"prettier": {
// Enables or disables formatting with Prettier for any given language.
"allowed": false,
// Forces Prettier integration to use a specific parser name when formatting files with the language.
"plugins": [],
// Default Prettier options, in the format as in package.json section for Prettier.
// If project installs Prettier via its package.json, these options will be ignored.
// // Whether to consider prettier formatter or not when attempting to format a file.
// "allowed": false,
//
// // Use regular Prettier json configuration.
// // If Prettier is allowed, Zed will use this for its Prettier instance for any applicable file, if
// // the project has no other Prettier installed.
// "plugins": [],
//
// // Use regular Prettier json configuration.
// // If Prettier is allowed, Zed will use this for its Prettier instance for any applicable file, if
// // the project has no other Prettier installed.
// "trailingComma": "es5",
// "tabWidth": 4,
// "semi": false,
// "singleQuote": true
// Forces Prettier integration to use a specific parser name when formatting files with the language
// when set to a non-empty string.
"parser": ""
},
// Settings for auto-closing of JSX tags.
"jsx_tag_auto_close": {
@@ -1911,10 +1795,6 @@
// }
// }
},
// DAP Specific settings.
"dap": {
// Specify the DAP name as a key here.
},
// Common language server settings.
"global_lsp_settings": {
// Whether to show the LSP servers button in the status bar.
@@ -1922,23 +1802,13 @@
},
// Jupyter settings
"jupyter": {
"enabled": true,
"kernel_selections": {}
"enabled": true
// Specify the language name as the key and the kernel name as the value.
// "kernel_selections": {
// "python": "conda-base"
// "typescript": "deno"
// }
},
// REPL settings.
"repl": {
// Maximum number of columns to keep in REPL's scrollback buffer.
// Clamped with [20, 512] range.
"max_columns": 128,
// Maximum number of lines to keep in REPL's scrollback buffer.
// Clamped with [4, 256] range.
"max_lines": 32
},
// Vim settings
"vim": {
"default_mode": "normal",
@@ -2029,10 +1899,7 @@
"debugger": {
"stepping_granularity": "line",
"save_breakpoints": true,
"timeout": 2000,
"dock": "bottom",
"log_dap_communications": true,
"format_dap_log_messages": true,
"button": true
},
// Configures any number of settings profiles that are temporarily applied on
@@ -2041,7 +1908,7 @@
// Examples:
// "profiles": {
// "Presenting": {
// "agent_ui_font_size": 20.0,
// "agent_font_size": 20.0,
// "buffer_font_size": 20.0,
// "theme": "One Light",
// "ui_font_size": 20.0
@@ -2054,11 +1921,5 @@
// }
// }
// }
"profiles": {},
// A map of log scopes to the desired log level.
// Useful for filtering out noisy logs or enabling more verbose logging.
//
// Example: {"log": {"client": "warn"}}
"log": {}
"profiles": []
}

View File

@@ -44,11 +44,7 @@
// }
// }
"shell": "system",
// Whether to show the task line in the output of the spawned task, defaults to `true`.
"show_summary": true,
// Whether to show the command line in the output of the spawned task, defaults to `true`.
"show_command": true
// Represents the tags for inline runnable indicators, or spawning multiple tasks at once.
// "tags": []
"tags": []
}
]

Binary file not shown.

View File

@@ -93,7 +93,7 @@
"terminal.ansi.bright_cyan": "#4c806fff",
"terminal.ansi.dim_cyan": "#cbf2e4ff",
"terminal.ansi.white": "#bfbdb6ff",
"terminal.ansi.bright_white": "#fafafaff",
"terminal.ansi.bright_white": "#bfbdb6ff",
"terminal.ansi.dim_white": "#787876ff",
"link_text.hover": "#5ac1feff",
"conflict": "#feb454ff",
@@ -192,7 +192,7 @@
"font_weight": null
},
"comment": {
"color": "#5c6773ff",
"color": "#abb5be8c",
"font_style": null,
"font_weight": null
},
@@ -239,7 +239,7 @@
"hint": {
"color": "#628b80ff",
"font_style": null,
"font_weight": null
"font_weight": 700
},
"keyword": {
"color": "#ff8f3fff",
@@ -316,11 +316,6 @@
"font_style": null,
"font_weight": null
},
"punctuation.markup": {
"color": "#a6a5a0ff",
"font_style": null,
"font_weight": null
},
"punctuation.special": {
"color": "#d2a6ffff",
"font_style": null,
@@ -484,7 +479,7 @@
"terminal.ansi.bright_cyan": "#ace0cbff",
"terminal.ansi.dim_cyan": "#2a5f4aff",
"terminal.ansi.white": "#fcfcfcff",
"terminal.ansi.bright_white": "#ffffffff",
"terminal.ansi.bright_white": "#fcfcfcff",
"terminal.ansi.dim_white": "#bcbec0ff",
"link_text.hover": "#3b9ee5ff",
"conflict": "#f1ad49ff",
@@ -583,7 +578,7 @@
"font_weight": null
},
"comment": {
"color": "#abb0b6ff",
"color": "#787b8099",
"font_style": null,
"font_weight": null
},
@@ -630,7 +625,7 @@
"hint": {
"color": "#8ca7c2ff",
"font_style": null,
"font_weight": null
"font_weight": 700
},
"keyword": {
"color": "#fa8d3eff",
@@ -707,11 +702,6 @@
"font_style": null,
"font_weight": null
},
"punctuation.markup": {
"color": "#73777bff",
"font_style": null,
"font_weight": null
},
"punctuation.special": {
"color": "#a37accff",
"font_style": null,
@@ -875,7 +865,7 @@
"terminal.ansi.bright_cyan": "#4c806fff",
"terminal.ansi.dim_cyan": "#cbf2e4ff",
"terminal.ansi.white": "#cccac2ff",
"terminal.ansi.bright_white": "#fafafaff",
"terminal.ansi.bright_white": "#cccac2ff",
"terminal.ansi.dim_white": "#898a8aff",
"link_text.hover": "#72cffeff",
"conflict": "#fecf72ff",
@@ -974,7 +964,7 @@
"font_weight": null
},
"comment": {
"color": "#5c6773ff",
"color": "#b8cfe680",
"font_style": null,
"font_weight": null
},
@@ -1021,7 +1011,7 @@
"hint": {
"color": "#7399a3ff",
"font_style": null,
"font_weight": null
"font_weight": 700
},
"keyword": {
"color": "#ffad65ff",
@@ -1098,11 +1088,6 @@
"font_style": null,
"font_weight": null
},
"punctuation.markup": {
"color": "#b4b3aeff",
"font_style": null,
"font_weight": null
},
"punctuation.special": {
"color": "#dfbfffff",
"font_style": null,

View File

@@ -94,7 +94,7 @@
"terminal.ansi.bright_cyan": "#45603eff",
"terminal.ansi.dim_cyan": "#c7dfbdff",
"terminal.ansi.white": "#fbf1c7ff",
"terminal.ansi.bright_white": "#ffffffff",
"terminal.ansi.bright_white": "#fbf1c7ff",
"terminal.ansi.dim_white": "#b0a189ff",
"link_text.hover": "#83a598ff",
"version_control.added": "#b7bb26ff",
@@ -248,7 +248,7 @@
"hint": {
"color": "#8c957dff",
"font_style": null,
"font_weight": null
"font_weight": 700
},
"keyword": {
"color": "#fb4833ff",
@@ -325,11 +325,6 @@
"font_style": null,
"font_weight": null
},
"punctuation.markup": {
"color": "#83a598ff",
"font_style": null,
"font_weight": null
},
"punctuation.special": {
"color": "#e5d5adff",
"font_style": null,
@@ -499,7 +494,7 @@
"terminal.ansi.bright_cyan": "#45603eff",
"terminal.ansi.dim_cyan": "#c7dfbdff",
"terminal.ansi.white": "#fbf1c7ff",
"terminal.ansi.bright_white": "#ffffffff",
"terminal.ansi.bright_white": "#fbf1c7ff",
"terminal.ansi.dim_white": "#b0a189ff",
"link_text.hover": "#83a598ff",
"version_control.added": "#b7bb26ff",
@@ -653,7 +648,7 @@
"hint": {
"color": "#8c957dff",
"font_style": null,
"font_weight": null
"font_weight": 700
},
"keyword": {
"color": "#fb4833ff",
@@ -730,11 +725,6 @@
"font_style": null,
"font_weight": null
},
"punctuation.markup": {
"color": "#83a598ff",
"font_style": null,
"font_weight": null
},
"punctuation.special": {
"color": "#e5d5adff",
"font_style": null,
@@ -904,7 +894,7 @@
"terminal.ansi.bright_cyan": "#45603eff",
"terminal.ansi.dim_cyan": "#c7dfbdff",
"terminal.ansi.white": "#fbf1c7ff",
"terminal.ansi.bright_white": "#ffffffff",
"terminal.ansi.bright_white": "#fbf1c7ff",
"terminal.ansi.dim_white": "#b0a189ff",
"link_text.hover": "#83a598ff",
"version_control.added": "#b7bb26ff",
@@ -1058,7 +1048,7 @@
"hint": {
"color": "#8c957dff",
"font_style": null,
"font_weight": null
"font_weight": 700
},
"keyword": {
"color": "#fb4833ff",
@@ -1135,11 +1125,6 @@
"font_style": null,
"font_weight": null
},
"punctuation.markup": {
"color": "#83a598ff",
"font_style": null,
"font_weight": null
},
"punctuation.special": {
"color": "#e5d5adff",
"font_style": null,
@@ -1309,7 +1294,7 @@
"terminal.ansi.bright_cyan": "#9fbca8ff",
"terminal.ansi.dim_cyan": "#253e2eff",
"terminal.ansi.white": "#fbf1c7ff",
"terminal.ansi.bright_white": "#ffffffff",
"terminal.ansi.bright_white": "#fbf1c7ff",
"terminal.ansi.dim_white": "#b0a189ff",
"link_text.hover": "#0b6678ff",
"version_control.added": "#797410ff",
@@ -1463,7 +1448,7 @@
"hint": {
"color": "#677562ff",
"font_style": null,
"font_weight": null
"font_weight": 700
},
"keyword": {
"color": "#9d0006ff",
@@ -1540,11 +1525,6 @@
"font_style": null,
"font_weight": null
},
"punctuation.markup": {
"color": "#066578ff",
"font_style": null,
"font_weight": null
},
"punctuation.special": {
"color": "#413d3aff",
"font_style": null,
@@ -1714,7 +1694,7 @@
"terminal.ansi.bright_cyan": "#9fbca8ff",
"terminal.ansi.dim_cyan": "#253e2eff",
"terminal.ansi.white": "#f9f5d7ff",
"terminal.ansi.bright_white": "#ffffffff",
"terminal.ansi.bright_white": "#f9f5d7ff",
"terminal.ansi.dim_white": "#b0a189ff",
"link_text.hover": "#0b6678ff",
"version_control.added": "#797410ff",
@@ -1868,7 +1848,7 @@
"hint": {
"color": "#677562ff",
"font_style": null,
"font_weight": null
"font_weight": 700
},
"keyword": {
"color": "#9d0006ff",
@@ -1945,11 +1925,6 @@
"font_style": null,
"font_weight": null
},
"punctuation.markup": {
"color": "#066578ff",
"font_style": null,
"font_weight": null
},
"punctuation.special": {
"color": "#413d3aff",
"font_style": null,
@@ -2119,7 +2094,7 @@
"terminal.ansi.bright_cyan": "#9fbca8ff",
"terminal.ansi.dim_cyan": "#253e2eff",
"terminal.ansi.white": "#f2e5bcff",
"terminal.ansi.bright_white": "#ffffffff",
"terminal.ansi.bright_white": "#f2e5bcff",
"terminal.ansi.dim_white": "#b0a189ff",
"link_text.hover": "#0b6678ff",
"version_control.added": "#797410ff",
@@ -2273,7 +2248,7 @@
"hint": {
"color": "#677562ff",
"font_style": null,
"font_weight": null
"font_weight": 700
},
"keyword": {
"color": "#9d0006ff",
@@ -2350,11 +2325,6 @@
"font_style": null,
"font_weight": null
},
"punctuation.markup": {
"color": "#066578ff",
"font_style": null,
"font_weight": null
},
"punctuation.special": {
"color": "#413d3aff",
"font_style": null,

View File

@@ -93,7 +93,7 @@
"terminal.ansi.bright_cyan": "#3a565bff",
"terminal.ansi.dim_cyan": "#b9d9dfff",
"terminal.ansi.white": "#dce0e5ff",
"terminal.ansi.bright_white": "#fafafaff",
"terminal.ansi.bright_white": "#dce0e5ff",
"terminal.ansi.dim_white": "#575d65ff",
"link_text.hover": "#74ade8ff",
"version_control.added": "#27a657ff",
@@ -244,7 +244,7 @@
"hint": {
"color": "#788ca6ff",
"font_style": null,
"font_weight": null
"font_weight": 700
},
"keyword": {
"color": "#b477cfff",
@@ -321,11 +321,6 @@
"font_style": null,
"font_weight": null
},
"punctuation.markup": {
"color": "#d07277ff",
"font_style": null,
"font_weight": null
},
"punctuation.special": {
"color": "#b1574bff",
"font_style": null,
@@ -473,7 +468,7 @@
"terminal.bright_foreground": "#242529ff",
"terminal.dim_foreground": "#fafafaff",
"terminal.ansi.black": "#242529ff",
"terminal.ansi.bright_black": "#747579ff",
"terminal.ansi.bright_black": "#242529ff",
"terminal.ansi.dim_black": "#97979aff",
"terminal.ansi.red": "#d36151ff",
"terminal.ansi.bright_red": "#f0b0a4ff",
@@ -494,7 +489,7 @@
"terminal.ansi.bright_cyan": "#a3bedaff",
"terminal.ansi.dim_cyan": "#254058ff",
"terminal.ansi.white": "#fafafaff",
"terminal.ansi.bright_white": "#ffffffff",
"terminal.ansi.bright_white": "#fafafaff",
"terminal.ansi.dim_white": "#aaaaaaff",
"link_text.hover": "#5c78e2ff",
"version_control.added": "#27a657ff",
@@ -643,7 +638,7 @@
"hint": {
"color": "#7274a7ff",
"font_style": null,
"font_weight": null
"font_weight": 700
},
"keyword": {
"color": "#a449abff",
@@ -720,11 +715,6 @@
"font_style": null,
"font_weight": null
},
"punctuation.markup": {
"color": "#d3604fff",
"font_style": null,
"font_weight": null
},
"punctuation.special": {
"color": "#b92b46ff",
"font_style": null,

View File

@@ -5,16 +5,3 @@ ignore-interior-mutability = [
# and Hash impls do not use fields with interior mutability.
"agent::context::AgentContextKey"
]
disallowed-methods = [
{ path = "std::process::Command::spawn", reason = "Spawning `std::process::Command` can block the current thread for an unknown duration", replacement = "smol::process::Command::spawn" },
{ path = "std::process::Command::output", reason = "Spawning `std::process::Command` can block the current thread for an unknown duration", replacement = "smol::process::Command::output" },
{ path = "std::process::Command::status", reason = "Spawning `std::process::Command` can block the current thread for an unknown duration", replacement = "smol::process::Command::status" },
{ path = "serde_json::from_reader", reason = "Parsing from a buffer is much slower than first reading the buffer into a Vec/String, see https://github.com/serde-rs/json/issues/160#issuecomment-253446892. Use `serde_json::from_slice` instead." },
{ path = "serde_json_lenient::from_reader", reason = "Parsing from a buffer is much slower than first reading the buffer into a Vec/String, see https://github.com/serde-rs/json/issues/160#issuecomment-253446892, Use `serde_json_lenient::from_slice` instead." },
]
disallowed-types = [
# { path = "std::collections::HashMap", replacement = "collections::HashMap" },
# { path = "std::collections::HashSet", replacement = "collections::HashSet" },
# { path = "indexmap::IndexSet", replacement = "collections::IndexSet" },
# { path = "indexmap::IndexMap", replacement = "collections::IndexMap" },
]

View File

@@ -1,6 +1,6 @@
services:
postgres:
image: docker.io/library/postgres:15
image: postgres:15
container_name: zed_postgres
ports:
- 5432:5432
@@ -23,7 +23,7 @@ services:
- ./.blob_store:/data
livekit_server:
image: docker.io/livekit/livekit-server
image: livekit/livekit-server
container_name: livekit_server
entrypoint: /livekit-server --config /livekit.yaml
ports:
@@ -34,7 +34,7 @@ services:
- ./livekit.yaml:/livekit.yaml
postgrest_app:
image: docker.io/postgrest/postgrest
image: postgrest/postgrest
container_name: postgrest_app
ports:
- 8081:8081
@@ -47,7 +47,7 @@ services:
- postgres
postgrest_llm:
image: docker.io/postgrest/postgrest
image: postgrest/postgrest
container_name: postgrest_llm
ports:
- 8082:8082
@@ -60,7 +60,7 @@ services:
- postgres
stripe-mock:
image: docker.io/stripe/stripe-mock:v0.178.0
image: stripe/stripe-mock:v0.178.0
ports:
- 12111:12111
- 12112:12112

View File

@@ -18,7 +18,6 @@ test-support = ["gpui/test-support", "project/test-support", "dep:parking_lot"]
[dependencies]
action_log.workspace = true
agent-client-protocol.workspace = true
agent_settings.workspace = true
anyhow.workspace = true
buffer_diff.workspace = true
collections.workspace = true
@@ -31,14 +30,12 @@ language.workspace = true
language_model.workspace = true
markdown.workspace = true
parking_lot = { workspace = true, optional = true }
portable-pty.workspace = true
project.workspace = true
prompt_store.workspace = true
serde.workspace = true
serde_json.workspace = true
settings.workspace = true
smol.workspace = true
task.workspace = true
terminal.workspace = true
ui.workspace = true
url.workspace = true

File diff suppressed because it is too large Load Diff

View File

@@ -38,29 +38,23 @@ pub trait AgentConnection {
cx: &mut App,
) -> Task<Result<acp::PromptResponse>>;
fn prompt_capabilities(&self) -> acp::PromptCapabilities;
fn resume(
&self,
_session_id: &acp::SessionId,
_cx: &App,
_cx: &mut App,
) -> Option<Rc<dyn AgentSessionResume>> {
None
}
fn cancel(&self, session_id: &acp::SessionId, cx: &mut App);
fn truncate(
fn session_editor(
&self,
_session_id: &acp::SessionId,
_cx: &App,
) -> Option<Rc<dyn AgentSessionTruncate>> {
None
}
fn set_title(
&self,
_session_id: &acp::SessionId,
_cx: &App,
) -> Option<Rc<dyn AgentSessionSetTitle>> {
_cx: &mut App,
) -> Option<Rc<dyn AgentSessionEditor>> {
None
}
@@ -68,7 +62,7 @@ pub trait AgentConnection {
///
/// If the agent does not support model selection, returns [None].
/// This allows sharing the selector in UI components.
fn model_selector(&self, _session_id: &acp::SessionId) -> Option<Rc<dyn AgentModelSelector>> {
fn model_selector(&self) -> Option<Rc<dyn AgentModelSelector>> {
None
}
@@ -76,14 +70,6 @@ pub trait AgentConnection {
None
}
fn session_modes(
&self,
_session_id: &acp::SessionId,
_cx: &App,
) -> Option<Rc<dyn AgentSessionModes>> {
None
}
fn into_any(self: Rc<Self>) -> Rc<dyn Any>;
}
@@ -93,18 +79,14 @@ impl dyn AgentConnection {
}
}
pub trait AgentSessionTruncate {
fn run(&self, message_id: UserMessageId, cx: &mut App) -> Task<Result<()>>;
pub trait AgentSessionEditor {
fn truncate(&self, message_id: UserMessageId, cx: &mut App) -> Task<Result<()>>;
}
pub trait AgentSessionResume {
fn run(&self, cx: &mut App) -> Task<Result<acp::PromptResponse>>;
}
pub trait AgentSessionSetTitle {
fn run(&self, title: SharedString, cx: &mut App) -> Task<Result<()>>;
}
pub trait AgentTelemetry {
/// The name of the agent used for telemetry.
fn agent_name(&self) -> String;
@@ -118,14 +100,6 @@ pub trait AgentTelemetry {
) -> Task<Result<serde_json::Value>>;
}
pub trait AgentSessionModes {
fn current_mode(&self) -> acp::SessionModeId;
fn all_modes(&self) -> Vec<acp::SessionMode>;
fn set_mode(&self, mode: acp::SessionModeId, cx: &mut App) -> Task<Result<()>>;
}
#[derive(Debug)]
pub struct AuthRequired {
pub description: Option<String>,
@@ -177,48 +151,61 @@ pub trait AgentModelSelector: 'static {
/// If the session doesn't exist or the model is invalid, it returns an error.
///
/// # Parameters
/// - `session_id`: The ID of the session (thread) to apply the model to.
/// - `model`: The model to select (should be one from [list_models]).
/// - `cx`: The GPUI app context.
///
/// # Returns
/// A task resolving to `Ok(())` on success or an error.
fn select_model(&self, model_id: acp::ModelId, cx: &mut App) -> Task<Result<()>>;
fn select_model(
&self,
session_id: acp::SessionId,
model_id: AgentModelId,
cx: &mut App,
) -> Task<Result<()>>;
/// Retrieves the currently selected model for a specific session (thread).
///
/// # Parameters
/// - `session_id`: The ID of the session (thread) to query.
/// - `cx`: The GPUI app context.
///
/// # Returns
/// A task resolving to the selected model (always set) or an error (e.g., session not found).
fn selected_model(&self, cx: &mut App) -> Task<Result<AgentModelInfo>>;
fn selected_model(
&self,
session_id: &acp::SessionId,
cx: &mut App,
) -> Task<Result<AgentModelInfo>>;
/// Whenever the model list is updated the receiver will be notified.
/// Optional for agents that don't update their model list.
fn watch(&self, _cx: &mut App) -> Option<watch::Receiver<()>> {
None
fn watch(&self, cx: &mut App) -> watch::Receiver<()>;
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct AgentModelId(pub SharedString);
impl std::ops::Deref for AgentModelId {
type Target = SharedString;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl fmt::Display for AgentModelId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AgentModelInfo {
pub id: acp::ModelId,
pub id: AgentModelId,
pub name: SharedString,
pub description: Option<SharedString>,
pub icon: Option<IconName>,
}
impl From<acp::ModelInfo> for AgentModelInfo {
fn from(info: acp::ModelInfo) -> Self {
Self {
id: info.model_id,
name: info.name.into(),
description: info.description.map(|desc| desc.into()),
icon: None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct AgentModelGroupName(pub SharedString);
@@ -330,20 +317,13 @@ mod test_support {
) -> Task<gpui::Result<Entity<AcpThread>>> {
let session_id = acp::SessionId(self.sessions.lock().len().to_string().into());
let action_log = cx.new(|_| ActionLog::new(project.clone()));
let thread = cx.new(|cx| {
let thread = cx.new(|_cx| {
AcpThread::new(
"Test",
self.clone(),
project,
action_log,
session_id.clone(),
watch::Receiver::constant(acp::PromptCapabilities {
image: true,
audio: true,
embedded_context: true,
meta: None,
}),
cx,
)
});
self.sessions.lock().insert(
@@ -356,6 +336,14 @@ mod test_support {
Task::ready(Ok(thread))
}
fn prompt_capabilities(&self) -> acp::PromptCapabilities {
acp::PromptCapabilities {
image: true,
audio: true,
embedded_context: true,
}
}
fn authenticate(
&self,
_method_id: acp::AuthMethodId,
@@ -381,10 +369,7 @@ mod test_support {
response_tx.replace(tx);
cx.spawn(async move |_| {
let stop_reason = rx.await?;
Ok(acp::PromptResponse {
stop_reason,
meta: None,
})
Ok(acp::PromptResponse { stop_reason })
})
} else {
for update in self.next_prompt_updates.lock().drain(..) {
@@ -400,16 +385,14 @@ mod test_support {
};
let task = cx.spawn(async move |cx| {
if let Some((tool_call, options)) = permission_request {
thread
.update(cx, |thread, cx| {
thread.request_tool_call_authorization(
tool_call.clone().into(),
options.clone(),
false,
cx,
)
})??
.await;
let permission = thread.update(cx, |thread, cx| {
thread.request_tool_call_authorization(
tool_call.clone().into(),
options.clone(),
cx,
)
})?;
permission?.await?;
}
thread.update(cx, |thread, cx| {
thread.handle_session_update(update.clone(), cx).unwrap();
@@ -423,7 +406,6 @@ mod test_support {
try_join_all(tasks).await?;
Ok(acp::PromptResponse {
stop_reason: acp::StopReason::EndTurn,
meta: None,
})
})
}
@@ -438,15 +420,15 @@ mod test_support {
.response_tx
.take()
{
end_turn_tx.send(acp::StopReason::Cancelled).unwrap();
end_turn_tx.send(acp::StopReason::Canceled).unwrap();
}
}
fn truncate(
fn session_editor(
&self,
_session_id: &agent_client_protocol::SessionId,
_cx: &App,
) -> Option<Rc<dyn AgentSessionTruncate>> {
_cx: &mut App,
) -> Option<Rc<dyn AgentSessionEditor>> {
Some(Rc::new(StubAgentSessionEditor))
}
@@ -457,8 +439,8 @@ mod test_support {
struct StubAgentSessionEditor;
impl AgentSessionTruncate for StubAgentSessionEditor {
fn run(&self, _: UserMessageId, _: &mut App) -> Task<Result<()>> {
impl AgentSessionEditor for StubAgentSessionEditor {
fn truncate(&self, _: UserMessageId, _: &mut App) -> Task<Result<()>> {
Task::ready(Ok(()))
}
}

View File

@@ -1,12 +1,17 @@
use anyhow::Result;
use buffer_diff::{BufferDiff, BufferDiffSnapshot};
use editor::{MultiBuffer, PathKey, multibuffer_context_lines};
use editor::{MultiBuffer, PathKey};
use gpui::{App, AppContext, AsyncApp, Context, Entity, Subscription, Task};
use itertools::Itertools;
use language::{
Anchor, Buffer, Capability, LanguageRegistry, OffsetRangeExt as _, Point, Rope, TextBuffer,
};
use std::{cmp::Reverse, ops::Range, path::Path, sync::Arc};
use std::{
cmp::Reverse,
ops::Range,
path::{Path, PathBuf},
sync::Arc,
};
use util::ResultExt;
pub enum Diff {
@@ -16,53 +21,64 @@ pub enum Diff {
impl Diff {
pub fn finalized(
path: String,
path: PathBuf,
old_text: Option<String>,
new_text: String,
language_registry: Arc<LanguageRegistry>,
cx: &mut Context<Self>,
) -> Self {
let multibuffer = cx.new(|_cx| MultiBuffer::without_headers(Capability::ReadOnly));
let new_buffer = cx.new(|cx| Buffer::local(new_text, cx));
let base_text = old_text.clone().unwrap_or(String::new()).into();
let old_buffer = cx.new(|cx| Buffer::local(old_text.unwrap_or("".into()), cx));
let new_buffer_snapshot = new_buffer.read(cx).text_snapshot();
let buffer_diff = cx.new(|cx| BufferDiff::new(&new_buffer_snapshot, cx));
let task = cx.spawn({
let multibuffer = multibuffer.clone();
let path = path.clone();
let buffer = new_buffer.clone();
async move |_, cx| {
let language = language_registry
.load_language_for_file_path(Path::new(&path))
.language_for_file_path(&path)
.await
.log_err();
buffer.update(cx, |buffer, cx| buffer.set_language(language.clone(), cx))?;
new_buffer.update(cx, |buffer, cx| buffer.set_language(language.clone(), cx))?;
let diff = build_buffer_diff(
old_text.unwrap_or("".into()).into(),
&buffer,
Some(language_registry.clone()),
cx,
)
.await?;
let old_buffer_snapshot = old_buffer.update(cx, |buffer, cx| {
buffer.set_language(language, cx);
buffer.snapshot()
})?;
buffer_diff
.update(cx, |diff, cx| {
diff.set_base_text(
old_buffer_snapshot,
Some(language_registry),
new_buffer_snapshot,
cx,
)
})?
.await?;
multibuffer
.update(cx, |multibuffer, cx| {
let hunk_ranges = {
let buffer = buffer.read(cx);
let diff = diff.read(cx);
let buffer = new_buffer.read(cx);
let diff = buffer_diff.read(cx);
diff.hunks_intersecting_range(Anchor::MIN..Anchor::MAX, buffer, cx)
.map(|diff_hunk| diff_hunk.buffer_range.to_point(buffer))
.collect::<Vec<_>>()
};
multibuffer.set_excerpts_for_path(
PathKey::for_buffer(&buffer, cx),
buffer.clone(),
PathKey::for_buffer(&new_buffer, cx),
new_buffer.clone(),
hunk_ranges,
multibuffer_context_lines(cx),
editor::DEFAULT_MULTIBUFFER_CONTEXT,
cx,
);
multibuffer.add_diff(diff, cx);
multibuffer.add_diff(buffer_diff, cx);
})
.log_err();
@@ -73,26 +89,23 @@ impl Diff {
Self::Finalized(FinalizedDiff {
multibuffer,
path,
base_text,
new_buffer,
_update_diff: task,
})
}
pub fn new(buffer: Entity<Buffer>, cx: &mut Context<Self>) -> Self {
let buffer_text_snapshot = buffer.read(cx).text_snapshot();
let base_text_snapshot = buffer.read(cx).snapshot();
let base_text = base_text_snapshot.text();
debug_assert_eq!(buffer_text_snapshot.text(), base_text);
let buffer_snapshot = buffer.read(cx).snapshot();
let base_text = buffer_snapshot.text();
let language_registry = buffer.read(cx).language_registry();
let text_snapshot = buffer.read(cx).text_snapshot();
let buffer_diff = cx.new(|cx| {
let mut diff = BufferDiff::new_unchanged(&buffer_text_snapshot, base_text_snapshot);
let snapshot = diff.snapshot(cx);
let secondary_diff = cx.new(|cx| {
let mut diff = BufferDiff::new(&buffer_text_snapshot, cx);
diff.set_snapshot(snapshot, &buffer_text_snapshot, cx);
diff
});
diff.set_secondary_diff(secondary_diff);
let mut diff = BufferDiff::new(&text_snapshot, cx);
let _ = diff.set_base_text(
buffer_snapshot.clone(),
language_registry,
text_snapshot,
cx,
);
diff
});
@@ -110,7 +123,7 @@ impl Diff {
diff.update(cx);
}
}),
new_buffer: buffer,
buffer,
diff: buffer_diff,
revealed_ranges: Vec::new(),
update_diff: Task::ready(Ok(())),
@@ -145,17 +158,14 @@ impl Diff {
.map(|buffer| buffer.read(cx).text())
.join("\n");
let path = match self {
Diff::Pending(PendingDiff {
new_buffer: buffer, ..
}) => buffer
.read(cx)
.file()
.map(|file| file.path().display(file.path_style(cx))),
Diff::Finalized(FinalizedDiff { path, .. }) => Some(path.as_str().into()),
Diff::Pending(PendingDiff { buffer, .. }) => {
buffer.read(cx).file().map(|file| file.path().as_ref())
}
Diff::Finalized(FinalizedDiff { path, .. }) => Some(path.as_path()),
};
format!(
"Diff: {}\n```\n{}\n```\n",
path.unwrap_or("untitled".into()),
path.unwrap_or(Path::new("untitled")).display(),
buffer_text
)
}
@@ -163,33 +173,12 @@ impl Diff {
pub fn has_revealed_range(&self, cx: &App) -> bool {
self.multibuffer().read(cx).excerpt_paths().next().is_some()
}
pub fn needs_update(&self, old_text: &str, new_text: &str, cx: &App) -> bool {
match self {
Diff::Pending(PendingDiff {
base_text,
new_buffer,
..
}) => {
base_text.as_str() != old_text
|| !new_buffer.read(cx).as_rope().chunks().equals_str(new_text)
}
Diff::Finalized(FinalizedDiff {
base_text,
new_buffer,
..
}) => {
base_text.as_str() != old_text
|| !new_buffer.read(cx).as_rope().chunks().equals_str(new_text)
}
}
}
}
pub struct PendingDiff {
multibuffer: Entity<MultiBuffer>,
base_text: Arc<String>,
new_buffer: Entity<Buffer>,
buffer: Entity<Buffer>,
diff: Entity<BufferDiff>,
revealed_ranges: Vec<Range<Anchor>>,
_subscription: Subscription,
@@ -198,7 +187,7 @@ pub struct PendingDiff {
impl PendingDiff {
pub fn update(&mut self, cx: &mut Context<Diff>) {
let buffer = self.new_buffer.clone();
let buffer = self.buffer.clone();
let buffer_diff = self.diff.clone();
let base_text = self.base_text.clone();
self.update_diff = cx.spawn(async move |diff, cx| {
@@ -215,10 +204,7 @@ impl PendingDiff {
)
.await?;
buffer_diff.update(cx, |diff, cx| {
diff.set_snapshot(diff_snapshot.clone(), &text_snapshot, cx);
diff.secondary_diff().unwrap().update(cx, |diff, cx| {
diff.set_snapshot(diff_snapshot.clone(), &text_snapshot, cx);
});
diff.set_snapshot(diff_snapshot, &text_snapshot, cx)
})?;
diff.update(cx, |diff, cx| {
if let Diff::Pending(diff) = diff {
@@ -236,24 +222,24 @@ impl PendingDiff {
fn finalize(&self, cx: &mut Context<Diff>) -> FinalizedDiff {
let ranges = self.excerpt_ranges(cx);
let base_text = self.base_text.clone();
let language_registry = self.new_buffer.read(cx).language_registry();
let language_registry = self.buffer.read(cx).language_registry();
let path = self
.new_buffer
.buffer
.read(cx)
.file()
.map(|file| file.path().display(file.path_style(cx)))
.unwrap_or("untitled".into())
.map(|file| file.path().as_ref())
.unwrap_or(Path::new("untitled"))
.into();
// Replace the buffer in the multibuffer with the snapshot
let buffer = cx.new(|cx| {
let language = self.new_buffer.read(cx).language().cloned();
let language = self.buffer.read(cx).language().cloned();
let buffer = TextBuffer::new_normalized(
0,
cx.entity_id().as_non_zero_u64().into(),
self.new_buffer.read(cx).line_ending(),
self.new_buffer.read(cx).as_rope().clone(),
self.buffer.read(cx).line_ending(),
self.buffer.read(cx).as_rope().clone(),
);
let mut buffer = Buffer::build(buffer, None, Capability::ReadWrite);
buffer.set_language(language, cx);
@@ -277,7 +263,7 @@ impl PendingDiff {
path_key,
buffer,
ranges,
multibuffer_context_lines(cx),
editor::DEFAULT_MULTIBUFFER_CONTEXT,
cx,
);
multibuffer.add_diff(buffer_diff.clone(), cx);
@@ -289,9 +275,7 @@ impl PendingDiff {
FinalizedDiff {
path,
base_text: self.base_text.clone(),
multibuffer: self.multibuffer.clone(),
new_buffer: self.new_buffer.clone(),
_update_diff: update_diff,
}
}
@@ -300,10 +284,10 @@ impl PendingDiff {
let ranges = self.excerpt_ranges(cx);
self.multibuffer.update(cx, |multibuffer, cx| {
multibuffer.set_excerpts_for_path(
PathKey::for_buffer(&self.new_buffer, cx),
self.new_buffer.clone(),
PathKey::for_buffer(&self.buffer, cx),
self.buffer.clone(),
ranges,
multibuffer_context_lines(cx),
editor::DEFAULT_MULTIBUFFER_CONTEXT,
cx,
);
let end = multibuffer.len(cx);
@@ -313,7 +297,7 @@ impl PendingDiff {
}
fn excerpt_ranges(&self, cx: &App) -> Vec<Range<Point>> {
let buffer = self.new_buffer.read(cx);
let buffer = self.buffer.read(cx);
let diff = self.diff.read(cx);
let mut ranges = diff
.hunks_intersecting_range(Anchor::MIN..Anchor::MAX, buffer, cx)
@@ -346,9 +330,7 @@ impl PendingDiff {
}
pub struct FinalizedDiff {
path: String,
base_text: Arc<String>,
new_buffer: Entity<Buffer>,
path: PathBuf,
multibuffer: Entity<MultiBuffer>,
_update_diff: Task<Result<()>>,
}
@@ -402,21 +384,3 @@ async fn build_buffer_diff(
diff
})
}
#[cfg(test)]
mod tests {
use gpui::{AppContext as _, TestAppContext};
use language::Buffer;
use crate::Diff;
#[gpui::test]
async fn test_pending_diff(cx: &mut TestAppContext) {
let buffer = cx.new(|cx| Buffer::local("hello!", cx));
let _diff = cx.new(|cx| Diff::new(buffer.clone(), cx));
buffer.update(cx, |buffer, cx| {
buffer.set_text("HELLO!", cx);
});
cx.run_until_parked();
}
}

View File

@@ -5,7 +5,7 @@ use prompt_store::{PromptId, UserPromptId};
use serde::{Deserialize, Serialize};
use std::{
fmt,
ops::RangeInclusive,
ops::Range,
path::{Path, PathBuf},
str::FromStr,
};
@@ -17,14 +17,13 @@ pub enum MentionUri {
File {
abs_path: PathBuf,
},
PastedImage,
Directory {
abs_path: PathBuf,
},
Symbol {
abs_path: PathBuf,
path: PathBuf,
name: String,
line_range: RangeInclusive<u32>,
line_range: Range<u32>,
},
Thread {
id: acp::SessionId,
@@ -39,9 +38,8 @@ pub enum MentionUri {
name: String,
},
Selection {
#[serde(default, skip_serializing_if = "Option::is_none")]
abs_path: Option<PathBuf>,
line_range: RangeInclusive<u32>,
path: PathBuf,
line_range: Range<u32>,
},
Fetch {
url: Url,
@@ -50,44 +48,36 @@ pub enum MentionUri {
impl MentionUri {
pub fn parse(input: &str) -> Result<Self> {
fn parse_line_range(fragment: &str) -> Result<RangeInclusive<u32>> {
let range = fragment
.strip_prefix("L")
.context("Line range must start with \"L\"")?;
let (start, end) = range
.split_once(":")
.context("Line range must use colon as separator")?;
let range = start
.parse::<u32>()
.context("Parsing line range start")?
.checked_sub(1)
.context("Line numbers should be 1-based")?
..=end
.parse::<u32>()
.context("Parsing line range end")?
.checked_sub(1)
.context("Line numbers should be 1-based")?;
Ok(range)
}
let url = url::Url::parse(input)?;
let path = url.path();
match url.scheme() {
"file" => {
let path = url.to_file_path().ok().context("Extracting file path")?;
if let Some(fragment) = url.fragment() {
let line_range = parse_line_range(fragment)?;
let range = fragment
.strip_prefix("L")
.context("Line range must start with \"L\"")?;
let (start, end) = range
.split_once(":")
.context("Line range must use colon as separator")?;
let line_range = start
.parse::<u32>()
.context("Parsing line range start")?
.checked_sub(1)
.context("Line numbers should be 1-based")?
..end
.parse::<u32>()
.context("Parsing line range end")?
.checked_sub(1)
.context("Line numbers should be 1-based")?;
if let Some(name) = single_query_param(&url, "symbol")? {
Ok(Self::Symbol {
name,
abs_path: path,
path,
line_range,
})
} else {
Ok(Self::Selection {
abs_path: Some(path),
line_range,
})
Ok(Self::Selection { path, line_range })
}
} else if input.ends_with("/") {
Ok(Self::Directory { abs_path: path })
@@ -115,50 +105,6 @@ impl MentionUri {
id: rule_id.into(),
name,
})
} else if path.starts_with("/agent/pasted-image") {
Ok(Self::PastedImage)
} else if path.starts_with("/agent/untitled-buffer") {
let fragment = url
.fragment()
.context("Missing fragment for untitled buffer selection")?;
let line_range = parse_line_range(fragment)?;
Ok(Self::Selection {
abs_path: None,
line_range,
})
} else if let Some(name) = path.strip_prefix("/agent/symbol/") {
let fragment = url
.fragment()
.context("Missing fragment for untitled buffer selection")?;
let line_range = parse_line_range(fragment)?;
let path =
single_query_param(&url, "path")?.context("Missing path for symbol")?;
Ok(Self::Symbol {
name: name.to_string(),
abs_path: path.into(),
line_range,
})
} else if path.starts_with("/agent/file") {
let path =
single_query_param(&url, "path")?.context("Missing path for file")?;
Ok(Self::File {
abs_path: path.into(),
})
} else if path.starts_with("/agent/directory") {
let path =
single_query_param(&url, "path")?.context("Missing path for directory")?;
Ok(Self::Directory {
abs_path: path.into(),
})
} else if path.starts_with("/agent/selection") {
let fragment = url.fragment().context("Missing fragment for selection")?;
let line_range = parse_line_range(fragment)?;
let path =
single_query_param(&url, "path")?.context("Missing path for selection")?;
Ok(Self::Selection {
abs_path: Some(path.into()),
line_range,
})
} else {
bail!("invalid zed url: {:?}", input);
}
@@ -175,16 +121,13 @@ impl MentionUri {
.unwrap_or_default()
.to_string_lossy()
.into_owned(),
MentionUri::PastedImage => "Image".to_string(),
MentionUri::Symbol { name, .. } => name.clone(),
MentionUri::Thread { name, .. } => name.clone(),
MentionUri::TextThread { name, .. } => name.clone(),
MentionUri::Rule { name, .. } => name.clone(),
MentionUri::Selection {
abs_path: path,
line_range,
..
} => selection_name(path.as_deref(), line_range),
path, line_range, ..
} => selection_name(path, line_range),
MentionUri::Fetch { url } => url.to_string(),
}
}
@@ -194,8 +137,7 @@ impl MentionUri {
MentionUri::File { abs_path } => {
FileIcons::get_icon(abs_path, cx).unwrap_or_else(|| IconName::File.path().into())
}
MentionUri::PastedImage => IconName::Image.path().into(),
MentionUri::Directory { abs_path } => FileIcons::get_folder_icon(false, abs_path, cx)
MentionUri::Directory { .. } => FileIcons::get_folder_icon(false, cx)
.unwrap_or_else(|| IconName::Folder.path().into()),
MentionUri::Symbol { .. } => IconName::Code.path().into(),
MentionUri::Thread { .. } => IconName::Thread.path().into(),
@@ -213,52 +155,31 @@ impl MentionUri {
pub fn to_uri(&self) -> Url {
match self {
MentionUri::File { abs_path } => {
let mut url = Url::parse("zed:///").unwrap();
url.set_path("/agent/file");
url.query_pairs_mut()
.append_pair("path", &abs_path.to_string_lossy());
url
Url::from_file_path(abs_path).expect("mention path should be absolute")
}
MentionUri::PastedImage => Url::parse("zed:///agent/pasted-image").unwrap(),
MentionUri::Directory { abs_path } => {
let mut url = Url::parse("zed:///").unwrap();
url.set_path("/agent/directory");
url.query_pairs_mut()
.append_pair("path", &abs_path.to_string_lossy());
url
Url::from_directory_path(abs_path).expect("mention path should be absolute")
}
MentionUri::Symbol {
abs_path,
path,
name,
line_range,
} => {
let mut url = Url::parse("zed:///").unwrap();
url.set_path(&format!("/agent/symbol/{name}"));
url.query_pairs_mut()
.append_pair("path", &abs_path.to_string_lossy());
let mut url = Url::from_file_path(path).expect("mention path should be absolute");
url.query_pairs_mut().append_pair("symbol", name);
url.set_fragment(Some(&format!(
"L{}:{}",
line_range.start() + 1,
line_range.end() + 1
line_range.start + 1,
line_range.end + 1
)));
url
}
MentionUri::Selection {
abs_path,
line_range,
} => {
let mut url = Url::parse("zed:///").unwrap();
if let Some(abs_path) = abs_path {
url.set_path("/agent/selection");
url.query_pairs_mut()
.append_pair("path", &abs_path.to_string_lossy());
} else {
url.set_path("/agent/untitled-buffer");
};
MentionUri::Selection { path, line_range } => {
let mut url = Url::from_file_path(path).expect("mention path should be absolute");
url.set_fragment(Some(&format!(
"L{}:{}",
line_range.start() + 1,
line_range.end() + 1
line_range.start + 1,
line_range.end + 1
)));
url
}
@@ -270,10 +191,7 @@ impl MentionUri {
}
MentionUri::TextThread { path, name } => {
let mut url = Url::parse("zed:///").unwrap();
url.set_path(&format!(
"/agent/text-thread/{}",
path.to_string_lossy().trim_start_matches('/')
));
url.set_path(&format!("/agent/text-thread/{}", path.to_string_lossy()));
url.query_pairs_mut().append_pair("name", name);
url
}
@@ -319,14 +237,12 @@ fn single_query_param(url: &Url, name: &'static str) -> Result<Option<String>> {
}
}
pub fn selection_name(path: Option<&Path>, line_range: &RangeInclusive<u32>) -> String {
pub fn selection_name(path: &Path, line_range: &Range<u32>) -> String {
format!(
"{} ({}:{})",
path.and_then(|path| path.file_name())
.unwrap_or("Untitled".as_ref())
.display(),
*line_range.start() + 1,
*line_range.end() + 1
path.file_name().unwrap_or_default().display(),
line_range.start + 1,
line_range.end + 1
)
}
@@ -338,32 +254,37 @@ mod tests {
#[test]
fn test_parse_file_uri() {
let old_uri = uri!("file:///path/to/file.rs");
let parsed = MentionUri::parse(old_uri).unwrap();
let file_uri = uri!("file:///path/to/file.rs");
let parsed = MentionUri::parse(file_uri).unwrap();
match &parsed {
MentionUri::File { abs_path } => {
assert_eq!(abs_path.to_str().unwrap(), path!("/path/to/file.rs"));
}
_ => panic!("Expected File variant"),
}
let new_uri = parsed.to_uri().to_string();
assert!(new_uri.starts_with("zed:///agent/file"));
assert_eq!(MentionUri::parse(&new_uri).unwrap(), parsed);
assert_eq!(parsed.to_uri().to_string(), file_uri);
}
#[test]
fn test_parse_directory_uri() {
let old_uri = uri!("file:///path/to/dir/");
let parsed = MentionUri::parse(old_uri).unwrap();
let file_uri = uri!("file:///path/to/dir/");
let parsed = MentionUri::parse(file_uri).unwrap();
match &parsed {
MentionUri::Directory { abs_path } => {
assert_eq!(abs_path.to_str().unwrap(), path!("/path/to/dir/"));
}
_ => panic!("Expected Directory variant"),
}
let new_uri = parsed.to_uri().to_string();
assert!(new_uri.starts_with("zed:///agent/directory"));
assert_eq!(MentionUri::parse(&new_uri).unwrap(), parsed);
assert_eq!(parsed.to_uri().to_string(), file_uri);
}
#[test]
fn test_to_directory_uri_with_slash() {
let uri = MentionUri::Directory {
abs_path: PathBuf::from(path!("/path/to/dir/")),
};
let expected = uri!("file:///path/to/dir/");
assert_eq!(uri.to_uri().to_string(), expected);
}
#[test]
@@ -371,69 +292,41 @@ mod tests {
let uri = MentionUri::Directory {
abs_path: PathBuf::from(path!("/path/to/dir")),
};
let uri_string = uri.to_uri().to_string();
assert!(uri_string.starts_with("zed:///agent/directory"));
assert_eq!(MentionUri::parse(&uri_string).unwrap(), uri);
let expected = uri!("file:///path/to/dir/");
assert_eq!(uri.to_uri().to_string(), expected);
}
#[test]
fn test_parse_symbol_uri() {
let old_uri = uri!("file:///path/to/file.rs?symbol=MySymbol#L10:20");
let parsed = MentionUri::parse(old_uri).unwrap();
let symbol_uri = uri!("file:///path/to/file.rs?symbol=MySymbol#L10:20");
let parsed = MentionUri::parse(symbol_uri).unwrap();
match &parsed {
MentionUri::Symbol {
abs_path: path,
path,
name,
line_range,
} => {
assert_eq!(path.to_str().unwrap(), path!("/path/to/file.rs"));
assert_eq!(name, "MySymbol");
assert_eq!(line_range.start(), &9);
assert_eq!(line_range.end(), &19);
assert_eq!(line_range.start, 9);
assert_eq!(line_range.end, 19);
}
_ => panic!("Expected Symbol variant"),
}
let new_uri = parsed.to_uri().to_string();
assert!(new_uri.starts_with("zed:///agent/symbol/MySymbol"));
assert_eq!(MentionUri::parse(&new_uri).unwrap(), parsed);
assert_eq!(parsed.to_uri().to_string(), symbol_uri);
}
#[test]
fn test_parse_selection_uri() {
let old_uri = uri!("file:///path/to/file.rs#L5:15");
let parsed = MentionUri::parse(old_uri).unwrap();
match &parsed {
MentionUri::Selection {
abs_path: path,
line_range,
} => {
assert_eq!(
path.as_ref().unwrap().to_str().unwrap(),
path!("/path/to/file.rs")
);
assert_eq!(line_range.start(), &4);
assert_eq!(line_range.end(), &14);
}
_ => panic!("Expected Selection variant"),
}
let new_uri = parsed.to_uri().to_string();
assert!(new_uri.starts_with("zed:///agent/selection"));
assert_eq!(MentionUri::parse(&new_uri).unwrap(), parsed);
}
#[test]
fn test_parse_untitled_selection_uri() {
let selection_uri = uri!("zed:///agent/untitled-buffer#L1:10");
let selection_uri = uri!("file:///path/to/file.rs#L5:15");
let parsed = MentionUri::parse(selection_uri).unwrap();
match &parsed {
MentionUri::Selection {
abs_path: None,
line_range,
} => {
assert_eq!(line_range.start(), &0);
assert_eq!(line_range.end(), &9);
MentionUri::Selection { path, line_range } => {
assert_eq!(path.to_str().unwrap(), path!("/path/to/file.rs"));
assert_eq!(line_range.start, 4);
assert_eq!(line_range.end, 14);
}
_ => panic!("Expected Selection variant without path"),
_ => panic!("Expected Selection variant"),
}
assert_eq!(parsed.to_uri().to_string(), selection_uri);
}

View File

@@ -1,46 +1,37 @@
use agent_client_protocol as acp;
use futures::{FutureExt as _, future::Shared};
use gpui::{App, AppContext, Context, Entity, Task};
use gpui::{App, AppContext, Context, Entity};
use language::LanguageRegistry;
use markdown::Markdown;
use std::{path::PathBuf, process::ExitStatus, sync::Arc, time::Instant};
pub struct Terminal {
id: acp::TerminalId,
command: Entity<Markdown>,
working_dir: Option<PathBuf>,
terminal: Entity<terminal::Terminal>,
started_at: Instant,
output: Option<TerminalOutput>,
output_byte_limit: Option<usize>,
_output_task: Shared<Task<acp::TerminalExitStatus>>,
}
pub struct TerminalOutput {
pub ended_at: Instant,
pub exit_status: Option<ExitStatus>,
pub content: String,
pub was_content_truncated: bool,
pub original_content_len: usize,
pub content_line_count: usize,
pub finished_with_empty_output: bool,
}
impl Terminal {
pub fn new(
id: acp::TerminalId,
command_label: &str,
command: String,
working_dir: Option<PathBuf>,
output_byte_limit: Option<usize>,
terminal: Entity<terminal::Terminal>,
language_registry: Arc<LanguageRegistry>,
cx: &mut Context<Self>,
) -> Self {
let command_task = terminal.read(cx).wait_for_completed_task(cx);
Self {
id,
command: cx.new(|cx| {
Markdown::new(
format!("```\n{}\n```", command_label).into(),
format!("```\n{}\n```", command).into(),
Some(language_registry.clone()),
None,
cx,
@@ -50,97 +41,27 @@ impl Terminal {
terminal,
started_at: Instant::now(),
output: None,
output_byte_limit,
_output_task: cx
.spawn(async move |this, cx| {
let exit_status = command_task.await;
this.update(cx, |this, cx| {
let (content, original_content_len) = this.truncated_output(cx);
let content_line_count = this.terminal.read(cx).total_lines();
this.output = Some(TerminalOutput {
ended_at: Instant::now(),
exit_status,
content,
original_content_len,
content_line_count,
});
cx.notify();
})
.ok();
let exit_status = exit_status.map(portable_pty::ExitStatus::from);
acp::TerminalExitStatus {
exit_code: exit_status.as_ref().map(|e| e.exit_code()),
signal: exit_status.and_then(|e| e.signal().map(Into::into)),
meta: None,
}
})
.shared(),
}
}
pub fn id(&self) -> &acp::TerminalId {
&self.id
}
pub fn wait_for_exit(&self) -> Shared<Task<acp::TerminalExitStatus>> {
self._output_task.clone()
}
pub fn kill(&mut self, cx: &mut App) {
self.terminal.update(cx, |terminal, _cx| {
terminal.kill_active_task();
pub fn finish(
&mut self,
exit_status: Option<ExitStatus>,
original_content_len: usize,
truncated_content_len: usize,
content_line_count: usize,
finished_with_empty_output: bool,
cx: &mut Context<Self>,
) {
self.output = Some(TerminalOutput {
ended_at: Instant::now(),
exit_status,
was_content_truncated: truncated_content_len < original_content_len,
original_content_len,
content_line_count,
finished_with_empty_output,
});
}
pub fn current_output(&self, cx: &App) -> acp::TerminalOutputResponse {
if let Some(output) = self.output.as_ref() {
let exit_status = output.exit_status.map(portable_pty::ExitStatus::from);
acp::TerminalOutputResponse {
output: output.content.clone(),
truncated: output.original_content_len > output.content.len(),
exit_status: Some(acp::TerminalExitStatus {
exit_code: exit_status.as_ref().map(|e| e.exit_code()),
signal: exit_status.and_then(|e| e.signal().map(Into::into)),
meta: None,
}),
meta: None,
}
} else {
let (current_content, original_len) = self.truncated_output(cx);
acp::TerminalOutputResponse {
truncated: current_content.len() < original_len,
output: current_content,
exit_status: None,
meta: None,
}
}
}
fn truncated_output(&self, cx: &App) -> (String, usize) {
let terminal = self.terminal.read(cx);
let mut content = terminal.get_content();
let original_content_len = content.len();
if let Some(limit) = self.output_byte_limit
&& content.len() > limit
{
let mut end_ix = limit.min(content.len());
while !content.is_char_boundary(end_ix) {
end_ix -= 1;
}
// Don't truncate mid-line, clear the remainder of the last line
end_ix = content[..end_ix].rfind('\n').unwrap_or(end_ix);
content.truncate(end_ix);
}
(content, original_content_len)
cx.notify();
}
pub fn command(&self) -> &Entity<Markdown> {

View File

@@ -1,30 +0,0 @@
[package]
name = "acp_tools"
version = "0.1.0"
edition.workspace = true
publish.workspace = true
license = "GPL-3.0-or-later"
[lints]
workspace = true
[lib]
path = "src/acp_tools.rs"
doctest = false
[dependencies]
agent-client-protocol.workspace = true
collections.workspace = true
gpui.workspace = true
language.workspace= true
markdown.workspace = true
project.workspace = true
serde.workspace = true
serde_json.workspace = true
settings.workspace = true
theme.workspace = true
ui.workspace = true
util.workspace = true
workspace-hack.workspace = true
workspace.workspace = true

View File

@@ -1,494 +0,0 @@
use std::{
cell::RefCell,
collections::HashSet,
fmt::Display,
rc::{Rc, Weak},
sync::Arc,
};
use agent_client_protocol as acp;
use collections::HashMap;
use gpui::{
App, Empty, Entity, EventEmitter, FocusHandle, Focusable, Global, ListAlignment, ListState,
StyleRefinement, Subscription, Task, TextStyleRefinement, Window, actions, list, prelude::*,
};
use language::LanguageRegistry;
use markdown::{CodeBlockRenderer, Markdown, MarkdownElement, MarkdownStyle};
use project::Project;
use settings::Settings;
use theme::ThemeSettings;
use ui::prelude::*;
use util::ResultExt as _;
use workspace::{Item, Workspace};
actions!(dev, [OpenAcpLogs]);
pub fn init(cx: &mut App) {
cx.observe_new(
|workspace: &mut Workspace, _window, _cx: &mut Context<Workspace>| {
workspace.register_action(|workspace, _: &OpenAcpLogs, window, cx| {
let acp_tools =
Box::new(cx.new(|cx| AcpTools::new(workspace.project().clone(), cx)));
workspace.add_item_to_active_pane(acp_tools, None, true, window, cx);
});
},
)
.detach();
}
struct GlobalAcpConnectionRegistry(Entity<AcpConnectionRegistry>);
impl Global for GlobalAcpConnectionRegistry {}
#[derive(Default)]
pub struct AcpConnectionRegistry {
active_connection: RefCell<Option<ActiveConnection>>,
}
struct ActiveConnection {
server_name: SharedString,
connection: Weak<acp::ClientSideConnection>,
}
impl AcpConnectionRegistry {
pub fn default_global(cx: &mut App) -> Entity<Self> {
if cx.has_global::<GlobalAcpConnectionRegistry>() {
cx.global::<GlobalAcpConnectionRegistry>().0.clone()
} else {
let registry = cx.new(|_cx| AcpConnectionRegistry::default());
cx.set_global(GlobalAcpConnectionRegistry(registry.clone()));
registry
}
}
pub fn set_active_connection(
&self,
server_name: impl Into<SharedString>,
connection: &Rc<acp::ClientSideConnection>,
cx: &mut Context<Self>,
) {
self.active_connection.replace(Some(ActiveConnection {
server_name: server_name.into(),
connection: Rc::downgrade(connection),
}));
cx.notify();
}
}
struct AcpTools {
project: Entity<Project>,
focus_handle: FocusHandle,
expanded: HashSet<usize>,
watched_connection: Option<WatchedConnection>,
connection_registry: Entity<AcpConnectionRegistry>,
_subscription: Subscription,
}
struct WatchedConnection {
server_name: SharedString,
messages: Vec<WatchedConnectionMessage>,
list_state: ListState,
connection: Weak<acp::ClientSideConnection>,
incoming_request_methods: HashMap<i32, Arc<str>>,
outgoing_request_methods: HashMap<i32, Arc<str>>,
_task: Task<()>,
}
impl AcpTools {
fn new(project: Entity<Project>, cx: &mut Context<Self>) -> Self {
let connection_registry = AcpConnectionRegistry::default_global(cx);
let subscription = cx.observe(&connection_registry, |this, _, cx| {
this.update_connection(cx);
cx.notify();
});
let mut this = Self {
project,
focus_handle: cx.focus_handle(),
expanded: HashSet::default(),
watched_connection: None,
connection_registry,
_subscription: subscription,
};
this.update_connection(cx);
this
}
fn update_connection(&mut self, cx: &mut Context<Self>) {
let active_connection = self.connection_registry.read(cx).active_connection.borrow();
let Some(active_connection) = active_connection.as_ref() else {
return;
};
if let Some(watched_connection) = self.watched_connection.as_ref() {
if Weak::ptr_eq(
&watched_connection.connection,
&active_connection.connection,
) {
return;
}
}
if let Some(connection) = active_connection.connection.upgrade() {
let mut receiver = connection.subscribe();
let task = cx.spawn(async move |this, cx| {
while let Ok(message) = receiver.recv().await {
this.update(cx, |this, cx| {
this.push_stream_message(message, cx);
})
.ok();
}
});
self.watched_connection = Some(WatchedConnection {
server_name: active_connection.server_name.clone(),
messages: vec![],
list_state: ListState::new(0, ListAlignment::Bottom, px(2048.)),
connection: active_connection.connection.clone(),
incoming_request_methods: HashMap::default(),
outgoing_request_methods: HashMap::default(),
_task: task,
});
}
}
fn push_stream_message(&mut self, stream_message: acp::StreamMessage, cx: &mut Context<Self>) {
let Some(connection) = self.watched_connection.as_mut() else {
return;
};
let language_registry = self.project.read(cx).languages().clone();
let index = connection.messages.len();
let (request_id, method, message_type, params) = match stream_message.message {
acp::StreamMessageContent::Request { id, method, params } => {
let method_map = match stream_message.direction {
acp::StreamMessageDirection::Incoming => {
&mut connection.incoming_request_methods
}
acp::StreamMessageDirection::Outgoing => {
&mut connection.outgoing_request_methods
}
};
method_map.insert(id, method.clone());
(Some(id), method.into(), MessageType::Request, Ok(params))
}
acp::StreamMessageContent::Response { id, result } => {
let method_map = match stream_message.direction {
acp::StreamMessageDirection::Incoming => {
&mut connection.outgoing_request_methods
}
acp::StreamMessageDirection::Outgoing => {
&mut connection.incoming_request_methods
}
};
if let Some(method) = method_map.remove(&id) {
(Some(id), method.into(), MessageType::Response, result)
} else {
(
Some(id),
"[unrecognized response]".into(),
MessageType::Response,
result,
)
}
}
acp::StreamMessageContent::Notification { method, params } => {
(None, method.into(), MessageType::Notification, Ok(params))
}
};
let message = WatchedConnectionMessage {
name: method,
message_type,
request_id,
direction: stream_message.direction,
collapsed_params_md: match params.as_ref() {
Ok(params) => params
.as_ref()
.map(|params| collapsed_params_md(params, &language_registry, cx)),
Err(err) => {
if let Ok(err) = &serde_json::to_value(err) {
Some(collapsed_params_md(&err, &language_registry, cx))
} else {
None
}
}
},
expanded_params_md: None,
params,
};
connection.messages.push(message);
connection.list_state.splice(index..index, 1);
cx.notify();
}
fn render_message(
&mut self,
index: usize,
window: &mut Window,
cx: &mut Context<Self>,
) -> AnyElement {
let Some(connection) = self.watched_connection.as_ref() else {
return Empty.into_any();
};
let Some(message) = connection.messages.get(index) else {
return Empty.into_any();
};
let base_size = TextSize::Editor.rems(cx);
let theme_settings = ThemeSettings::get_global(cx);
let text_style = window.text_style();
let colors = cx.theme().colors();
let expanded = self.expanded.contains(&index);
v_flex()
.w_full()
.px_4()
.py_3()
.border_color(colors.border)
.border_b_1()
.gap_2()
.items_start()
.font_buffer(cx)
.text_size(base_size)
.id(index)
.group("message")
.hover(|this| this.bg(colors.element_background.opacity(0.5)))
.on_click(cx.listener(move |this, _, _, cx| {
if this.expanded.contains(&index) {
this.expanded.remove(&index);
} else {
this.expanded.insert(index);
let Some(connection) = &mut this.watched_connection else {
return;
};
let Some(message) = connection.messages.get_mut(index) else {
return;
};
message.expanded(this.project.read(cx).languages().clone(), cx);
connection.list_state.scroll_to_reveal_item(index);
}
cx.notify()
}))
.child(
h_flex()
.w_full()
.gap_2()
.items_center()
.flex_shrink_0()
.child(match message.direction {
acp::StreamMessageDirection::Incoming => {
ui::Icon::new(ui::IconName::ArrowDown).color(Color::Error)
}
acp::StreamMessageDirection::Outgoing => {
ui::Icon::new(ui::IconName::ArrowUp).color(Color::Success)
}
})
.child(
Label::new(message.name.clone())
.buffer_font(cx)
.color(Color::Muted),
)
.child(div().flex_1())
.child(
div()
.child(ui::Chip::new(message.message_type.to_string()))
.visible_on_hover("message"),
)
.children(
message
.request_id
.map(|req_id| div().child(ui::Chip::new(req_id.to_string()))),
),
)
// I'm aware using markdown is a hack. Trying to get something working for the demo.
// Will clean up soon!
.when_some(
if expanded {
message.expanded_params_md.clone()
} else {
message.collapsed_params_md.clone()
},
|this, params| {
this.child(
div().pl_6().w_full().child(
MarkdownElement::new(
params,
MarkdownStyle {
base_text_style: text_style,
selection_background_color: colors.element_selection_background,
syntax: cx.theme().syntax().clone(),
code_block_overflow_x_scroll: true,
code_block: StyleRefinement {
text: Some(TextStyleRefinement {
font_family: Some(
theme_settings.buffer_font.family.clone(),
),
font_size: Some((base_size * 0.8).into()),
..Default::default()
}),
..Default::default()
},
..Default::default()
},
)
.code_block_renderer(
CodeBlockRenderer::Default {
copy_button: false,
copy_button_on_hover: expanded,
border: false,
},
),
),
)
},
)
.into_any()
}
}
struct WatchedConnectionMessage {
name: SharedString,
request_id: Option<i32>,
direction: acp::StreamMessageDirection,
message_type: MessageType,
params: Result<Option<serde_json::Value>, acp::Error>,
collapsed_params_md: Option<Entity<Markdown>>,
expanded_params_md: Option<Entity<Markdown>>,
}
impl WatchedConnectionMessage {
fn expanded(&mut self, language_registry: Arc<LanguageRegistry>, cx: &mut App) {
let params_md = match &self.params {
Ok(Some(params)) => Some(expanded_params_md(params, &language_registry, cx)),
Err(err) => {
if let Some(err) = &serde_json::to_value(err).log_err() {
Some(expanded_params_md(&err, &language_registry, cx))
} else {
None
}
}
_ => None,
};
self.expanded_params_md = params_md;
}
}
fn collapsed_params_md(
params: &serde_json::Value,
language_registry: &Arc<LanguageRegistry>,
cx: &mut App,
) -> Entity<Markdown> {
let params_json = serde_json::to_string(params).unwrap_or_default();
let mut spaced_out_json = String::with_capacity(params_json.len() + params_json.len() / 4);
for ch in params_json.chars() {
match ch {
'{' => spaced_out_json.push_str("{ "),
'}' => spaced_out_json.push_str(" }"),
':' => spaced_out_json.push_str(": "),
',' => spaced_out_json.push_str(", "),
c => spaced_out_json.push(c),
}
}
let params_md = format!("```json\n{}\n```", spaced_out_json);
cx.new(|cx| Markdown::new(params_md.into(), Some(language_registry.clone()), None, cx))
}
fn expanded_params_md(
params: &serde_json::Value,
language_registry: &Arc<LanguageRegistry>,
cx: &mut App,
) -> Entity<Markdown> {
let params_json = serde_json::to_string_pretty(params).unwrap_or_default();
let params_md = format!("```json\n{}\n```", params_json);
cx.new(|cx| Markdown::new(params_md.into(), Some(language_registry.clone()), None, cx))
}
enum MessageType {
Request,
Response,
Notification,
}
impl Display for MessageType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MessageType::Request => write!(f, "Request"),
MessageType::Response => write!(f, "Response"),
MessageType::Notification => write!(f, "Notification"),
}
}
}
enum AcpToolsEvent {}
impl EventEmitter<AcpToolsEvent> for AcpTools {}
impl Item for AcpTools {
type Event = AcpToolsEvent;
fn tab_content_text(&self, _detail: usize, _cx: &App) -> ui::SharedString {
format!(
"ACP: {}",
self.watched_connection
.as_ref()
.map_or("Disconnected", |connection| &connection.server_name)
)
.into()
}
fn tab_icon(&self, _window: &Window, _cx: &App) -> Option<Icon> {
Some(ui::Icon::new(IconName::Thread))
}
}
impl Focusable for AcpTools {
fn focus_handle(&self, _cx: &App) -> FocusHandle {
self.focus_handle.clone()
}
}
impl Render for AcpTools {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
v_flex()
.track_focus(&self.focus_handle)
.size_full()
.bg(cx.theme().colors().editor_background)
.child(match self.watched_connection.as_ref() {
Some(connection) => {
if connection.messages.is_empty() {
h_flex()
.size_full()
.justify_center()
.items_center()
.child("No messages recorded yet")
.into_any()
} else {
list(
connection.list_state.clone(),
cx.processor(Self::render_message),
)
.with_sizing_behavior(gpui::ListSizingBehavior::Auto)
.flex_grow()
.into_any()
}
}
None => h_flex()
.size_full()
.justify_center()
.items_center()
.child("No active connection")
.into_any(),
})
}
}

View File

@@ -8,7 +8,10 @@ use language::{Anchor, Buffer, BufferEvent, DiskState, Point, ToPoint};
use project::{Project, ProjectItem, lsp_store::OpenLspBufferHandle};
use std::{cmp, ops::Range, sync::Arc};
use text::{Edit, Patch, Rope};
use util::{RangeExt, ResultExt as _};
use util::{
RangeExt, ResultExt as _,
paths::{PathStyle, RemotePathBuf},
};
/// Tracks actions performed by tools in a thread
pub struct ActionLog {
@@ -59,13 +62,7 @@ impl ActionLog {
let file_path = buffer
.read(cx)
.file()
.map(|file| {
let mut path = file.full_path(cx).to_string_lossy().into_owned();
if file.path_style(cx).is_windows() {
path = path.replace('\\', "/");
}
path
})
.map(|file| RemotePathBuf::new(file.full_path(cx), PathStyle::Posix).to_proto())
.unwrap_or_else(|| format!("buffer_{}", buffer.entity_id()));
let mut result = String::new();
@@ -2221,7 +2218,7 @@ mod tests {
action_log.update(cx, |log, cx| log.buffer_read(buffer.clone(), cx));
for _ in 0..operations {
match rng.random_range(0..100) {
match rng.gen_range(0..100) {
0..25 => {
action_log.update(cx, |log, cx| {
let range = buffer.read(cx).random_byte_range(0, &mut rng);
@@ -2240,7 +2237,7 @@ mod tests {
.unwrap();
}
_ => {
let is_agent_edit = rng.random_bool(0.5);
let is_agent_edit = rng.gen_bool(0.5);
if is_agent_edit {
log::info!("agent edit");
} else {
@@ -2255,7 +2252,7 @@ mod tests {
}
}
if rng.random_bool(0.2) {
if rng.gen_bool(0.2) {
quiesce(&action_log, &buffer, cx);
}
}
@@ -2304,7 +2301,7 @@ mod tests {
.await;
fs.set_head_for_repo(
path!("/project/.git").as_ref(),
&[("file.txt", "a\nb\nc\nd\ne\nf\ng\nh\ni\nj".into())],
&[("file.txt".into(), "a\nb\nc\nd\ne\nf\ng\nh\ni\nj".into())],
"0000000",
);
cx.run_until_parked();
@@ -2387,7 +2384,7 @@ mod tests {
// - Ignores the last line edit (j stays as j)
fs.set_head_for_repo(
path!("/project/.git").as_ref(),
&[("file.txt", "A\nb\nc\nf\nG\nh\ni\nj".into())],
&[("file.txt".into(), "A\nb\nc\nf\nG\nh\ni\nj".into())],
"0000001",
);
cx.run_until_parked();
@@ -2418,7 +2415,10 @@ mod tests {
// Make another commit that accepts the NEW line but with different content
fs.set_head_for_repo(
path!("/project/.git").as_ref(),
&[("file.txt", "A\nb\nc\nf\nGGG\nh\nDIFFERENT\ni\nj".into())],
&[(
"file.txt".into(),
"A\nb\nc\nf\nGGG\nh\nDIFFERENT\ni\nj".into(),
)],
"0000002",
);
cx.run_until_parked();
@@ -2444,7 +2444,7 @@ mod tests {
// Final commit that accepts all remaining edits
fs.set_head_for_repo(
path!("/project/.git").as_ref(),
&[("file.txt", "A\nb\nc\nf\nGGG\nh\nNEW\ni\nJ".into())],
&[("file.txt".into(), "A\nb\nc\nf\nGGG\nh\nNEW\ni\nJ".into())],
"0000003",
);
cx.run_until_parked();

View File

@@ -1,10 +1,11 @@
use auto_update::{AutoUpdateStatus, AutoUpdater, DismissMessage, VersionCheckType};
use auto_update::{AutoUpdateStatus, AutoUpdater, DismissErrorMessage, VersionCheckType};
use editor::Editor;
use extension_host::{ExtensionOperation, ExtensionStore};
use extension_host::ExtensionStore;
use futures::StreamExt;
use gpui::{
App, Context, CursorStyle, Entity, EventEmitter, InteractiveElement as _, ParentElement as _,
Render, SharedString, StatefulInteractiveElement, Styled, Window, actions,
Animation, AnimationExt as _, App, Context, CursorStyle, Entity, EventEmitter,
InteractiveElement as _, ParentElement as _, Render, SharedString, StatefulInteractiveElement,
Styled, Transformation, Window, actions, percentage,
};
use language::{
BinaryStatus, LanguageRegistry, LanguageServerId, LanguageServerName,
@@ -20,13 +21,11 @@ use std::{
cmp::Reverse,
collections::HashSet,
fmt::Write,
path::Path,
sync::Arc,
time::{Duration, Instant},
};
use ui::{
ButtonLike, CommonAnimationExt, ContextMenu, PopoverMenu, PopoverMenuHandle, Tooltip,
prelude::*,
};
use ui::{ButtonLike, ContextMenu, PopoverMenu, PopoverMenuHandle, Tooltip, prelude::*};
use util::truncate_and_trailoff;
use workspace::{StatusItemView, Workspace, item::ItemHandle};
@@ -83,6 +82,7 @@ impl ActivityIndicator {
) -> Entity<ActivityIndicator> {
let project = workspace.project().clone();
let auto_updater = AutoUpdater::get(cx);
let workspace_handle = cx.entity();
let this = cx.new(|cx| {
let mut status_events = languages.language_server_binary_statuses();
cx.spawn(async move |this, cx| {
@@ -100,6 +100,20 @@ impl ActivityIndicator {
})
.detach();
cx.subscribe_in(
&workspace_handle,
window,
|activity_indicator, _, event, window, cx| {
if let workspace::Event::ClearActivityIndicator = event
&& activity_indicator.statuses.pop().is_some()
{
activity_indicator.dismiss_error_message(&DismissErrorMessage, window, cx);
cx.notify();
}
},
)
.detach();
cx.subscribe(
&project.read(cx).lsp_store(),
|activity_indicator, _, event, cx| {
@@ -211,8 +225,7 @@ impl ActivityIndicator {
server_name,
status,
} => {
let create_buffer =
project.update(cx, |project, cx| project.create_buffer(false, cx));
let create_buffer = project.update(cx, |project, cx| project.create_buffer(cx));
let status = status.clone();
let server_name = server_name.clone();
cx.spawn_in(window, async move |workspace, cx| {
@@ -279,13 +292,18 @@ impl ActivityIndicator {
});
}
fn dismiss_message(&mut self, _: &DismissMessage, _: &mut Window, cx: &mut Context<Self>) {
let dismissed = if let Some(updater) = &self.auto_updater {
updater.update(cx, |updater, cx| updater.dismiss(cx))
fn dismiss_error_message(
&mut self,
_: &DismissErrorMessage,
_: &mut Window,
cx: &mut Context<Self>,
) {
let error_dismissed = if let Some(updater) = &self.auto_updater {
updater.update(cx, |updater, cx| updater.dismiss_error(cx))
} else {
false
};
if dismissed {
if error_dismissed {
return;
}
@@ -327,13 +345,17 @@ impl ActivityIndicator {
.flatten()
}
fn pending_environment_error<'a>(&'a self, cx: &'a App) -> Option<&'a EnvironmentErrorMessage> {
self.project.read(cx).peek_environment_error(cx)
fn pending_environment_errors<'a>(
&'a self,
cx: &'a App,
) -> impl Iterator<Item = (&'a Arc<Path>, &'a EnvironmentErrorMessage)> {
self.project.read(cx).shell_environment_errors(cx)
}
fn content_to_render(&mut self, cx: &mut Context<Self>) -> Option<Content> {
// Show if any direnv calls failed
if let Some(error) = self.pending_environment_error(cx) {
if let Some((abs_path, error)) = self.pending_environment_errors(cx).next() {
let abs_path = abs_path.clone();
return Some(Content {
icon: Some(
Icon::new(IconName::Warning)
@@ -343,7 +365,7 @@ impl ActivityIndicator {
message: error.0.clone(),
on_click: Some(Arc::new(move |this, window, cx| {
this.project.update(cx, |project, cx| {
project.pop_environment_error(cx);
project.remove_environment_error(&abs_path, cx);
});
window.dispatch_action(Box::new(workspace::OpenLog), cx);
})),
@@ -383,7 +405,13 @@ impl ActivityIndicator {
icon: Some(
Icon::new(IconName::ArrowCircle)
.size(IconSize::Small)
.with_rotate_animation(2)
.with_animation(
"arrow-circle",
Animation::new(Duration::from_secs(2)).repeat(),
|icon, delta| {
icon.transform(Transformation::rotate(percentage(delta)))
},
)
.into_any_element(),
),
message,
@@ -405,7 +433,11 @@ impl ActivityIndicator {
icon: Some(
Icon::new(IconName::ArrowCircle)
.size(IconSize::Small)
.with_rotate_animation(2)
.with_animation(
"arrow-circle",
Animation::new(Duration::from_secs(2)).repeat(),
|icon, delta| icon.transform(Transformation::rotate(percentage(delta))),
)
.into_any_element(),
),
message: format!("Debug: {}", session.read(cx).adapter()),
@@ -428,7 +460,11 @@ impl ActivityIndicator {
icon: Some(
Icon::new(IconName::ArrowCircle)
.size(IconSize::Small)
.with_rotate_animation(2)
.with_animation(
"arrow-circle",
Animation::new(Duration::from_secs(2)).repeat(),
|icon, delta| icon.transform(Transformation::rotate(percentage(delta))),
)
.into_any_element(),
),
message: job_info.message.into(),
@@ -503,7 +539,7 @@ impl ActivityIndicator {
on_click: Some(Arc::new(move |this, window, cx| {
this.statuses
.retain(|status| !downloading.contains(&status.name));
this.dismiss_message(&DismissMessage, window, cx)
this.dismiss_error_message(&DismissErrorMessage, window, cx)
})),
tooltip_message: None,
});
@@ -532,7 +568,7 @@ impl ActivityIndicator {
on_click: Some(Arc::new(move |this, window, cx| {
this.statuses
.retain(|status| !checking_for_update.contains(&status.name));
this.dismiss_message(&DismissMessage, window, cx)
this.dismiss_error_message(&DismissErrorMessage, window, cx)
})),
tooltip_message: None,
});
@@ -635,19 +671,17 @@ impl ActivityIndicator {
}
// Show any application auto-update info.
self.auto_updater
.as_ref()
.and_then(|updater| match &updater.read(cx).status() {
if let Some(updater) = &self.auto_updater {
return match &updater.read(cx).status() {
AutoUpdateStatus::Checking => Some(Content {
icon: Some(
Icon::new(IconName::LoadCircle)
Icon::new(IconName::Download)
.size(IconSize::Small)
.with_rotate_animation(3)
.into_any_element(),
),
message: "Checking for Zed updates…".to_string(),
on_click: Some(Arc::new(|this, window, cx| {
this.dismiss_message(&DismissMessage, window, cx)
this.dismiss_error_message(&DismissErrorMessage, window, cx)
})),
tooltip_message: None,
}),
@@ -659,20 +693,19 @@ impl ActivityIndicator {
),
message: "Downloading Zed update…".to_string(),
on_click: Some(Arc::new(|this, window, cx| {
this.dismiss_message(&DismissMessage, window, cx)
this.dismiss_error_message(&DismissErrorMessage, window, cx)
})),
tooltip_message: Some(Self::version_tooltip_message(version)),
}),
AutoUpdateStatus::Installing { version } => Some(Content {
icon: Some(
Icon::new(IconName::LoadCircle)
Icon::new(IconName::Download)
.size(IconSize::Small)
.with_rotate_animation(3)
.into_any_element(),
),
message: "Installing Zed update…".to_string(),
on_click: Some(Arc::new(|this, window, cx| {
this.dismiss_message(&DismissMessage, window, cx)
this.dismiss_error_message(&DismissErrorMessage, window, cx)
})),
tooltip_message: Some(Self::version_tooltip_message(version)),
}),
@@ -682,63 +715,41 @@ impl ActivityIndicator {
on_click: Some(Arc::new(move |_, _, cx| workspace::reload(cx))),
tooltip_message: Some(Self::version_tooltip_message(version)),
}),
AutoUpdateStatus::Errored { error } => Some(Content {
AutoUpdateStatus::Errored => Some(Content {
icon: Some(
Icon::new(IconName::Warning)
.size(IconSize::Small)
.into_any_element(),
),
message: "Failed to update Zed".to_string(),
message: "Auto update failed".to_string(),
on_click: Some(Arc::new(|this, window, cx| {
window.dispatch_action(Box::new(workspace::OpenLog), cx);
this.dismiss_message(&DismissMessage, window, cx);
this.dismiss_error_message(&DismissErrorMessage, window, cx)
})),
tooltip_message: Some(format!("{error}")),
tooltip_message: None,
}),
AutoUpdateStatus::Idle => None,
})
.or_else(|| {
if let Some(extension_store) =
ExtensionStore::try_global(cx).map(|extension_store| extension_store.read(cx))
&& let Some((extension_id, operation)) =
extension_store.outstanding_operations().iter().next()
{
let (message, icon, rotate) = match operation {
ExtensionOperation::Install => (
format!("Installing {extension_id} extension…"),
IconName::LoadCircle,
true,
),
ExtensionOperation::Upgrade => (
format!("Updating {extension_id} extension…"),
IconName::Download,
false,
),
ExtensionOperation::Remove => (
format!("Removing {extension_id} extension…"),
IconName::LoadCircle,
true,
),
};
};
}
Some(Content {
icon: Some(Icon::new(icon).size(IconSize::Small).map(|this| {
if rotate {
this.with_rotate_animation(3).into_any_element()
} else {
this.into_any_element()
}
})),
message,
on_click: Some(Arc::new(|this, window, cx| {
this.dismiss_message(&Default::default(), window, cx)
})),
tooltip_message: None,
})
} else {
None
}
})
if let Some(extension_store) =
ExtensionStore::try_global(cx).map(|extension_store| extension_store.read(cx))
&& let Some(extension_id) = extension_store.outstanding_operations().keys().next()
{
return Some(Content {
icon: Some(
Icon::new(IconName::Download)
.size(IconSize::Small)
.into_any_element(),
),
message: format!("Updating {extension_id} extension…"),
on_click: Some(Arc::new(|this, window, cx| {
this.dismiss_error_message(&DismissErrorMessage, window, cx)
})),
tooltip_message: None,
});
}
None
}
fn version_tooltip_message(version: &VersionCheckType) -> String {
@@ -770,7 +781,7 @@ impl Render for ActivityIndicator {
let result = h_flex()
.id("activity-indicator")
.on_action(cx.listener(Self::show_error_message))
.on_action(cx.listener(Self::dismiss_message));
.on_action(cx.listener(Self::dismiss_error_message));
let Some(content) = self.content_to_render(cx) else {
return result;
};

View File

@@ -63,7 +63,6 @@ time.workspace = true
util.workspace = true
uuid.workspace = true
workspace-hack.workspace = true
zed_env_vars.workspace = true
zstd.workspace = true
[dev-dependencies]

View File

@@ -9,14 +9,12 @@ pub mod tool_use;
pub use context::{AgentContext, ContextId, ContextLoadResult};
pub use context_store::ContextStore;
use fs::Fs;
use std::sync::Arc;
pub use thread::{
LastRestoreCheckpoint, Message, MessageCrease, MessageId, MessageSegment, Thread, ThreadError,
ThreadEvent, ThreadFeedback, ThreadId, ThreadSummary, TokenUsageRatio,
};
pub use thread_store::{SerializedThread, TextThreadStore, ThreadStore};
pub fn init(fs: Arc<dyn Fs>, cx: &mut gpui::App) {
thread_store::init(fs, cx);
pub fn init(cx: &mut gpui::App) {
thread_store::init(cx);
}

View File

@@ -49,10 +49,10 @@ impl AgentProfile {
.unwrap_or_default(),
};
update_settings_file(fs, cx, {
update_settings_file::<AgentSettings>(fs, cx, {
let id = id.clone();
move |settings, _cx| {
profile_settings.save_to_settings(id, settings).log_err();
settings.create_profile(id, profile_settings).log_err();
}
});

View File

@@ -6,7 +6,7 @@ use futures::future;
use futures::{FutureExt, future::Shared};
use gpui::{App, AppContext as _, ElementId, Entity, SharedString, Task};
use icons::IconName;
use language::Buffer;
use language::{Buffer, ParseStatus};
use language_model::{LanguageModelImage, LanguageModelRequestMessage, MessageContent};
use project::{Project, ProjectEntryId, ProjectPath, Worktree};
use prompt_store::{PromptStore, UserPromptId};
@@ -18,7 +18,6 @@ use std::path::PathBuf;
use std::{ops::Range, path::Path, sync::Arc};
use text::{Anchor, OffsetRangeExt as _};
use util::markdown::MarkdownCodeBlock;
use util::rel_path::RelPath;
use util::{ResultExt as _, post_inc};
pub const RULES_ICON: IconName = IconName::Reader;
@@ -159,7 +158,7 @@ pub struct FileContextHandle {
#[derive(Debug, Clone)]
pub struct FileContext {
pub handle: FileContextHandle,
pub full_path: String,
pub full_path: Arc<Path>,
pub text: SharedString,
pub is_outline: bool,
}
@@ -187,24 +186,51 @@ impl FileContextHandle {
log::error!("file context missing path");
return Task::ready(None);
};
let full_path = file.full_path(cx).to_string_lossy().into_owned();
let full_path: Arc<Path> = file.full_path(cx).into();
let rope = buffer_ref.as_rope().clone();
let buffer = self.buffer.clone();
cx.spawn(async move |cx| {
let buffer_content =
outline::get_buffer_content_or_outline(buffer.clone(), Some(&full_path), &cx)
.await
.unwrap_or_else(|_| outline::BufferContent {
text: rope.to_string(),
is_outline: false,
});
// For large files, use outline instead of full content
if rope.len() > outline::AUTO_OUTLINE_SIZE {
// Wait until the buffer has been fully parsed, so we can read its outline
if let Ok(mut parse_status) =
buffer.read_with(cx, |buffer, _| buffer.parse_status())
{
while *parse_status.borrow() != ParseStatus::Idle {
parse_status.changed().await.log_err();
}
if let Ok(snapshot) = buffer.read_with(cx, |buffer, _| buffer.snapshot())
&& let Some(outline) = snapshot.outline(None)
{
let items = outline
.items
.into_iter()
.map(|item| item.to_point(&snapshot));
if let Ok(outline_text) =
outline::render_outline(items, None, 0, usize::MAX).await
{
let context = AgentContext::File(FileContext {
handle: self,
full_path,
text: outline_text.into(),
is_outline: true,
});
return Some((context, vec![buffer]));
}
}
}
}
// Fallback to full content if we couldn't build an outline
// (or didn't need to because the file was small enough)
let context = AgentContext::File(FileContext {
handle: self,
full_path,
text: buffer_content.text.into(),
is_outline: buffer_content.is_outline,
text: rope.to_string().into(),
is_outline: false,
});
Some((context, vec![buffer]))
})
@@ -236,14 +262,14 @@ pub struct DirectoryContextHandle {
#[derive(Debug, Clone)]
pub struct DirectoryContext {
pub handle: DirectoryContextHandle,
pub full_path: String,
pub full_path: Arc<Path>,
pub descendants: Vec<DirectoryContextDescendant>,
}
#[derive(Debug, Clone)]
pub struct DirectoryContextDescendant {
/// Path within the directory.
pub rel_path: Arc<RelPath>,
pub rel_path: Arc<Path>,
pub fenced_codeblock: SharedString,
}
@@ -274,16 +300,13 @@ impl DirectoryContextHandle {
}
let directory_path = entry.path.clone();
let directory_full_path = worktree_ref
.full_path(&directory_path)
.to_string_lossy()
.to_string();
let directory_full_path = worktree_ref.full_path(&directory_path).into();
let file_paths = collect_files_in_path(worktree_ref, &directory_path);
let descendants_future = future::join_all(file_paths.into_iter().map(|path| {
let worktree_ref = worktree.read(cx);
let worktree_id = worktree_ref.id();
let full_path = worktree_ref.full_path(&path).to_string_lossy().into_owned();
let full_path = worktree_ref.full_path(&path);
let rel_path = path
.strip_prefix(&directory_path)
@@ -364,7 +387,7 @@ pub struct SymbolContextHandle {
#[derive(Debug, Clone)]
pub struct SymbolContext {
pub handle: SymbolContextHandle,
pub full_path: String,
pub full_path: Arc<Path>,
pub line_range: Range<Point>,
pub text: SharedString,
}
@@ -403,7 +426,7 @@ impl SymbolContextHandle {
log::error!("symbol context's file has no path");
return Task::ready(None);
};
let full_path = file.full_path(cx).to_string_lossy().into_owned();
let full_path = file.full_path(cx).into();
let line_range = self.enclosing_range.to_point(&buffer_ref.snapshot());
let text = self.text(cx);
let buffer = self.buffer.clone();
@@ -437,7 +460,7 @@ pub struct SelectionContextHandle {
#[derive(Debug, Clone)]
pub struct SelectionContext {
pub handle: SelectionContextHandle,
pub full_path: String,
pub full_path: Arc<Path>,
pub line_range: Range<Point>,
pub text: SharedString,
}
@@ -476,7 +499,7 @@ impl SelectionContextHandle {
let text = self.text(cx);
let buffer = self.buffer.clone();
let context = AgentContext::Selection(SelectionContext {
full_path: full_path.to_string_lossy().into_owned(),
full_path: full_path.into(),
line_range: self.line_range(cx),
text,
handle: self,
@@ -706,7 +729,7 @@ impl Display for RulesContext {
#[derive(Debug, Clone)]
pub struct ImageContext {
pub project_path: Option<ProjectPath>,
pub full_path: Option<String>,
pub full_path: Option<Arc<Path>>,
pub original_image: Arc<gpui::Image>,
// TODO: handle this elsewhere and remove `ignore-interior-mutability` opt-out in clippy.toml
// needed due to a false positive of `clippy::mutable_key_type`.
@@ -972,7 +995,7 @@ pub fn load_context(
})
}
fn collect_files_in_path(worktree: &Worktree, path: &RelPath) -> Vec<Arc<RelPath>> {
fn collect_files_in_path(worktree: &Worktree, path: &Path) -> Vec<Arc<Path>> {
let mut files = Vec::new();
for entry in worktree.child_entries(path) {
@@ -986,17 +1009,14 @@ fn collect_files_in_path(worktree: &Worktree, path: &RelPath) -> Vec<Arc<RelPath
files
}
fn codeblock_tag(full_path: &str, line_range: Option<Range<Point>>) -> String {
fn codeblock_tag(full_path: &Path, line_range: Option<Range<Point>>) -> String {
let mut result = String::new();
if let Some(extension) = Path::new(full_path)
.extension()
.and_then(|ext| ext.to_str())
{
if let Some(extension) = full_path.extension().and_then(|ext| ext.to_str()) {
let _ = write!(result, "{} ", extension);
}
let _ = write!(result, "{}", full_path);
let _ = write!(result, "{}", full_path.display());
if let Some(range) = line_range {
if range.start.row == range.end.row {

View File

@@ -14,10 +14,7 @@ use futures::{self, FutureExt};
use gpui::{App, Context, Entity, EventEmitter, Image, SharedString, Task, WeakEntity};
use language::{Buffer, File as _};
use language_model::LanguageModelImage;
use project::{
Project, ProjectItem, ProjectPath, Symbol, image_store::is_image_file,
lsp_store::SymbolLocation,
};
use project::{Project, ProjectItem, ProjectPath, Symbol, image_store::is_image_file};
use prompt_store::UserPromptId;
use ref_cast::RefCast as _;
use std::{
@@ -312,7 +309,7 @@ impl ContextStore {
let item = image_item.read(cx);
this.insert_image(
Some(item.project_path(cx)),
Some(item.file.full_path(cx).to_string_lossy().into_owned()),
Some(item.file.full_path(cx).into()),
item.image.clone(),
remove_if_exists,
cx,
@@ -328,7 +325,7 @@ impl ContextStore {
fn insert_image(
&mut self,
project_path: Option<ProjectPath>,
full_path: Option<String>,
full_path: Option<Arc<Path>>,
image: Arc<Image>,
remove_if_exists: bool,
cx: &mut Context<ContextStore>,
@@ -503,7 +500,7 @@ impl ContextStore {
let Some(context_path) = buffer.project_path(cx) else {
return false;
};
if symbol.path != SymbolLocation::InProject(context_path) {
if context_path != symbol.path {
return false;
}
let context_range = context.range.to_point_utf16(&buffer.snapshot());

View File

@@ -1,4 +1,7 @@
use crate::{ThreadId, thread_store::SerializedThreadMetadata};
use crate::{
ThreadId,
thread_store::{SerializedThreadMetadata, ThreadStore},
};
use anyhow::{Context as _, Result};
use assistant_context::SavedContextMetadata;
use chrono::{DateTime, Utc};
@@ -58,6 +61,7 @@ enum SerializedRecentOpen {
}
pub struct HistoryStore {
thread_store: Entity<ThreadStore>,
context_store: Entity<assistant_context::ContextStore>,
recently_opened_entries: VecDeque<HistoryEntryId>,
_subscriptions: Vec<gpui::Subscription>,
@@ -66,11 +70,15 @@ pub struct HistoryStore {
impl HistoryStore {
pub fn new(
thread_store: Entity<ThreadStore>,
context_store: Entity<assistant_context::ContextStore>,
initial_recent_entries: impl IntoIterator<Item = HistoryEntryId>,
cx: &mut Context<Self>,
) -> Self {
let subscriptions = vec![cx.observe(&context_store, |_, _, cx| cx.notify())];
let subscriptions = vec![
cx.observe(&thread_store, |_, _, cx| cx.notify()),
cx.observe(&context_store, |_, _, cx| cx.notify()),
];
cx.spawn(async move |this, cx| {
let entries = Self::load_recently_opened_entries(cx).await.log_err()?;
@@ -88,6 +96,7 @@ impl HistoryStore {
.detach();
Self {
thread_store,
context_store,
recently_opened_entries: initial_recent_entries.into_iter().collect(),
_subscriptions: subscriptions,
@@ -103,6 +112,13 @@ impl HistoryStore {
return history_entries;
}
history_entries.extend(
self.thread_store
.read(cx)
.reverse_chronological_threads()
.cloned()
.map(HistoryEntry::Thread),
);
history_entries.extend(
self.context_store
.read(cx)
@@ -125,6 +141,22 @@ impl HistoryStore {
return Vec::new();
}
let thread_entries = self
.thread_store
.read(cx)
.reverse_chronological_threads()
.flat_map(|thread| {
self.recently_opened_entries
.iter()
.enumerate()
.flat_map(|(index, entry)| match entry {
HistoryEntryId::Thread(id) if &thread.id == id => {
Some((index, HistoryEntry::Thread(thread.clone())))
}
_ => None,
})
});
let context_entries =
self.context_store
.read(cx)
@@ -141,7 +173,8 @@ impl HistoryStore {
})
});
context_entries
thread_entries
.chain(context_entries)
// optimization to halt iteration early
.take(self.recently_opened_entries.len())
.sorted_unstable_by_key(|(index, _)| *index)
@@ -155,7 +188,7 @@ impl HistoryStore {
.iter()
.filter_map(|entry| match entry {
HistoryEntryId::Context(path) => path.file_name().map(|file| {
SerializedRecentOpen::ContextName(file.to_string_lossy().into_owned())
SerializedRecentOpen::ContextName(file.to_string_lossy().to_string())
}),
HistoryEntryId::Thread(id) => Some(SerializedRecentOpen::Thread(id.to_string())),
})

View File

@@ -234,6 +234,7 @@ impl MessageSegment {
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ProjectSnapshot {
pub worktree_snapshots: Vec<WorktreeSnapshot>,
pub unsaved_buffer_paths: Vec<String>,
pub timestamp: DateTime<Utc>,
}
@@ -1276,6 +1277,62 @@ impl Thread {
);
}
pub fn retry_last_completion(
&mut self,
window: Option<AnyWindowHandle>,
cx: &mut Context<Self>,
) {
// Clear any existing error state
self.retry_state = None;
// Use the last error context if available, otherwise fall back to configured model
let (model, intent) = if let Some((model, intent)) = self.last_error_context.take() {
(model, intent)
} else if let Some(configured_model) = self.configured_model.as_ref() {
let model = configured_model.model.clone();
let intent = if self.has_pending_tool_uses() {
CompletionIntent::ToolResults
} else {
CompletionIntent::UserPrompt
};
(model, intent)
} else if let Some(configured_model) = self.get_or_init_configured_model(cx) {
let model = configured_model.model.clone();
let intent = if self.has_pending_tool_uses() {
CompletionIntent::ToolResults
} else {
CompletionIntent::UserPrompt
};
(model, intent)
} else {
return;
};
self.send_to_model(model, intent, window, cx);
}
pub fn enable_burn_mode_and_retry(
&mut self,
window: Option<AnyWindowHandle>,
cx: &mut Context<Self>,
) {
self.completion_mode = CompletionMode::Burn;
cx.emit(ThreadEvent::ProfileChanged);
self.retry_last_completion(window, cx);
}
pub fn used_tools_since_last_user_message(&self) -> bool {
for message in self.messages.iter().rev() {
if self.tool_use.message_has_tool_results(message.id) {
return true;
} else if message.role == Role::User {
return false;
}
}
false
}
pub fn to_completion_request(
&self,
model: Arc<dyn LanguageModel>,
@@ -2800,11 +2857,27 @@ impl Thread {
.map(|worktree| Self::worktree_snapshot(worktree, git_store.clone(), cx))
.collect();
cx.spawn(async move |_, _| {
cx.spawn(async move |_, cx| {
let worktree_snapshots = futures::future::join_all(worktree_snapshots).await;
let mut unsaved_buffers = Vec::new();
cx.update(|app_cx| {
let buffer_store = project.read(app_cx).buffer_store();
for buffer_handle in buffer_store.read(app_cx).buffers() {
let buffer = buffer_handle.read(app_cx);
if buffer.is_dirty()
&& let Some(file) = buffer.file()
{
let path = file.path().to_string_lossy().to_string();
unsaved_buffers.push(path);
}
}
})
.ok();
Arc::new(ProjectSnapshot {
worktree_snapshots,
unsaved_buffer_paths: unsaved_buffers,
timestamp: Utc::now(),
})
})
@@ -2819,7 +2892,7 @@ impl Thread {
// Get worktree path and snapshot
let worktree_info = cx.update(|app_cx| {
let worktree = worktree.read(app_cx);
let path = worktree.abs_path().to_string_lossy().into_owned();
let path = worktree.abs_path().to_string_lossy().to_string();
let snapshot = worktree.snapshot();
(path, snapshot)
});
@@ -3199,10 +3272,9 @@ mod tests {
// Test-specific constants
const TEST_RATE_LIMIT_RETRY_SECS: u64 = 30;
use agent_settings::{AgentProfileId, AgentSettings};
use agent_settings::{AgentProfileId, AgentSettings, LanguageModelParameters};
use assistant_tool::ToolRegistry;
use assistant_tools;
use fs::Fs;
use futures::StreamExt;
use futures::future::BoxFuture;
use futures::stream::BoxStream;
@@ -3217,18 +3289,18 @@ mod tests {
use project::{FakeFs, Project};
use prompt_store::PromptBuilder;
use serde_json::json;
use settings::{LanguageModelParameters, Settings, SettingsStore};
use settings::{Settings, SettingsStore};
use std::sync::Arc;
use std::time::Duration;
use theme::ThemeSettings;
use util::path;
use workspace::Workspace;
#[gpui::test]
async fn test_message_with_context(cx: &mut TestAppContext) {
let fs = init_test_settings(cx);
init_test_settings(cx);
let project = create_test_project(
&fs,
cx,
json!({"code.rs": "fn main() {\n println!(\"Hello, world!\");\n}"}),
)
@@ -3303,10 +3375,9 @@ fn main() {{
#[gpui::test]
async fn test_only_include_new_contexts(cx: &mut TestAppContext) {
let fs = init_test_settings(cx);
init_test_settings(cx);
let project = create_test_project(
&fs,
cx,
json!({
"file1.rs": "fn function1() {}\n",
@@ -3460,10 +3531,9 @@ fn main() {{
#[gpui::test]
async fn test_message_without_files(cx: &mut TestAppContext) {
let fs = init_test_settings(cx);
init_test_settings(cx);
let project = create_test_project(
&fs,
cx,
json!({"code.rs": "fn main() {\n println!(\"Hello, world!\");\n}"}),
)
@@ -3540,10 +3610,9 @@ fn main() {{
#[gpui::test]
#[ignore] // turn this test on when project_notifications tool is re-enabled
async fn test_stale_buffer_notification(cx: &mut TestAppContext) {
let fs = init_test_settings(cx);
init_test_settings(cx);
let project = create_test_project(
&fs,
cx,
json!({"code.rs": "fn main() {\n println!(\"Hello, world!\");\n}"}),
)
@@ -3669,10 +3738,9 @@ fn main() {{
#[gpui::test]
async fn test_storing_profile_setting_per_thread(cx: &mut TestAppContext) {
let fs = init_test_settings(cx);
init_test_settings(cx);
let project = create_test_project(
&fs,
cx,
json!({"code.rs": "fn main() {\n println!(\"Hello, world!\");\n}"}),
)
@@ -3692,10 +3760,9 @@ fn main() {{
#[gpui::test]
async fn test_serializing_thread_profile(cx: &mut TestAppContext) {
let fs = init_test_settings(cx);
init_test_settings(cx);
let project = create_test_project(
&fs,
cx,
json!({"code.rs": "fn main() {\n println!(\"Hello, world!\");\n}"}),
)
@@ -3736,10 +3803,9 @@ fn main() {{
#[gpui::test]
async fn test_temperature_setting(cx: &mut TestAppContext) {
let fs = init_test_settings(cx);
init_test_settings(cx);
let project = create_test_project(
&fs,
cx,
json!({"code.rs": "fn main() {\n println!(\"Hello, world!\");\n}"}),
)
@@ -3831,9 +3897,9 @@ fn main() {{
#[gpui::test]
async fn test_thread_summary(cx: &mut TestAppContext) {
let fs = init_test_settings(cx);
init_test_settings(cx);
let project = create_test_project(&fs, cx, json!({})).await;
let project = create_test_project(cx, json!({})).await;
let (_, _thread_store, thread, _context_store, model) =
setup_test_environment(cx, project.clone()).await;
@@ -3916,9 +3982,9 @@ fn main() {{
#[gpui::test]
async fn test_thread_summary_error_set_manually(cx: &mut TestAppContext) {
let fs = init_test_settings(cx);
init_test_settings(cx);
let project = create_test_project(&fs, cx, json!({})).await;
let project = create_test_project(cx, json!({})).await;
let (_, _thread_store, thread, _context_store, model) =
setup_test_environment(cx, project.clone()).await;
@@ -3938,9 +4004,9 @@ fn main() {{
#[gpui::test]
async fn test_thread_summary_error_retry(cx: &mut TestAppContext) {
let fs = init_test_settings(cx);
init_test_settings(cx);
let project = create_test_project(&fs, cx, json!({})).await;
let project = create_test_project(cx, json!({})).await;
let (_, _thread_store, thread, _context_store, model) =
setup_test_environment(cx, project.clone()).await;
@@ -4092,9 +4158,9 @@ fn main() {{
#[gpui::test]
async fn test_retry_on_overloaded_error(cx: &mut TestAppContext) {
let fs = init_test_settings(cx);
init_test_settings(cx);
let project = create_test_project(&fs, cx, json!({})).await;
let project = create_test_project(cx, json!({})).await;
let (_, _, thread, _, _base_model) = setup_test_environment(cx, project.clone()).await;
// Enable Burn Mode to allow retries
@@ -4170,9 +4236,9 @@ fn main() {{
#[gpui::test]
async fn test_retry_on_internal_server_error(cx: &mut TestAppContext) {
let fs = init_test_settings(cx);
init_test_settings(cx);
let project = create_test_project(&fs, cx, json!({})).await;
let project = create_test_project(cx, json!({})).await;
let (_, _, thread, _, _base_model) = setup_test_environment(cx, project.clone()).await;
// Enable Burn Mode to allow retries
@@ -4252,9 +4318,9 @@ fn main() {{
#[gpui::test]
async fn test_exponential_backoff_on_retries(cx: &mut TestAppContext) {
let fs = init_test_settings(cx);
init_test_settings(cx);
let project = create_test_project(&fs, cx, json!({})).await;
let project = create_test_project(cx, json!({})).await;
let (_, _, thread, _, _base_model) = setup_test_environment(cx, project.clone()).await;
// Enable Burn Mode to allow retries
@@ -4372,9 +4438,9 @@ fn main() {{
#[gpui::test]
async fn test_max_retries_exceeded(cx: &mut TestAppContext) {
let fs = init_test_settings(cx);
init_test_settings(cx);
let project = create_test_project(&fs, cx, json!({})).await;
let project = create_test_project(cx, json!({})).await;
let (_, _, thread, _, _base_model) = setup_test_environment(cx, project.clone()).await;
// Enable Burn Mode to allow retries
@@ -4463,9 +4529,9 @@ fn main() {{
#[gpui::test]
async fn test_retry_message_removed_on_retry(cx: &mut TestAppContext) {
let fs = init_test_settings(cx);
init_test_settings(cx);
let project = create_test_project(&fs, cx, json!({})).await;
let project = create_test_project(cx, json!({})).await;
let (_, _, thread, _, _base_model) = setup_test_environment(cx, project.clone()).await;
// Enable Burn Mode to allow retries
@@ -4636,9 +4702,9 @@ fn main() {{
#[gpui::test]
async fn test_successful_completion_clears_retry_state(cx: &mut TestAppContext) {
let fs = init_test_settings(cx);
init_test_settings(cx);
let project = create_test_project(&fs, cx, json!({})).await;
let project = create_test_project(cx, json!({})).await;
let (_, _, thread, _, _base_model) = setup_test_environment(cx, project.clone()).await;
// Enable Burn Mode to allow retries
@@ -4802,9 +4868,9 @@ fn main() {{
#[gpui::test]
async fn test_rate_limit_retry_single_attempt(cx: &mut TestAppContext) {
let fs = init_test_settings(cx);
init_test_settings(cx);
let project = create_test_project(&fs, cx, json!({})).await;
let project = create_test_project(cx, json!({})).await;
let (_, _, thread, _, _base_model) = setup_test_environment(cx, project.clone()).await;
// Enable Burn Mode to allow retries
@@ -4987,9 +5053,9 @@ fn main() {{
#[gpui::test]
async fn test_ui_only_messages_not_sent_to_model(cx: &mut TestAppContext) {
let fs = init_test_settings(cx);
init_test_settings(cx);
let project = create_test_project(&fs, cx, json!({})).await;
let project = create_test_project(cx, json!({})).await;
let (_, _, thread, _, model) = setup_test_environment(cx, project.clone()).await;
// Insert a regular user message
@@ -5087,9 +5153,9 @@ fn main() {{
#[gpui::test]
async fn test_no_retry_without_burn_mode(cx: &mut TestAppContext) {
let fs = init_test_settings(cx);
init_test_settings(cx);
let project = create_test_project(&fs, cx, json!({})).await;
let project = create_test_project(cx, json!({})).await;
let (_, _, thread, _, _base_model) = setup_test_environment(cx, project.clone()).await;
// Ensure we're in Normal mode (not Burn mode)
@@ -5160,9 +5226,9 @@ fn main() {{
#[gpui::test]
async fn test_retry_canceled_on_stop(cx: &mut TestAppContext) {
let fs = init_test_settings(cx);
init_test_settings(cx);
let project = create_test_project(&fs, cx, json!({})).await;
let project = create_test_project(cx, json!({})).await;
let (_, _, thread, _, _base_model) = setup_test_environment(cx, project.clone()).await;
// Enable Burn Mode to allow retries
@@ -5268,8 +5334,7 @@ fn main() {{
cx.run_until_parked();
}
fn init_test_settings(cx: &mut TestAppContext) -> Arc<dyn Fs> {
let fs = FakeFs::new(cx.executor());
fn init_test_settings(cx: &mut TestAppContext) {
cx.update(|cx| {
let settings_store = SettingsStore::test(cx);
cx.set_global(settings_store);
@@ -5277,10 +5342,10 @@ fn main() {{
Project::init_settings(cx);
AgentSettings::register(cx);
prompt_store::init(cx);
thread_store::init(fs.clone(), cx);
thread_store::init(cx);
workspace::init_settings(cx);
language_model::init_settings(cx);
theme::init(theme::LoadThemes::JustBase, cx);
ThemeSettings::register(cx);
ToolRegistry::default_global(cx);
assistant_tool::init(cx);
@@ -5291,17 +5356,16 @@ fn main() {{
));
assistant_tools::init(http_client, cx);
});
fs
}
// Helper to create a test project with test files
async fn create_test_project(
fs: &Arc<dyn Fs>,
cx: &mut TestAppContext,
files: serde_json::Value,
) -> Entity<Project> {
fs.as_fake().insert_tree(path!("/test"), files).await;
Project::test(fs.clone(), [path!("/test").as_ref()], cx).await
let fs = FakeFs::new(cx.executor());
fs.insert_tree(path!("/test"), files).await;
Project::test(fs, [path!("/test").as_ref()], cx).await
}
async fn setup_test_environment(

View File

@@ -10,7 +10,6 @@ use assistant_tool::{Tool, ToolId, ToolWorkingSet};
use chrono::{DateTime, Utc};
use collections::HashMap;
use context_server::ContextServerId;
use fs::{Fs, RemoveOptions};
use futures::{
FutureExt as _, StreamExt as _,
channel::{mpsc, oneshot},
@@ -38,11 +37,12 @@ use std::{
cell::{Ref, RefCell},
path::{Path, PathBuf},
rc::Rc,
sync::{Arc, LazyLock, Mutex},
sync::{Arc, Mutex},
};
use util::{ResultExt as _, rel_path::RelPath};
use util::ResultExt as _;
use zed_env_vars::ZED_STATELESS;
pub static ZED_STATELESS: std::sync::LazyLock<bool> =
std::sync::LazyLock::new(|| std::env::var("ZED_STATELESS").is_ok_and(|v| !v.is_empty()));
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum DataType {
@@ -74,22 +74,20 @@ impl Column for DataType {
}
}
static RULES_FILE_NAMES: LazyLock<[&RelPath; 9]> = LazyLock::new(|| {
[
RelPath::unix(".rules").unwrap(),
RelPath::unix(".cursorrules").unwrap(),
RelPath::unix(".windsurfrules").unwrap(),
RelPath::unix(".clinerules").unwrap(),
RelPath::unix(".github/copilot-instructions.md").unwrap(),
RelPath::unix("CLAUDE.md").unwrap(),
RelPath::unix("AGENT.md").unwrap(),
RelPath::unix("AGENTS.md").unwrap(),
RelPath::unix("GEMINI.md").unwrap(),
]
});
const RULES_FILE_NAMES: [&str; 9] = [
".rules",
".cursorrules",
".windsurfrules",
".clinerules",
".github/copilot-instructions.md",
"CLAUDE.md",
"AGENT.md",
"AGENTS.md",
"GEMINI.md",
];
pub fn init(fs: Arc<dyn Fs>, cx: &mut App) {
ThreadsDatabase::init(fs, cx);
pub fn init(cx: &mut App) {
ThreadsDatabase::init(cx);
}
/// A system prompt shared by all threads created by this ThreadStore
@@ -234,10 +232,11 @@ impl ThreadStore {
self.enqueue_system_prompt_reload();
}
project::Event::WorktreeUpdatedEntries(_, items) => {
if items
.iter()
.any(|(path, _, _)| RULES_FILE_NAMES.iter().any(|name| path.as_ref() == *name))
{
if items.iter().any(|(path, _, _)| {
RULES_FILE_NAMES
.iter()
.any(|name| path.as_ref() == Path::new(name))
}) {
self.enqueue_system_prompt_reload();
}
}
@@ -329,7 +328,7 @@ impl ThreadStore {
cx: &mut App,
) -> Task<(WorktreeContext, Option<RulesLoadingError>)> {
let tree = worktree.read(cx);
let root_name = tree.root_name_str().into();
let root_name = tree.root_name().into();
let abs_path = tree.abs_path();
let mut context = WorktreeContext {
@@ -871,13 +870,13 @@ impl ThreadsDatabase {
GlobalThreadsDatabase::global(cx).0.clone()
}
fn init(fs: Arc<dyn Fs>, cx: &mut App) {
fn init(cx: &mut App) {
let executor = cx.background_executor().clone();
let database_future = executor
.spawn({
let executor = executor.clone();
let threads_dir = paths::data_dir().join("threads");
async move { ThreadsDatabase::new(fs, threads_dir, executor).await }
async move { ThreadsDatabase::new(threads_dir, executor) }
})
.then(|result| future::ready(result.map(Arc::new).map_err(Arc::new)))
.boxed()
@@ -886,31 +885,16 @@ impl ThreadsDatabase {
cx.set_global(GlobalThreadsDatabase(database_future));
}
pub async fn new(
fs: Arc<dyn Fs>,
threads_dir: PathBuf,
executor: BackgroundExecutor,
) -> Result<Self> {
fs.create_dir(&threads_dir).await?;
pub fn new(threads_dir: PathBuf, executor: BackgroundExecutor) -> Result<Self> {
std::fs::create_dir_all(&threads_dir)?;
let sqlite_path = threads_dir.join("threads.db");
let mdb_path = threads_dir.join("threads-db.1.mdb");
let needs_migration_from_heed = fs.is_file(&mdb_path).await;
let needs_migration_from_heed = mdb_path.exists();
let connection = if *ZED_STATELESS {
let connection = if *ZED_STATELESS || cfg!(any(feature = "test-support", test)) {
Connection::open_memory(Some("THREAD_FALLBACK_DB"))
} else if cfg!(any(feature = "test-support", test)) {
// rust stores the name of the test on the current thread.
// We use this to automatically create a database that will
// be shared within the test (for the test_retrieve_old_thread)
// but not with concurrent tests.
let thread = std::thread::current();
let test_name = thread.name();
Connection::open_memory(Some(&format!(
"THREAD_FALLBACK_{}",
test_name.unwrap_or_default()
)))
} else {
Connection::open_file(&sqlite_path.to_string_lossy())
};
@@ -938,14 +922,7 @@ impl ThreadsDatabase {
.spawn(async move {
log::info!("Starting threads.db migration");
Self::migrate_from_heed(&mdb_path, db_connection, executor_clone)?;
fs.remove_dir(
&mdb_path,
RemoveOptions {
recursive: true,
ignore_if_not_exists: true,
},
)
.await?;
std::fs::remove_dir_all(mdb_path)?;
log::info!("threads.db migrated to sqlite");
Ok::<(), anyhow::Error>(())
})

View File

@@ -10,7 +10,6 @@ path = "src/agent2.rs"
[features]
test-support = ["db/test-support"]
e2e = []
[lints]
workspace = true
@@ -48,6 +47,7 @@ log.workspace = true
open.workspace = true
parking_lot.workspace = true
paths.workspace = true
portable-pty.workspace = true
project.workspace = true
prompt_store.workspace = true
rust-embed.workspace = true
@@ -60,20 +60,18 @@ sqlez.workspace = true
task.workspace = true
telemetry.workspace = true
terminal.workspace = true
thiserror.workspace = true
text.workspace = true
ui.workspace = true
util.workspace = true
uuid.workspace = true
watch.workspace = true
web_search.workspace = true
which.workspace = true
workspace-hack.workspace = true
zed_env_vars.workspace = true
zstd.workspace = true
[dev-dependencies]
agent = { workspace = true, "features" = ["test-support"] }
agent_servers = { workspace = true, "features" = ["test-support"] }
assistant_context = { workspace = true, "features" = ["test-support"] }
ctor.workspace = true
client = { workspace = true, "features" = ["test-support"] }

View File

@@ -2,15 +2,15 @@ use crate::{
ContextServerRegistry, Thread, ThreadEvent, ThreadsDatabase, ToolCallAuthorization,
UserMessageContent, templates::Templates,
};
use crate::{HistoryStore, TerminalHandle, ThreadEnvironment, TitleUpdated, TokenUsageUpdated};
use crate::{HistoryStore, TokenUsageUpdated};
use acp_thread::{AcpThread, AgentModelSelector};
use action_log::ActionLog;
use agent_client_protocol as acp;
use agent_settings::AgentSettings;
use anyhow::{Context as _, Result, anyhow};
use collections::{HashSet, IndexMap};
use fs::Fs;
use futures::channel::{mpsc, oneshot};
use futures::future::Shared;
use futures::channel::mpsc;
use futures::{StreamExt, future};
use gpui::{
App, AppContext, AsyncApp, Context, Entity, SharedString, Subscription, Task, WeakEntity,
@@ -20,14 +20,13 @@ use project::{Project, ProjectItem, ProjectPath, Worktree};
use prompt_store::{
ProjectContext, PromptId, PromptStore, RulesFileContext, UserRulesContext, WorktreeContext,
};
use settings::{LanguageModelSelection, update_settings_file};
use settings::update_settings_file;
use std::any::Any;
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::path::Path;
use std::rc::Rc;
use std::sync::Arc;
use util::ResultExt;
use util::rel_path::RelPath;
const RULES_FILE_NAMES: [&str; 9] = [
".rules",
@@ -57,24 +56,21 @@ struct Session {
pub struct LanguageModels {
/// Access language model by ID
models: HashMap<acp::ModelId, Arc<dyn LanguageModel>>,
models: HashMap<acp_thread::AgentModelId, Arc<dyn LanguageModel>>,
/// Cached list for returning language model information
model_list: acp_thread::AgentModelList,
refresh_models_rx: watch::Receiver<()>,
refresh_models_tx: watch::Sender<()>,
_authenticate_all_providers_task: Task<()>,
}
impl LanguageModels {
fn new(cx: &mut App) -> Self {
fn new(cx: &App) -> Self {
let (refresh_models_tx, refresh_models_rx) = watch::channel(());
let mut this = Self {
models: HashMap::default(),
model_list: acp_thread::AgentModelList::Grouped(IndexMap::default()),
refresh_models_rx,
refresh_models_tx,
_authenticate_all_providers_task: Self::authenticate_all_language_model_providers(cx),
};
this.refresh_list(cx);
this
@@ -94,7 +90,7 @@ impl LanguageModels {
let mut recommended = Vec::new();
for provider in &providers {
for model in provider.recommended_models(cx) {
recommended_models.insert((model.provider_id(), model.id()));
recommended_models.insert(model.id());
recommended.push(Self::map_language_model_to_info(&model, provider));
}
}
@@ -111,7 +107,7 @@ impl LanguageModels {
for model in provider.provided_models(cx) {
let model_info = Self::map_language_model_to_info(&model, &provider);
let model_id = model_info.id.clone();
if !recommended_models.contains(&(model.provider_id(), model.id())) {
if !recommended_models.contains(&model.id()) {
provider_models.push(model_info);
}
models.insert(model_id, model);
@@ -133,7 +129,10 @@ impl LanguageModels {
self.refresh_models_rx.clone()
}
pub fn model_from_id(&self, model_id: &acp::ModelId) -> Option<Arc<dyn LanguageModel>> {
pub fn model_from_id(
&self,
model_id: &acp_thread::AgentModelId,
) -> Option<Arc<dyn LanguageModel>> {
self.models.get(model_id).cloned()
}
@@ -144,67 +143,12 @@ impl LanguageModels {
acp_thread::AgentModelInfo {
id: Self::model_id(model),
name: model.name().0,
description: None,
icon: Some(provider.icon()),
}
}
fn model_id(model: &Arc<dyn LanguageModel>) -> acp::ModelId {
acp::ModelId(format!("{}/{}", model.provider_id().0, model.id().0).into())
}
fn authenticate_all_language_model_providers(cx: &mut App) -> Task<()> {
let authenticate_all_providers = LanguageModelRegistry::global(cx)
.read(cx)
.providers()
.iter()
.map(|provider| (provider.id(), provider.name(), provider.authenticate(cx)))
.collect::<Vec<_>>();
cx.background_spawn(async move {
for (provider_id, provider_name, authenticate_task) in authenticate_all_providers {
if let Err(err) = authenticate_task.await {
match err {
language_model::AuthenticateError::CredentialsNotFound => {
// Since we're authenticating these providers in the
// background for the purposes of populating the
// language selector, we don't care about providers
// where the credentials are not found.
}
language_model::AuthenticateError::ConnectionRefused => {
// Not logging connection refused errors as they are mostly from LM Studio's noisy auth failures.
// LM Studio only has one auth method (endpoint call) which fails for users who haven't enabled it.
// TODO: Better manage LM Studio auth logic to avoid these noisy failures.
}
_ => {
// Some providers have noisy failure states that we
// don't want to spam the logs with every time the
// language model selector is initialized.
//
// Ideally these should have more clear failure modes
// that we know are safe to ignore here, like what we do
// with `CredentialsNotFound` above.
match provider_id.0.as_ref() {
"lmstudio" | "ollama" => {
// LM Studio and Ollama both make fetch requests to the local APIs to determine if they are "authenticated".
//
// These fail noisily, so we don't log them.
}
"copilot_chat" => {
// Copilot Chat returns an error if Copilot is not enabled, so we don't log those errors.
}
_ => {
log::error!(
"Failed to authenticate provider: {}: {err}",
provider_name.0
);
}
}
}
}
}
}
})
fn model_id(model: &Arc<dyn LanguageModel>) -> acp_thread::AgentModelId {
acp_thread::AgentModelId(format!("{}/{}", model.provider_id().0, model.id().0).into())
}
}
@@ -236,7 +180,7 @@ impl NativeAgent {
fs: Arc<dyn Fs>,
cx: &mut AsyncApp,
) -> Result<Entity<NativeAgent>> {
log::debug!("Creating new NativeAgent");
log::info!("Creating new NativeAgent");
let project_context = cx
.update(|cx| Self::build_project_context(&project, prompt_store.as_ref(), cx))?
@@ -283,43 +227,32 @@ impl NativeAgent {
cx: &mut Context<Self>,
) -> Entity<AcpThread> {
let connection = Rc::new(NativeAgentConnection(cx.entity()));
let registry = LanguageModelRegistry::read_global(cx);
let summarization_model = registry.thread_summary_model().map(|c| c.model);
thread_handle.update(cx, |thread, cx| {
thread.set_summarization_model(summarization_model, cx);
thread.add_default_tools(cx)
});
let thread = thread_handle.read(cx);
let session_id = thread.id().clone();
let title = thread.title();
let project = thread.project.clone();
let action_log = thread.action_log.clone();
let prompt_capabilities_rx = thread.prompt_capabilities_rx.clone();
let acp_thread = cx.new(|cx| {
let acp_thread = cx.new(|_cx| {
acp_thread::AcpThread::new(
title,
connection,
project.clone(),
action_log.clone(),
session_id.clone(),
prompt_capabilities_rx,
cx,
)
});
let registry = LanguageModelRegistry::read_global(cx);
let summarization_model = registry.thread_summary_model().map(|c| c.model);
thread_handle.update(cx, |thread, cx| {
thread.set_summarization_model(summarization_model, cx);
thread.add_default_tools(
Rc::new(AcpThreadEnvironment {
acp_thread: acp_thread.downgrade(),
}) as _,
cx,
)
});
let subscriptions = vec![
cx.observe_release(&acp_thread, |this, acp_thread, _cx| {
this.sessions.remove(acp_thread.session_id());
}),
cx.subscribe(&thread_handle, Self::handle_thread_title_updated),
cx.subscribe(&thread_handle, Self::handle_thread_token_usage_updated),
cx.observe(&thread_handle, move |this, thread, cx| {
this.save_thread(thread, cx)
@@ -435,7 +368,7 @@ impl NativeAgent {
cx: &mut App,
) -> Task<(WorktreeContext, Option<RulesLoadingError>)> {
let tree = worktree.read(cx);
let root_name = tree.root_name_str().into();
let root_name = tree.root_name().into();
let abs_path = tree.abs_path();
let mut context = WorktreeContext {
@@ -475,7 +408,7 @@ impl NativeAgent {
.into_iter()
.filter_map(|name| {
worktree
.entry_for_path(RelPath::unix(name).unwrap())
.entry_for_path(name)
.filter(|entry| entry.is_file())
.map(|entry| entry.path.clone())
})
@@ -508,26 +441,6 @@ impl NativeAgent {
})
}
fn handle_thread_title_updated(
&mut self,
thread: Entity<Thread>,
_: &TitleUpdated,
cx: &mut Context<Self>,
) {
let session_id = thread.read(cx).id();
let Some(session) = self.sessions.get(session_id) else {
return;
};
let thread = thread.downgrade();
let acp_thread = session.acp_thread.clone();
cx.spawn(async move |_, cx| {
let title = thread.read_with(cx, |thread, _| thread.title())?;
let task = acp_thread.update(cx, |acp_thread, cx| acp_thread.set_title(title, cx))?;
task.await
})
.detach_and_log_err(cx);
}
fn handle_thread_token_usage_updated(
&mut self,
thread: Entity<Thread>,
@@ -559,7 +472,7 @@ impl NativeAgent {
if items.iter().any(|(path, _, _)| {
RULES_FILE_NAMES
.iter()
.any(|name| path.as_ref() == RelPath::unix(name).unwrap())
.any(|name| path.as_ref() == Path::new(name))
}) {
self.project_context_needs_refresh.send(()).ok();
}
@@ -753,7 +666,6 @@ impl NativeAgentConnection {
acp::ContentBlock::Text(acp::TextContent {
text,
annotations: None,
meta: None,
}),
false,
cx,
@@ -766,7 +678,6 @@ impl NativeAgentConnection {
acp::ContentBlock::Text(acp::TextContent {
text,
annotations: None,
meta: None,
}),
true,
cx,
@@ -778,17 +689,18 @@ impl NativeAgentConnection {
options,
response,
}) => {
let outcome_task = acp_thread.update(cx, |thread, cx| {
thread.request_tool_call_authorization(
tool_call, options, true, cx,
)
})??;
let recv = acp_thread.update(cx, |thread, cx| {
thread.request_tool_call_authorization(tool_call, options, cx)
})?;
cx.background_spawn(async move {
if let acp::RequestPermissionOutcome::Selected { option_id } =
outcome_task.await
if let Some(recv) = recv.log_err()
&& let Some(option) = recv
.await
.context("authorization sender was dropped")
.log_err()
{
response
.send(option_id)
.send(option)
.map(|_| anyhow!("authorization receiver was dropped"))
.log_err();
}
@@ -805,6 +717,10 @@ impl NativeAgentConnection {
thread.update_tool_call(update, cx)
})??;
}
ThreadEvent::TitleUpdate(title) => {
acp_thread
.update(cx, |thread, cx| thread.update_title(title, cx))??;
}
ThreadEvent::Retry(status) => {
acp_thread.update(cx, |thread, cx| {
thread.update_retry_status(status, cx)
@@ -812,10 +728,7 @@ impl NativeAgentConnection {
}
ThreadEvent::Stop(stop_reason) => {
log::debug!("Assistant message complete: {:?}", stop_reason);
return Ok(acp::PromptResponse {
stop_reason,
meta: None,
});
return Ok(acp::PromptResponse { stop_reason });
}
}
}
@@ -826,24 +739,18 @@ impl NativeAgentConnection {
}
}
log::debug!("Response stream completed");
log::info!("Response stream completed");
anyhow::Ok(acp::PromptResponse {
stop_reason: acp::StopReason::EndTurn,
meta: None,
})
})
}
}
struct NativeAgentModelSelector {
session_id: acp::SessionId,
connection: NativeAgentConnection,
}
impl acp_thread::AgentModelSelector for NativeAgentModelSelector {
impl AgentModelSelector for NativeAgentConnection {
fn list_models(&self, cx: &mut App) -> Task<Result<acp_thread::AgentModelList>> {
log::debug!("NativeAgentConnection::list_models called");
let list = self.connection.0.read(cx).models.model_list.clone();
let list = self.0.read(cx).models.model_list.clone();
Task::ready(if list.is_empty() {
Err(anyhow::anyhow!("No models available"))
} else {
@@ -851,24 +758,24 @@ impl acp_thread::AgentModelSelector for NativeAgentModelSelector {
})
}
fn select_model(&self, model_id: acp::ModelId, cx: &mut App) -> Task<Result<()>> {
log::debug!(
"Setting model for session {}: {}",
self.session_id,
model_id
);
fn select_model(
&self,
session_id: acp::SessionId,
model_id: acp_thread::AgentModelId,
cx: &mut App,
) -> Task<Result<()>> {
log::info!("Setting model for session {}: {}", session_id, model_id);
let Some(thread) = self
.connection
.0
.read(cx)
.sessions
.get(&self.session_id)
.get(&session_id)
.map(|session| session.thread.clone())
else {
return Task::ready(Err(anyhow!("Session not found")));
};
let Some(model) = self.connection.0.read(cx).models.model_from_id(&model_id) else {
let Some(model) = self.0.read(cx).models.model_from_id(&model_id) else {
return Task::ready(Err(anyhow!("Invalid model ID {}", model_id)));
};
@@ -876,32 +783,29 @@ impl acp_thread::AgentModelSelector for NativeAgentModelSelector {
thread.set_model(model.clone(), cx);
});
update_settings_file(
self.connection.0.read(cx).fs.clone(),
update_settings_file::<AgentSettings>(
self.0.read(cx).fs.clone(),
cx,
move |settings, _cx| {
let provider = model.provider_id().0.to_string();
let model = model.id().0.to_string();
settings
.agent
.get_or_insert_default()
.set_model(LanguageModelSelection {
provider: provider.into(),
model,
});
settings.set_model(model);
},
);
Task::ready(Ok(()))
}
fn selected_model(&self, cx: &mut App) -> Task<Result<acp_thread::AgentModelInfo>> {
fn selected_model(
&self,
session_id: &acp::SessionId,
cx: &mut App,
) -> Task<Result<acp_thread::AgentModelInfo>> {
let session_id = session_id.clone();
let Some(thread) = self
.connection
.0
.read(cx)
.sessions
.get(&self.session_id)
.get(&session_id)
.map(|session| session.thread.clone())
else {
return Task::ready(Err(anyhow!("Session not found")));
@@ -918,8 +822,8 @@ impl acp_thread::AgentModelSelector for NativeAgentModelSelector {
)))
}
fn watch(&self, cx: &mut App) -> Option<watch::Receiver<()>> {
Some(self.connection.0.read(cx).models.watch())
fn watch(&self, cx: &mut App) -> watch::Receiver<()> {
self.0.read(cx).models.watch()
}
}
@@ -931,11 +835,12 @@ impl acp_thread::AgentConnection for NativeAgentConnection {
cx: &mut App,
) -> Task<Result<Entity<acp_thread::AcpThread>>> {
let agent = self.0.clone();
log::debug!("Creating new thread for project at: {:?}", cwd);
log::info!("Creating new thread for project at: {:?}", cwd);
cx.spawn(async move |cx| {
log::debug!("Starting thread creation in async context");
let action_log = cx.new(|_cx| ActionLog::new(project.clone()))?;
// Create Thread
let thread = agent.update(
cx,
@@ -951,16 +856,20 @@ impl acp_thread::AgentConnection for NativeAgentConnection {
.models
.model_from_id(&LanguageModels::model_id(&default_model.model))
});
Ok(cx.new(|cx| {
let thread = cx.new(|cx| {
Thread::new(
project.clone(),
agent.project_context.clone(),
agent.context_server_registry.clone(),
action_log.clone(),
agent.templates.clone(),
default_model,
cx,
)
}))
});
Ok(thread)
},
)??;
agent.update(cx, |agent, cx| agent.register_session(thread, cx))
@@ -975,11 +884,8 @@ impl acp_thread::AgentConnection for NativeAgentConnection {
Task::ready(Ok(()))
}
fn model_selector(&self, session_id: &acp::SessionId) -> Option<Rc<dyn AgentModelSelector>> {
Some(Rc::new(NativeAgentModelSelector {
session_id: session_id.clone(),
connection: self.clone(),
}) as Rc<dyn AgentModelSelector>)
fn model_selector(&self) -> Option<Rc<dyn AgentModelSelector>> {
Some(Rc::new(self.clone()) as Rc<dyn AgentModelSelector>)
}
fn prompt(
@@ -999,7 +905,7 @@ impl acp_thread::AgentConnection for NativeAgentConnection {
.into_iter()
.map(Into::into)
.collect::<Vec<_>>();
log::debug!("Converted prompt to message: {} chars", content.len());
log::info!("Converted prompt to message: {} chars", content.len());
log::debug!("Message id: {:?}", id);
log::debug!("Message content: {:?}", content);
@@ -1007,10 +913,18 @@ impl acp_thread::AgentConnection for NativeAgentConnection {
})
}
fn prompt_capabilities(&self) -> acp::PromptCapabilities {
acp::PromptCapabilities {
image: true,
audio: false,
embedded_context: true,
}
}
fn resume(
&self,
session_id: &acp::SessionId,
_cx: &App,
_cx: &mut App,
) -> Option<Rc<dyn acp_thread::AgentSessionResume>> {
Some(Rc::new(NativeAgentSessionResume {
connection: self.clone(),
@@ -1027,14 +941,14 @@ impl acp_thread::AgentConnection for NativeAgentConnection {
});
}
fn truncate(
fn session_editor(
&self,
session_id: &agent_client_protocol::SessionId,
cx: &App,
) -> Option<Rc<dyn acp_thread::AgentSessionTruncate>> {
self.0.read_with(cx, |agent, _cx| {
cx: &mut App,
) -> Option<Rc<dyn acp_thread::AgentSessionEditor>> {
self.0.update(cx, |agent, _cx| {
agent.sessions.get(session_id).map(|session| {
Rc::new(NativeAgentSessionTruncate {
Rc::new(NativeAgentSessionEditor {
thread: session.thread.clone(),
acp_thread: session.acp_thread.clone(),
}) as _
@@ -1042,17 +956,6 @@ impl acp_thread::AgentConnection for NativeAgentConnection {
})
}
fn set_title(
&self,
session_id: &acp::SessionId,
_cx: &App,
) -> Option<Rc<dyn acp_thread::AgentSessionSetTitle>> {
Some(Rc::new(NativeAgentSessionSetTitle {
connection: self.clone(),
session_id: session_id.clone(),
}) as _)
}
fn telemetry(&self) -> Option<Rc<dyn acp_thread::AgentTelemetry>> {
Some(Rc::new(self.clone()) as Rc<dyn acp_thread::AgentTelemetry>)
}
@@ -1083,13 +986,13 @@ impl acp_thread::AgentTelemetry for NativeAgentConnection {
}
}
struct NativeAgentSessionTruncate {
struct NativeAgentSessionEditor {
thread: Entity<Thread>,
acp_thread: WeakEntity<AcpThread>,
}
impl acp_thread::AgentSessionTruncate for NativeAgentSessionTruncate {
fn run(&self, message_id: acp_thread::UserMessageId, cx: &mut App) -> Task<Result<()>> {
impl acp_thread::AgentSessionEditor for NativeAgentSessionEditor {
fn truncate(&self, message_id: acp_thread::UserMessageId, cx: &mut App) -> Task<Result<()>> {
match self.thread.update(cx, |thread, cx| {
thread.truncate(message_id.clone(), cx)?;
Ok(thread.latest_token_usage())
@@ -1121,95 +1024,21 @@ impl acp_thread::AgentSessionResume for NativeAgentSessionResume {
}
}
struct NativeAgentSessionSetTitle {
connection: NativeAgentConnection,
session_id: acp::SessionId,
}
impl acp_thread::AgentSessionSetTitle for NativeAgentSessionSetTitle {
fn run(&self, title: SharedString, cx: &mut App) -> Task<Result<()>> {
let Some(session) = self.connection.0.read(cx).sessions.get(&self.session_id) else {
return Task::ready(Err(anyhow!("session not found")));
};
let thread = session.thread.clone();
thread.update(cx, |thread, cx| thread.set_title(title, cx));
Task::ready(Ok(()))
}
}
pub struct AcpThreadEnvironment {
acp_thread: WeakEntity<AcpThread>,
}
impl ThreadEnvironment for AcpThreadEnvironment {
fn create_terminal(
&self,
command: String,
cwd: Option<PathBuf>,
output_byte_limit: Option<u64>,
cx: &mut AsyncApp,
) -> Task<Result<Rc<dyn TerminalHandle>>> {
let task = self.acp_thread.update(cx, |thread, cx| {
thread.create_terminal(command, vec![], vec![], cwd, output_byte_limit, cx)
});
let acp_thread = self.acp_thread.clone();
cx.spawn(async move |cx| {
let terminal = task?.await?;
let (drop_tx, drop_rx) = oneshot::channel();
let terminal_id = terminal.read_with(cx, |terminal, _cx| terminal.id().clone())?;
cx.spawn(async move |cx| {
drop_rx.await.ok();
acp_thread.update(cx, |thread, cx| thread.release_terminal(terminal_id, cx))
})
.detach();
let handle = AcpTerminalHandle {
terminal,
_drop_tx: Some(drop_tx),
};
Ok(Rc::new(handle) as _)
})
}
}
pub struct AcpTerminalHandle {
terminal: Entity<acp_thread::Terminal>,
_drop_tx: Option<oneshot::Sender<()>>,
}
impl TerminalHandle for AcpTerminalHandle {
fn id(&self, cx: &AsyncApp) -> Result<acp::TerminalId> {
self.terminal.read_with(cx, |term, _cx| term.id().clone())
}
fn wait_for_exit(&self, cx: &AsyncApp) -> Result<Shared<Task<acp::TerminalExitStatus>>> {
self.terminal
.read_with(cx, |term, _cx| term.wait_for_exit())
}
fn current_output(&self, cx: &AsyncApp) -> Result<acp::TerminalOutputResponse> {
self.terminal
.read_with(cx, |term, cx| term.current_output(cx))
}
}
#[cfg(test)]
mod tests {
use crate::HistoryEntryId;
use super::*;
use acp_thread::{AgentConnection, AgentModelGroupName, AgentModelInfo, MentionUri};
use acp_thread::{
AgentConnection, AgentModelGroupName, AgentModelId, AgentModelInfo, MentionUri,
};
use fs::FakeFs;
use gpui::TestAppContext;
use indoc::formatdoc;
use indoc::indoc;
use language_model::fake_provider::FakeLanguageModel;
use serde_json::json;
use settings::SettingsStore;
use util::{path, rel_path::rel_path};
use util::path;
#[gpui::test]
async fn test_maintaining_project_context(cx: &mut TestAppContext) {
@@ -1259,17 +1088,14 @@ mod tests {
fs.insert_file("/a/.rules", Vec::new()).await;
cx.run_until_parked();
agent.read_with(cx, |agent, cx| {
let rules_entry = worktree
.read(cx)
.entry_for_path(rel_path(".rules"))
.unwrap();
let rules_entry = worktree.read(cx).entry_for_path(".rules").unwrap();
assert_eq!(
agent.project_context.read(cx).worktrees,
vec![WorktreeContext {
root_name: "a".into(),
abs_path: Path::new("/a").into(),
rules_file: Some(RulesFileContext {
path_in_worktree: rel_path(".rules").into(),
path_in_worktree: Path::new(".rules").into(),
text: "".into(),
project_entry_id: rules_entry.id.to_usize()
})
@@ -1299,25 +1125,7 @@ mod tests {
.unwrap(),
);
// Create a thread/session
let acp_thread = cx
.update(|cx| {
Rc::new(connection.clone()).new_thread(project.clone(), Path::new("/a"), cx)
})
.await
.unwrap();
let session_id = cx.update(|cx| acp_thread.read(cx).session_id().clone());
let models = cx
.update(|cx| {
connection
.model_selector(&session_id)
.unwrap()
.list_models(cx)
})
.await
.unwrap();
let models = cx.update(|cx| connection.list_models(cx)).await.unwrap();
let acp_thread::AgentModelList::Grouped(models) = models else {
panic!("Unexpected model group");
@@ -1327,9 +1135,8 @@ mod tests {
IndexMap::from_iter([(
AgentModelGroupName("Fake".into()),
vec![AgentModelInfo {
id: acp::ModelId("fake/fake".into()),
id: AgentModelId("fake/fake".into()),
name: "Fake".into(),
description: None,
icon: Some(ui::IconName::ZedAssistant),
}]
)])
@@ -1386,9 +1193,8 @@ mod tests {
let session_id = cx.update(|cx| acp_thread.read(cx).session_id().clone());
// Select a model
let selector = connection.model_selector(&session_id).unwrap();
let model_id = acp::ModelId("fake/fake".into());
cx.update(|cx| selector.select_model(model_id.clone(), cx))
let model_id = AgentModelId("fake/fake".into());
cx.update(|cx| connection.select_model(session_id.clone(), model_id.clone(), cx))
.await
.unwrap();
@@ -1418,6 +1224,7 @@ mod tests {
}
#[gpui::test]
#[cfg_attr(target_os = "windows", ignore)] // TODO: Fix this test on Windows
async fn test_save_load_thread(cx: &mut TestAppContext) {
init_test(cx);
let fs = FakeFs::new(cx.executor());
@@ -1462,12 +1269,18 @@ mod tests {
let model = Arc::new(FakeLanguageModel::default());
let summary_model = Arc::new(FakeLanguageModel::default());
thread.update(cx, |thread, cx| {
thread.set_model(model.clone(), cx);
thread.set_summarization_model(Some(summary_model.clone()), cx);
thread.set_model(model, cx);
thread.set_summarization_model(Some(summary_model), cx);
});
cx.run_until_parked();
assert_eq!(history_entries(&history_store, cx), vec![]);
let model = thread.read_with(cx, |thread, _| thread.model().unwrap().clone());
let model = model.as_fake();
let summary_model = thread.read_with(cx, |thread, _| {
thread.summarization_model().unwrap().clone()
});
let summary_model = summary_model.as_fake();
let send = acp_thread.update(cx, |thread, cx| {
thread.send(
vec![
@@ -1484,7 +1297,6 @@ mod tests {
mime_type: None,
size: None,
title: None,
meta: None,
}),
" mean?".into(),
],
@@ -1497,22 +1309,17 @@ mod tests {
model.send_last_completion_stream_text_chunk("Lorem.");
model.end_last_completion_stream();
cx.run_until_parked();
summary_model
.send_last_completion_stream_text_chunk(&format!("Explaining {}", path!("/a/b.md")));
summary_model.send_last_completion_stream_text_chunk("Explaining /a/b.md");
summary_model.end_last_completion_stream();
send.await.unwrap();
let uri = MentionUri::File {
abs_path: path!("/a/b.md").into(),
}
.to_uri();
acp_thread.read_with(cx, |thread, cx| {
assert_eq!(
thread.to_markdown(cx),
formatdoc! {"
indoc! {"
## User
What does [@b.md]({uri}) mean?
What does [@b.md](file:///a/b.md) mean?
## Assistant
@@ -1522,8 +1329,6 @@ mod tests {
)
});
cx.run_until_parked();
// Drop the ACP thread, which should cause the session to be dropped as well.
cx.update(|_| {
drop(thread);
@@ -1538,7 +1343,7 @@ mod tests {
history_entries(&history_store, cx),
vec![(
HistoryEntryId::AcpThread(session_id.clone()),
format!("Explaining {}", path!("/a/b.md"))
"Explaining /a/b.md".into()
)]
);
let acp_thread = agent
@@ -1548,10 +1353,10 @@ mod tests {
acp_thread.read_with(cx, |thread, cx| {
assert_eq!(
thread.to_markdown(cx),
formatdoc! {"
indoc! {"
## User
What does [@b.md]({uri}) mean?
What does [@b.md](file:///a/b.md) mean?
## Assistant
@@ -1566,9 +1371,10 @@ mod tests {
history: &Entity<HistoryStore>,
cx: &mut TestAppContext,
) -> Vec<(HistoryEntryId, String)> {
history.read_with(cx, |history, _| {
history.read_with(cx, |history, cx| {
history
.entries()
.entries(cx)
.iter()
.map(|e| (e.id(), e.title().to_string()))
.collect::<Vec<_>>()
})

View File

@@ -18,7 +18,6 @@ use sqlez::{
};
use std::sync::Arc;
use ui::{App, SharedString};
use zed_env_vars::ZED_STATELESS;
pub type DbMessage = crate::Message;
pub type DbSummary = DetailedSummaryState;
@@ -202,6 +201,9 @@ impl DbThread {
}
}
pub static ZED_STATELESS: std::sync::LazyLock<bool> =
std::sync::LazyLock::new(|| std::env::var("ZED_STATELESS").is_ok_and(|v| !v.is_empty()));
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum DataType {
#[serde(rename = "json")]
@@ -264,19 +266,8 @@ impl ThreadsDatabase {
}
pub fn new(executor: BackgroundExecutor) -> Result<Self> {
let connection = if *ZED_STATELESS {
let connection = if *ZED_STATELESS || cfg!(any(feature = "test-support", test)) {
Connection::open_memory(Some("THREAD_FALLBACK_DB"))
} else if cfg!(any(feature = "test-support", test)) {
// rust stores the name of the test on the current thread.
// We use this to automatically create a database that will
// be shared within the test (for the test_retrieve_old_thread)
// but not with concurrent tests.
let thread = std::thread::current();
let test_name = thread.name();
Connection::open_memory(Some(&format!(
"THREAD_FALLBACK_{}",
test_name.unwrap_or_default()
)))
} else {
let threads_dir = paths::data_dir().join("threads");
std::fs::create_dir_all(&threads_dir)?;
@@ -422,7 +413,7 @@ mod tests {
use agent::MessageSegment;
use agent::context::LoadedContext;
use client::Client;
use fs::{FakeFs, Fs};
use fs::FakeFs;
use gpui::AppContext;
use gpui::TestAppContext;
use http_client::FakeHttpClient;
@@ -430,7 +421,7 @@ mod tests {
use project::Project;
use settings::SettingsStore;
fn init_test(fs: Arc<dyn Fs>, cx: &mut TestAppContext) {
fn init_test(cx: &mut TestAppContext) {
env_logger::try_init().ok();
cx.update(|cx| {
let settings_store = SettingsStore::test(cx);
@@ -441,7 +432,7 @@ mod tests {
let http_client = FakeHttpClient::with_404_response();
let clock = Arc::new(clock::FakeSystemClock::new());
let client = Client::new(clock, http_client, cx);
agent::init(fs, cx);
agent::init(cx);
agent_settings::init(cx);
language_model::init(client, cx);
});
@@ -449,8 +440,8 @@ mod tests {
#[gpui::test]
async fn test_retrieving_old_thread(cx: &mut TestAppContext) {
init_test(cx);
let fs = FakeFs::new(cx.executor());
init_test(fs.clone(), cx);
let project = Project::test(fs, [], cx).await;
// Save a thread using the old agent.

View File

@@ -10,7 +10,6 @@ use itertools::Itertools;
use paths::contexts_dir;
use serde::{Deserialize, Serialize};
use std::{collections::VecDeque, path::Path, sync::Arc, time::Duration};
use ui::ElementId;
use util::ResultExt as _;
const MAX_RECENTLY_OPENED_ENTRIES: usize = 6;
@@ -69,15 +68,6 @@ pub enum HistoryEntryId {
TextThread(Arc<Path>),
}
impl Into<ElementId> for HistoryEntryId {
fn into(self) -> ElementId {
match self {
HistoryEntryId::AcpThread(session_id) => ElementId::Name(session_id.0.into()),
HistoryEntryId::TextThread(path) => ElementId::Path(path),
}
}
}
#[derive(Serialize, Deserialize, Debug)]
enum SerializedRecentOpen {
AcpThread(String),
@@ -86,7 +76,6 @@ enum SerializedRecentOpen {
pub struct HistoryStore {
threads: Vec<DbThreadMetadata>,
entries: Vec<HistoryEntry>,
context_store: Entity<assistant_context::ContextStore>,
recently_opened_entries: VecDeque<HistoryEntryId>,
_subscriptions: Vec<gpui::Subscription>,
@@ -98,7 +87,7 @@ impl HistoryStore {
context_store: Entity<assistant_context::ContextStore>,
cx: &mut Context<Self>,
) -> Self {
let subscriptions = vec![cx.observe(&context_store, |this, _, cx| this.update_entries(cx))];
let subscriptions = vec![cx.observe(&context_store, |_, _, cx| cx.notify())];
cx.spawn(async move |this, cx| {
let entries = Self::load_recently_opened_entries(cx).await;
@@ -117,7 +106,6 @@ impl HistoryStore {
context_store,
recently_opened_entries: VecDeque::default(),
threads: Vec::default(),
entries: Vec::default(),
_subscriptions: subscriptions,
_save_recently_opened_entries_task: Task::ready(()),
}
@@ -183,18 +171,20 @@ impl HistoryStore {
}
}
this.threads = threads;
this.update_entries(cx);
cx.notify();
})
})
.detach_and_log_err(cx);
}
fn update_entries(&mut self, cx: &mut Context<Self>) {
pub fn entries(&self, cx: &App) -> Vec<HistoryEntry> {
let mut history_entries = Vec::new();
#[cfg(debug_assertions)]
if std::env::var("ZED_SIMULATE_NO_THREAD_HISTORY").is_ok() {
return;
return history_entries;
}
let mut history_entries = Vec::new();
history_entries.extend(self.threads.iter().cloned().map(HistoryEntry::AcpThread));
history_entries.extend(
self.context_store
@@ -205,12 +195,17 @@ impl HistoryStore {
);
history_entries.sort_unstable_by_key(|entry| std::cmp::Reverse(entry.updated_at()));
self.entries = history_entries;
cx.notify()
history_entries
}
pub fn is_empty(&self, _cx: &App) -> bool {
self.entries.is_empty()
pub fn is_empty(&self, cx: &App) -> bool {
self.threads.is_empty()
&& self
.context_store
.read(cx)
.unordered_contexts()
.next()
.is_none()
}
pub fn recently_opened_entries(&self, cx: &App) -> Vec<HistoryEntry> {
@@ -262,7 +257,7 @@ impl HistoryStore {
.iter()
.filter_map(|entry| match entry {
HistoryEntryId::TextThread(path) => path.file_name().map(|file| {
SerializedRecentOpen::TextThread(file.to_string_lossy().into_owned())
SerializedRecentOpen::TextThread(file.to_string_lossy().to_string())
}),
HistoryEntryId::AcpThread(id) => {
Some(SerializedRecentOpen::AcpThread(id.to_string()))
@@ -350,8 +345,4 @@ impl HistoryStore {
.retain(|old_entry| old_entry != entry);
self.save_recently_opened_entries(cx);
}
pub fn entries(&self) -> impl Iterator<Item = HistoryEntry> {
self.entries.iter().cloned()
}
}

View File

@@ -1,9 +1,10 @@
use std::{any::Any, path::Path, rc::Rc, sync::Arc};
use agent_servers::{AgentServer, AgentServerDelegate};
use agent_servers::AgentServer;
use anyhow::Result;
use fs::Fs;
use gpui::{App, Entity, SharedString, Task};
use gpui::{App, Entity, Task};
use project::Project;
use prompt_store::PromptStore;
use crate::{HistoryStore, NativeAgent, NativeAgentConnection, templates::Templates};
@@ -21,12 +22,16 @@ impl NativeAgentServer {
}
impl AgentServer for NativeAgentServer {
fn telemetry_id(&self) -> &'static str {
"zed"
fn name(&self) -> &'static str {
"Native Agent"
}
fn name(&self) -> SharedString {
"Zed Agent".into()
fn empty_state_headline(&self) -> &'static str {
""
}
fn empty_state_message(&self) -> &'static str {
""
}
fn logo(&self) -> ui::IconName {
@@ -35,20 +40,15 @@ impl AgentServer for NativeAgentServer {
fn connect(
&self,
_root_dir: Option<&Path>,
delegate: AgentServerDelegate,
_root_dir: &Path,
project: &Entity<Project>,
cx: &mut App,
) -> Task<
Result<(
Rc<dyn acp_thread::AgentConnection>,
Option<task::SpawnInTerminal>,
)>,
> {
log::debug!(
) -> Task<Result<Rc<dyn acp_thread::AgentConnection>>> {
log::info!(
"NativeAgentServer::connect called for path: {:?}",
_root_dir
);
let project = delegate.project().clone();
let project = project.clone();
let fs = self.fs.clone();
let history = self.history.clone();
let prompt_store = PromptStore::global(cx);
@@ -63,12 +63,9 @@ impl AgentServer for NativeAgentServer {
// Create the connection wrapper
let connection = NativeAgentConnection(agent);
log::debug!("NativeAgentServer connection established successfully");
log::info!("NativeAgentServer connection established successfully");
Ok((
Rc::new(connection) as Rc<dyn acp_thread::AgentConnection>,
None,
))
Ok(Rc::new(connection) as Rc<dyn acp_thread::AgentConnection>)
})
}
@@ -76,52 +73,3 @@ impl AgentServer for NativeAgentServer {
self
}
}
#[cfg(test)]
mod tests {
use super::*;
use assistant_context::ContextStore;
use gpui::AppContext;
agent_servers::e2e_tests::common_e2e_tests!(
async |fs, project, cx| {
let auth = cx.update(|cx| {
prompt_store::init(cx);
terminal::init(cx);
let registry = language_model::LanguageModelRegistry::read_global(cx);
let auth = registry
.provider(&language_model::ANTHROPIC_PROVIDER_ID)
.unwrap()
.authenticate(cx);
cx.spawn(async move |_| auth.await)
});
auth.await.unwrap();
cx.update(|cx| {
let registry = language_model::LanguageModelRegistry::global(cx);
registry.update(cx, |registry, cx| {
registry.select_default_model(
Some(&language_model::SelectedModel {
provider: language_model::ANTHROPIC_PROVIDER_ID,
model: language_model::LanguageModelId("claude-sonnet-4-latest".into()),
}),
cx,
);
});
});
let history = cx.update(|cx| {
let context_store = cx.new(move |cx| ContextStore::fake(project.clone(), cx));
cx.new(move |cx| HistoryStore::new(context_store, cx))
});
NativeAgentServer::new(fs.clone(), history)
},
allow_option_id = "allow"
);
}

View File

@@ -48,15 +48,16 @@ The one exception to this is if the user references something you don't know abo
## Code Block Formatting
Whenever you mention a code block, you MUST use ONLY use the following format:
```path/to/Something.blah#L123-456
(code goes here)
```
The `#L123-456` means the line number range 123 through 456, and the path/to/Something.blah is a path in the project. (If there is no valid path in the project, then you can use /dev/null/path.extension for its path.) This is the ONLY valid way to format code blocks, because the Markdown parser does not understand the more common ```language syntax, or bare ``` blocks. It only understands this path-based syntax, and if the path is missing, then it will error and you will have to do it over again.
The `#L123-456` means the line number range 123 through 456, and the path/to/Something.blah
is a path in the project. (If there is no valid path in the project, then you can use
/dev/null/path.extension for its path.) This is the ONLY valid way to format code blocks, because the Markdown parser
does not understand the more common ```language syntax, or bare ``` blocks. It only
understands this path-based syntax, and if the path is missing, then it will error and you will have to do it over again.
Just to be really clear about this, if you ever find yourself writing three backticks followed by a language name, STOP!
You have made a mistake. You can only ever put paths after triple backticks!
<example>
Based on all the information I've gathered, here's a summary of how this system works:
1. The README file is loaded into the system.
@@ -73,7 +74,6 @@ This is the last header in the README.
```
4. Finally, it passes this information on to the next process.
</example>
<example>
In Markdown, hash marks signify headings. For example:
```/dev/null/example.md#L1-3
@@ -82,7 +82,6 @@ In Markdown, hash marks signify headings. For example:
### Level 3 heading
```
</example>
Here are examples of ways you must never render code blocks:
<bad_example_do_not_do_this>
In Markdown, hash marks signify headings. For example:
@@ -92,9 +91,7 @@ In Markdown, hash marks signify headings. For example:
### Level 3 heading
```
</bad_example_do_not_do_this>
This example is unacceptable because it does not include the path.
<bad_example_do_not_do_this>
In Markdown, hash marks signify headings. For example:
```markdown
@@ -104,15 +101,14 @@ In Markdown, hash marks signify headings. For example:
```
</bad_example_do_not_do_this>
This example is unacceptable because it has the language instead of the path.
<bad_example_do_not_do_this>
In Markdown, hash marks signify headings. For example:
# Level 1 heading
## Level 2 heading
### Level 3 heading
</bad_example_do_not_do_this>
This example is unacceptable because it uses indentation to mark the code block instead of backticks with a path.
This example is unacceptable because it uses indentation to mark the code block
instead of backticks with a path.
<bad_example_do_not_do_this>
In Markdown, hash marks signify headings. For example:
```markdown

File diff suppressed because it is too large Load Diff

View File

@@ -16,19 +16,15 @@ impl AgentTool for EchoTool {
type Input = EchoToolInput;
type Output = String;
fn name() -> &'static str {
"echo"
fn name(&self) -> SharedString {
"echo".into()
}
fn kind() -> acp::ToolKind {
fn kind(&self) -> acp::ToolKind {
acp::ToolKind::Other
}
fn initial_title(
&self,
_input: Result<Self::Input, serde_json::Value>,
_cx: &mut App,
) -> SharedString {
fn initial_title(&self, _input: Result<Self::Input, serde_json::Value>) -> SharedString {
"Echo".into()
}
@@ -55,15 +51,11 @@ impl AgentTool for DelayTool {
type Input = DelayToolInput;
type Output = String;
fn name() -> &'static str {
"delay"
fn name(&self) -> SharedString {
"delay".into()
}
fn initial_title(
&self,
input: Result<Self::Input, serde_json::Value>,
_cx: &mut App,
) -> SharedString {
fn initial_title(&self, input: Result<Self::Input, serde_json::Value>) -> SharedString {
if let Ok(input) = input {
format!("Delay {}ms", input.ms).into()
} else {
@@ -71,7 +63,7 @@ impl AgentTool for DelayTool {
}
}
fn kind() -> acp::ToolKind {
fn kind(&self) -> acp::ToolKind {
acp::ToolKind::Other
}
@@ -100,19 +92,15 @@ impl AgentTool for ToolRequiringPermission {
type Input = ToolRequiringPermissionInput;
type Output = String;
fn name() -> &'static str {
"tool_requiring_permission"
fn name(&self) -> SharedString {
"tool_requiring_permission".into()
}
fn kind() -> acp::ToolKind {
fn kind(&self) -> acp::ToolKind {
acp::ToolKind::Other
}
fn initial_title(
&self,
_input: Result<Self::Input, serde_json::Value>,
_cx: &mut App,
) -> SharedString {
fn initial_title(&self, _input: Result<Self::Input, serde_json::Value>) -> SharedString {
"This tool requires permission".into()
}
@@ -139,19 +127,15 @@ impl AgentTool for InfiniteTool {
type Input = InfiniteToolInput;
type Output = String;
fn name() -> &'static str {
"infinite"
fn name(&self) -> SharedString {
"infinite".into()
}
fn kind() -> acp::ToolKind {
fn kind(&self) -> acp::ToolKind {
acp::ToolKind::Other
}
fn initial_title(
&self,
_input: Result<Self::Input, serde_json::Value>,
_cx: &mut App,
) -> SharedString {
fn initial_title(&self, _input: Result<Self::Input, serde_json::Value>) -> SharedString {
"Infinite Tool".into()
}
@@ -194,19 +178,15 @@ impl AgentTool for WordListTool {
type Input = WordListInput;
type Output = String;
fn name() -> &'static str {
"word_list"
fn name(&self) -> SharedString {
"word_list".into()
}
fn kind() -> acp::ToolKind {
fn kind(&self) -> acp::ToolKind {
acp::ToolKind::Other
}
fn initial_title(
&self,
_input: Result<Self::Input, serde_json::Value>,
_cx: &mut App,
) -> SharedString {
fn initial_title(&self, _input: Result<Self::Input, serde_json::Value>) -> SharedString {
"List of random words".into()
}

File diff suppressed because it is too large Load Diff

View File

@@ -16,29 +16,6 @@ mod terminal_tool;
mod thinking_tool;
mod web_search_tool;
/// A list of all built in tool names, for use in deduplicating MCP tool names
pub fn default_tool_names() -> impl Iterator<Item = &'static str> {
[
CopyPathTool::name(),
CreateDirectoryTool::name(),
DeletePathTool::name(),
DiagnosticsTool::name(),
EditFileTool::name(),
FetchTool::name(),
FindPathTool::name(),
GrepTool::name(),
ListDirectoryTool::name(),
MovePathTool::name(),
NowTool::name(),
OpenTool::name(),
ReadFileTool::name(),
TerminalTool::name(),
ThinkingTool::name(),
WebSearchTool::name(),
]
.into_iter()
}
pub use context_server_registry::*;
pub use copy_path_tool::*;
pub use create_directory_tool::*;
@@ -56,5 +33,3 @@ pub use read_file_tool::*;
pub use terminal_tool::*;
pub use thinking_tool::*;
pub use web_search_tool::*;
use crate::AgentTool;

View File

@@ -145,7 +145,7 @@ impl AnyAgentTool for ContextServerTool {
ToolKind::Other
}
fn initial_title(&self, _input: serde_json::Value, _cx: &mut App) -> SharedString {
fn initial_title(&self, _input: serde_json::Value) -> SharedString {
format!("Run MCP tool `{}`", self.tool.name).into()
}
@@ -169,18 +169,15 @@ impl AnyAgentTool for ContextServerTool {
fn run(
self: Arc<Self>,
input: serde_json::Value,
event_stream: ToolCallEventStream,
_event_stream: ToolCallEventStream,
cx: &mut App,
) -> Task<Result<AgentToolOutput>> {
let Some(server) = self.store.read(cx).get_running_server(&self.server_id) else {
return Task::ready(Err(anyhow!("Context server not found")));
};
let tool_name = self.tool.name.clone();
let authorize = event_stream.authorize(self.initial_title(input.clone(), cx), cx);
cx.spawn(async move |_cx| {
authorize.await?;
let Some(protocol) = server.client() else {
bail!("Context server not initialized");
};

View File

@@ -1,7 +1,7 @@
use crate::{AgentTool, ToolCallEventStream};
use agent_client_protocol::ToolKind;
use anyhow::{Context as _, Result, anyhow};
use gpui::{App, AppContext, Entity, Task};
use gpui::{App, AppContext, Entity, SharedString, Task};
use project::Project;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
@@ -9,14 +9,14 @@ use std::sync::Arc;
use util::markdown::MarkdownInlineCode;
/// Copies a file or directory in the project, and returns confirmation that the copy succeeded.
/// Directory contents will be copied recursively.
/// Directory contents will be copied recursively (like `cp -r`).
///
/// This tool should be used when it's desirable to create a copy of a file or directory without modifying the original.
/// It's much more efficient than doing this by separately reading and then writing the file or directory's contents, so this tool should be preferred over that approach whenever copying is the goal.
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct CopyPathToolInput {
/// The source path of the file or directory to copy.
/// If a directory is specified, its contents will be copied recursively.
/// If a directory is specified, its contents will be copied recursively (like `cp -r`).
///
/// <example>
/// If the project has the following files:
@@ -50,19 +50,15 @@ impl AgentTool for CopyPathTool {
type Input = CopyPathToolInput;
type Output = String;
fn name() -> &'static str {
"copy_path"
fn name(&self) -> SharedString {
"copy_path".into()
}
fn kind() -> ToolKind {
fn kind(&self) -> ToolKind {
ToolKind::Move
}
fn initial_title(
&self,
input: Result<Self::Input, serde_json::Value>,
_cx: &mut App,
) -> ui::SharedString {
fn initial_title(&self, input: Result<Self::Input, serde_json::Value>) -> ui::SharedString {
if let Ok(input) = input {
let src = MarkdownInlineCode(&input.source_path);
let dest = MarkdownInlineCode(&input.destination_path);
@@ -84,7 +80,9 @@ impl AgentTool for CopyPathTool {
.and_then(|project_path| project.entry_for_path(&project_path, cx))
{
Some(entity) => match project.find_project_path(&input.destination_path, cx) {
Some(project_path) => project.copy_entry(entity.id, project_path, cx),
Some(project_path) => {
project.copy_entry(entity.id, None, project_path.path, cx)
}
None => Task::ready(Err(anyhow!(
"Destination path {} was outside the project.",
input.destination_path

View File

@@ -11,7 +11,7 @@ use crate::{AgentTool, ToolCallEventStream};
/// Creates a new directory at the specified path within the project. Returns confirmation that the directory was created.
///
/// This tool creates a directory and all necessary parent directories. It should be used whenever you need to create new directories within the project.
/// This tool creates a directory and all necessary parent directories (similar to `mkdir -p`). It should be used whenever you need to create new directories within the project.
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct CreateDirectoryToolInput {
/// The path of the new directory.
@@ -41,19 +41,15 @@ impl AgentTool for CreateDirectoryTool {
type Input = CreateDirectoryToolInput;
type Output = String;
fn name() -> &'static str {
"create_directory"
fn name(&self) -> SharedString {
"create_directory".into()
}
fn kind() -> ToolKind {
fn kind(&self) -> ToolKind {
ToolKind::Read
}
fn initial_title(
&self,
input: Result<Self::Input, serde_json::Value>,
_cx: &mut App,
) -> SharedString {
fn initial_title(&self, input: Result<Self::Input, serde_json::Value>) -> SharedString {
if let Ok(input) = input {
format!("Create directory {}", MarkdownInlineCode(&input.path)).into()
} else {

View File

@@ -44,19 +44,15 @@ impl AgentTool for DeletePathTool {
type Input = DeletePathToolInput;
type Output = String;
fn name() -> &'static str {
"delete_path"
fn name(&self) -> SharedString {
"delete_path".into()
}
fn kind() -> ToolKind {
fn kind(&self) -> ToolKind {
ToolKind::Delete
}
fn initial_title(
&self,
input: Result<Self::Input, serde_json::Value>,
_cx: &mut App,
) -> SharedString {
fn initial_title(&self, input: Result<Self::Input, serde_json::Value>) -> SharedString {
if let Ok(input) = input {
format!("Delete “`{}`”", input.path).into()
} else {

Some files were not shown because too many files have changed in this diff Show More