diff --git a/.cargo/ci-config.toml b/.cargo/ci-config.toml
deleted file mode 100644
index 664419837b3559..00000000000000
--- a/.cargo/ci-config.toml
+++ /dev/null
@@ -1,15 +0,0 @@
-# This config is different from config.toml in this directory, as the latter is recognized by Cargo.
-# This file is placed in $HOME/.cargo/config.toml on CI runs. Cargo then merges Zeds .cargo/config.toml with $HOME/.cargo/config.toml
-# with preference for settings from Zeds config.toml.
-# TL;DR: If a value is set in both ci-config.toml and config.toml, config.toml value takes precedence.
-# Arrays are merged together though. See: https://doc.rust-lang.org/cargo/reference/config.html#hierarchical-structure
-# The intent for this file is to configure CI build process with a divergance from Zed developers experience; for example, in this config file
-# we use `-D warnings` for rustflags (which makes compilation fail in presence of warnings during build process). Placing that in developers `config.toml`
-# would be incovenient.
-# We *could* override things like RUSTFLAGS manually by setting them as environment variables, but that is less DRY; worse yet, if you forget to set proper environment variables
-# in one spot, that's going to trigger a rebuild of all of the artifacts. Using ci-config.toml we can define these overrides for CI in one spot and not worry about it.
-[build]
-rustflags = ["-D", "warnings"]
-
-[alias]
-xtask = "run --package xtask --"
diff --git a/.cargo/collab-config.toml b/.cargo/collab-config.toml
new file mode 100644
index 00000000000000..74603802d8e5d6
--- /dev/null
+++ b/.cargo/collab-config.toml
@@ -0,0 +1,5 @@
+# This file is used to build collab in a Docker image.
+# In particular, we don't use clang.
+[build]
+# v0 mangling scheme provides more detailed backtraces around closures
+rustflags = ["-C", "symbol-mangling-version=v0", "--cfg", "tokio_unstable"]
diff --git a/.cargo/config.toml b/.cargo/config.toml
index d73dead142ffd7..39fabdb5b8519a 100644
--- a/.cargo/config.toml
+++ b/.cargo/config.toml
@@ -4,3 +4,11 @@ rustflags = ["-C", "symbol-mangling-version=v0", "--cfg", "tokio_unstable"]
[alias]
xtask = "run --package xtask --"
+
+[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"]
diff --git a/.dockerignore b/.dockerignore
index a6e6c35ee50fe0..337b4d42623c48 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,6 +1,13 @@
+.git
+.github
+**/.gitignore
+**/.gitkeep
+.gitattributes
+.mailmap
**/target
zed.xcworkspace
.DS_Store
+compose.yml
plugins/bin
script/node_modules
styles/node_modules
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
new file mode 100644
index 00000000000000..726accb0ae45f0
--- /dev/null
+++ b/.git-blame-ignore-revs
@@ -0,0 +1,28 @@
+# .git-blame-ignore-revs
+#
+# This file consists of a list of commits that should be ignored for
+# `git blame` purposes. This is useful for ignoring commits that only
+# changed whitespace / indentation / formatting, but did not change
+# the underlying syntax tree.
+#
+# GitHub will pick this up automatically for blame views:
+# https://docs.github.com/en/repositories/working-with-files/using-files/viewing-a-file#ignore-commits-in-the-blame-view
+# To use this file locally, run:
+# git blame --ignore-revs-file .git-blame-ignore-revs
+# To always use this file by default, run:
+# git config --local blame.ignoreRevsFile .git-blame-ignore-revs
+# To disable this functionality, run:
+# git config --local blame.ignoreRevsFile ""
+# Comments are optional, but may provide helpful context.
+
+# 2023-04-20 Set default tab_size for JSON to 2 and apply new formatting
+# https://github.com/zed-industries/zed/pull/2394
+eca93c124a488b4e538946cd2d313bd571aa2b86
+
+# 2024-02-25 Format JSON files in assets/
+# https://github.com/zed-industries/zed/pull/8405
+ffdda588b41f7d9d270ffe76cab116f828ad545e
+
+# 2024-07-05 Improved formatting of default keymaps (single line per bind)
+# https://github.com/zed-industries/zed/pull/13887
+813cc3f5e537372fc86720b5e71b6e1c815440ab
diff --git a/.github/ISSUE_TEMPLATE/0_feature_request.yml b/.github/ISSUE_TEMPLATE/0_feature_request.yml
index c5e1fa9237e147..d8dc7950f68643 100644
--- a/.github/ISSUE_TEMPLATE/0_feature_request.yml
+++ b/.github/ISSUE_TEMPLATE/0_feature_request.yml
@@ -2,23 +2,23 @@ name: Feature Request
description: "Tip: open this issue template from within Zed with the `request feature` command palette action"
labels: ["admin read", "triage", "enhancement"]
body:
- - type: checkboxes
- attributes:
- label: Check for existing issues
- description: Check the backlog of issues to reduce the chances of creating duplicates; if an issue already exists, place a `+1` (👍) on it.
- options:
- - label: Completed
- required: true
- - type: textarea
- attributes:
- label: Describe the feature
- description: A clear and concise description of what you want to happen.
- validations:
+ - type: checkboxes
+ attributes:
+ label: Check for existing issues
+ description: Check the backlog of issues to reduce the chances of creating duplicates; if an issue already exists, place a `+1` (👍) on it.
+ options:
+ - label: Completed
required: true
- - type: textarea
- attributes:
- label: |
- If applicable, add mockups / screenshots to help present your vision of the feature
- description: Drag images into the text input below
- validations:
- required: false
+ - type: textarea
+ attributes:
+ label: Describe the feature
+ description: A clear and concise description of what you want to happen.
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: |
+ If applicable, add mockups / screenshots to help present your vision of the feature
+ description: Drag images into the text input below
+ validations:
+ required: false
diff --git a/.github/ISSUE_TEMPLATE/1_bug_report.yml b/.github/ISSUE_TEMPLATE/1_bug_report.yml
index ccdd084533ae1d..a4c1e5aa6ee8c5 100644
--- a/.github/ISSUE_TEMPLATE/1_bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/1_bug_report.yml
@@ -1,40 +1,46 @@
name: Bug Report
description: |
- Use this template for **non-crash-related** bug reports.
- Tip: open this issue template from within Zed with the `file bug report` command palette action.
+ Use this template for **non-crash-related** bug reports.
+ Tip: open this issue template from within Zed with the `file bug report` command palette action.
labels: ["admin read", "triage", "defect"]
body:
- - type: checkboxes
- attributes:
- label: Check for existing issues
- description: Check the backlog of issues to reduce the chances of creating duplicates; if an issue already exists, place a `+1` (👍) on it.
- options:
- - label: Completed
- required: true
- - type: textarea
- attributes:
- label: Describe the bug / provide steps to reproduce it
- description: A clear and concise description of what the bug is.
- validations:
+ - type: checkboxes
+ attributes:
+ label: Check for existing issues
+ description: Check the backlog of issues to reduce the chances of creating duplicates; if an issue already exists, place a `+1` (👍) on it.
+ options:
+ - label: Completed
required: true
- - type: textarea
- id: environment
- attributes:
- label: Environment
- description: Run the `copy system specs into clipboard` command palette action and paste the output in the field below.
- validations:
- required: true
- - type: textarea
- attributes:
- label: If applicable, add mockups / screenshots to help explain present your vision of the feature
- description: Drag issues into the text input below
- validations:
- required: false
- - type: textarea
- attributes:
- label: If applicable, attach your `~/Library/Logs/Zed/Zed.log` file to this issue.
- description: |
- Drag Zed.log into the text input below.
- If you only need the most recent lines, you can run the `zed: open log` command palette action to see the last 1000.
- validations:
- required: false
+ - type: textarea
+ attributes:
+ label: Describe the bug / provide steps to reproduce it
+ description: A clear and concise description of what the bug is.
+ validations:
+ required: true
+ - type: textarea
+ id: environment
+ attributes:
+ label: Environment
+ description: Run the `copy system specs into clipboard` command palette action and paste the output in the field below.
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: If applicable, add mockups / screenshots to help explain present your vision of the feature
+ description: Drag issues into the text input below
+ validations:
+ required: false
+ - type: textarea
+ attributes:
+ label: If applicable, attach your Zed.log file to this issue.
+ description: |
+ macOS: `~/Library/Logs/Zed/Zed.log`
+ Linux: `~/.local/share/zed/logs/Zed.log` or $XDG_DATA_HOME
+ If you only need the most recent lines, you can run the `zed: open log` command palette action to see the last 1000.
+ value: |
+ Zed.log
+
+
+
+ validations:
+ required: false
diff --git a/.github/ISSUE_TEMPLATE/2_crash_report.yml b/.github/ISSUE_TEMPLATE/2_crash_report.yml
index c877ff1f4d4c9b..b170315d1cd497 100644
--- a/.github/ISSUE_TEMPLATE/2_crash_report.yml
+++ b/.github/ISSUE_TEMPLATE/2_crash_report.yml
@@ -1,33 +1,39 @@
name: Crash Report
description: |
- Use this template for crash reports.
+ Use this template for crash reports.
labels: ["admin read", "triage", "defect", "panic / crash"]
body:
- - type: checkboxes
- attributes:
- label: Check for existing issues
- description: Check the backlog of issues to reduce the chances of creating duplicates; if an issue already exists, place a `+1` (👍) on it.
- options:
- - label: Completed
- required: true
- - type: textarea
- attributes:
- label: Describe the bug / provide steps to reproduce it
- description: A clear and concise description of what the bug is.
- validations:
+ - type: checkboxes
+ attributes:
+ label: Check for existing issues
+ description: Check the backlog of issues to reduce the chances of creating duplicates; if an issue already exists, place a `+1` (👍) on it.
+ options:
+ - label: Completed
required: true
- - type: textarea
- id: environment
- attributes:
- label: Environment
- description: Run the `copy system specs into clipboard` command palette action and paste the output in the field below.
- validations:
- required: true
- - type: textarea
- attributes:
- label: If applicable, attach your `~/Library/Logs/Zed/Zed.log` file to this issue.
- description: |
- Drag Zed.log into the text input below.
- If you only need the most recent lines, you can run the `zed: open log` command palette action to see the last 1000.
- validations:
- required: false
+ - type: textarea
+ attributes:
+ label: Describe the bug / provide steps to reproduce it
+ description: A clear and concise description of what the bug is.
+ validations:
+ required: true
+ - type: textarea
+ id: environment
+ attributes:
+ label: Environment
+ description: Run the `copy system specs into clipboard` command palette action and paste the output in the field below.
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: If applicable, attach your `~/Library/Logs/Zed/Zed.log` file to this issue.
+ description: |
+ macOS: `~/Library/Logs/Zed/Zed.log`
+ Linux: `~/.local/share/zed/logs/Zed.log` or $XDG_DATA_HOME
+ If you only need the most recent lines, you can run the `zed: open log` command palette action to see the last 1000.
+ value: |
+ Zed.log
+
+
+
+ validations:
+ required: false
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index b4f6090ab258fa..ecfc7a9ab81e87 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -2,7 +2,7 @@
Release Notes:
-- Added/Fixed/Improved ... ([#](https://github.com/zed-industries/zed/issues/)).
+- Added/Fixed/Improved ... ([#NNNNN](https://github.com/zed-industries/zed/issues/NNNNN)).
Optionally, include screenshots / media showcasing your addition that can be included in the release notes.
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 35d764afb9044d..9c834ec25c1f46 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -23,6 +23,7 @@ env:
jobs:
style:
+ timeout-minutes: 60
name: Check formatting and spelling
runs-on:
- self-hosted
@@ -37,9 +38,6 @@ jobs:
- name: Remove untracked files
run: git clean -df
- - name: Set up default .cargo/config.toml
- run: cp ./.cargo/ci-config.toml ~/.cargo/config.toml
-
- name: Check spelling
run: |
if ! which typos > /dev/null; then
@@ -53,6 +51,9 @@ jobs:
- name: Check unused dependencies
uses: bnjbvr/cargo-machete@main
+ - name: Check licenses are present
+ run: script/check-licenses
+
- name: Check license generation
run: script/generate-licenses /tmp/zed_licenses_output
@@ -73,10 +74,11 @@ jobs:
version: v1.29.0
- uses: bufbuild/buf-breaking-action@v1
with:
- input: "crates/rpc/proto/"
- against: "https://github.com/${GITHUB_REPOSITORY}.git#branch=${BUF_BASE_BRANCH},subdir=crates/rpc/proto/"
+ input: "crates/proto/proto/"
+ against: "https://github.com/${GITHUB_REPOSITORY}.git#branch=${BUF_BASE_BRANCH},subdir=crates/proto/proto/"
macos_tests:
+ timeout-minutes: 60
name: (macOS) Run Clippy and tests
runs-on:
- self-hosted
@@ -88,7 +90,7 @@ jobs:
clean: false
- name: cargo clippy
- run: cargo xtask clippy
+ run: ./script/clippy
- name: Run tests
uses: ./.github/actions/run_tests
@@ -99,8 +101,8 @@ jobs:
- name: Build other binaries and features
run: cargo build --workspace --bins --all-features; cargo check -p gpui --features "macos-blade"
- # todo(linux): Actually run the tests
linux_tests:
+ timeout-minutes: 60
name: (Linux) Run Clippy and tests
runs-on:
- self-hosted
@@ -115,13 +117,17 @@ jobs:
clean: false
- name: cargo clippy
- run: cargo xtask clippy
+ run: ./script/clippy
+
+ - name: Run tests
+ uses: ./.github/actions/run_tests
- name: Build Zed
run: cargo build -p zed
# todo(windows): Actually run the tests
windows_tests:
+ timeout-minutes: 60
name: (Windows) Run Clippy and tests
runs-on: hosted-windows-1
steps:
@@ -136,12 +142,13 @@ jobs:
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: cargo clippy
- run: cargo xtask clippy
+ run: ./script/clippy
- name: Build Zed
run: cargo build -p zed
bundle-mac:
+ timeout-minutes: 60
name: Create a macOS bundle
runs-on:
- self-hosted
@@ -247,11 +254,12 @@ jobs:
target/aarch64-apple-darwin/release/Zed-aarch64.dmg
target/x86_64-apple-darwin/release/Zed-x86_64.dmg
target/release/Zed.dmg
- body_file: target/release-notes.md
+ body_path: target/release-notes.md
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
bundle-linux:
+ timeout-minutes: 60
name: Create a Linux bundle
runs-on:
- self-hosted
@@ -299,10 +307,7 @@ jobs:
exit 1
fi
- - name: Generate license file
- run: script/generate-licenses
-
- - name: Create and upload Linux .tar.gz bundle
+ - name: Create Linux .tar.gz bundle
run: script/bundle-linux
- name: Upload Linux bundle to workflow run if main branch or specific label
@@ -310,11 +315,10 @@ jobs:
if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
with:
name: zed-${{ github.event.pull_request.head.sha || github.sha }}-x86_64-unknown-linux-gnu.tar.gz
- path: zed-*.tar.gz
+ path: target/release/zed-*.tar.gz
- name: Upload app bundle to release
uses: softprops/action-gh-release@v1
- if: ${{ env.RELEASE_CHANNEL == 'preview' }}
with:
draft: true
prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}
@@ -322,3 +326,86 @@ jobs:
body: ""
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ bundle-linux-aarch64:
+ timeout-minutes: 60
+ name: Create arm64 Linux bundle
+ runs-on:
+ - hosted-linux-arm-1
+ if: ${{ startsWith(github.ref, 'refs/tags/v') || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
+ needs: [linux_tests]
+ env:
+ ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
+ steps:
+ - name: Checkout repo
+ uses: actions/checkout@v4
+ with:
+ clean: false
+ - name: "Setup jq"
+ uses: dcarbone/install-jq-action@v2
+
+ - name: Set up Clang
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y llvm-10 clang-10 build-essential cmake pkg-config libasound2-dev libfontconfig-dev libwayland-dev libxkbcommon-x11-dev libssl-dev libsqlite3-dev libzstd-dev libvulkan1 libgit2-dev
+ echo "/usr/lib/llvm-10/bin" >> $GITHUB_PATH
+
+ - uses: rui314/setup-mold@v1
+ with:
+ mold-version: 2.32.0
+
+ - name: rustup
+ run: |
+ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
+ echo "$HOME/.cargo/bin" >> $GITHUB_PATH
+
+ - name: Limit target directory size
+ run: script/clear-target-dir-if-larger-than 100
+
+ - name: Determine version and release channel
+ if: ${{ startsWith(github.ref, 'refs/tags/v') }}
+ run: |
+ set -eu
+
+ version=$(script/get-crate-version zed)
+ channel=$(cat crates/zed/RELEASE_CHANNEL)
+ echo "Publishing version: ${version} on release channel ${channel}"
+ echo "RELEASE_CHANNEL=${channel}" >> $GITHUB_ENV
+
+ expected_tag_name=""
+ case ${channel} in
+ stable)
+ expected_tag_name="v${version}";;
+ preview)
+ expected_tag_name="v${version}-pre";;
+ nightly)
+ expected_tag_name="v${version}-nightly";;
+ *)
+ echo "can't publish a release on channel ${channel}"
+ exit 1;;
+ esac
+ if [[ $GITHUB_REF_NAME != $expected_tag_name ]]; then
+ echo "invalid release tag ${GITHUB_REF_NAME}. expected ${expected_tag_name}"
+ exit 1
+ fi
+
+ - name: Create and upload Linux .tar.gz bundle
+ run: script/bundle-linux
+
+ - name: Upload Linux bundle to workflow run if main branch or specific label
+ uses: actions/upload-artifact@v4
+ if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
+ with:
+ name: zed-${{ github.event.pull_request.head.sha || github.sha }}-aarch64-unknown-linux-gnu.tar.gz
+ path: target/release/zed-*.tar.gz
+
+ - name: Upload app bundle to release
+ uses: softprops/action-gh-release@v1
+ if: ${{ env.RELEASE_CHANNEL == 'preview' || env.RELEASE_CHANNEL == 'stable' }}
+ with:
+ draft: true
+ prerelease: ${{ env.RELEASE_CHANNEL == 'preview' }}
+ files: target/release/zed-linux-aarch64.tar.gz
+ body: ""
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/danger.yml b/.github/workflows/danger.yml
index a6044dc4f464c3..b14358dbe790c0 100644
--- a/.github/workflows/danger.yml
+++ b/.github/workflows/danger.yml
@@ -18,7 +18,7 @@ jobs:
- uses: pnpm/action-setup@v3
with:
- version: 8
+ version: 9
- name: Setup Node
uses: actions/setup-node@v4
diff --git a/.github/workflows/deploy_collab.yml b/.github/workflows/deploy_collab.yml
index e6f741bcb16a4d..654532e2aecdd7 100644
--- a/.github/workflows/deploy_collab.yml
+++ b/.github/workflows/deploy_collab.yml
@@ -27,7 +27,7 @@ jobs:
uses: ./.github/actions/check_style
- name: Run clippy
- run: cargo xtask clippy
+ run: ./script/clippy
tests:
name: Run tests
@@ -75,6 +75,9 @@ jobs:
with:
clean: false
+ - name: Set up default .cargo/config.toml
+ run: cp ./.cargo/collab-config.toml ./.cargo/config.toml
+
- name: Build docker image
run: docker build . --build-arg GITHUB_SHA=$GITHUB_SHA --tag registry.digitalocean.com/zed/collab:$GITHUB_SHA
diff --git a/.github/workflows/release_nightly.yml b/.github/workflows/release_nightly.yml
index cd31885ca0db8c..33827b574cb974 100644
--- a/.github/workflows/release_nightly.yml
+++ b/.github/workflows/release_nightly.yml
@@ -15,6 +15,7 @@ env:
jobs:
style:
+ timeout-minutes: 60
name: Check formatting and Clippy lints
if: github.repository_owner == 'zed-industries'
runs-on:
@@ -31,8 +32,9 @@ jobs:
uses: ./.github/actions/check_style
- name: Run clippy
- run: cargo xtask clippy
+ run: ./script/clippy
tests:
+ timeout-minutes: 60
name: Run tests
if: github.repository_owner == 'zed-industries'
runs-on:
@@ -49,6 +51,7 @@ jobs:
uses: ./.github/actions/run_tests
bundle-mac:
+ timeout-minutes: 60
name: Create a macOS bundle
if: github.repository_owner == 'zed-industries'
runs-on:
@@ -90,8 +93,9 @@ jobs:
- name: Upload Zed Nightly
run: script/upload-nightly macos
- bundle-deb:
- name: Create a Linux *.tar.gz bundle
+ bundle-linux-x86:
+ timeout-minutes: 60
+ name: Create a Linux *.tar.gz bundle for x86
if: github.repository_owner == 'zed-industries'
runs-on:
- self-hosted
@@ -117,8 +121,57 @@ jobs:
echo "Publishing version: ${version} on release channel nightly"
echo "nightly" > crates/zed/RELEASE_CHANNEL
- - name: Generate license file
- run: script/generate-licenses
+ - name: Create Linux .tar.gz bundle
+ run: script/bundle-linux
+
+ - name: Upload Zed Nightly
+ run: script/upload-nightly linux-targz
+
+ bundle-linux-arm:
+ timeout-minutes: 60
+ name: Create a Linux *.tar.gz bundle for ARM
+ if: github.repository_owner == 'zed-industries'
+ runs-on:
+ - self-hosted
+ - hosted-linux-arm-1
+ needs: tests
+ env:
+ DIGITALOCEAN_SPACES_ACCESS_KEY: ${{ secrets.DIGITALOCEAN_SPACES_ACCESS_KEY }}
+ DIGITALOCEAN_SPACES_SECRET_KEY: ${{ secrets.DIGITALOCEAN_SPACES_SECRET_KEY }}
+ ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
+ steps:
+ - name: Checkout repo
+ uses: actions/checkout@v4
+ with:
+ clean: false
+
+ - name: "Setup jq"
+ uses: dcarbone/install-jq-action@v2
+
+ - name: Set up Clang
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y llvm-10 clang-10 build-essential cmake pkg-config libasound2-dev libfontconfig-dev libwayland-dev libxkbcommon-x11-dev libssl-dev libsqlite3-dev libzstd-dev libvulkan1 libgit2-dev
+ echo "/usr/lib/llvm-10/bin" >> $GITHUB_PATH
+
+ - uses: rui314/setup-mold@v1
+ with:
+ mold-version: 2.32.0
+
+ - name: rustup
+ run: |
+ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
+ echo "$HOME/.cargo/bin" >> $GITHUB_PATH
+
+ - name: Limit target directory size
+ run: script/clear-target-dir-if-larger-than 100
+
+ - name: Set release channel to nightly
+ run: |
+ set -euo pipefail
+ version=$(git rev-parse --short HEAD)
+ echo "Publishing version: ${version} on release channel nightly"
+ echo "nightly" > crates/zed/RELEASE_CHANNEL
- name: Create Linux .tar.gz bundle
run: script/bundle-linux
diff --git a/.gitignore b/.gitignore
index 48e329d820b334..de15d0abc360e9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+/.direnv
.idea
**/target
**/cargo-target
@@ -7,6 +8,8 @@
/script/node_modules
/crates/theme/schemas/theme.json
/crates/collab/seed.json
+/crates/zed/resources/flatpak/flatpak-cargo-sources.json
+/dev.zed.Zed*.json
/assets/*licenses.md
**/venv
.build
@@ -25,3 +28,4 @@ DerivedData/
.blob_store
.vscode
.wrangler
+.flatpak-builder
diff --git a/.mailmap b/.mailmap
index ef4cd1c4c2ff2d..ee29b0f328675c 100644
--- a/.mailmap
+++ b/.mailmap
@@ -7,14 +7,24 @@
# Reference: https://git-scm.com/docs/gitmailmap
# Keep these entries sorted alphabetically.
-# In Zed: `editor: sort lines case sensitive`
+# In Zed: `editor: sort lines case insensitive`
+Alex Viscreanu
+Alex Viscreanu
+amtoaer
+amtoaer
Antonio Scandurra
Antonio Scandurra
+Bennet Bo Fenner
+Bennet Bo Fenner <53836821+bennetbo@users.noreply.github.com>
+Bennet Bo Fenner
Christian Bergschneider
Christian Bergschneider
Conrad Irwin
Conrad Irwin
+Danilo Leal
+Danilo Leal <67129314+danilo-leal@users.noreply.github.com>
+Evren Sen <146845123+evrsen@users.noreply.github.com>
Fernando Tagawa
Fernando Tagawa
Greg Morenz
@@ -48,12 +58,27 @@ Nate Butler
Nathan Sobo
Nathan Sobo
Nathan Sobo
+Nigel Jose
+Nigel Jose
+Peter Tripp
+Peter Tripp
Petros Amoiridis
Petros Amoiridis
Piotr Osiewicz
Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com>
+Pocæus
+Pocæus
+Rashid Almheiri
+Rashid Almheiri <69181766+huwaireb@users.noreply.github.com>
+Richard Feldman
+Richard Feldman
Robert Clover
Robert Clover
+Sergey Onufrienko
Thorsten Ball
Thorsten Ball
Thorsten Ball
+Vitaly Slobodin
+Vitaly Slobodin
+WindSoilder
+张小白 <364772080@qq.com>
diff --git a/.zed/settings.json b/.zed/settings.json
index eedf2f37534ca8..e966ceb5d60927 100644
--- a/.zed/settings.json
+++ b/.zed/settings.json
@@ -14,11 +14,24 @@
},
"JSON": {
"tab_size": 2,
+ "preferred_line_length": 100,
+ "formatter": "prettier"
+ },
+ "JSONC": {
+ "tab_size": 2,
+ "preferred_line_length": 100,
"formatter": "prettier"
},
"JavaScript": {
"tab_size": 2,
"formatter": "prettier"
+ },
+ "Rust": {
+ "tasks": {
+ "variables": {
+ "RUST_DEFAULT_PACKAGE_RUN": "zed"
+ }
+ }
}
},
"formatter": "auto",
diff --git a/.zed/tasks.json b/.zed/tasks.json
index 80465969e2b3b1..259ab07f3e0656 100644
--- a/.zed/tasks.json
+++ b/.zed/tasks.json
@@ -1,7 +1,7 @@
[
{
"label": "clippy",
- "command": "cargo",
- "args": ["xtask", "clippy"]
+ "command": "./script/clippy",
+ "args": []
}
]
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index b9719e90faf108..85e3aec944a717 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -41,7 +41,7 @@ We plan to set aside time each week to pair program with contributors on promisi
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**
+- [`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.**
- [`editor`](/crates/editor) contains the core `Editor` type that drives both the code editor and all various input fields within Zed. It also handles a display layer for LSP features such as Inlay Hints or code completions.
- [`project`](/crates/project) manages files and navigation within the filetree. It is also Zed's side of communication with LSP.
- [`workspace`](/crates/workspace) handles local state serialization and groups projects together.
diff --git a/Cargo.toml b/Cargo.toml
index 92cddee4b94383..2a409cc6558a03 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,7 +4,6 @@ members = [
"crates/anthropic",
"crates/assets",
"crates/assistant",
- "crates/assistant2",
"crates/assistant_slash_command",
"crates/assistant_tooling",
"crates/audio",
@@ -22,6 +21,7 @@ members = [
"crates/command_palette_hooks",
"crates/copilot",
"crates/db",
+ "crates/dev_server_projects",
"crates/diagnostics",
"crates/editor",
"crates/extension",
@@ -42,8 +42,10 @@ members = [
"crates/gpui",
"crates/gpui_macros",
"crates/headless",
+ "crates/html_to_markdown",
"crates/http",
"crates/image_viewer",
+ "crates/indexed_docs",
"crates/inline_completion_button",
"crates/install_cli",
"crates/journal",
@@ -60,48 +62,55 @@ members = [
"crates/menu",
"crates/multi_buffer",
"crates/node_runtime",
+ "crates/notebook",
"crates/notifications",
+ "crates/ollama",
"crates/open_ai",
"crates/outline",
+ "crates/outline_panel",
+ "crates/paths",
"crates/picker",
"crates/prettier",
"crates/project",
"crates/project_panel",
"crates/project_symbols",
+ "crates/proto",
"crates/quick_action_bar",
"crates/recent_projects",
"crates/refineable",
"crates/refineable/derive_refineable",
"crates/release_channel",
- "crates/dev_server_projects",
+ "crates/repl",
"crates/rich_text",
"crates/rope",
"crates/rpc",
- "crates/task",
- "crates/tasks_ui",
"crates/search",
"crates/semantic_index",
"crates/semantic_version",
"crates/settings",
"crates/snippet",
+ "crates/snippet_provider",
"crates/sqlez",
"crates/sqlez_macros",
"crates/story",
"crates/storybook",
"crates/sum_tree",
- "crates/tab_switcher",
"crates/supermaven",
"crates/supermaven_api",
+ "crates/tab_switcher",
+ "crates/task",
+ "crates/tasks_ui",
+ "crates/telemetry_events",
"crates/terminal",
"crates/terminal_view",
"crates/text",
"crates/theme",
"crates/theme_importer",
"crates/theme_selector",
- "crates/telemetry_events",
"crates/time_format",
+ "crates/title_bar",
"crates/ui",
- "crates/ui_text_field",
+ "crates/ui_input",
"crates/util",
"crates/vcs_menu",
"crates/vim",
@@ -130,8 +139,10 @@ members = [
"extensions/prisma",
"extensions/purescript",
"extensions/ruby",
+ "extensions/snippets",
"extensions/svelte",
"extensions/terraform",
+ "extensions/test-extension",
"extensions/toml",
"extensions/uiua",
"extensions/vue",
@@ -148,12 +159,10 @@ ai = { path = "crates/ai" }
anthropic = { path = "crates/anthropic" }
assets = { path = "crates/assets" }
assistant = { path = "crates/assistant" }
-assistant2 = { path = "crates/assistant2" }
assistant_slash_command = { path = "crates/assistant_slash_command" }
assistant_tooling = { path = "crates/assistant_tooling" }
audio = { path = "crates/audio" }
auto_update = { path = "crates/auto_update" }
-base64 = "0.13"
breadcrumbs = { path = "crates/breadcrumbs" }
call = { path = "crates/call" }
channel = { path = "crates/channel" }
@@ -163,11 +172,11 @@ clock = { path = "crates/clock" }
collab = { path = "crates/collab" }
collab_ui = { path = "crates/collab_ui" }
collections = { path = "crates/collections" }
-color = { path = "crates/color" }
command_palette = { path = "crates/command_palette" }
command_palette_hooks = { path = "crates/command_palette_hooks" }
copilot = { path = "crates/copilot" }
db = { path = "crates/db" }
+dev_server_projects = { path = "crates/dev_server_projects" }
diagnostics = { path = "crates/diagnostics" }
editor = { path = "crates/editor" }
extension = { path = "crates/extension" }
@@ -186,11 +195,14 @@ google_ai = { path = "crates/google_ai" }
gpui = { path = "crates/gpui" }
gpui_macros = { path = "crates/gpui_macros" }
headless = { path = "crates/headless" }
+html_to_markdown = { path = "crates/html_to_markdown" }
http = { path = "crates/http" }
-install_cli = { path = "crates/install_cli" }
image_viewer = { path = "crates/image_viewer" }
+indexed_docs = { path = "crates/indexed_docs" }
inline_completion_button = { path = "crates/inline_completion_button" }
+install_cli = { path = "crates/install_cli" }
journal = { path = "crates/journal" }
+notebook = { path = "crates/notebook" }
language = { path = "crates/language" }
language_selector = { path = "crates/language_selector" }
language_tools = { path = "crates/language_tools" }
@@ -205,77 +217,91 @@ menu = { path = "crates/menu" }
multi_buffer = { path = "crates/multi_buffer" }
node_runtime = { path = "crates/node_runtime" }
notifications = { path = "crates/notifications" }
+ollama = { path = "crates/ollama" }
open_ai = { path = "crates/open_ai" }
outline = { path = "crates/outline" }
+outline_panel = { path = "crates/outline_panel" }
+paths = { path = "crates/paths" }
picker = { path = "crates/picker" }
plugin = { path = "crates/plugin" }
plugin_macros = { path = "crates/plugin_macros" }
prettier = { path = "crates/prettier" }
project = { path = "crates/project" }
-worktree = { path = "crates/worktree" }
project_panel = { path = "crates/project_panel" }
project_symbols = { path = "crates/project_symbols" }
+proto = { path = "crates/proto" }
quick_action_bar = { path = "crates/quick_action_bar" }
recent_projects = { path = "crates/recent_projects" }
release_channel = { path = "crates/release_channel" }
-dev_server_projects = { path = "crates/dev_server_projects" }
+repl = { path = "crates/repl" }
rich_text = { path = "crates/rich_text" }
rope = { path = "crates/rope" }
rpc = { path = "crates/rpc" }
-task = { path = "crates/task" }
-tasks_ui = { path = "crates/tasks_ui" }
search = { path = "crates/search" }
semantic_index = { path = "crates/semantic_index" }
semantic_version = { path = "crates/semantic_version" }
settings = { path = "crates/settings" }
snippet = { path = "crates/snippet" }
+snippet_provider = { path = "crates/snippet_provider" }
sqlez = { path = "crates/sqlez" }
sqlez_macros = { path = "crates/sqlez_macros" }
-supermaven = { path = "crates/supermaven" }
-supermaven_api = { path = "crates/supermaven_api" }
story = { path = "crates/story" }
storybook = { path = "crates/storybook" }
sum_tree = { path = "crates/sum_tree" }
+supermaven = { path = "crates/supermaven" }
+supermaven_api = { path = "crates/supermaven_api" }
tab_switcher = { path = "crates/tab_switcher" }
+task = { path = "crates/task" }
+tasks_ui = { path = "crates/tasks_ui" }
+telemetry_events = { path = "crates/telemetry_events" }
terminal = { path = "crates/terminal" }
terminal_view = { path = "crates/terminal_view" }
text = { path = "crates/text" }
theme = { path = "crates/theme" }
theme_importer = { path = "crates/theme_importer" }
theme_selector = { path = "crates/theme_selector" }
-telemetry_events = { path = "crates/telemetry_events" }
time_format = { path = "crates/time_format" }
+title_bar = { path = "crates/title_bar" }
ui = { path = "crates/ui" }
-ui_text_field = { path = "crates/ui_text_field" }
+ui_input = { path = "crates/ui_input" }
util = { path = "crates/util" }
vcs_menu = { path = "crates/vcs_menu" }
vim = { path = "crates/vim" }
welcome = { path = "crates/welcome" }
workspace = { path = "crates/workspace" }
+worktree = { path = "crates/worktree" }
zed = { path = "crates/zed" }
zed_actions = { path = "crates/zed_actions" }
-anyhow = "1.0.57"
+alacritty_terminal = "0.23"
any_vec = "0.13"
+anyhow = "1.0.57"
+ashpd = "0.9.1"
async-compression = { version = "0.4", features = ["gzip", "futures-io"] }
+async-dispatcher = { version = "0.1" }
async-fs = "1.6"
async-recursion = "1.0.0"
async-tar = "0.4.2"
async-trait = "0.1"
+async-watch = "0.3.1"
async_zip = { version = "0.0.17", features = ["deflate", "deflate64"] }
-bitflags = "2.4.2"
-blade-graphics = { git = "https://github.com/kvark/blade", rev = "e35b2d41f221a48b75f7cf2e78a81e7ecb7a383c" }
-blade-macros = { git = "https://github.com/kvark/blade", rev = "e35b2d41f221a48b75f7cf2e78a81e7ecb7a383c" }
+base64 = "0.13"
+bitflags = "2.6.0"
+blade-graphics = { git = "https://github.com/zed-industries/blade", rev = "a477c2008db27db0b9f745715e119b3ee7ab7818" }
+blade-macros = { git = "https://github.com/zed-industries/blade", rev = "a477c2008db27db0b9f745715e119b3ee7ab7818" }
+blade-util = { git = "https://github.com/zed-industries/blade", rev = "a477c2008db27db0b9f745715e119b3ee7ab7818" }
cap-std = "3.0"
cargo_toml = "0.20"
chrono = { version = "0.4", features = ["serde"] }
clap = { version = "4.4", features = ["derive"] }
clickhouse = { version = "0.11.6" }
-ctor = "0.2.6"
-signal-hook = "0.3.17"
+cocoa = "0.25"
core-foundation = { version = "0.9.3" }
core-foundation-sys = "0.8.6"
+ctor = "0.2.6"
+dashmap = "5.5.3"
derive_more = "0.99.17"
+dirs = "4.0"
emojis = "0.6.1"
env_logger = "0.9"
exec = "0.3.1"
@@ -283,17 +309,17 @@ fork = "0.1.23"
futures = "0.3"
futures-batch = "0.6.1"
futures-lite = "1.13"
-git2 = { version = "0.18", default-features = false }
+git2 = { version = "0.19", default-features = false }
globset = "0.4"
-heed = { git = "https://github.com/meilisearch/heed", rev = "036ac23f73a021894974b9adc815bc95b3e0482a", features = [
- "read-txn-no-tls",
-] }
+heed = { version = "0.20.1", features = ["read-txn-no-tls"] }
hex = "0.4.3"
+html5ever = "0.27.0"
ignore = "0.4.22"
+image = "0.25.1"
+indexmap = { version = "1.6.2", features = ["serde"] }
indoc = "1"
# We explicitly disable http2 support in isahc.
isahc = { version = "1.7.2", default-features = false, features = [
- "static-curl",
"text-decoding",
] }
itertools = "0.11.0"
@@ -301,8 +327,10 @@ lazy_static = "1.4.0"
libc = "0.2"
linkify = "0.10.0"
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
+markup5ever_rcdom = "0.3.0"
nanoid = "0.4"
nix = "0.28"
+num-format = "0.4.4"
once_cell = "1.19.0"
ordered-float = "2.1.1"
palette = { version = "0.7.5", default-features = false, features = ["std"] }
@@ -319,6 +347,9 @@ rand = "0.8.5"
refineable = { path = "./crates/refineable" }
regex = "1.5"
repair_json = "0.1.0"
+runtimelib = { version = "0.12", default-features = false, features = [
+ "async-dispatcher-runtime",
+] }
rusqlite = { version = "0.29.0", features = ["blob", "array", "modern_sqlite"] }
rust-embed = { version = "8.4", features = ["include-exclude"] }
schemars = "0.8"
@@ -334,6 +365,9 @@ serde_repr = "0.1"
sha2 = "0.10"
shellexpand = "2.1.0"
shlex = "1.3.0"
+signal-hook = "0.3.17"
+similar = "1.3"
+simplelog = "0.12.2"
smallvec = { version = "1.6", features = ["union"] }
smol = "1.2"
strum = { version = "0.25.0", features = ["derive"] }
@@ -353,28 +387,28 @@ toml = "0.8"
tokio = { version = "1", features = ["full"] }
tower-http = "0.4.4"
tree-sitter = { version = "0.20", features = ["wasm"] }
-tree-sitter-bash = { git = "https://github.com/tree-sitter/tree-sitter-bash", rev = "7331995b19b8f8aba2d5e26deb51d2195c18bc94" }
+tree-sitter-bash = "0.20.5"
tree-sitter-c = "0.20.1"
-tree-sitter-cpp = { git = "https://github.com/tree-sitter/tree-sitter-cpp", rev = "f44509141e7e483323d2ec178f2d2e6c0fc041c1" }
-tree-sitter-css = { git = "https://github.com/tree-sitter/tree-sitter-css", rev = "769203d0f9abe1a9a691ac2b9fe4bb4397a73c51" }
-tree-sitter-elixir = { git = "https://github.com/elixir-lang/tree-sitter-elixir", rev = "a2861e88a730287a60c11ea9299c033c7d076e30" }
+tree-sitter-cpp = "0.20.5"
+tree-sitter-css = "0.20"
+tree-sitter-elixir = "0.1.1"
tree-sitter-embedded-template = "0.20.0"
tree-sitter-go = { git = "https://github.com/tree-sitter/tree-sitter-go", rev = "b82ab803d887002a0af11f6ce63d72884580bf33" }
-tree-sitter-gomod = { git = "https://github.com/camdencheek/tree-sitter-go-mod" }
+tree-sitter-gomod = "1.0.1"
tree-sitter-gowork = { git = "https://github.com/d1y/tree-sitter-go-work" }
rustc-demangle = "0.1.23"
tree-sitter-heex = { git = "https://github.com/phoenixframework/tree-sitter-heex", rev = "2e1348c3cf2c9323e87c2744796cf3f3868aa82a" }
tree-sitter-html = "0.19.0"
tree-sitter-jsdoc = { git = "https://github.com/tree-sitter/tree-sitter-jsdoc", rev = "6a6cf9e7341af32d8e2b2e24a37fbfebefc3dc55" }
-tree-sitter-json = { git = "https://github.com/tree-sitter/tree-sitter-json", rev = "40a81c01a40ac48744e0c8ccabbaba1920441199" }
+tree-sitter-json = "0.20.2"
tree-sitter-markdown = { git = "https://github.com/MDeiml/tree-sitter-markdown", rev = "330ecab87a3e3a7211ac69bbadc19eabecdb1cca" }
tree-sitter-proto = { git = "https://github.com/rewinfrey/tree-sitter-proto", rev = "36d54f288aee112f13a67b550ad32634d0c2cb52" }
tree-sitter-python = "0.20.2"
tree-sitter-regex = "0.20.0"
tree-sitter-ruby = "0.20.0"
tree-sitter-rust = "0.20.3"
-tree-sitter-typescript = { git = "https://github.com/tree-sitter/tree-sitter-typescript", rev = "5d20856f34315b068c41edaee2ac8a100081d259" }
-tree-sitter-yaml = { git = "https://github.com/zed-industries/tree-sitter-yaml", rev = "f545a41f57502e1b5ddf2a6668896c1b0620f930" }
+tree-sitter-typescript = "0.20.5"
+tree-sitter-yaml = "0.0.1"
unindent = "0.1.7"
unicase = "2.6"
unicode-segmentation = "1.10"
@@ -395,12 +429,13 @@ wit-component = "0.201"
sys-locale = "0.3.1"
[workspace.dependencies.windows]
-version = "0.56.0"
+version = "0.57"
features = [
"implement",
"Foundation_Numerics",
"System",
"System_Threading",
+ "UI_ViewManagement",
"Wdk_System_SystemServices",
"Win32_Globalization",
"Win32_Graphics_Direct2D",
@@ -419,11 +454,11 @@ features = [
"Win32_System_Com_StructuredStorage",
"Win32_System_DataExchange",
"Win32_System_LibraryLoader",
+ "Win32_System_Memory",
"Win32_System_Ole",
"Win32_System_SystemInformation",
"Win32_System_SystemServices",
"Win32_System_Threading",
- "Win32_System_Time",
"Win32_System_WinRT",
"Win32_UI_Controls",
"Win32_UI_HiDpi",
@@ -436,11 +471,12 @@ features = [
[patch.crates-io]
tree-sitter = { git = "https://github.com/tree-sitter/tree-sitter", rev = "7b4894ba2ae81b988846676f54c0988d4027ef4f" }
# Workaround for a broken nightly build of gpui: See #7644 and revisit once 0.5.3 is released.
-pathfinder_simd = { git = "https://github.com/servo/pathfinder.git", rev = "30419d07660dc11a21e42ef4a7fa329600cff152" }
+pathfinder_simd = { git = "https://github.com/servo/pathfinder.git", rev = "4968e819c0d9b015437ffc694511e175801a17c7" }
[profile.dev]
split-debuginfo = "unpacked"
debug = "limited"
+codegen-units = 16
[profile.dev.package]
taffy = { opt-level = 3 }
@@ -459,6 +495,11 @@ codegen-units = 1
[profile.release.package]
zed = { codegen-units = 16 }
+[profile.release-fast]
+inherits = "release"
+lto = false
+codegen-units = 16
+
[workspace.lints.clippy]
dbg_macro = "deny"
todo = "deny"
@@ -480,7 +521,7 @@ single_range_in_vec_init = "allow"
# There are a bunch of rules currently failing in the `style` group, so
# allow all of those, for now.
-style = "allow"
+style = { level = "allow", priority = -1 }
# Individual rules that have violations in the codebase:
almost_complete_range = "allow"
diff --git a/Dockerfile b/Dockerfile
index 0614ae589e2fb1..6c8d3dab3b644b 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,6 +1,6 @@
# syntax = docker/dockerfile:1.2
-FROM rust:1.78-bookworm as builder
+FROM rust:1.79-bookworm as builder
WORKDIR app
COPY . .
diff --git a/Makefile b/Makefile
new file mode 100644
index 00000000000000..9860b52bb58f54
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,18 @@
+SHELL = /bin/zsh
+
+.PHONY: notebook-py-deps notebook
+
+PYTHON_VERSION := 3.12
+POETRY_DIR := crates/notebook
+RUST_LOG = error
+
+notebook-py-deps:
+ poetry install --directory $(POETRY_DIR) --no-root
+
+notebook: notebook-py-deps
+ VENV=$(shell poetry --directory $(POETRY_DIR) env info --path) \
+ PYTHONPATH=$(shell poetry --directory $(POETRY_DIR) env info --path)/lib/python$(PYTHON_VERSION)/site-packages \
+ PYO3_PYTHON=$(shell poetry --directory $(POETRY_DIR) env info --path)/bin/python$(PYTHON_VERSION) \
+ PYTHONEXECUTABLE=$(shell poetry --directory $(POETRY_DIR) env info --path)/bin/python$(PYTHON_VERSION) \
+ RUST_LOG=$(RUST_LOG) \
+ cargo run
diff --git a/README.md b/README.md
index a5ae33d0db6783..a3b7aeb84f594c 100644
--- a/README.md
+++ b/README.md
@@ -4,42 +4,36 @@
Welcome to Zed, a high-performance, multiplayer code editor from the creators of [Atom](https://github.com/atom/atom) and [Tree-sitter](https://github.com/tree-sitter/tree-sitter).
-## Installation
+--------
-You can [download](https://zed.dev/download) Zed today for macOS (v10.15+).
+### Installation
-Support for additional platforms is on our [roadmap](https://zed.dev/roadmap):
-- Linux ([tracking issue](https://github.com/zed-industries/zed/issues/7015))
-- Windows ([tracking issue](https://github.com/zed-industries/zed/issues/5394))
-- Web ([tracking issue](https://github.com/zed-industries/zed/issues/5396))
-
-For macOS users, you can also install Zed using [Homebrew](https://brew.sh/):
+
+
+
-```sh
-brew install --cask zed
-```
+On macOS and Linux you can [download Zed directly](https://zed.dev/download) or [install Zed via your local package manager](https://zed.dev/docs/linux#installing-via-a-package-manager).
-Alternatively, to install the Preview release:
+Other platforms are not yet available:
-```sh
-brew install --cask zed@preview
-```
+- Windows ([tracking issue](https://github.com/zed-industries/zed/issues/5394))
+- Web ([tracking issue](https://github.com/zed-industries/zed/issues/5396))
-## Developing Zed
+### Developing Zed
- [Building Zed for macOS](./docs/src/development/macos.md)
- [Building Zed for Linux](./docs/src/development/linux.md)
- [Building Zed for Windows](./docs/src/development/windows.md)
- [Running Collaboration Locally](./docs/src/development/local-collaboration.md)
-## Contributing
+### Contributing
See [CONTRIBUTING.md](./CONTRIBUTING.md) for ways you can contribute to Zed.
Also... we're hiring! Check out our [jobs](https://zed.dev/jobs) page for open roles.
-## Licensing
+### Licensing
License information for third party dependencies must be correctly provided for CI to pass.
diff --git a/assets/fonts/plex-mono/ZedPlexMono-Bold.ttf b/assets/fonts/plex-mono/ZedPlexMono-Bold.ttf
new file mode 100644
index 00000000000000..d5f4b5e2855fe9
Binary files /dev/null and b/assets/fonts/plex-mono/ZedPlexMono-Bold.ttf differ
diff --git a/assets/fonts/plex-mono/ZedPlexMono-BoldItalic.ttf b/assets/fonts/plex-mono/ZedPlexMono-BoldItalic.ttf
new file mode 100644
index 00000000000000..05eaf7cccde1c6
Binary files /dev/null and b/assets/fonts/plex-mono/ZedPlexMono-BoldItalic.ttf differ
diff --git a/assets/fonts/plex-mono/ZedPlexMono-Italic.ttf b/assets/fonts/plex-mono/ZedPlexMono-Italic.ttf
new file mode 100644
index 00000000000000..3b078217578da8
Binary files /dev/null and b/assets/fonts/plex-mono/ZedPlexMono-Italic.ttf differ
diff --git a/assets/fonts/plex-mono/ZedPlexMono-Regular.ttf b/assets/fonts/plex-mono/ZedPlexMono-Regular.ttf
new file mode 100644
index 00000000000000..61dbb583619e20
Binary files /dev/null and b/assets/fonts/plex-mono/ZedPlexMono-Regular.ttf differ
diff --git a/assets/fonts/plex-mono/license.txt b/assets/fonts/plex-mono/license.txt
new file mode 100644
index 00000000000000..f72f76504cd73c
--- /dev/null
+++ b/assets/fonts/plex-mono/license.txt
@@ -0,0 +1,92 @@
+Copyright © 2017 IBM Corp. with Reserved Font Name "Plex"
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
\ No newline at end of file
diff --git a/assets/fonts/plex-sans/ZedPlexSans-Bold.ttf b/assets/fonts/plex-sans/ZedPlexSans-Bold.ttf
new file mode 100644
index 00000000000000..f1e66392f7c5a3
Binary files /dev/null and b/assets/fonts/plex-sans/ZedPlexSans-Bold.ttf differ
diff --git a/assets/fonts/plex-sans/ZedPlexSans-BoldItalic.ttf b/assets/fonts/plex-sans/ZedPlexSans-BoldItalic.ttf
new file mode 100644
index 00000000000000..7612dc516742f8
Binary files /dev/null and b/assets/fonts/plex-sans/ZedPlexSans-BoldItalic.ttf differ
diff --git a/assets/fonts/plex-sans/ZedPlexSans-Italic.ttf b/assets/fonts/plex-sans/ZedPlexSans-Italic.ttf
new file mode 100644
index 00000000000000..8769c232ee6923
Binary files /dev/null and b/assets/fonts/plex-sans/ZedPlexSans-Italic.ttf differ
diff --git a/assets/fonts/plex-sans/ZedPlexSans-Regular.ttf b/assets/fonts/plex-sans/ZedPlexSans-Regular.ttf
new file mode 100644
index 00000000000000..3ea293d59a31d2
Binary files /dev/null and b/assets/fonts/plex-sans/ZedPlexSans-Regular.ttf differ
diff --git a/assets/fonts/plex-sans/license.txt b/assets/fonts/plex-sans/license.txt
new file mode 100644
index 00000000000000..f72f76504cd73c
--- /dev/null
+++ b/assets/fonts/plex-sans/license.txt
@@ -0,0 +1,92 @@
+Copyright © 2017 IBM Corp. with Reserved Font Name "Plex"
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
\ No newline at end of file
diff --git a/assets/fonts/zed-mono/zed-mono-extended.ttf b/assets/fonts/zed-mono/zed-mono-extended.ttf
deleted file mode 100644
index 05b8c7085e51d4..00000000000000
Binary files a/assets/fonts/zed-mono/zed-mono-extended.ttf and /dev/null differ
diff --git a/assets/fonts/zed-mono/zed-mono-extendedbold.ttf b/assets/fonts/zed-mono/zed-mono-extendedbold.ttf
deleted file mode 100644
index d5dde1bb14d580..00000000000000
Binary files a/assets/fonts/zed-mono/zed-mono-extendedbold.ttf and /dev/null differ
diff --git a/assets/fonts/zed-mono/zed-mono-extendedbolditalic.ttf b/assets/fonts/zed-mono/zed-mono-extendedbolditalic.ttf
deleted file mode 100644
index bcd8c7e618e0b6..00000000000000
Binary files a/assets/fonts/zed-mono/zed-mono-extendedbolditalic.ttf and /dev/null differ
diff --git a/assets/fonts/zed-mono/zed-mono-extendeditalic.ttf b/assets/fonts/zed-mono/zed-mono-extendeditalic.ttf
deleted file mode 100644
index 023c5a87cea6c1..00000000000000
Binary files a/assets/fonts/zed-mono/zed-mono-extendeditalic.ttf and /dev/null differ
diff --git a/assets/fonts/zed-sans/zed-sans-extended.ttf b/assets/fonts/zed-sans/zed-sans-extended.ttf
deleted file mode 100644
index 07a96856803998..00000000000000
Binary files a/assets/fonts/zed-sans/zed-sans-extended.ttf and /dev/null differ
diff --git a/assets/fonts/zed-sans/zed-sans-extendedbold.ttf b/assets/fonts/zed-sans/zed-sans-extendedbold.ttf
deleted file mode 100644
index 696c3cdd5b8ecd..00000000000000
Binary files a/assets/fonts/zed-sans/zed-sans-extendedbold.ttf and /dev/null differ
diff --git a/assets/fonts/zed-sans/zed-sans-extendedbolditalic.ttf b/assets/fonts/zed-sans/zed-sans-extendedbolditalic.ttf
deleted file mode 100644
index 74cb8f7a3c6dd6..00000000000000
Binary files a/assets/fonts/zed-sans/zed-sans-extendedbolditalic.ttf and /dev/null differ
diff --git a/assets/fonts/zed-sans/zed-sans-extendeditalic.ttf b/assets/fonts/zed-sans/zed-sans-extendeditalic.ttf
deleted file mode 100644
index 9460e5a7dd690f..00000000000000
Binary files a/assets/fonts/zed-sans/zed-sans-extendeditalic.ttf and /dev/null differ
diff --git a/assets/icons/arrow_down_from_line.svg b/assets/icons/arrow_down_from_line.svg
new file mode 100644
index 00000000000000..89316973a00ab0
--- /dev/null
+++ b/assets/icons/arrow_down_from_line.svg
@@ -0,0 +1 @@
+
diff --git a/assets/icons/arrow_up_from_line.svg b/assets/icons/arrow_up_from_line.svg
new file mode 100644
index 00000000000000..50a075e42bd4e6
--- /dev/null
+++ b/assets/icons/arrow_up_from_line.svg
@@ -0,0 +1 @@
+
diff --git a/assets/icons/book.svg b/assets/icons/book.svg
new file mode 100644
index 00000000000000..d30f81f32ea777
--- /dev/null
+++ b/assets/icons/book.svg
@@ -0,0 +1 @@
+
diff --git a/assets/icons/book_copy.svg b/assets/icons/book_copy.svg
new file mode 100644
index 00000000000000..b055d47b5fe45c
--- /dev/null
+++ b/assets/icons/book_copy.svg
@@ -0,0 +1 @@
+
diff --git a/assets/icons/book_plus.svg b/assets/icons/book_plus.svg
new file mode 100644
index 00000000000000..2868f07cd098d7
--- /dev/null
+++ b/assets/icons/book_plus.svg
@@ -0,0 +1 @@
+
diff --git a/assets/icons/chevron_down_small.svg b/assets/icons/chevron_down_small.svg
new file mode 100644
index 00000000000000..8f8a99d4b97d16
--- /dev/null
+++ b/assets/icons/chevron_down_small.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/assets/icons/chevron_up_down.svg b/assets/icons/chevron_up_down.svg
new file mode 100644
index 00000000000000..a7414ec8a0706a
--- /dev/null
+++ b/assets/icons/chevron_up_down.svg
@@ -0,0 +1 @@
+
diff --git a/assets/icons/context.svg b/assets/icons/context.svg
new file mode 100644
index 00000000000000..837b3aadd938a7
--- /dev/null
+++ b/assets/icons/context.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/assets/icons/file_icons/file_types.json b/assets/icons/file_icons/file_types.json
index 5c2e13068856c6..fd0dc448c4e54f 100644
--- a/assets/icons/file_icons/file_types.json
+++ b/assets/icons/file_icons/file_types.json
@@ -1,15 +1,15 @@
{
"stems": {
+ "Dockerfile": "docker",
"Podfile": "ruby",
- "Procfile": "heroku",
- "Dockerfile": "docker"
+ "Procfile": "heroku"
},
"suffixes": {
- "astro": "astro",
"Emakefile": "erlang",
"aac": "audio",
"accdb": "storage",
"app.src": "erlang",
+ "astro": "astro",
"avi": "video",
"avif": "image",
"bak": "backup",
@@ -22,12 +22,12 @@
"c": "c",
"cc": "cpp",
"cjs": "javascript",
+ "coffee": "coffeescript",
"conf": "settings",
"cpp": "cpp",
"css": "css",
"csv": "storage",
"cts": "typescript",
- "coffee": "coffeescript",
"dart": "dart",
"dat": "storage",
"db": "storage",
@@ -61,12 +61,12 @@
"graphql": "graphql",
"graphqls": "graphql",
"h": "c",
- "hpp": "cpp",
"handlebars": "code",
"hbs": "template",
"heex": "elixir",
- "heif": "image",
"heic": "image",
+ "heif": "image",
+ "hpp": "cpp",
"hrl": "erlang",
"hs": "haskell",
"htm": "template",
@@ -74,6 +74,7 @@
"ib": "storage",
"ico": "image",
"ini": "settings",
+ "inl": "cpp",
"j2k": "image",
"java": "java",
"jfif": "image",
@@ -81,9 +82,9 @@
"jpeg": "image",
"jpg": "image",
"js": "javascript",
- "jsx": "react",
"json": "storage",
"jsonc": "storage",
+ "jsx": "react",
"jxl": "image",
"kt": "kotlin",
"ldf": "storage",
@@ -93,14 +94,15 @@
"lua": "lua",
"m4a": "audio",
"m4v": "video",
+ "markdown": "document",
"md": "document",
"mdb": "storage",
"mdf": "storage",
"mdx": "document",
"metadata": "code",
- "mkv": "video",
"mjs": "javascript",
"mka": "audio",
+ "mkv": "video",
"ml": "ocaml",
"mli": "ocaml",
"mov": "video",
@@ -109,8 +111,8 @@
"mts": "typescript",
"myd": "storage",
"myi": "storage",
- "nu": "terminal",
"nim": "nim",
+ "nu": "terminal",
"odp": "document",
"ods": "document",
"odt": "document",
@@ -132,33 +134,33 @@
"psd": "image",
"py": "python",
"qoi": "image",
+ "r": "r",
"rb": "ruby",
"rebar.config": "erlang",
"rkt": "code",
"rs": "rust",
- "r": "r",
"rtf": "document",
"sav": "storage",
+ "sc": "scala",
+ "scala": "scala",
"scm": "code",
"sdf": "storage",
"sh": "terminal",
+ "sql": "storage",
"sqlite": "storage",
"svelte": "template",
"svg": "image",
- "sc": "scala",
- "scala": "scala",
- "sql": "storage",
"swift": "swift",
+ "tcl": "tcl",
"tf": "terraform",
"tfvars": "terraform",
"tiff": "image",
"toml": "toml",
"ts": "typescript",
"tsv": "storage",
- "ttf": "font",
"tsx": "react",
+ "ttf": "font",
"txt": "document",
- "tcl": "tcl",
"vue": "vue",
"wav": "audio",
"webm": "video",
@@ -190,27 +192,30 @@
"audio": {
"icon": "icons/file_icons/audio.svg"
},
+ "bun": {
+ "icon": "icons/file_icons/bun.svg"
+ },
+ "c": {
+ "icon": "icons/file_icons/c.svg"
+ },
"code": {
"icon": "icons/file_icons/code.svg"
},
+ "coffeescript": {
+ "icon": "icons/file_icons/coffeescript.svg"
+ },
"collapsed_chevron": {
"icon": "icons/file_icons/chevron_right.svg"
},
"collapsed_folder": {
"icon": "icons/file_icons/folder.svg"
},
- "c": {
- "icon": "icons/file_icons/c.svg"
- },
"cpp": {
"icon": "icons/file_icons/cpp.svg"
},
"css": {
"icon": "icons/file_icons/css.svg"
},
- "coffeescript": {
- "icon": "icons/file_icons/coffeescript.svg"
- },
"dart": {
"icon": "icons/file_icons/dart.svg"
},
@@ -247,18 +252,18 @@
"fsharp": {
"icon": "icons/file_icons/fsharp.svg"
},
- "haskell": {
- "icon": "icons/file_icons/haskell.svg"
- },
- "heroku": {
- "icon": "icons/file_icons/heroku.svg"
- },
"go": {
"icon": "icons/file_icons/go.svg"
},
"graphql": {
"icon": "icons/file_icons/graphql.svg"
},
+ "haskell": {
+ "icon": "icons/file_icons/haskell.svg"
+ },
+ "heroku": {
+ "icon": "icons/file_icons/heroku.svg"
+ },
"image": {
"icon": "icons/file_icons/image.svg"
},
@@ -274,21 +279,18 @@
"lock": {
"icon": "icons/file_icons/lock.svg"
},
- "bun": {
- "icon": "icons/file_icons/bun.svg"
- },
"log": {
"icon": "icons/file_icons/info.svg"
},
"lua": {
"icon": "icons/file_icons/lua.svg"
},
- "ocaml": {
- "icon": "icons/file_icons/ocaml.svg"
- },
"nim": {
"icon": "icons/file_icons/nim.svg"
},
+ "ocaml": {
+ "icon": "icons/file_icons/ocaml.svg"
+ },
"phoenix": {
"icon": "icons/file_icons/phoenix.svg"
},
@@ -316,36 +318,36 @@
"rust": {
"icon": "icons/file_icons/rust.svg"
},
+ "scala": {
+ "icon": "icons/file_icons/scala.svg"
+ },
"settings": {
"icon": "icons/file_icons/settings.svg"
},
"storage": {
"icon": "icons/file_icons/database.svg"
},
- "scala": {
- "icon": "icons/file_icons/scala.svg"
- },
"swift": {
"icon": "icons/file_icons/swift.svg"
},
+ "tcl": {
+ "icon": "icons/file_icons/tcl.svg"
+ },
"template": {
"icon": "icons/file_icons/html.svg"
},
- "terraform": {
- "icon": "icons/file_icons/terraform.svg"
- },
"terminal": {
"icon": "icons/file_icons/terminal.svg"
},
+ "terraform": {
+ "icon": "icons/file_icons/terraform.svg"
+ },
"toml": {
"icon": "icons/file_icons/toml.svg"
},
"typescript": {
"icon": "icons/file_icons/typescript.svg"
},
- "tcl": {
- "icon": "icons/file_icons/tcl.svg"
- },
"vcs": {
"icon": "icons/file_icons/git.svg"
},
diff --git a/assets/icons/font.svg b/assets/icons/font.svg
new file mode 100644
index 00000000000000..861ab1a41540b3
--- /dev/null
+++ b/assets/icons/font.svg
@@ -0,0 +1 @@
+
diff --git a/assets/icons/font_size.svg b/assets/icons/font_size.svg
new file mode 100644
index 00000000000000..cfba2deb6c0297
--- /dev/null
+++ b/assets/icons/font_size.svg
@@ -0,0 +1 @@
+
diff --git a/assets/icons/font_weight.svg b/assets/icons/font_weight.svg
new file mode 100644
index 00000000000000..3ebbfa77bc77e6
--- /dev/null
+++ b/assets/icons/font_weight.svg
@@ -0,0 +1 @@
+
diff --git a/assets/icons/generic_close.svg b/assets/icons/generic_close.svg
new file mode 100644
index 00000000000000..0fd213daf9c81f
--- /dev/null
+++ b/assets/icons/generic_close.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/assets/icons/generic_maximize.svg b/assets/icons/generic_maximize.svg
new file mode 100644
index 00000000000000..e44abd8f06a8dd
--- /dev/null
+++ b/assets/icons/generic_maximize.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/assets/icons/generic_minimize.svg b/assets/icons/generic_minimize.svg
new file mode 100644
index 00000000000000..4b43cde2743e26
--- /dev/null
+++ b/assets/icons/generic_minimize.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/assets/icons/generic_restore.svg b/assets/icons/generic_restore.svg
new file mode 100644
index 00000000000000..3bf581f2cd6e9c
--- /dev/null
+++ b/assets/icons/generic_restore.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/assets/icons/line_height.svg b/assets/icons/line_height.svg
new file mode 100644
index 00000000000000..904cfad8a8638c
--- /dev/null
+++ b/assets/icons/line_height.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/assets/icons/list_tree.svg b/assets/icons/list_tree.svg
new file mode 100644
index 00000000000000..8cf157ec135d13
--- /dev/null
+++ b/assets/icons/list_tree.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/icons/repl_neutral.svg b/assets/icons/repl_neutral.svg
new file mode 100644
index 00000000000000..db647fe40b24a3
--- /dev/null
+++ b/assets/icons/repl_neutral.svg
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/icons/repl_off.svg b/assets/icons/repl_off.svg
new file mode 100644
index 00000000000000..51ada0db4621c3
--- /dev/null
+++ b/assets/icons/repl_off.svg
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/icons/repl_pause.svg b/assets/icons/repl_pause.svg
new file mode 100644
index 00000000000000..2ac327df3b0d88
--- /dev/null
+++ b/assets/icons/repl_pause.svg
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/icons/repl_play.svg b/assets/icons/repl_play.svg
new file mode 100644
index 00000000000000..d23b8991126371
--- /dev/null
+++ b/assets/icons/repl_play.svg
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/icons/rerun.svg b/assets/icons/rerun.svg
new file mode 100644
index 00000000000000..4d22f924f5d7e7
--- /dev/null
+++ b/assets/icons/rerun.svg
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/assets/icons/reveal.svg b/assets/icons/reveal.svg
new file mode 100644
index 00000000000000..ff5444d8f84c31
--- /dev/null
+++ b/assets/icons/reveal.svg
@@ -0,0 +1 @@
+
diff --git a/assets/icons/rotate_ccw.svg b/assets/icons/rotate_ccw.svg
new file mode 100644
index 00000000000000..4eff13b94b698d
--- /dev/null
+++ b/assets/icons/rotate_ccw.svg
@@ -0,0 +1 @@
+
diff --git a/assets/icons/rotate_cw.svg b/assets/icons/rotate_cw.svg
new file mode 100644
index 00000000000000..019367745fa9ba
--- /dev/null
+++ b/assets/icons/rotate_cw.svg
@@ -0,0 +1 @@
+
diff --git a/assets/icons/save.svg b/assets/icons/save.svg
new file mode 100644
index 00000000000000..f83d035331c2ba
--- /dev/null
+++ b/assets/icons/save.svg
@@ -0,0 +1 @@
+
diff --git a/assets/icons/search_selection.svg b/assets/icons/search_selection.svg
new file mode 100644
index 00000000000000..b970db14300b18
--- /dev/null
+++ b/assets/icons/search_selection.svg
@@ -0,0 +1 @@
+
diff --git a/assets/icons/sparkle.svg b/assets/icons/sparkle.svg
new file mode 100644
index 00000000000000..f420f527f138cc
--- /dev/null
+++ b/assets/icons/sparkle.svg
@@ -0,0 +1 @@
+
diff --git a/assets/icons/sparkle_filled.svg b/assets/icons/sparkle_filled.svg
new file mode 100644
index 00000000000000..96837f618ddd56
--- /dev/null
+++ b/assets/icons/sparkle_filled.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/assets/icons/star.svg b/assets/icons/star.svg
new file mode 100644
index 00000000000000..71d4f3f7cc29b1
--- /dev/null
+++ b/assets/icons/star.svg
@@ -0,0 +1 @@
+
diff --git a/assets/icons/star_filled.svg b/assets/icons/star_filled.svg
new file mode 100644
index 00000000000000..4aaad4b7fd61c9
--- /dev/null
+++ b/assets/icons/star_filled.svg
@@ -0,0 +1 @@
+
diff --git a/assets/icons/stop.svg b/assets/icons/stop.svg
new file mode 100644
index 00000000000000..3beabd53947bfd
--- /dev/null
+++ b/assets/icons/stop.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/assets/icons/text-cursor.svg b/assets/icons/text-cursor.svg
new file mode 100644
index 00000000000000..2e7b95b2039455
--- /dev/null
+++ b/assets/icons/text-cursor.svg
@@ -0,0 +1 @@
+
diff --git a/assets/icons/triangle_right.svg b/assets/icons/triangle_right.svg
new file mode 100644
index 00000000000000..2c78a316f7cd82
--- /dev/null
+++ b/assets/icons/triangle_right.svg
@@ -0,0 +1 @@
+
diff --git a/assets/icons/visible.svg b/assets/icons/visible.svg
new file mode 100644
index 00000000000000..0a7e65d60d7ee8
--- /dev/null
+++ b/assets/icons/visible.svg
@@ -0,0 +1 @@
+
diff --git a/assets/icons/zed_assistant_filled.svg b/assets/icons/zed_assistant_filled.svg
new file mode 100644
index 00000000000000..8d16fd98499b23
--- /dev/null
+++ b/assets/icons/zed_assistant_filled.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/assets/keymaps/default-linux.json b/assets/keymaps/default-linux.json
index 2d7e693b3c75b5..8be6d123900a95 100644
--- a/assets/keymaps/default-linux.json
+++ b/assets/keymaps/default-linux.json
@@ -1,13 +1,16 @@
[
- // todo(linux): Review the editor bindings
// Standard Linux bindings
{
"bindings": {
"up": "menu::SelectPrev",
+ "shift-tab": "menu::SelectPrev",
+ "home": "menu::SelectFirst",
"pageup": "menu::SelectFirst",
"shift-pageup": "menu::SelectFirst",
"ctrl-p": "menu::SelectPrev",
"down": "menu::SelectNext",
+ "tab": "menu::SelectNext",
+ "end": "menu::SelectLast",
"pagedown": "menu::SelectLast",
"shift-pagedown": "menu::SelectFirst",
"ctrl-n": "menu::SelectNext",
@@ -16,7 +19,6 @@
"escape": "menu::Cancel",
"ctrl-escape": "menu::Cancel",
"ctrl-c": "menu::Cancel",
- "shift-enter": "picker::UseSelectedQuery",
"alt-enter": ["picker::ConfirmInput", { "secondary": false }],
"ctrl-alt-enter": ["picker::ConfirmInput", { "secondary": true }],
"ctrl-shift-w": "workspace::CloseWindow",
@@ -28,7 +30,6 @@
"ctrl-0": "zed::ResetBufferFontSize",
"ctrl-,": "zed::OpenSettings",
"ctrl-q": "zed::Quit",
- "alt-f9": "zed::Hide",
"f11": "zed::ToggleFullScreen"
}
},
@@ -43,106 +44,61 @@
"tab": "editor::Tab",
"shift-tab": "editor::TabPrev",
"ctrl-k": "editor::CutToEndOfLine",
- "ctrl-t": "editor::Transpose",
- // "ctrl-backspace": "editor::DeleteToBeginningOfLine",
- // "ctrl-delete": "editor::DeleteToEndOfLine",
+ // "ctrl-t": "editor::Transpose",
"ctrl-backspace": "editor::DeleteToPreviousWordStart",
- // "ctrl-w": "editor::DeleteToPreviousWordStart",
"ctrl-delete": "editor::DeleteToNextWordEnd",
- // "alt-h": "editor::DeleteToPreviousWordStart",
- // "alt-d": "editor::DeleteToNextWordEnd",
+ "shift-delete": "editor::Cut",
"ctrl-x": "editor::Cut",
- "ctrl-c": "editor::Copy",
"ctrl-insert": "editor::Copy",
- "ctrl-v": "editor::Paste",
+ "ctrl-c": "editor::Copy",
"shift-insert": "editor::Paste",
+ "ctrl-v": "editor::Paste",
+ "ctrl-y": "editor::Redo",
"ctrl-z": "editor::Undo",
"ctrl-shift-z": "editor::Redo",
"up": "editor::MoveUp",
- // "ctrl-up": "editor::MoveToStartOfParagraph", todo(linux) Should be "scroll down by 1 line"
- "pageup": "editor::PageUp",
- // "shift-pageup": "editor::MovePageUp", todo(linux) should be 'select page up'
+ "ctrl-up": "editor::LineUp",
+ "ctrl-down": "editor::LineDown",
+ "pageup": "editor::MovePageUp",
+ "alt-pageup": "editor::PageUp",
+ "shift-pageup": "editor::SelectPageUp",
"home": "editor::MoveToBeginningOfLine",
"down": "editor::MoveDown",
- // "ctrl-down": "editor::MoveToEndOfParagraph", todo(linux) should be "scroll up by 1 line"
- "pagedown": "editor::PageDown",
- // "shift-pagedown": "editor::MovePageDown", todo(linux) should be 'select page down'
+ "pagedown": "editor::MovePageDown",
+ "alt-pagedown": "editor::PageDown",
+ "shift-pagedown": "editor::SelectPageDown",
"end": "editor::MoveToEndOfLine",
"left": "editor::MoveLeft",
"right": "editor::MoveRight",
"ctrl-left": "editor::MoveToPreviousWordStart",
- // "alt-b": "editor::MoveToPreviousWordStart",
"ctrl-right": "editor::MoveToNextWordEnd",
- // "alt-f": "editor::MoveToNextWordEnd",
- // "cmd-left": "editor::MoveToBeginningOfLine",
- // "ctrl-a": "editor::MoveToBeginningOfLine",
- // "cmd-right": "editor::MoveToEndOfLine",
- // "ctrl-e": "editor::MoveToEndOfLine",
"ctrl-home": "editor::MoveToBeginning",
"ctrl-end": "editor::MoveToEnd",
"shift-up": "editor::SelectUp",
"shift-down": "editor::SelectDown",
"shift-left": "editor::SelectLeft",
"shift-right": "editor::SelectRight",
- "ctrl-shift-left": "editor::SelectToPreviousWordStart",
- "ctrl-shift-right": "editor::SelectToNextWordEnd",
- "ctrl-shift-up": "editor::AddSelectionAbove",
- "ctrl-shift-down": "editor::AddSelectionBelow",
- // "ctrl-shift-up": "editor::SelectToStartOfParagraph",
- // "ctrl-shift-down": "editor::SelectToEndOfParagraph",
+ "ctrl-shift-left": "editor::SelectToPreviousWordStart", // cursorWordLeftSelect
+ "ctrl-shift-right": "editor::SelectToNextWordEnd", // cursorWordRightSelect
"ctrl-shift-home": "editor::SelectToBeginning",
"ctrl-shift-end": "editor::SelectToEnd",
"ctrl-a": "editor::SelectAll",
"ctrl-l": "editor::SelectLine",
"ctrl-shift-i": "editor::Format",
- // "cmd-shift-left": [
- // "editor::SelectToBeginningOfLine",
- // {
- // "stop_at_soft_wraps": true
- // }
- // ],
- "shift-home": [
- "editor::SelectToBeginningOfLine",
- {
- "stop_at_soft_wraps": true
- }
- ],
- // "ctrl-shift-a": [
- // "editor::SelectToBeginningOfLine",
- // {
- // "stop_at_soft_wraps": true
- // }
- // ],
- // "cmd-shift-right": [
- // "editor::SelectToEndOfLine",
- // {
- // "stop_at_soft_wraps": true
- // }
- // ],
- "shift-end": [
- "editor::SelectToEndOfLine",
- {
- "stop_at_soft_wraps": true
- }
- ],
- // "ctrl-shift-e": [
- // "editor::SelectToEndOfLine",
- // {
- // "stop_at_soft_wraps": true
- // }
- // ],
- // "alt-v": [
- // "editor::MovePageUp",
- // {
- // "center_cursor": true
- // }
- // ],
+ // "cmd-shift-left": ["editor::SelectToBeginningOfLine", {"stop_at_soft_wraps": true }],
+ "shift-home": ["editor::SelectToBeginningOfLine", { "stop_at_soft_wraps": true }],
+ // "ctrl-shift-a": ["editor::SelectToBeginningOfLine", { "stop_at_soft_wraps": true }],
+ // "cmd-shift-right": ["editor::SelectToEndOfLine", { "stop_at_soft_wraps": true }],
+ "shift-end": ["editor::SelectToEndOfLine", { "stop_at_soft_wraps": true }],
+ // "ctrl-shift-e": ["editor::SelectToEndOfLine", { "stop_at_soft_wraps": true }],
+ // "alt-v": ["editor::MovePageUp", { "center_cursor": true }],
"ctrl-alt-space": "editor::ShowCharacterPalette",
"ctrl-;": "editor::ToggleLineNumbers",
"ctrl-k ctrl-r": "editor::RevertSelectedHunks",
"ctrl-'": "editor::ToggleHunkDiff",
"ctrl-\"": "editor::ExpandAllHunkDiffs",
- "ctrl-alt-g b": "editor::ToggleGitBlame"
+ "ctrl-i": "editor::ShowSignatureHelp",
+ "alt-g b": "editor::ToggleGitBlame"
}
},
{
@@ -154,19 +110,11 @@
"ctrl-enter": "editor::NewlineAbove",
"alt-z": "editor::ToggleSoftWrap",
"ctrl-f": "buffer_search::Deploy",
- "ctrl-h": [
- "buffer_search::Deploy",
- {
- "replace_enabled": true
- }
- ],
- // "cmd-e": [
- // "buffer_search::Deploy",
- // {
- // "focus": false
- // }
- // ],
- "ctrl->": "assistant::QuoteSelection"
+ "ctrl-h": ["buffer_search::Deploy", { "replace_enabled": true }],
+ // "cmd-e": ["buffer_search::Deploy", { "focus": false }],
+ "ctrl->": "assistant::QuoteSelection",
+ "ctrl-<": "assistant::InsertIntoEditor",
+ "ctrl-alt-e": "editor::SelectEnclosingSymbol"
}
},
{
@@ -201,17 +149,15 @@
"context": "AssistantPanel",
"bindings": {
"ctrl-g": "search::SelectNextMatch",
- "ctrl-shift-g": "search::SelectPrevMatch"
+ "ctrl-shift-g": "search::SelectPrevMatch",
+ "alt-m": "assistant::ToggleModelSelector"
}
},
{
- "context": "ConversationEditor > Editor",
+ "context": "PromptLibrary",
"bindings": {
- "ctrl-enter": "assistant::Assist",
- "ctrl-s": "workspace::Save",
- "ctrl->": "assistant::QuoteSelection",
- "shift-enter": "assistant::Split",
- "ctrl-r": "assistant::CycleMessageRole"
+ "ctrl-n": "prompt_library::NewPrompt",
+ "ctrl-shift-s": "prompt_library::ToggleDefaultPrompt"
}
},
{
@@ -223,7 +169,8 @@
"shift-enter": "search::SelectPrevMatch",
"alt-enter": "search::SelectAllMatches",
"ctrl-f": "search::FocusSearch",
- "ctrl-h": "search::ToggleReplace"
+ "ctrl-h": "search::ToggleReplace",
+ "ctrl-l": "search::ToggleSelection"
}
},
{
@@ -258,7 +205,7 @@
}
},
{
- "context": "ProjectSearchBar && in_replace",
+ "context": "ProjectSearchBar && in_replace > Editor",
"bindings": {
"enter": "search::ReplaceNext",
"ctrl-alt-enter": "search::ReplaceAll"
@@ -279,6 +226,7 @@
"ctrl-pageup": "pane::ActivatePrevItem",
"ctrl-pagedown": "pane::ActivateNextItem",
"ctrl-w": "pane::CloseActiveItem",
+ "ctrl-f4": "pane::CloseActiveItem",
"alt-ctrl-t": "pane::CloseInactiveItems",
"alt-ctrl-shift-w": "workspace::CloseInactiveTabsAndPanes",
"ctrl-k u": "pane::CloseCleanItems",
@@ -287,6 +235,7 @@
"ctrl-alt-g": "search::SelectNextMatch",
"ctrl-alt-shift-g": "search::SelectPrevMatch",
"ctrl-alt-shift-h": "search::ToggleReplace",
+ "ctrl-alt-shift-l": "search::ToggleSelection",
"alt-enter": "search::SelectAllMatches",
"alt-c": "search::ToggleCaseSensitive",
"alt-w": "search::ToggleWholeWord",
@@ -296,55 +245,36 @@
"ctrl-alt-shift-x": "search::ToggleRegex"
}
},
+ {
+ "context": "Terminal",
+ "bindings": {
+ "ctrl-w": ["terminal::SendKeystroke", "ctrl-w"],
+ "ctrl-e": ["terminal::SendKeystroke", "ctrl-e"]
+ }
+ },
// Bindings from VS Code
{
"context": "Editor",
"bindings": {
"ctrl-[": "editor::Outdent",
"ctrl-]": "editor::Indent",
- "shift-alt-up": "editor::AddSelectionAbove",
- "shift-alt-down": "editor::AddSelectionBelow",
+ "shift-alt-up": "editor::AddSelectionAbove", // Insert Cursor Above
+ "shift-alt-down": "editor::AddSelectionBelow", // Insert Cursor Below
"ctrl-shift-k": "editor::DeleteLine",
"alt-up": "editor::MoveLineUp",
"alt-down": "editor::MoveLineDown",
"ctrl-alt-shift-up": "editor::DuplicateLineUp",
"ctrl-alt-shift-down": "editor::DuplicateLineDown",
- "ctrl-shift-left": "editor::SelectToPreviousWordStart",
- "ctrl-shift-right": "editor::SelectToNextWordEnd",
- "ctrl-shift-up": "editor::SelectLargerSyntaxNode", //todo(linux) tmp keybinding
- "ctrl-shift-down": "editor::SelectSmallerSyntaxNode", //todo(linux) tmp keybinding
- "ctrl-d": [
- "editor::SelectNext",
- {
- "replace_newest": false
- }
- ],
- "ctrl-shift-l": "editor::SelectAllMatches",
- "ctrl-shift-d": [
- "editor::SelectPrevious",
- {
- "replace_newest": false
- }
- ],
- "ctrl-k ctrl-d": [
- "editor::SelectNext",
- {
- "replace_newest": true
- }
- ],
- "ctrl-k ctrl-shift-d": [
- "editor::SelectPrevious",
- {
- "replace_newest": true
- }
- ],
+ "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-shift-down": ["editor::SelectNext", { "replace_newest": false }], // Add selection to Next Find Match
+ "ctrl-shift-up": ["editor::SelectPrevious", { "replace_newest": false }],
+ "ctrl-k ctrl-d": ["editor::SelectNext", { "replace_newest": true }],
+ "ctrl-k ctrl-shift-d": ["editor::SelectPrevious", { "replace_newest": true }],
"ctrl-k ctrl-i": "editor::Hover",
- "ctrl-/": [
- "editor::ToggleComments",
- {
- "advance_downwards": false
- }
- ],
+ "ctrl-/": ["editor::ToggleComments", { "advance_downwards": false }],
"ctrl-u": "editor::UndoSelection",
"ctrl-shift-u": "editor::RedoSelection",
"f8": "editor::GoToDiagnostic",
@@ -352,16 +282,23 @@
"f2": "editor::Rename",
"f12": "editor::GoToDefinition",
"alt-f12": "editor::GoToDefinitionSplit",
+ "ctrl-shift-f10": "editor::GoToDefinitionSplit",
"ctrl-f12": "editor::GoToTypeDefinition",
"shift-f12": "editor::GoToImplementation",
"alt-ctrl-f12": "editor::GoToTypeDefinitionSplit",
"alt-shift-f12": "editor::FindAllReferences",
"ctrl-m": "editor::MoveToEnclosingBracket",
+ "ctrl-shift-\\": "editor::MoveToEnclosingBracket",
"ctrl-shift-[": "editor::Fold",
"ctrl-shift-]": "editor::UnfoldLines",
"ctrl-space": "editor::ShowCompletions",
"ctrl-.": "editor::ToggleCodeActions",
- "alt-ctrl-r": "editor::RevealInFinder",
+ "alt-ctrl-r": "editor::RevealInFileManager",
+ "ctrl-k r": "editor::RevealInFileManager",
+ "ctrl-k p": "editor::CopyPath",
+ "ctrl-\\": "pane::SplitRight",
+ "ctrl-k v": "markdown::OpenPreviewToTheSide",
+ "ctrl-shift-v": "markdown::OpenPreview",
"ctrl-alt-shift-c": "editor::DisplayCursorNames"
}
},
@@ -388,6 +325,8 @@
"ctrl-alt--": "pane::GoBack",
"ctrl-alt-_": "pane::GoForward",
"ctrl-shift-t": "pane::ReopenClosedItem",
+ "f3": "search::SelectNextMatch",
+ "shift-f3": "search::SelectPrevMatch",
"ctrl-shift-f": "project_search::ToggleFocus"
}
},
@@ -395,12 +334,7 @@
"context": "Workspace",
"bindings": {
// Change the default action on `menu::Confirm` by setting the parameter
- // "alt-cmd-o": [
- // "projects::OpenRecent",
- // {
- // "create_new_window": true
- // }
- // ]
+ // "alt-ctrl-o": ["projects::OpenRecent", { "create_new_window": true }],
"alt-ctrl-o": "projects::OpenRecent",
"alt-ctrl-shift-b": "branches::OpenRecent",
"ctrl-~": "workspace::NewTerminal",
@@ -419,27 +353,24 @@
"alt-7": ["workspace::ActivatePane", 6],
"alt-8": ["workspace::ActivatePane", 7],
"alt-9": ["workspace::ActivatePane", 8],
- "ctrl-alt-b": "workspace::ToggleLeftDock",
- "ctrl-b": "workspace::ToggleRightDock",
+ "ctrl-alt-b": "workspace::ToggleRightDock",
+ "ctrl-b": "workspace::ToggleLeftDock",
"ctrl-j": "workspace::ToggleBottomDock",
"ctrl-alt-y": "workspace::CloseAllDocks",
"ctrl-shift-f": "pane::DeploySearch",
- "ctrl-shift-h": [
- "pane::DeploySearch",
- {
- "replace_enabled": true
- }
- ],
+ "ctrl-shift-h": ["pane::DeploySearch", { "replace_enabled": true }],
"ctrl-k ctrl-s": "zed::OpenKeymap",
"ctrl-k ctrl-t": "theme_selector::Toggle",
- "ctrl-shift-t": "project_symbols::Toggle",
+ "ctrl-t": "project_symbols::Toggle",
"ctrl-p": "file_finder::Toggle",
"ctrl-tab": "tab_switcher::Toggle",
"ctrl-shift-tab": ["tab_switcher::Toggle", { "select_last": true }],
"ctrl-e": "file_finder::Toggle",
"ctrl-shift-p": "command_palette::Toggle",
+ "f1": "command_palette::Toggle",
"ctrl-shift-m": "diagnostics::Deploy",
"ctrl-shift-e": "project_panel::ToggleFocus",
+ "ctrl-shift-b": "outline_panel::ToggleFocus",
"ctrl-?": "assistant::ToggleFocus",
"ctrl-alt-s": "workspace::SaveAll",
"ctrl-k m": "language_selector::Toggle",
@@ -452,6 +383,7 @@
"ctrl-k shift-right": ["workspace::SwapPaneInDirection", "Right"],
"ctrl-k shift-up": ["workspace::SwapPaneInDirection", "Up"],
"ctrl-k shift-down": ["workspace::SwapPaneInDirection", "Down"],
+ "ctrl-shift-x": "zed::Extensions",
"alt-t": "task::Rerun",
"alt-shift-t": "task::Spawn"
}
@@ -462,13 +394,13 @@
"bindings": {
"ctrl-shift-k": "editor::DeleteLine",
"ctrl-shift-d": "editor::DuplicateLineDown",
- "ctrl-j": "editor::JoinLines",
+ "ctrl-shift-j": "editor::JoinLines",
"ctrl-alt-backspace": "editor::DeleteToPreviousSubwordStart",
"ctrl-alt-h": "editor::DeleteToPreviousSubwordStart",
"ctrl-alt-delete": "editor::DeleteToNextSubwordEnd",
"ctrl-alt-d": "editor::DeleteToNextSubwordEnd",
"ctrl-alt-left": "editor::MoveToPreviousSubwordStart",
- "ctrl-alt-b": "editor::MoveToPreviousSubwordStart",
+ // "ctrl-alt-b": "editor::MoveToPreviousSubwordStart",
"ctrl-alt-right": "editor::MoveToNextSubwordEnd",
"ctrl-alt-f": "editor::MoveToNextSubwordEnd",
"ctrl-alt-shift-left": "editor::SelectToPreviousSubwordStart",
@@ -545,12 +477,39 @@
"ctrl-enter": "assistant::InlineAssist"
}
},
+ {
+ "context": "ContextEditor > Editor",
+ "bindings": {
+ "ctrl-enter": "assistant::Assist",
+ "ctrl-s": "workspace::Save",
+ "ctrl->": "assistant::QuoteSelection",
+ "ctrl-<": "assistant::InsertIntoEditor",
+ "shift-enter": "assistant::Split",
+ "ctrl-r": "assistant::CycleMessageRole",
+ "enter": "assistant::ConfirmCommand",
+ "alt-enter": "editor::Newline"
+ }
+ },
{
"context": "ProjectSearchBar && !in_replace",
"bindings": {
"ctrl-enter": "project_search::SearchInNew"
}
},
+ {
+ "context": "OutlinePanel",
+ "bindings": {
+ "escape": "menu::Cancel",
+ "left": "outline_panel::CollapseSelectedEntry",
+ "right": "outline_panel::ExpandSelectedEntry",
+ "ctrl-alt-c": "outline_panel::CopyPath",
+ "alt-ctrl-shift-c": "outline_panel::CopyRelativePath",
+ "alt-ctrl-r": "outline_panel::RevealInFileManager",
+ "space": "outline_panel::Open",
+ "shift-down": "menu::SelectNext",
+ "shift-up": "menu::SelectPrev"
+ }
+ },
{
"context": "ProjectPanel",
"bindings": {
@@ -567,12 +526,16 @@
"alt-ctrl-shift-c": "project_panel::CopyRelativePath",
"f2": "project_panel::Rename",
"enter": "project_panel::Rename",
- "backspace": "project_panel::Trash",
- "delete": "project_panel::Trash",
+ "backspace": ["project_panel::Trash", { "skip_prompt": false }],
+ "shift-delete": ["project_panel::Delete", { "skip_prompt": false }],
+ "delete": ["project_panel::Trash", { "skip_prompt": false }],
"ctrl-backspace": ["project_panel::Delete", { "skip_prompt": false }],
"ctrl-delete": ["project_panel::Delete", { "skip_prompt": false }],
- "alt-ctrl-r": "project_panel::RevealInFinder",
- "alt-shift-f": "project_panel::NewSearchInDirectory"
+ "alt-ctrl-r": "project_panel::RevealInFileManager",
+ "alt-shift-f": "project_panel::NewSearchInDirectory",
+ "shift-down": "menu::SelectNext",
+ "shift-up": "menu::SelectPrev",
+ "escape": "menu::Cancel"
}
},
{
@@ -600,6 +563,13 @@
"tab": "channel_modal::ToggleMode"
}
},
+ {
+ "context": "Picker > Editor",
+ "bindings": {
+ "tab": "picker::ConfirmCompletion",
+ "alt-enter": ["picker::ConfirmInput", { "secondary": false }]
+ }
+ },
{
"context": "ChannelModal > Picker > Editor",
"bindings": {
@@ -627,6 +597,7 @@
"ctrl-insert": "terminal::Copy",
"shift-ctrl-v": "terminal::Paste",
"shift-insert": "terminal::Paste",
+ "ctrl-enter": "assistant::InlineAssist",
"up": ["terminal::SendKeystroke", "up"],
"pageup": ["terminal::SendKeystroke", "pageup"],
"down": ["terminal::SendKeystroke", "down"],
@@ -634,11 +605,12 @@
"escape": ["terminal::SendKeystroke", "escape"],
"enter": ["terminal::SendKeystroke", "enter"],
"ctrl-c": ["terminal::SendKeystroke", "ctrl-c"],
-
- // Some nice conveniences
- "ctrl-backspace": ["terminal::SendText", "\u0015"],
- "ctrl-right": ["terminal::SendText", "\u0005"],
- "ctrl-left": ["terminal::SendText", "\u0001"]
+ "shift-pageup": "terminal::ScrollPageUp",
+ "shift-pagedown": "terminal::ScrollPageDown",
+ "shift-up": "terminal::ScrollLineUp",
+ "shift-down": "terminal::ScrollLineDown",
+ "shift-home": "terminal::ScrollToTop",
+ "shift-end": "terminal::ScrollToBottom"
}
}
]
diff --git a/assets/keymaps/default-macos.json b/assets/keymaps/default-macos.json
index 09464c3d604ceb..1527e3e9433bbc 100644
--- a/assets/keymaps/default-macos.json
+++ b/assets/keymaps/default-macos.json
@@ -3,10 +3,14 @@
{
"bindings": {
"up": "menu::SelectPrev",
+ "shift-tab": "menu::SelectPrev",
+ "home": "menu::SelectFirst",
"pageup": "menu::SelectFirst",
"shift-pageup": "menu::SelectFirst",
"ctrl-p": "menu::SelectPrev",
"down": "menu::SelectNext",
+ "tab": "menu::SelectNext",
+ "end": "menu::SelectLast",
"pagedown": "menu::SelectLast",
"shift-pagedown": "menu::SelectFirst",
"ctrl-n": "menu::SelectNext",
@@ -61,13 +65,17 @@
"cmd-shift-z": "editor::Redo",
"up": "editor::MoveUp",
"ctrl-up": "editor::MoveToStartOfParagraph",
- "pageup": "editor::PageUp",
- "shift-pageup": "editor::MovePageUp",
+ "pageup": "editor::MovePageUp",
+ "shift-pageup": "editor::SelectPageUp",
+ "cmd-pageup": "editor::PageUp",
+ "ctrl-pageup": "editor::LineUp",
"home": "editor::MoveToBeginningOfLine",
"down": "editor::MoveDown",
"ctrl-down": "editor::MoveToEndOfParagraph",
- "pagedown": "editor::PageDown",
- "shift-pagedown": "editor::MovePageDown",
+ "pagedown": "editor::MovePageDown",
+ "shift-pagedown": "editor::SelectPageDown",
+ "cmd-pagedown": "editor::PageDown",
+ "ctrl-pagedown": "editor::LineDown",
"end": "editor::MoveToEndOfLine",
"left": "editor::MoveLeft",
"right": "editor::MoveRight",
@@ -75,7 +83,7 @@
"ctrl-n": "editor::MoveDown",
"ctrl-b": "editor::MoveLeft",
"ctrl-f": "editor::MoveRight",
- "ctrl-l": "editor::NextScreen",
+ "ctrl-l": "editor::ScrollCursorCenter",
"alt-left": "editor::MoveToPreviousWordStart",
"alt-b": "editor::MoveToPreviousWordStart",
"alt-right": "editor::MoveToNextWordEnd",
@@ -94,9 +102,9 @@
"ctrl-shift-b": "editor::SelectLeft",
"shift-right": "editor::SelectRight",
"ctrl-shift-f": "editor::SelectRight",
- "alt-shift-left": "editor::SelectToPreviousWordStart",
+ "alt-shift-left": "editor::SelectToPreviousWordStart", // cursorWordLeftSelect
"alt-shift-b": "editor::SelectToPreviousWordStart",
- "alt-shift-right": "editor::SelectToNextWordEnd",
+ "alt-shift-right": "editor::SelectToNextWordEnd", // cursorWordRightSelect
"alt-shift-f": "editor::SelectToNextWordEnd",
"ctrl-shift-up": "editor::SelectToStartOfParagraph",
"ctrl-shift-down": "editor::SelectToEndOfParagraph",
@@ -105,60 +113,21 @@
"cmd-a": "editor::SelectAll",
"cmd-l": "editor::SelectLine",
"cmd-shift-i": "editor::Format",
- "cmd-shift-left": [
- "editor::SelectToBeginningOfLine",
- {
- "stop_at_soft_wraps": true
- }
- ],
- "shift-home": [
- "editor::SelectToBeginningOfLine",
- {
- "stop_at_soft_wraps": true
- }
- ],
- "ctrl-shift-a": [
- "editor::SelectToBeginningOfLine",
- {
- "stop_at_soft_wraps": true
- }
- ],
- "cmd-shift-right": [
- "editor::SelectToEndOfLine",
- {
- "stop_at_soft_wraps": true
- }
- ],
- "shift-end": [
- "editor::SelectToEndOfLine",
- {
- "stop_at_soft_wraps": true
- }
- ],
- "ctrl-shift-e": [
- "editor::SelectToEndOfLine",
- {
- "stop_at_soft_wraps": true
- }
- ],
- "ctrl-v": [
- "editor::MovePageDown",
- {
- "center_cursor": true
- }
- ],
- "alt-v": [
- "editor::MovePageUp",
- {
- "center_cursor": true
- }
- ],
+ "cmd-shift-left": ["editor::SelectToBeginningOfLine", { "stop_at_soft_wraps": true }],
+ "shift-home": ["editor::SelectToBeginningOfLine", { "stop_at_soft_wraps": true }],
+ "ctrl-shift-a": ["editor::SelectToBeginningOfLine", { "stop_at_soft_wraps": true }],
+ "cmd-shift-right": ["editor::SelectToEndOfLine", { "stop_at_soft_wraps": true }],
+ "shift-end": ["editor::SelectToEndOfLine", { "stop_at_soft_wraps": true }],
+ "ctrl-shift-e": ["editor::SelectToEndOfLine", { "stop_at_soft_wraps": true }],
+ "ctrl-v": ["editor::MovePageDown", { "center_cursor": true }],
+ "alt-v": ["editor::MovePageUp", { "center_cursor": true }],
"ctrl-cmd-space": "editor::ShowCharacterPalette",
"cmd-;": "editor::ToggleLineNumbers",
"cmd-alt-z": "editor::RevertSelectedHunks",
"cmd-'": "editor::ToggleHunkDiff",
"cmd-\"": "editor::ExpandAllHunkDiffs",
- "cmd-alt-g b": "editor::ToggleGitBlame"
+ "cmd-alt-g b": "editor::ToggleGitBlame",
+ "cmd-i": "editor::ShowSignatureHelp"
}
},
{
@@ -167,22 +136,20 @@
"enter": "editor::Newline",
"shift-enter": "editor::Newline",
"cmd-shift-enter": "editor::NewlineAbove",
- "cmd-enter": "editor::NewlineBelow",
"alt-z": "editor::ToggleSoftWrap",
"cmd-f": "buffer_search::Deploy",
- "cmd-alt-f": [
- "buffer_search::Deploy",
- {
- "replace_enabled": true
- }
- ],
- "cmd-e": [
- "buffer_search::Deploy",
- {
- "focus": false
- }
- ],
- "cmd->": "assistant::QuoteSelection"
+ "cmd-alt-f": ["buffer_search::Deploy", { "replace_enabled": true }],
+ "cmd-alt-l": ["buffer_search::Deploy", { "selection_search_enabled": true }],
+ "cmd-e": ["buffer_search::Deploy", { "focus": false }],
+ "cmd->": "assistant::QuoteSelection",
+ "cmd-<": "assistant::InsertIntoEditor",
+ "cmd-alt-e": "editor::SelectEnclosingSymbol"
+ }
+ },
+ {
+ "context": "Editor && mode == full && !jupyter",
+ "bindings": {
+ "cmd-enter": "editor::NewlineBelow"
}
},
{
@@ -214,20 +181,32 @@
}
},
{
- "context": "AssistantPanel", // Used in the assistant crate, which we're replacing
+ "context": "AssistantPanel",
"bindings": {
"cmd-g": "search::SelectNextMatch",
- "cmd-shift-g": "search::SelectPrevMatch"
+ "cmd-shift-g": "search::SelectPrevMatch",
+ "alt-m": "assistant::ToggleModelSelector"
}
},
{
- "context": "ConversationEditor > Editor",
+ "context": "ContextEditor > Editor",
"bindings": {
"cmd-enter": "assistant::Assist",
"cmd-s": "workspace::Save",
"cmd->": "assistant::QuoteSelection",
+ "cmd-<": "assistant::InsertIntoEditor",
"shift-enter": "assistant::Split",
- "ctrl-r": "assistant::CycleMessageRole"
+ "ctrl-r": "assistant::CycleMessageRole",
+ "enter": "assistant::ConfirmCommand",
+ "alt-enter": "editor::Newline"
+ }
+ },
+ {
+ "context": "PromptLibrary",
+ "bindings": {
+ "cmd-n": "prompt_library::NewPrompt",
+ "cmd-shift-s": "prompt_library::ToggleDefaultPrompt",
+ "cmd-w": "workspace::CloseWindow"
}
},
{
@@ -239,7 +218,8 @@
"shift-enter": "search::SelectPrevMatch",
"alt-enter": "search::SelectAllMatches",
"cmd-f": "search::FocusSearch",
- "cmd-alt-f": "search::ToggleReplace"
+ "cmd-alt-f": "search::ToggleReplace",
+ "cmd-alt-l": "search::ToggleSelection"
}
},
{
@@ -260,6 +240,7 @@
"context": "ProjectSearchBar",
"bindings": {
"escape": "project_search::ToggleFocus",
+ "cmd-shift-j": "project_search::ToggleFilters",
"cmd-shift-f": "search::FocusSearch",
"cmd-shift-h": "search::ToggleReplace",
"alt-cmd-g": "search::ToggleRegex",
@@ -274,7 +255,7 @@
}
},
{
- "context": "ProjectSearchBar && in_replace",
+ "context": "ProjectSearchBar && in_replace > Editor",
"bindings": {
"enter": "search::ReplaceNext",
"cmd-enter": "search::ReplaceAll"
@@ -284,6 +265,7 @@
"context": "ProjectSearchView",
"bindings": {
"escape": "project_search::ToggleFocus",
+ "cmd-shift-j": "project_search::ToggleFilters",
"cmd-shift-h": "search::ToggleReplace",
"alt-cmd-g": "search::ToggleRegex",
"alt-cmd-x": "search::ToggleRegex"
@@ -305,6 +287,7 @@
"cmd-g": "search::SelectNextMatch",
"cmd-shift-g": "search::SelectPrevMatch",
"cmd-shift-h": "search::ToggleReplace",
+ "cmd-alt-l": "search::ToggleSelection",
"alt-enter": "search::SelectAllMatches",
"alt-cmd-c": "search::ToggleCaseSensitive",
"alt-cmd-w": "search::ToggleWholeWord",
@@ -319,49 +302,25 @@
"bindings": {
"cmd-[": "editor::Outdent",
"cmd-]": "editor::Indent",
- "cmd-alt-up": "editor::AddSelectionAbove",
+ "cmd-alt-up": "editor::AddSelectionAbove", // Insert cursor above
"cmd-ctrl-p": "editor::AddSelectionAbove",
- "cmd-alt-down": "editor::AddSelectionBelow",
+ "cmd-alt-down": "editor::AddSelectionBelow", // Insert cursor below
"cmd-ctrl-n": "editor::AddSelectionBelow",
"cmd-shift-k": "editor::DeleteLine",
"alt-up": "editor::MoveLineUp",
"alt-down": "editor::MoveLineDown",
"alt-shift-up": "editor::DuplicateLineUp",
"alt-shift-down": "editor::DuplicateLineDown",
- "ctrl-shift-right": "editor::SelectLargerSyntaxNode",
- "ctrl-shift-left": "editor::SelectSmallerSyntaxNode",
- "cmd-d": [
- "editor::SelectNext",
- {
- "replace_newest": false
- }
- ],
- "cmd-shift-l": "editor::SelectAllMatches",
- "ctrl-cmd-d": [
- "editor::SelectPrevious",
- {
- "replace_newest": false
- }
- ],
- "cmd-k cmd-d": [
- "editor::SelectNext",
- {
- "replace_newest": true
- }
- ],
- "cmd-k ctrl-cmd-d": [
- "editor::SelectPrevious",
- {
- "replace_newest": true
- }
- ],
+ "ctrl-shift-right": "editor::SelectLargerSyntaxNode", // Expand Selection
+ "ctrl-shift-left": "editor::SelectSmallerSyntaxNode", // Shrink Selection
+ "cmd-d": ["editor::SelectNext", { "replace_newest": false }], // Add selection to Next Find Match
+ "cmd-shift-l": "editor::SelectAllMatches", // Select all occurrences of current selection
+ "cmd-f2": "editor::SelectAllMatches", // Select all occurrences of current word
+ "ctrl-cmd-d": ["editor::SelectPrevious", { "replace_newest": false }],
+ "cmd-k cmd-d": ["editor::SelectNext", { "replace_newest": true }],
+ "cmd-k ctrl-cmd-d": ["editor::SelectPrevious", { "replace_newest": true }],
"cmd-k cmd-i": "editor::Hover",
- "cmd-/": [
- "editor::ToggleComments",
- {
- "advance_downwards": false
- }
- ],
+ "cmd-/": ["editor::ToggleComments", { "advance_downwards": false }],
"cmd-u": "editor::UndoSelection",
"cmd-shift-u": "editor::RedoSelection",
"f8": "editor::GoToDiagnostic",
@@ -374,11 +333,17 @@
"alt-cmd-f12": "editor::GoToTypeDefinitionSplit",
"alt-shift-f12": "editor::FindAllReferences",
"ctrl-m": "editor::MoveToEnclosingBracket",
+ "cmd-shift-\\": "editor::MoveToEnclosingBracket",
"alt-cmd-[": "editor::Fold",
"alt-cmd-]": "editor::UnfoldLines",
"ctrl-space": "editor::ShowCompletions",
"cmd-.": "editor::ToggleCodeActions",
- "alt-cmd-r": "editor::RevealInFinder",
+ "alt-cmd-r": "editor::RevealInFileManager",
+ "cmd-k r": "editor::RevealInFileManager",
+ "cmd-k p": "editor::CopyPath",
+ "cmd-\\": "pane::SplitRight",
+ "cmd-k v": "markdown::OpenPreviewToTheSide",
+ "cmd-shift-v": "markdown::OpenPreview",
"ctrl-cmd-c": "editor::DisplayCursorNames"
}
},
@@ -403,7 +368,7 @@
"ctrl-9": ["pane::ActivateItem", 8],
"ctrl-0": "pane::ActivateLastItem",
"ctrl--": "pane::GoBack",
- "ctrl-_": "pane::GoForward",
+ "ctrl-shift--": "pane::GoForward",
"cmd-shift-t": "pane::ReopenClosedItem",
"cmd-shift-f": "project_search::ToggleFocus"
}
@@ -412,12 +377,7 @@
"context": "Workspace",
"bindings": {
// Change the default action on `menu::Confirm` by setting the parameter
- // "alt-cmd-o": [
- // "projects::OpenRecent",
- // {
- // "create_new_window": true
- // }
- // ]
+ // "alt-cmd-o": ["projects::OpenRecent", {"create_new_window": true }],
"alt-cmd-o": "projects::OpenRecent",
"alt-cmd-b": "branches::OpenRecent",
"ctrl-~": "workspace::NewTerminal",
@@ -441,12 +401,7 @@
"cmd-j": "workspace::ToggleBottomDock",
"alt-cmd-y": "workspace::CloseAllDocks",
"cmd-shift-f": "pane::DeploySearch",
- "cmd-shift-h": [
- "pane::DeploySearch",
- {
- "replace_enabled": true
- }
- ],
+ "cmd-shift-h": ["pane::DeploySearch", { "replace_enabled": true }],
"cmd-k cmd-s": "zed::OpenKeymap",
"cmd-k cmd-t": "theme_selector::Toggle",
"cmd-t": "project_symbols::Toggle",
@@ -456,6 +411,7 @@
"cmd-shift-p": "command_palette::Toggle",
"cmd-shift-m": "diagnostics::Deploy",
"cmd-shift-e": "project_panel::ToggleFocus",
+ "cmd-shift-b": "outline_panel::ToggleFocus",
"cmd-?": "assistant::ToggleFocus",
"cmd-alt-s": "workspace::SaveAll",
"cmd-k m": "language_selector::Toggle",
@@ -468,6 +424,7 @@
"cmd-k shift-right": ["workspace::SwapPaneInDirection", "Right"],
"cmd-k shift-up": ["workspace::SwapPaneInDirection", "Up"],
"cmd-k shift-down": ["workspace::SwapPaneInDirection", "Down"],
+ "cmd-shift-x": "zed::Extensions",
"alt-t": "task::Rerun",
"alt-shift-t": "task::Spawn"
}
@@ -565,12 +522,27 @@
"cmd-enter": "project_search::SearchInNew"
}
},
+ {
+ "context": "OutlinePanel",
+ "bindings": {
+ "escape": "menu::Cancel",
+ "left": "outline_panel::CollapseSelectedEntry",
+ "right": "outline_panel::ExpandSelectedEntry",
+ "cmd-alt-c": "outline_panel::CopyPath",
+ "alt-cmd-shift-c": "outline_panel::CopyRelativePath",
+ "alt-cmd-r": "outline_panel::RevealInFileManager",
+ "space": "outline_panel::Open",
+ "shift-down": "menu::SelectNext",
+ "shift-up": "menu::SelectPrev"
+ }
+ },
{
"context": "ProjectPanel",
"bindings": {
"left": "project_panel::CollapseSelectedEntry",
"right": "project_panel::ExpandSelectedEntry",
"cmd-n": "project_panel::NewFile",
+ "cmd-d": "project_panel::Duplicate",
"alt-cmd-n": "project_panel::NewDirectory",
"cmd-x": "project_panel::Cut",
"cmd-c": "project_panel::Copy",
@@ -578,12 +550,18 @@
"cmd-alt-c": "project_panel::CopyPath",
"alt-cmd-shift-c": "project_panel::CopyRelativePath",
"enter": "project_panel::Rename",
+ "f2": "project_panel::Rename",
"backspace": ["project_panel::Trash", { "skip_prompt": false }],
"delete": ["project_panel::Trash", { "skip_prompt": false }],
- "cmd-backspace": ["project_panel::Delete", { "skip_prompt": false }],
+ "cmd-backspace": ["project_panel::Trash", { "skip_prompt": true }],
"cmd-delete": ["project_panel::Delete", { "skip_prompt": false }],
- "alt-cmd-r": "project_panel::RevealInFinder",
- "alt-shift-f": "project_panel::NewSearchInDirectory"
+ "alt-cmd-r": "project_panel::RevealInFileManager",
+ "cmd-alt-backspace": ["project_panel::Delete", { "skip_prompt": false }],
+
+ "alt-shift-f": "project_panel::NewSearchInDirectory",
+ "shift-down": "menu::SelectNext",
+ "shift-up": "menu::SelectPrev",
+ "escape": "menu::Cancel"
}
},
{
@@ -592,6 +570,12 @@
"space": "project_panel::Open"
}
},
+ {
+ "context": "Editor && jupyter && !ContextEditor",
+ "bindings": {
+ "cmd-enter": "repl::Run"
+ }
+ },
{
"context": "CollabPanel && not_editing",
"bindings": {
@@ -611,6 +595,14 @@
"tab": "channel_modal::ToggleMode"
}
},
+ {
+ "context": "Picker > Editor",
+ "bindings": {
+ "tab": "picker::ConfirmCompletion",
+ "alt-enter": ["picker::ConfirmInput", { "secondary": false }],
+ "cmd-alt-enter": ["picker::ConfirmInput", { "secondary": true }]
+ }
+ },
{
"context": "ChannelModal > Picker > Editor",
"bindings": {
@@ -630,14 +622,6 @@
"ctrl-backspace": "tab_switcher::CloseSelectedItem"
}
},
- {
- "context": "Picker",
- "bindings": {
- "alt-e": "picker::UseSelectedQuery",
- "alt-enter": ["picker::ConfirmInput", { "secondary": false }],
- "cmd-alt-enter": ["picker::ConfirmInput", { "secondary": true }]
- }
- },
{
"context": "Terminal",
"bindings": {
@@ -645,6 +629,7 @@
"cmd-c": "terminal::Copy",
"cmd-v": "terminal::Paste",
"cmd-k": "terminal::Clear",
+ "ctrl-enter": "assistant::InlineAssist",
// Some nice conveniences
"cmd-backspace": ["terminal::SendText", "\u0015"],
"cmd-right": ["terminal::SendText", "\u0005"],
@@ -660,7 +645,17 @@
"pagedown": ["terminal::SendKeystroke", "pagedown"],
"escape": ["terminal::SendKeystroke", "escape"],
"enter": ["terminal::SendKeystroke", "enter"],
- "ctrl-c": ["terminal::SendKeystroke", "ctrl-c"]
+ "ctrl-c": ["terminal::SendKeystroke", "ctrl-c"],
+ "cmd-up": "terminal::ScrollPageUp",
+ "cmd-down": "terminal::ScrollPageDown",
+ "shift-pageup": "terminal::ScrollPageUp",
+ "shift-pagedown": "terminal::ScrollPageDown",
+ "shift-up": "terminal::ScrollLineUp",
+ "shift-down": "terminal::ScrollLineDown",
+ "cmd-home": "terminal::ScrollToTop",
+ "cmd-end": "terminal::ScrollToBottom",
+ "shift-home": "terminal::ScrollToTop",
+ "shift-end": "terminal::ScrollToBottom"
}
}
]
diff --git a/assets/keymaps/initial.json b/assets/keymaps/initial.json
new file mode 100644
index 00000000000000..07af2894dee8af
--- /dev/null
+++ b/assets/keymaps/initial.json
@@ -0,0 +1,21 @@
+// Zed keymap
+//
+// For information on binding keys, see the Zed
+// documentation: https://zed.dev/docs/key-bindings
+//
+// To see the default key bindings run `zed: Open Default Keymap`
+// from the command palette.
+[
+ {
+ "context": "Workspace",
+ "bindings": {
+ // "shift shift": "file_finder::Toggle"
+ }
+ },
+ {
+ "context": "Editor",
+ "bindings": {
+ // "j k": ["workspace::SendKeystrokes", "escape"]
+ }
+ }
+]
diff --git a/assets/keymaps/linux/atom.json b/assets/keymaps/linux/atom.json
new file mode 100644
index 00000000000000..05caf32bcb9bff
--- /dev/null
+++ b/assets/keymaps/linux/atom.json
@@ -0,0 +1,94 @@
+// Default Keymap (Atom) for Zed on Linux
+[
+ {
+ "bindings": {
+ "ctrl-shift-f5": "workspace::Reload", // window:reload
+ "ctrl-k ctrl-n": "workspace::ActivatePreviousPane", // window:focus-next-pane
+ "ctrl-k ctrl-p": "workspace::ActivateNextPane" // window:focus-previous-pane
+ }
+ },
+ {
+ "context": "Editor",
+ "bindings": {
+ "ctrl-shift-l": "language_selector::Toggle", // grammar-selector:show
+ "ctrl-|": "pane::RevealInProjectPanel", // tree-view:reveal-active-file
+ "ctrl-b": "editor::GoToDefinition", // fuzzy-finder:toggle-buffer-finder
+ "ctrl-alt-b": "editor::GoToDefinitionSplit", // N/A: From JetBrains
+ "ctrl-<": "editor::ScrollCursorCenter", // editor:scroll-to-cursor
+ "f3": ["editor::SelectNext", { "replace_newest": true }], // find-and-replace:find-next
+ "shift-f3": ["editor::SelectPrevious", { "replace_newest": true }], //find-and-replace:find-previous
+ "alt-shift-down": "editor::AddSelectionBelow", // editor:add-selection-below
+ "alt-shift-up": "editor::AddSelectionAbove", // editor:add-selection-above
+ "ctrl-k ctrl-u": "editor::ConvertToUpperCase", // editor:upper-case
+ "ctrl-k ctrl-l": "editor::ConvertToLowerCase", // editor:lower-case
+ "ctrl-j": "editor::JoinLines", // editor:join-lines
+ "ctrl-shift-d": "editor::DuplicateLineDown", // editor:duplicate-lines
+ "ctrl-up": "editor::MoveLineUp", // editor:move-line-up
+ "ctrl-down": "editor::MoveLineDown", // editor:move-line-down
+ "ctrl-\\": "workspace::ToggleLeftDock", // tree-view:toggle
+ "ctrl-shift-m": "markdown::OpenPreviewToTheSide" // markdown-preview:toggle
+ }
+ },
+ {
+ "context": "Editor && mode == full",
+ "bindings": {
+ "ctrl-r": "outline::Toggle" // symbols-view:toggle-project-symbols
+ }
+ },
+ {
+ "context": "BufferSearchBar",
+ "bindings": {
+ "ctrl-f3": "search::SelectNextMatch", // find-and-replace:find-next-selected
+ "ctrl-shift-f3": "search::SelectPrevMatch" // find-and-replace:find-previous-selected
+ }
+ },
+ {
+ "context": "Workspace",
+ "bindings": {
+ "ctrl-\\": "workspace::ToggleLeftDock", // tree-view:toggle
+ "ctrl-k ctrl-b": "workspace::ToggleLeftDock", // tree-view:toggle
+ "ctrl-t": "file_finder::Toggle", // fuzzy-finder:toggle-file-finder
+ "ctrl-r": "project_symbols::Toggle" // symbols-view:toggle-project-symbols
+ }
+ },
+ {
+ "context": "Pane",
+ "bindings": {
+ // "ctrl-0": "project_panel::ToggleFocus", // tree-view:toggle-focus
+ "ctrl-1": ["pane::ActivateItem", 0], // tree-view:open-selected-entry-in-pane-1
+ "ctrl-2": ["pane::ActivateItem", 1], // tree-view:open-selected-entry-in-pane-2
+ "ctrl-3": ["pane::ActivateItem", 2], // tree-view:open-selected-entry-in-pane-3
+ "ctrl-4": ["pane::ActivateItem", 3], // tree-view:open-selected-entry-in-pane-4
+ "ctrl-5": ["pane::ActivateItem", 4], // tree-view:open-selected-entry-in-pane-5
+ "ctrl-6": ["pane::ActivateItem", 5], // tree-view:open-selected-entry-in-pane-6
+ "ctrl-7": ["pane::ActivateItem", 6], // tree-view:open-selected-entry-in-pane-7
+ "ctrl-8": ["pane::ActivateItem", 7], // tree-view:open-selected-entry-in-pane-8
+ "ctrl-9": ["pane::ActivateItem", 8] // tree-view:open-selected-entry-in-pane-9
+ }
+ },
+ {
+ "context": "ProjectPanel",
+ "bindings": {
+ "f2": "project_panel::Rename", // tree-view:rename
+ "backspace": ["project_panel::Trash", { "skip_prompt": false }],
+ "ctrl-x": "project_panel::Cut", // tree-view:cut
+ "ctrl-c": "project_panel::Copy", // tree-view:copy
+ "ctrl-v": "project_panel::Paste" // tree-view:paste
+ }
+ },
+ {
+ "context": "ProjectPanel && not_editing",
+ "bindings": {
+ "ctrl-shift-c": "project_panel::CopyPath", // tree-view:copy-full-path
+ "ctrl-[": "project_panel::CollapseSelectedEntry", // tree-view:collapse-directory
+ "ctrl-b": "project_panel::CollapseSelectedEntry", // tree-view:collapse-directory
+ "ctrl-]": "project_panel::ExpandSelectedEntry", // tree-view:expand-item
+ "ctrl-f": "project_panel::ExpandSelectedEntry", // tree-view:expand-item
+ "a": "project_panel::NewFile", // tree-view:add-file
+ "d": "project_panel::Duplicate", // tree-view:duplicate
+ "home": "menu::SelectFirst", // core:move-to-top
+ "end": "menu::SelectLast", // core:move-to-bottom
+ "shift-a": "project_panel::NewDirectory" // tree-view:add-folder
+ }
+ }
+]
diff --git a/assets/keymaps/linux/jetbrains.json b/assets/keymaps/linux/jetbrains.json
new file mode 100644
index 00000000000000..55ba63d8f3aa23
--- /dev/null
+++ b/assets/keymaps/linux/jetbrains.json
@@ -0,0 +1,91 @@
+[
+ {
+ "bindings": {
+ "ctrl-shift-[": "pane::ActivatePrevItem",
+ "ctrl-shift-]": "pane::ActivateNextItem"
+ }
+ },
+ {
+ "context": "Editor",
+ "bindings": {
+ "ctrl->": "zed::IncreaseBufferFontSize",
+ "ctrl-<": "zed::DecreaseBufferFontSize",
+ "ctrl-shift-j": "editor::JoinLines",
+ "ctrl-d": "editor::DuplicateLineDown",
+ "ctrl-y": "editor::DeleteLine",
+ "ctrl-m": "editor::ScrollCursorCenter",
+ "ctrl-pagedown": "editor::MovePageDown",
+ "ctrl-pageup": "editor::MovePageUp",
+ // "ctrl-alt-shift-b": "editor::SelectToPreviousWordStart",
+ "ctrl-alt-enter": "editor::NewlineAbove",
+ "shift-enter": "editor::NewlineBelow",
+ // "ctrl--": "editor::Fold", // TODO: `ctrl-numpad--` (numpad not implemented)
+ // "ctrl-+": "editor::UnfoldLines", // TODO: `ctrl-numpad+` (numpad not implemented)
+ "alt-shift-g": "editor::SplitSelectionIntoLines",
+ "alt-j": ["editor::SelectNext", { "replace_newest": false }],
+ "alt-shift-j": ["editor::SelectPrevious", { "replace_newest": false }],
+ "ctrl-/": ["editor::ToggleComments", { "advance_downwards": true }],
+ "alt-up": "editor::SelectLargerSyntaxNode",
+ "alt-down": "editor::SelectSmallerSyntaxNode",
+ "shift-alt-up": "editor::MoveLineUp",
+ "shift-alt-down": "editor::MoveLineDown",
+ "ctrl-alt-l": "editor::Format",
+ "shift-f6": "editor::Rename",
+ "ctrl-alt-left": "pane::GoBack",
+ "ctrl-alt-right": "pane::GoForward",
+ "alt-f7": "editor::FindAllReferences",
+ "ctrl-alt-f7": "editor::FindAllReferences",
+ // "ctrl-b": "editor::GoToDefinition", // Conflicts with workspace::ToggleLeftDock
+ // "ctrl-alt-b": "editor::GoToDefinitionSplit", // Conflicts with workspace::ToggleLeftDock
+ "ctrl-shift-b": "editor::GoToTypeDefinition",
+ "ctrl-alt-shift-b": "editor::GoToTypeDefinitionSplit",
+ "f2": "editor::GoToDiagnostic",
+ "shift-f2": "editor::GoToPrevDiagnostic",
+ "ctrl-alt-shift-down": "editor::GoToHunk",
+ "ctrl-alt-shift-up": "editor::GoToPrevHunk",
+ "ctrl-home": "editor::MoveToBeginning",
+ "ctrl-end": "editor::MoveToEnd",
+ "ctrl-shift-home": "editor::SelectToBeginning",
+ "ctrl-shift-end": "editor::SelectToEnd"
+ }
+ },
+ {
+ "context": "Editor && mode == full",
+ "bindings": {
+ "ctrl-f12": "outline::Toggle",
+ "alt-7": "outline::Toggle",
+ "ctrl-shift-n": "file_finder::Toggle",
+ "ctrl-g": "go_to_line::Toggle",
+ "alt-enter": "editor::ToggleCodeActions"
+ }
+ },
+ {
+ "context": "Workspace",
+ "bindings": {
+ "ctrl-shift-n": "file_finder::Toggle",
+ "ctrl-shift-a": "command_palette::Toggle",
+ "shift shift": "command_palette::Toggle",
+ "ctrl-alt-shift-n": "project_symbols::Toggle",
+ "alt-1": "workspace::ToggleLeftDock",
+ "ctrl-e": "tab_switcher::Toggle",
+ "alt-6": "diagnostics::Deploy"
+ }
+ },
+ {
+ "context": "Pane",
+ "bindings": {
+ "ctrl-alt-left": "pane::GoBack",
+ "ctrl-alt-right": "pane::GoForward"
+ }
+ },
+ {
+ "context": "ProjectPanel",
+ "bindings": {
+ "enter": "project_panel::Open",
+ "backspace": ["project_panel::Trash", { "skip_prompt": false }],
+ "delete": ["project_panel::Trash", { "skip_prompt": false }],
+ "shift-delete": ["project_panel::Delete", { "skip_prompt": false }],
+ "shift-f6": "project_panel::Rename"
+ }
+ }
+]
diff --git a/assets/keymaps/linux/sublime_text.json b/assets/keymaps/linux/sublime_text.json
new file mode 100644
index 00000000000000..7e9b41615aa100
--- /dev/null
+++ b/assets/keymaps/linux/sublime_text.json
@@ -0,0 +1,55 @@
+[
+ {
+ "bindings": {
+ "ctrl-shift-[": "pane::ActivatePrevItem",
+ "ctrl-shift-]": "pane::ActivateNextItem",
+ "ctrl-pageup": "pane::ActivatePrevItem",
+ "ctrl-pagedown": "pane::ActivateNextItem",
+ "ctrl-tab": "pane::ActivateNextItem",
+ "ctrl-shift-tab": "pane::ActivatePrevItem"
+ }
+ },
+ {
+ "context": "Editor",
+ "bindings": {
+ "ctrl-shift-up": "editor::AddSelectionAbove",
+ "ctrl-shift-down": "editor::AddSelectionBelow",
+ "ctrl-shift-m": "editor::SelectLargerSyntaxNode",
+ "ctrl-shift-l": "editor::SplitSelectionIntoLines",
+ "ctrl-shift-a": "editor::SelectLargerSyntaxNode",
+ "ctrl-shift-d": "editor::DuplicateLineDown",
+ "f12": "editor::GoToDefinition",
+ "ctrl-f12": "editor::GoToDefinitionSplit",
+ "shift-f12": "editor::FindAllReferences",
+ "ctrl-shift-f12": "editor::FindAllReferences",
+ "ctrl-.": "editor::GoToHunk",
+ "ctrl-,": "editor::GoToPrevHunk",
+ "ctrl-k ctrl-u": "editor::ConvertToUpperCase",
+ "ctrl-k ctrl-l": "editor::ConvertToLowerCase",
+ "shift-alt-m": "markdown::OpenPreviewToTheSide",
+ "ctrl-backspace": "editor::DeleteToPreviousWordStart",
+ "ctrl-delete": "editor::DeleteToNextWordEnd"
+ }
+ },
+ {
+ "context": "Editor && mode == full",
+ "bindings": {
+ "ctrl-r": "outline::Toggle"
+ }
+ },
+ {
+ "context": "Pane",
+ "bindings": {
+ "f4": "search::SelectNextMatch",
+ "shift-f4": "search::SelectPrevMatch"
+ }
+ },
+ {
+ "context": "Workspace",
+ "bindings": {
+ "ctrl-k ctrl-b": "workspace::ToggleLeftDock",
+ // "ctrl-0": "project_panel::ToggleFocus", // normally resets zoom
+ "shift-ctrl-r": "project_symbols::Toggle"
+ }
+ }
+]
diff --git a/assets/keymaps/atom.json b/assets/keymaps/macos/atom.json
similarity index 57%
rename from assets/keymaps/atom.json
rename to assets/keymaps/macos/atom.json
index 91844295b1c919..50e99927db361e 100644
--- a/assets/keymaps/atom.json
+++ b/assets/keymaps/macos/atom.json
@@ -1,6 +1,8 @@
+// Default Keymap (Atom) for Zed on MacOS
[
{
"bindings": {
+ "ctrl-alt-cmd-l": "workspace::Reload",
"cmd-k cmd-p": "workspace::ActivatePreviousPane",
"cmd-k cmd-n": "workspace::ActivateNextPane"
}
@@ -8,24 +10,24 @@
{
"context": "Editor",
"bindings": {
+ "ctrl-shift-l": "language_selector::Toggle",
+ "cmd-|": "pane::RevealInProjectPanel",
"cmd-b": "editor::GoToDefinition",
"alt-cmd-b": "editor::GoToDefinitionSplit",
"cmd-<": "editor::ScrollCursorCenter",
- "cmd-g": [
- "editor::SelectNext",
- {
- "replace_newest": true
- }
- ],
- "ctrl-cmd-g": [
- "editor::SelectPrevious",
- {
- "replace_newest": true
- }
- ],
+ "cmd-g": ["editor::SelectNext", { "replace_newest": true }],
+ "cmd-shift-g": ["editor::SelectPrevious", { "replace_newest": true }],
"ctrl-shift-down": "editor::AddSelectionBelow",
"ctrl-shift-up": "editor::AddSelectionAbove",
- "cmd-shift-backspace": "editor::DeleteToBeginningOfLine"
+ "cmd-shift-backspace": "editor::DeleteToBeginningOfLine",
+ "cmd-k cmd-u": "editor::ConvertToUpperCase",
+ "cmd-k cmd-l": "editor::ConvertToLowerCase",
+ "alt-enter": "editor::Newline",
+ "cmd-shift-d": "editor::DuplicateLineDown",
+ "ctrl-cmd-up": "editor::MoveLineUp",
+ "ctrl-cmd-down": "editor::MoveLineDown",
+ "cmd-\\": "workspace::ToggleLeftDock",
+ "ctrl-shift-m": "markdown::OpenPreviewToTheSide"
}
},
{
@@ -69,12 +71,26 @@
{
"context": "ProjectPanel",
"bindings": {
+ "f2": "project_panel::Rename",
+ "backspace": ["project_panel::Trash", { "skip_prompt": false }],
+ "cmd-x": "project_panel::Cut",
+ "cmd-c": "project_panel::Copy",
+ "cmd-v": "project_panel::Paste"
+ }
+ },
+ {
+ "context": "ProjectPanel && not_editing",
+ "bindings": {
+ "ctrl-shift-c": "project_panel::CopyPath",
"ctrl-[": "project_panel::CollapseSelectedEntry",
"ctrl-b": "project_panel::CollapseSelectedEntry",
- "alt-b": "project_panel::CollapseSelectedEntry",
"ctrl-]": "project_panel::ExpandSelectedEntry",
"ctrl-f": "project_panel::ExpandSelectedEntry",
- "ctrl-shift-c": "project_panel::CopyPath"
+ "a": "project_panel::NewFile",
+ "d": "project_panel::Duplicate",
+ "home": "menu::SelectFirst",
+ "end": "menu::SelectLast",
+ "shift-a": "project_panel::NewDirectory"
}
}
]
diff --git a/assets/keymaps/jetbrains.json b/assets/keymaps/macos/jetbrains.json
similarity index 80%
rename from assets/keymaps/jetbrains.json
rename to assets/keymaps/macos/jetbrains.json
index c099d60578827e..1d5f1181f48a6b 100644
--- a/assets/keymaps/jetbrains.json
+++ b/assets/keymaps/macos/jetbrains.json
@@ -21,24 +21,9 @@
"cmd--": "editor::Fold",
"cmd-+": "editor::UnfoldLines",
"alt-shift-g": "editor::SplitSelectionIntoLines",
- "ctrl-g": [
- "editor::SelectNext",
- {
- "replace_newest": false
- }
- ],
- "ctrl-cmd-g": [
- "editor::SelectPrevious",
- {
- "replace_newest": false
- }
- ],
- "cmd-/": [
- "editor::ToggleComments",
- {
- "advance_downwards": true
- }
- ],
+ "ctrl-g": ["editor::SelectNext", { "replace_newest": false }],
+ "ctrl-cmd-g": ["editor::SelectPrevious", { "replace_newest": false }],
+ "cmd-/": ["editor::ToggleComments", { "advance_downwards": true }],
"alt-up": "editor::SelectLargerSyntaxNode",
"alt-down": "editor::SelectSmallerSyntaxNode",
"shift-alt-up": "editor::MoveLineUp",
@@ -54,7 +39,7 @@
"cmd-shift-b": "editor::GoToTypeDefinition",
"cmd-alt-shift-b": "editor::GoToTypeDefinitionSplit",
"f2": "editor::GoToDiagnostic",
- "cmd-f2": "editor::GoToPrevDiagnostic",
+ "shift-f2": "editor::GoToPrevDiagnostic",
"ctrl-alt-shift-down": "editor::GoToHunk",
"ctrl-alt-shift-up": "editor::GoToPrevHunk",
"cmd-home": "editor::MoveToBeginning",
@@ -78,6 +63,7 @@
"bindings": {
"cmd-shift-o": "file_finder::Toggle",
"cmd-shift-a": "command_palette::Toggle",
+ "shift shift": "command_palette::Toggle",
"cmd-alt-o": "project_symbols::Toggle",
"cmd-1": "workspace::ToggleLeftDock",
"cmd-6": "diagnostics::Deploy"
@@ -94,6 +80,10 @@
"context": "ProjectPanel",
"bindings": {
"enter": "project_panel::Open",
+ "cmd-backspace": ["project_panel::Trash", { "skip_prompt": false }],
+ "backspace": ["project_panel::Trash", { "skip_prompt": false }],
+ "delete": ["project_panel::Trash", { "skip_prompt": false }],
+ "shift-delete": ["project_panel::Delete", { "skip_prompt": false }],
"shift-f6": "project_panel::Rename"
}
}
diff --git a/assets/keymaps/sublime_text.json b/assets/keymaps/macos/sublime_text.json
similarity index 77%
rename from assets/keymaps/sublime_text.json
rename to assets/keymaps/macos/sublime_text.json
index dc1fc1c3ef0286..06de3bfd1eba90 100644
--- a/assets/keymaps/sublime_text.json
+++ b/assets/keymaps/macos/sublime_text.json
@@ -3,11 +3,10 @@
"bindings": {
"cmd-shift-[": "pane::ActivatePrevItem",
"cmd-shift-]": "pane::ActivateNextItem",
- "ctrl-pagedown": "pane::ActivatePrevItem",
- "ctrl-pageup": "pane::ActivateNextItem",
- "ctrl-shift-tab": "pane::ActivateNextItem",
- "ctrl-tab": "pane::ActivatePrevItem",
- "cmd-+": "zed::IncreaseBufferFontSize"
+ "ctrl-pageup": "pane::ActivatePrevItem",
+ "ctrl-pagedown": "pane::ActivateNextItem",
+ "ctrl-tab": "pane::ActivateNextItem",
+ "ctrl-shift-tab": "pane::ActivatePrevItem"
}
},
{
@@ -19,12 +18,17 @@
"ctrl-shift-m": "editor::SelectLargerSyntaxNode",
"cmd-shift-l": "editor::SplitSelectionIntoLines",
"cmd-shift-a": "editor::SelectLargerSyntaxNode",
+ "cmd-shift-d": "editor::DuplicateLineDown",
"shift-f12": "editor::FindAllReferences",
"alt-cmd-down": "editor::GoToDefinition",
"ctrl-alt-cmd-down": "editor::GoToDefinitionSplit",
"alt-shift-cmd-down": "editor::FindAllReferences",
"ctrl-.": "editor::GoToHunk",
"ctrl-,": "editor::GoToPrevHunk",
+ "cmd-k cmd-u": "editor::ConvertToUpperCase",
+ "cmd-k cmd-l": "editor::ConvertToLowerCase",
+ "cmd-shift-j": "editor::JoinLines",
+ "shift-alt-m": "markdown::OpenPreviewToTheSide",
"ctrl-backspace": "editor::DeleteToPreviousWordStart",
"ctrl-delete": "editor::DeleteToNextWordEnd"
}
diff --git a/assets/keymaps/textmate.json b/assets/keymaps/macos/textmate.json
similarity index 75%
rename from assets/keymaps/textmate.json
rename to assets/keymaps/macos/textmate.json
index c3947dc3ce3c94..5395e9d940599f 100644
--- a/assets/keymaps/textmate.json
+++ b/assets/keymaps/macos/textmate.json
@@ -22,34 +22,14 @@
"alt-shift-delete": "editor::DeleteToNextWordEnd",
"ctrl-backspace": "editor::DeleteToPreviousSubwordStart",
"ctrl-delete": "editor::DeleteToNextSubwordEnd",
- "alt-left": [
- "editor::MoveToPreviousWordStart",
- {
- "stop_at_soft_wraps": true
- }
- ],
- "alt-right": [
- "editor::MoveToNextWordEnd",
- {
- "stop_at_soft_wraps": true
- }
- ],
+ "alt-left": ["editor::MoveToPreviousWordStart", { "stop_at_soft_wraps": true }],
+ "alt-right": ["editor::MoveToNextWordEnd", { "stop_at_soft_wraps": true }],
"ctrl-left": "editor::MoveToPreviousSubwordStart",
"ctrl-right": "editor::MoveToNextSubwordEnd",
"cmd-shift-left": "editor::SelectToBeginningOfLine",
"cmd-shift-right": "editor::SelectToEndOfLine",
- "alt-shift-left": [
- "editor::SelectToPreviousWordStart",
- {
- "stop_at_soft_wraps": true
- }
- ],
- "alt-shift-right": [
- "editor::SelectToNextWordEnd",
- {
- "stop_at_soft_wraps": true
- }
- ],
+ "alt-shift-left": ["editor::SelectToPreviousWordStart", { "stop_at_soft_wraps": true }],
+ "alt-shift-right": ["editor::SelectToNextWordEnd", { "stop_at_soft_wraps": true }],
"ctrl-shift-left": "editor::SelectToPreviousSubwordStart",
"ctrl-shift-right": "editor::SelectToNextSubwordEnd",
"ctrl-w": "editor::SelectNext",
@@ -87,7 +67,15 @@
},
{
"context": "ProjectPanel",
- "bindings": {}
+ "bindings": {
+ "cmd-backspace": ["project_panel::Trash", { "skip_prompt": true }],
+ "cmd-d": "project_panel::Duplicate",
+ "cmd-n": "project_panel::NewFolder",
+ "return": "project_panel::Rename",
+ "cmd-c": "project_panel::Copy",
+ "cmd-v": "project_panel::Paste",
+ "cmd-alt-c": "project_panel::CopyPath"
+ }
},
{
"context": "Dock",
diff --git a/assets/keymaps/vim.json b/assets/keymaps/vim.json
index 045beffeced4a1..d6e61893b7abff 100644
--- a/assets/keymaps/vim.json
+++ b/assets/keymaps/vim.json
@@ -1,36 +1,20 @@
[
{
- "context": "ProjectPanel || Editor",
+ "context": "VimControl && !menu",
"bindings": {
- "ctrl-6": "pane::AlternateFile"
- }
- },
- {
- "context": "Editor && VimControl && !VimWaiting && !menu",
- "bindings": {
- "i": [
- "vim::PushOperator",
- {
- "Object": {
- "around": false
- }
- }
- ],
- "a": [
- "vim::PushOperator",
- {
- "Object": {
- "around": true
- }
- }
- ],
+ "i": ["vim::PushOperator", { "Object": { "around": false } }],
+ "a": ["vim::PushOperator", { "Object": { "around": true } }],
":": "command_palette::Toggle",
"h": "vim::Left",
"left": "vim::Left",
"backspace": "vim::Backspace",
"j": "vim::Down",
"down": "vim::Down",
+ "ctrl-j": "vim::Down",
"enter": "vim::NextLineStart",
+ "ctrl-m": "vim::NextLineStart",
+ "+": "vim::NextLineStart",
+ "-": "vim::PreviousLineStart",
"tab": "vim::Tab",
"shift-tab": "vim::Tab",
"k": "vim::Up",
@@ -39,6 +23,7 @@
"right": "vim::Right",
"space": "vim::Space",
"$": "vim::EndOfLine",
+ "end": "vim::EndOfLine",
"^": "vim::FirstNonWhitespace",
"_": "vim::StartOfLineDownward",
"g _": "vim::EndOfLineDownward",
@@ -46,83 +31,32 @@
"{": "vim::StartOfParagraph",
"}": "vim::EndOfParagraph",
"|": "vim::GoToColumn",
-
// Word motions
"w": "vim::NextWordStart",
"e": "vim::NextWordEnd",
"b": "vim::PreviousWordStart",
"g e": "vim::PreviousWordEnd",
-
// Subword motions
// "w": "vim::NextSubwordStart",
// "b": "vim::PreviousSubwordStart",
// "e": "vim::NextSubwordEnd",
// "g e": "vim::PreviousSubwordEnd",
-
- "shift-w": [
- "vim::NextWordStart",
- {
- "ignorePunctuation": true
- }
- ],
- "shift-e": [
- "vim::NextWordEnd",
- {
- "ignorePunctuation": true
- }
- ],
- "shift-b": [
- "vim::PreviousWordStart",
- {
- "ignorePunctuation": true
- }
- ],
+ "shift-w": ["vim::NextWordStart", { "ignorePunctuation": true }],
+ "shift-e": ["vim::NextWordEnd", { "ignorePunctuation": true }],
+ "shift-b": ["vim::PreviousWordStart", { "ignorePunctuation": true }],
"g shift-e": ["vim::PreviousWordEnd", { "ignorePunctuation": true }],
-
"/": "vim::Search",
- "?": [
- "vim::Search",
- {
- "backwards": true
- }
- ],
+ "g /": "pane::DeploySearch",
+ "?": ["vim::Search", { "backwards": true }],
"*": "vim::MoveToNext",
"#": "vim::MoveToPrev",
"n": "vim::MoveToNextMatch",
"shift-n": "vim::MoveToPrevMatch",
"%": "vim::Matching",
- "f": [
- "vim::PushOperator",
- {
- "FindForward": {
- "before": false
- }
- }
- ],
- "t": [
- "vim::PushOperator",
- {
- "FindForward": {
- "before": true
- }
- }
- ],
- "shift-f": [
- "vim::PushOperator",
- {
- "FindBackward": {
- "after": false
- }
- }
- ],
- "shift-t": [
- "vim::PushOperator",
- {
- "FindBackward": {
- "after": true
- }
- }
- ],
+ "f": ["vim::PushOperator", { "FindForward": { "before": false } }],
+ "t": ["vim::PushOperator", { "FindForward": { "before": true } }],
+ "shift-f": ["vim::PushOperator", { "FindBackward": { "after": false } }],
+ "shift-t": ["vim::PushOperator", { "FindBackward": { "after": true } }],
"m": ["vim::PushOperator", "Mark"],
"'": ["vim::PushOperator", { "Jump": { "line": true } }],
"`": ["vim::PushOperator", { "Jump": { "line": false } }],
@@ -139,7 +73,8 @@
"ctrl-q": "vim::ToggleVisualBlock",
"shift-k": "editor::Hover",
"shift-r": "vim::ToggleReplace",
- "0": "vim::StartOfLine", // When no number operator present, use start of line motion
+ "0": "vim::StartOfLine",
+ "home": "vim::StartOfLine",
"ctrl-f": "vim::PageDown",
"pagedown": "vim::PageDown",
"ctrl-b": "vim::PageUp",
@@ -161,93 +96,29 @@
"g shift-n": "vim::SelectPreviousMatch",
"g l": "vim::SelectNext",
"g shift-l": "vim::SelectPrevious",
- "g >": [
- "editor::SelectNext",
- {
- "replace_newest": true
- }
- ],
- "g <": [
- "editor::SelectPrevious",
- {
- "replace_newest": true
- }
- ],
+ "g >": ["editor::SelectNext", { "replace_newest": true }],
+ "g <": ["editor::SelectPrevious", { "replace_newest": true }],
"g a": "editor::SelectAllMatches",
"g s": "outline::Toggle",
"g shift-s": "project_symbols::Toggle",
"g .": "editor::ToggleCodeActions", // zed specific
"g shift-a": "editor::FindAllReferences", // zed specific
"g space": "editor::OpenExcerpts", // zed specific
- "g *": [
- "vim::MoveToNext",
- {
- "partialWord": true
- }
- ],
- "g #": [
- "vim::MoveToPrev",
- {
- "partialWord": true
- }
- ],
- "g j": [
- "vim::Down",
- {
- "displayLines": true
- }
- ],
- "g down": [
- "vim::Down",
- {
- "displayLines": true
- }
- ],
- "g k": [
- "vim::Up",
- {
- "displayLines": true
- }
- ],
- "g up": [
- "vim::Up",
- {
- "displayLines": true
- }
- ],
- "g $": [
- "vim::EndOfLine",
- {
- "displayLines": true
- }
- ],
- "g end": [
- "vim::EndOfLine",
- {
- "displayLines": true
- }
- ],
- "g 0": [
- "vim::StartOfLine",
- {
- "displayLines": true
- }
- ],
- "g home": [
- "vim::StartOfLine",
- {
- "displayLines": true
- }
- ],
- "g ^": [
- "vim::FirstNonWhitespace",
- {
- "displayLines": true
- }
- ],
+ "g *": ["vim::MoveToNext", { "partialWord": true }],
+ "g #": ["vim::MoveToPrev", { "partialWord": true }],
+ "g j": ["vim::Down", { "displayLines": true }],
+ "g down": ["vim::Down", { "displayLines": true }],
+ "g k": ["vim::Up", { "displayLines": true }],
+ "g up": ["vim::Up", { "displayLines": true }],
+ "g $": ["vim::EndOfLine", { "displayLines": true }],
+ "g end": ["vim::EndOfLine", { "displayLines": true }],
+ "g 0": ["vim::StartOfLine", { "displayLines": true }],
+ "g home": ["vim::StartOfLine", { "displayLines": true }],
+ "g ^": ["vim::FirstNonWhitespace", { "displayLines": true }],
+ "g v": "vim::RestoreVisualSelection",
"g ]": "editor::GoToDiagnostic",
"g [": "editor::GoToPrevDiagnostic",
- "g i": ["workspace::SendKeystrokes", "` ^ i"],
+ "g i": "vim::InsertAtPrevious",
"g ,": "vim::ChangeListNewer",
"g ;": "vim::ChangeListOlder",
"shift-h": "vim::WindowTop",
@@ -261,18 +132,8 @@
"z c": "editor::Fold",
"z o": "editor::UnfoldLines",
"z f": "editor::FoldSelectedRanges",
- "shift-z shift-q": [
- "pane::CloseActiveItem",
- {
- "saveIntent": "skip"
- }
- ],
- "shift-z shift-z": [
- "pane::CloseActiveItem",
- {
- "saveIntent": "saveAll"
- }
- ],
+ "shift-z shift-q": ["pane::CloseActiveItem", { "saveIntent": "skip" }],
+ "shift-z shift-z": ["pane::CloseActiveItem", { "saveIntent": "saveAll" }],
// Count support
"1": ["vim::Number", 1],
"2": ["vim::Number", 2],
@@ -284,6 +145,7 @@
"8": ["vim::Number", 8],
"9": ["vim::Number", 9],
// window related commands (ctrl-w X)
+ "ctrl-w": null,
"ctrl-w left": ["workspace::ActivatePaneInDirection", "Left"],
"ctrl-w right": ["workspace::ActivatePaneInDirection", "Right"],
"ctrl-w up": ["workspace::ActivatePaneInDirection", "Up"],
@@ -327,27 +189,26 @@
"ctrl-w ctrl-o": "workspace::CloseInactiveTabsAndPanes",
"ctrl-w n": ["workspace::NewFileInDirection", "Up"],
"ctrl-w ctrl-n": ["workspace::NewFileInDirection", "Up"],
-
"ctrl-w d": "editor::GoToDefinitionSplit",
"ctrl-w g d": "editor::GoToDefinitionSplit",
"ctrl-w shift-d": "editor::GoToTypeDefinitionSplit",
"ctrl-w g shift-d": "editor::GoToTypeDefinitionSplit",
"ctrl-w space": "editor::OpenExcerptsSplit",
"ctrl-w g space": "editor::OpenExcerptsSplit",
- "-": "pane::RevealInProjectPanel"
+ "ctrl-6": "pane::AlternateFile"
}
},
{
- // escape is in its own section so that it cancels a pending count.
- "context": "Editor && vim_mode == normal && vim_operator == none && !VimWaiting",
+ "context": "VimControl && VimCount",
"bindings": {
- "escape": "editor::Cancel",
- "ctrl-[": "editor::Cancel"
+ "0": ["vim::Number", 0]
}
},
{
- "context": "Editor && vim_mode == normal && vim_operator == none && !VimWaiting",
+ "context": "vim_mode == normal",
"bindings": {
+ "escape": "editor::Cancel",
+ "ctrl-[": "editor::Cancel",
".": "vim::Repeat",
"c": ["vim::PushOperator", "Change"],
"shift-c": "vim::ChangeToEndOfLine",
@@ -355,7 +216,7 @@
"shift-d": "vim::DeleteToEndOfLine",
"shift-j": "vim::JoinLines",
"y": ["vim::PushOperator", "Yank"],
- "shift-y": "vim::YankLine",
+ "shift-y": "vim::YankToEndOfLine",
"i": "vim::InsertBefore",
"shift-i": "vim::InsertFirstNonWhitespace",
"a": "vim::InsertAfter",
@@ -368,19 +229,21 @@
"ctrl-a": "vim::Increment",
"ctrl-x": "vim::Decrement",
"p": "vim::Paste",
- "shift-p": [
- "vim::Paste",
- {
- "before": true
- }
- ],
- "u": "editor::Undo",
- "ctrl-r": "editor::Redo",
+ "shift-p": ["vim::Paste", { "before": true }],
+ "u": "vim::Undo",
+ "ctrl-r": "vim::Redo",
"r": ["vim::PushOperator", "Replace"],
"s": "vim::Substitute",
"shift-s": "vim::SubstituteLine",
- "> >": "vim::Indent",
- "< <": "vim::Outdent",
+ ">": ["vim::PushOperator", "Indent"],
+ "<": ["vim::PushOperator", "Outdent"],
+ "g u": ["vim::PushOperator", "Lowercase"],
+ "g shift-u": ["vim::PushOperator", "Uppercase"],
+ "g ~": ["vim::PushOperator", "OppositeCase"],
+ "\"": ["vim::PushOperator", "Register"],
+ "q": "vim::ToggleRecord",
+ "shift-q": "vim::ReplayLastRecording",
+ "@": ["vim::PushOperator", "ReplayRegister"],
"ctrl-pagedown": "pane::ActivateNextItem",
"ctrl-pageup": "pane::ActivatePrevItem",
// tree-sitter related commands
@@ -389,86 +252,107 @@
"] d": "editor::GoToDiagnostic",
"[ d": "editor::GoToPrevDiagnostic",
"] c": "editor::GoToHunk",
- "[ c": "editor::GoToPrevHunk"
+ "[ c": "editor::GoToPrevHunk",
+ "g c c": "vim::ToggleComments"
}
},
{
- "context": "Editor && vim_mode == visual && vim_operator == none && !VimWaiting",
+ "context": "vim_mode == visual",
"bindings": {
+ "u": "vim::ConvertToLowerCase",
+ "U": "vim::ConvertToUpperCase",
+ "o": "vim::OtherEnd",
+ "shift-o": "vim::OtherEnd",
+ "d": "vim::VisualDelete",
+ "x": "vim::VisualDelete",
+ "shift-d": "vim::VisualDeleteLine",
+ "shift-x": "vim::VisualDeleteLine",
+ "y": "vim::VisualYank",
+ "shift-y": "vim::VisualYank",
+ "p": "vim::Paste",
+ "shift-p": ["vim::Paste", { "preserveClipboard": true }],
+ "s": "vim::Substitute",
+ "shift-s": "vim::SubstituteLine",
+ "shift-r": "vim::SubstituteLine",
+ "c": "vim::Substitute",
+ "~": "vim::ChangeCase",
+ "*": ["vim::MoveToNext", { "partialWord": true }],
+ "#": ["vim::MoveToPrev", { "partialWord": true }],
+ "ctrl-a": "vim::Increment",
+ "ctrl-x": "vim::Decrement",
+ "g ctrl-a": ["vim::Increment", { "step": true }],
+ "g ctrl-x": ["vim::Decrement", { "step": true }],
+ "shift-i": "vim::InsertBefore",
+ "shift-a": "vim::InsertAfter",
+ "shift-j": "vim::JoinLines",
+ "r": ["vim::PushOperator", "Replace"],
+ "ctrl-c": ["vim::SwitchMode", "Normal"],
+ "escape": ["vim::SwitchMode", "Normal"],
+ "ctrl-[": ["vim::SwitchMode", "Normal"],
+ ">": "vim::Indent",
+ "<": "vim::Outdent",
+ "i": ["vim::PushOperator", { "Object": { "around": false } }],
+ "a": ["vim::PushOperator", { "Object": { "around": true } }],
+ "g c": "vim::ToggleComments",
+ "\"": ["vim::PushOperator", "Register"],
// tree-sitter related commands
"[ x": "editor::SelectLargerSyntaxNode",
"] x": "editor::SelectSmallerSyntaxNode"
}
},
{
- "context": "Editor && VimCount",
+ "context": "vim_mode == insert",
"bindings": {
- "0": ["vim::Number", 0]
- }
- },
- {
- "context": "Editor && vim_operator == c",
- "bindings": {
- "c": "vim::CurrentLine",
- "d": "editor::Rename" // zed specific
- }
- },
- {
- "context": "Editor && vim_mode == normal && vim_operator == c",
- "bindings": {
- "s": [
- "vim::PushOperator",
- {
- "ChangeSurrounds": {}
- }
- ]
- }
- },
- {
- "context": "Editor && vim_operator == d",
- "bindings": {
- "d": "vim::CurrentLine"
- }
- },
- {
- "context": "Editor && vim_mode == normal && vim_operator == d",
- "bindings": {
- "s": ["vim::PushOperator", "DeleteSurrounds"]
+ "escape": "vim::NormalBefore",
+ "ctrl-c": "vim::NormalBefore",
+ "ctrl-[": "vim::NormalBefore",
+ "ctrl-x": null,
+ "ctrl-x ctrl-o": "editor::ShowCompletions",
+ "ctrl-x ctrl-a": "assistant::InlineAssist", // zed specific
+ "ctrl-x ctrl-c": "editor::ShowInlineCompletion", // zed specific
+ "ctrl-x ctrl-l": "editor::ToggleCodeActions", // zed specific
+ "ctrl-x ctrl-z": "editor::Cancel",
+ "ctrl-w": "editor::DeleteToPreviousWordStart",
+ "ctrl-u": "editor::DeleteToBeginningOfLine",
+ "ctrl-t": "vim::Indent",
+ "ctrl-d": "vim::Outdent",
+ "ctrl-r": ["vim::PushOperator", "Register"]
}
},
{
- "context": "Editor && vim_operator == y",
+ "context": "vim_mode == replace",
"bindings": {
- "y": "vim::CurrentLine"
+ "escape": "vim::NormalBefore",
+ "ctrl-c": "vim::NormalBefore",
+ "ctrl-[": "vim::NormalBefore",
+ "backspace": "vim::UndoReplace",
+ "tab": "vim::Tab",
+ "enter": "vim::Enter"
}
},
{
- "context": "Editor && vim_mode == normal && vim_operator == y",
+ "context": "vim_mode == waiting",
"bindings": {
- "s": [
- "vim::PushOperator",
- {
- "AddSurrounds": {}
- }
- ]
+ "tab": "vim::Tab",
+ "enter": "vim::Enter",
+ "escape": "vim::ClearOperators",
+ "ctrl-c": "vim::ClearOperators",
+ "ctrl-[": "vim::ClearOperators"
}
},
{
- "context": "Editor && vim_operator == ys",
+ "context": "vim_mode == operator",
"bindings": {
- "s": "vim::CurrentLine"
+ "escape": "vim::ClearOperators",
+ "ctrl-c": "vim::ClearOperators",
+ "ctrl-[": "vim::ClearOperators"
}
},
{
- "context": "Editor && VimObject",
+ "context": "vim_operator == a || vim_operator == i || vim_operator == cs",
"bindings": {
"w": "vim::Word",
- "shift-w": [
- "vim::Word",
- {
- "ignorePunctuation": true
- }
- ],
+ "shift-w": ["vim::Word", { "ignorePunctuation": true }],
"t": "vim::Tag",
"s": "vim::Sentence",
"p": "vim::Paragraph",
@@ -490,130 +374,64 @@
}
},
{
- "context": "Editor && vim_mode == visual && !VimWaiting && !VimObject",
+ "context": "vim_operator == c",
"bindings": {
- "u": "vim::ConvertToLowerCase",
- "U": "vim::ConvertToUpperCase",
- "o": "vim::OtherEnd",
- "shift-o": "vim::OtherEnd",
- "d": "vim::VisualDelete",
- "x": "vim::VisualDelete",
- "shift-d": "vim::VisualDeleteLine",
- "shift-x": "vim::VisualDeleteLine",
- "y": "vim::VisualYank",
- "shift-y": "vim::VisualYank",
- "p": "vim::Paste",
- "shift-p": [
- "vim::Paste",
- {
- "preserveClipboard": true
- }
- ],
- "s": "vim::Substitute",
- "shift-s": "vim::SubstituteLine",
- "shift-r": "vim::SubstituteLine",
- "c": "vim::Substitute",
- "~": "vim::ChangeCase",
- "*": [
- "vim::MoveToNext",
- {
- "partialWord": true
- }
- ],
- "#": [
- "vim::MoveToPrev",
- {
- "partialWord": true
- }
- ],
- "ctrl-a": "vim::Increment",
- "ctrl-x": "vim::Decrement",
- "g ctrl-a": [
- "vim::Increment",
- {
- "step": true
- }
- ],
- "g ctrl-x": [
- "vim::Decrement",
- {
- "step": true
- }
- ],
- "shift-i": "vim::InsertBefore",
- "shift-a": "vim::InsertAfter",
- "shift-j": "vim::JoinLines",
- "r": ["vim::PushOperator", "Replace"],
- "ctrl-c": ["vim::SwitchMode", "Normal"],
- "escape": ["vim::SwitchMode", "Normal"],
- "ctrl-[": ["vim::SwitchMode", "Normal"],
- ">": "vim::Indent",
- "<": "vim::Outdent",
- "i": [
- "vim::PushOperator",
- {
- "Object": {
- "around": false
- }
- }
- ],
- "a": [
- "vim::PushOperator",
- {
- "Object": {
- "around": true
- }
- }
- ]
+ "c": "vim::CurrentLine",
+ "d": "editor::Rename", // zed specific
+ "s": ["vim::PushOperator", { "ChangeSurrounds": {} }]
}
},
{
- "context": "Editor && vim_mode == normal",
+ "context": "vim_operator == d",
"bindings": {
- "g c c": "editor::ToggleComments"
+ "d": "vim::CurrentLine",
+ "s": ["vim::PushOperator", "DeleteSurrounds"]
}
},
{
- "context": "Editor && vim_mode == visual",
+ "context": "vim_operator == gu",
"bindings": {
- "g c": "editor::ToggleComments"
+ "g u": "vim::CurrentLine",
+ "u": "vim::CurrentLine"
}
},
{
- "context": "Editor && vim_mode == insert",
+ "context": "vim_operator == gU",
"bindings": {
- "escape": "vim::NormalBefore",
- "ctrl-c": "vim::NormalBefore",
- "ctrl-[": "vim::NormalBefore",
- "ctrl-x ctrl-o": "editor::ShowCompletions",
- "ctrl-x ctrl-a": "assistant::InlineAssist", // zed specific
- "ctrl-x ctrl-c": "editor::ShowInlineCompletion", // zed specific
- "ctrl-x ctrl-l": "editor::ToggleCodeActions", // zed specific
- "ctrl-x ctrl-z": "editor::Cancel",
- "ctrl-w": "editor::DeleteToPreviousWordStart",
- "ctrl-u": "editor::DeleteToBeginningOfLine",
- "ctrl-t": "vim::Indent",
- "ctrl-d": "vim::Outdent",
- "ctrl-r \"": "editor::Paste",
- "ctrl-r +": "editor::Paste"
+ "g shift-u": "vim::CurrentLine",
+ "shift-u": "vim::CurrentLine"
}
},
{
- "context": "Editor && vim_mode == replace",
+ "context": "vim_operator == g~",
"bindings": {
- "escape": "vim::NormalBefore",
- "ctrl-c": "vim::NormalBefore",
- "ctrl-[": "vim::NormalBefore",
- "backspace": "vim::UndoReplace"
+ "g ~": "vim::CurrentLine",
+ "~": "vim::CurrentLine"
}
},
{
- "context": "Editor && VimWaiting",
+ "context": "vim_operator == y",
"bindings": {
- "tab": "vim::Tab",
- "enter": "vim::Enter",
- "escape": ["vim::SwitchMode", "Normal"],
- "ctrl-[": ["vim::SwitchMode", "Normal"]
+ "y": "vim::CurrentLine",
+ "s": ["vim::PushOperator", { "AddSurrounds": {} }]
+ }
+ },
+ {
+ "context": "vim_operator == ys",
+ "bindings": {
+ "s": "vim::CurrentLine"
+ }
+ },
+ {
+ "context": "vim_operator == >",
+ "bindings": {
+ ">": "vim::CurrentLine"
+ }
+ },
+ {
+ "context": "vim_operator == <",
+ "bindings": {
+ "<": "vim::CurrentLine"
}
},
{
@@ -626,7 +444,8 @@
{
"context": "EmptyPane || SharedScreen",
"bindings": {
- ":": "command_palette::Toggle"
+ ":": "command_palette::Toggle",
+ "g /": "pane::DeploySearch"
}
},
{
@@ -649,10 +468,20 @@
"t": "project_panel::OpenPermanent",
"v": "project_panel::OpenPermanent",
"p": "project_panel::Open",
- "x": "project_panel::RevealInFinder",
+ "x": "project_panel::RevealInFileManager",
"shift-g": "menu::SelectLast",
"g g": "menu::SelectFirst",
- "-": "project_panel::SelectParent"
+ "-": "project_panel::SelectParent",
+ "ctrl-6": "pane::AlternateFile"
+ }
+ },
+ {
+ "context": "OutlinePanel",
+ "bindings": {
+ "j": "menu::SelectNext",
+ "k": "menu::SelectPrev",
+ "shift-g": "menu::SelectLast",
+ "g g": "menu::SelectFirst"
}
}
]
diff --git a/assets/prompts/operations.md b/assets/prompts/operations.md
new file mode 100644
index 00000000000000..b77cfedf12048e
--- /dev/null
+++ b/assets/prompts/operations.md
@@ -0,0 +1,241 @@
+Your task is to map a step from the conversation above to operations on symbols inside the provided source files.
+
+Guidelines:
+- There's no need to describe *what* to do, just *where* to do it.
+- If creating a file, assume any subsequent updates are included at the time of creation.
+- Don't create and then update a file.
+- We'll create it in one shot.
+- Prefer updating symbols lower in the syntax tree if possible.
+- Never include operations on a parent symbol and one of its children in the same block.
+- Never nest an operation with another operation or include CDATA or other content. All operations are leaf nodes.
+- Include a description attribute for each operation with a brief, one-line description of the change to perform.
+- Descriptions are required for all operations except delete.
+- When generating multiple operations, ensure the descriptions are specific to each individual operation.
+- Avoid referring to the location in the description. Focus on the change to be made, not the location where it's made. That's implicit with the symbol you provide.
+- Don't generate multiple operations at the same location. Instead, combine them together in a single operation with a succinct combined description.
+
+The available operation types are:
+
+1. : Modify an existing symbol in a file.
+2. : Create a new file.
+3. : Add a new symbol as sibling after an existing symbol in a file.
+4. : Add a new symbol as the last child of an existing symbol in a file.
+5. : Add a new symbol as the first child of an existing symbol in a file.
+6. : Remove an existing symbol from a file. The `description` attribute is invalid for delete, but required for other ops.
+
+All operations *require* a path.
+Operations that *require* a symbol: , ,
+Operations that don't allow a symbol:
+Operations that have an *optional* symbol: ,
+
+Example 1:
+
+User:
+ ```rs src/rectangle.rs
+ struct Rectangle {
+ width: f64,
+ height: f64,
+ }
+
+ impl Rectangle {
+ fn new(width: f64, height: f64) -> Self {
+ Rectangle { width, height }
+ }
+ }
+ ```
+
+ Symbols for src/rectangle.rs:
+ - struct Rectangle
+ - impl Rectangle
+ - impl Rectangle fn new
+
+ Add new methods 'calculate_area' and 'calculate_perimeter' to the Rectangle struct
+ Implement the 'Display' trait for the Rectangle struct
+
+ What are the operations for the step: Add a new method 'calculate_area' to the Rectangle struct
+
+Assistant (wrong):
+
+
+
+
+
+This demonstrates what NOT to do. NEVER append multiple children at the same location.
+
+Assistant (corrected):
+
+
+
+
+User:
+What are the operations for the step: Implement the 'Display' trait for the Rectangle struct
+
+Assistant:
+
+
+
+
+Example 2:
+
+User:
+```rs src/user.rs
+struct User {
+ pub name: String,
+ age: u32,
+ email: String,
+}
+
+impl User {
+ fn new(name: String, age: u32, email: String) -> Self {
+ User { name, age, email }
+ }
+
+ pub fn print_info(&self) {
+ println!("Name: {}, Age: {}, Email: {}", self.name, self.age, self.email);
+ }
+}
+```
+
+Symbols for src/user.rs:
+- struct User
+- struct User pub name
+- struct User age
+- struct User email
+- impl User
+- impl User fn new
+- impl User pub fn print_info
+
+Update the 'print_info' method to use formatted output
+Remove the 'email' field from the User struct
+
+What are the operations for the step: Update the 'print_info' method to use formatted output
+
+Assistant:
+
+
+
+
+User:
+What are the operations for the step: Remove the 'email' field from the User struct
+
+Assistant:
+
+
+
+
+Example 3:
+
+User:
+```rs src/vehicle.rs
+struct Vehicle {
+ make: String,
+ model: String,
+ year: u32,
+}
+
+impl Vehicle {
+ fn new(make: String, model: String, year: u32) -> Self {
+ Vehicle { make, model, year }
+ }
+
+ fn print_year(&self) {
+ println!("Year: {}", self.year);
+ }
+}
+```
+
+Symbols for src/vehicle.rs:
+- struct Vehicle
+- struct Vehicle make
+- struct Vehicle model
+- struct Vehicle year
+- impl Vehicle
+- impl Vehicle fn new
+- impl Vehicle fn print_year
+
+Add a 'use std::fmt;' statement at the beginning of the file
+Add a new method 'start_engine' in the Vehicle impl block
+
+What are the operations for the step: Add a 'use std::fmt;' statement at the beginning of the file
+
+Assistant:
+
+
+
+
+User:
+What are the operations for the step: Add a new method 'start_engine' in the Vehicle impl block
+
+Assistant:
+
+
+
+
+Example 4:
+
+User:
+```rs src/employee.rs
+struct Employee {
+ name: String,
+ position: String,
+ salary: u32,
+ department: String,
+}
+
+impl Employee {
+ fn new(name: String, position: String, salary: u32, department: String) -> Self {
+ Employee { name, position, salary, department }
+ }
+
+ fn print_details(&self) {
+ println!("Name: {}, Position: {}, Salary: {}, Department: {}",
+ self.name, self.position, self.salary, self.department);
+ }
+
+ fn give_raise(&mut self, amount: u32) {
+ self.salary += amount;
+ }
+}
+```
+
+Symbols for src/employee.rs:
+- struct Employee
+- struct Employee name
+- struct Employee position
+- struct Employee salary
+- struct Employee department
+- impl Employee
+- impl Employee fn new
+- impl Employee fn print_details
+- impl Employee fn give_raise
+
+Make salary an f32
+
+What are the operations for the step: Make salary an f32
+
+A (wrong):
+
+
+
+
+
+This example demonstrates what not to do. `struct Employee salary` is a child of `struct Employee`.
+
+A (corrected):
+
+
+
+
+User:
+ What are the correct operations for the step: Remove the 'department' field and update the 'print_details' method
+
+A:
+
+
+
+
+
+Now generate the operations for the following step.
+Output only valid XML containing valid operations with their required attributes.
+NEVER output code or any other text inside tags. If you do, you will replaced with another model.
+Your response *MUST* begin with and end with :
diff --git a/assets/settings/default.json b/assets/settings/default.json
index a1cc720e8c94fd..7dafecfa1de1d4 100644
--- a/assets/settings/default.json
+++ b/assets/settings/default.json
@@ -1,19 +1,15 @@
{
// The name of the Zed theme to use for the UI.
//
- // The theme can also be set to follow system preferences:
- //
- // "theme": {
- // "mode": "system",
- // "light": "One Light",
- // "dark": "One Dark"
- // }
- //
- // Where `mode` is one of:
+ // `mode` is one of:
// - "system": Use the theme that corresponds to the system's appearance
// - "light": Use the theme indicated by the "light" field
// - "dark": Use the theme indicated by the "dark" field
- "theme": "One Dark",
+ "theme": {
+ "mode": "system",
+ "light": "One Light",
+ "dark": "One Dark"
+ },
// The name of a base set of key bindings to use.
// This setting can take four values, each named after another
// text editor:
@@ -29,7 +25,7 @@
"inline_completion_provider": "copilot"
},
// The name of a font to use for rendering text in the editor
- "buffer_font_family": "Zed Mono",
+ "buffer_font_family": "Zed Plex Mono",
// The OpenType features to enable for text in the editor.
"buffer_font_features": {
// Disable ligatures:
@@ -37,24 +33,29 @@
},
// The default font size for text in the editor
"buffer_font_size": 15,
+ // The weight of the editor font in standard CSS units from 100 to 900.
+ "buffer_font_weight": 400,
// Set the buffer's line height.
// May take 3 values:
// 1. Use a line height that's comfortable for reading (1.618)
- // "line_height": "comfortable"
+ // "buffer_line_height": "comfortable"
// 2. Use a standard line height, (1.3)
- // "line_height": "standard",
+ // "buffer_line_height": "standard",
// 3. Use a custom line height
- // "line_height": {
+ // "buffer_line_height": {
// "custom": 2
// },
"buffer_line_height": "comfortable",
// The name of a font to use for rendering text in the UI
- "ui_font_family": ".SystemUIFont",
+ // (On macOS) You can set this to ".SystemUIFont" to use the system font
+ "ui_font_family": "Zed Plex Sans",
// The OpenType features to enable for text in the UI
"ui_font_features": {
// Disable ligatures:
"calt": false
},
+ // The weight of the UI font in standard CSS units from 100 to 900.
+ "ui_font_weight": 400,
// The default font size for text in the UI
"ui_font_size": 16,
// The factor to grow the active pane by. Defaults to 1.0
@@ -93,6 +94,9 @@
// 3. Never close the window
// "when_closing_with_no_tabs": "keep_window_open",
"when_closing_with_no_tabs": "platform_default",
+ // 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,
// Whether the cursor blinks in the editor.
"cursor_blink": true,
// How to highlight the current line in the editor.
@@ -115,24 +119,24 @@
// The debounce delay before re-querying the language server for completion
// documentation when not included in original completion list.
"completion_documentation_secondary_query_debounce": 300,
- // Whether to show wrap guides 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 additional guides as specified
- // by the 'wrap_guides' setting.
+ // Show method signatures in the editor, when inside parentheses.
+ "auto_signature_help": false,
+ /// Whether to show the signature help after completion or a bracket pair inserted.
+ /// If `auto_signature_help` is enabled, this setting will be treated as enabled also.
+ "show_signature_help_after_edits": true,
+ // 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 softwrap is set to 'preferred_line_length', and will show any
+ // additional guides as specified by the 'wrap_guides' setting.
"show_wrap_guides": true,
// Character counts at which to show wrap guides in the editor.
"wrap_guides": [],
// Hide the values of in variables from visual display in private files
"redact_private_values": false,
+ // The default number of lines to expand excerpts in the multibuffer by.
+ "expand_excerpt_lines": 3,
// Globs to match against file paths to determine if a file is private.
- "private_files": [
- "**/.env*",
- "**/*.pem",
- "**/*.key",
- "**/*.cert",
- "**/*.crt",
- "**/secrets.yml"
- ],
+ "private_files": ["**/.env*", "**/*.pem", "**/*.key", "**/*.cert", "**/*.crt", "**/secrets.yml"],
// Whether to use additional LSP queries to format (and amend) the code after
// every "trigger" symbol input, defined by LSP server capabilities.
"use_on_type_format": true,
@@ -140,38 +144,50 @@
// opening parenthesis, bracket, brace, single or double quote characters.
// For example, when you type (, Zed will add a closing ) at the correct position.
"use_autoclose": true,
+ // Whether to automatically surround selected text when typing opening parenthesis,
+ // 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,
// Controls how the editor handles the autoclosed characters.
// When set to `false`(default), skipping over and auto-removing of the closing characters
// happen only for auto-inserted characters.
// Otherwise(when `true`), the closing characters are always skipped over and auto-removed
// no matter how they were inserted.
"always_treat_brackets_as_autoclosed": false,
- // Controls whether copilot provides suggestion immediately
- // or waits for a `copilot::Toggle`
- "show_copilot_suggestions": true,
+ // Controls whether inline completions are shown immediately (true)
+ // or manually by triggering `editor::ShowInlineCompletion` (false).
+ "show_inline_completions": true,
// Whether to show tabs and spaces in the editor.
// This setting can take three values:
//
// 1. Draw tabs and spaces only for the selected text (default):
// "selection"
// 2. Do not draw any tabs or spaces:
- // "none"
+ // "none"
// 3. Draw all invisible symbols:
- // "all"
+ // "all"
+ // 4. Draw whitespaces at boundaries only:
+ // "boundary"
+ // For a whitespace to be on a boundary, any of the following conditions need to be met:
+ // - It is a tab
+ // - It is adjacent to an edge (start or end)
+ // - It is adjacent to a whitespace (left or right)
"show_whitespaces": "selection",
// Settings related to calls in Zed
"calls": {
// Join calls with the microphone live by default
"mute_on_join": false,
// Share your project when you are the first to join a channel
- "share_on_join": true
+ "share_on_join": false
},
// Toolbar related settings
"toolbar": {
// Whether to show breadcrumbs.
"breadcrumbs": true,
// Whether to show quick action buttons.
- "quick_actions": true
+ "quick_actions": true,
+ // Whether to show the Selections menu in the editor toolbar
+ "selections_menu": true
},
// Scrollbar related settings
"scrollbar": {
@@ -213,6 +229,8 @@
"line_numbers": true,
// Whether to show code action buttons in the gutter.
"code_actions": true,
+ // Whether to show runnables buttons in the gutter.
+ "runnables": true,
// Whether to show fold buttons in the gutter.
"folds": true
},
@@ -221,6 +239,8 @@
"enabled": true,
/// The width of the indent guides in pixels, between 1 and 10.
"line_width": 1,
+ /// The width of the active indent guide in pixels, between 1 and 10.
+ "active_line_width": 1,
/// Determines how indent guides are colored.
/// This setting can take the following three values:
///
@@ -235,12 +255,16 @@
/// 2. "indent_aware"
"background_coloring": "disabled"
},
+ // Whether the editor will scroll beyond the last line.
+ "scroll_beyond_last_line": "one_page",
// The number of lines to keep above/below the cursor when scrolling.
"vertical_scroll_margin": 3,
// Scroll sensitivity multiplier. This multiplier is applied
// to both the horizontal and vertical delta values while scrolling.
"scroll_sensitivity": 1.0,
"relative_line_numbers": false,
+ // If 'search_wrap' is disabled, search result do not wrap around the end of the file.
+ "search_wrap": true,
// When to populate a new search's query based on the text under the cursor.
// This setting can take the following three values:
//
@@ -286,9 +310,39 @@
// when a corresponding project entry becomes active.
// Gitignored entries are never auto revealed.
"auto_reveal_entries": true,
+ // Whether to fold directories automatically and show compact folders
+ // (e.g. "a/b/c" ) when a directory has only one subdirectory inside.
+ "auto_fold_dirs": false,
+ /// Scrollbar-related settings
+ "scrollbar": {
+ /// When to show the scrollbar in the project panel.
+ ///
+ /// Default: always
+ "show": "always"
+ }
+ },
+ "outline_panel": {
+ // Whether to show the outline panel button in the status bar
+ "button": true,
+ // Default width of the outline panel.
+ "default_width": 300,
+ // Where to dock the outline panel. Can be 'left' or 'right'.
+ "dock": "left",
+ // Whether to show file icons in the outline panel.
+ "file_icons": true,
+ // Whether to show folder icons or chevrons for directories in the outline panel.
+ "folder_icons": true,
+ // Whether to show the git status in the outline panel.
+ "git_status": true,
+ // Amount of indentation for nested items.
+ "indent_size": 20,
+ // Whether to reveal it in the outline panel automatically,
+ // when a corresponding outline entry becomes active.
+ // Gitignored entries are never auto revealed.
+ "auto_reveal_entries": true,
/// Whether to fold directories automatically
/// when a directory has only one directory inside.
- "auto_fold_dirs": false
+ "auto_fold_dirs": true
},
"collaboration_panel": {
// Whether to show the collaboration panel button in the status bar.
@@ -342,6 +396,7 @@
// 2. "gpt-4"
// 3. "gpt-4-turbo-preview"
// 4. "gpt-4o"
+ // 5. "gpt-4o-mini"
"default_model": "gpt-4o"
}
},
@@ -349,6 +404,9 @@
"show_call_status_icon": true,
// Whether to use language servers to provide code intelligence.
"enable_language_server": true,
+ // Whether to perform linked edits of associated ranges, if the language server supports it.
+ // For example, when editing opening tag, the contents of the closing tag will be edited as well.
+ "linked_edits": true,
// The list of language servers to use (or disable) for all languages.
//
// This is typically customized on a per-language basis.
@@ -377,7 +435,9 @@
// Show git status colors in the editor tabs.
"git_status": false,
// Position of the close button on the editor tabs.
- "close_position": "right"
+ "close_position": "right",
+ // Whether to show the file icon for a tab.
+ "file_icons": false
},
// Settings related to preview tabs.
"preview_tabs": {
@@ -420,16 +480,16 @@
// or falling back to formatting via language server:
// "formatter": "auto"
"formatter": "auto",
- // How to soft-wrap long lines of text. This setting can take
- // three values:
+ // How to soft-wrap long lines of text.
+ // Possible values:
//
// 1. Do not soft wrap.
// "soft_wrap": "none",
// 2. Prefer a single line generally, unless an overly long line is encountered.
// "soft_wrap": "prefer_line",
- // 3. Soft wrap lines that overflow the editor:
+ // 3. Soft wrap lines that overflow the editor.
// "soft_wrap": "editor_width",
- // 4. Soft wrap lines at the preferred line length
+ // 4. Soft wrap lines at the preferred line length.
// "soft_wrap": "preferred_line_length",
"soft_wrap": "prefer_line",
// The column at which to soft-wrap lines, for buffers where soft-wrap
@@ -447,7 +507,8 @@
// Send anonymized usage data like what languages you're using Zed with.
"metrics": true
},
- // Automatically update Zed
+ // Automatically update Zed. This setting may be ignored on Linux if
+ // installed through a package manager.
"auto_update": true,
// Diagnostics configuration.
"diagnostics": {
@@ -484,9 +545,16 @@
// "delay_ms": 600
}
},
- "copilot": {
- // The set of glob patterns for which copilot should be disabled
- // in any matching file.
+ // Configuration for how direnv configuration should be loaded. May take 2 values:
+ // 1. Load direnv configuration through the shell hook, works for POSIX shells and fish.
+ // "load_direnv": "shell_hook"
+ // 2. Load direnv configuration using `direnv export json` directly.
+ // This can help with some shells that otherwise would not detect
+ // the direnv environment, such as nushell or elvish.
+ // "load_direnv": "direct"
+ "load_direnv": "shell_hook",
+ "inline_completions": {
+ // A list of globs representing files that inline completions should be disabled for.
"disabled_globs": [".env"]
},
// Settings specific to journaling
@@ -612,13 +680,17 @@
// "font_size": 15,
// Set the terminal's font family. If this option is not included,
// the terminal will default to matching the buffer's font family.
- // "font_family": "Zed Mono",
+ // "font_family": "Zed Plex Mono",
// Sets the maximum number of lines in the terminal's scrollback buffer.
// Default: 10_000, maximum: 100_000 (all bigger values set will be treated as 100_000), 0 disables the scrolling.
// Existing terminals will not pick up this change until they are recreated.
// "max_scroll_history_lines": 10000,
},
"code_actions_on_format": {},
+ /// Settings related to running tasks.
+ "tasks": {
+ "variables": {}
+ },
// An object whose keys are language names, and whose values
// are arrays of filenames or extensions of files that should
// use those languages.
@@ -631,7 +703,10 @@
// "TOML": ["Embargo.lock"]
// }
//
- "file_types": {},
+ "file_types": {
+ "JSON": ["flake.lock"],
+ "JSONC": ["**/.zed/**/*.json", "**/zed/**/*.json"]
+ },
// The extensions that Zed should automatically install on startup.
//
// If you don't want any of these extensions, add this field to your settings
@@ -653,10 +728,12 @@
}
},
"C": {
- "format_on_save": "off"
+ "format_on_save": "off",
+ "use_on_type_format": false
},
"C++": {
- "format_on_save": "off"
+ "format_on_save": "off",
+ "use_on_type_format": false
},
"CSS": {
"prettier": {
@@ -666,9 +743,6 @@
"Elixir": {
"language_servers": ["elixir-ls", "!next-ls", "!lexical", "..."]
},
- "Gleam": {
- "tab_size": 2
- },
"Go": {
"code_actions_on_format": {
"source.organizeImports": true
@@ -694,6 +768,7 @@
}
},
"JavaScript": {
+ "language_servers": ["!typescript-language-server", "vtsls", "..."],
"prettier": {
"allowed": true
}
@@ -703,26 +778,28 @@
"allowed": true
}
},
- "Make": {
- "hard_tabs": true
+ "JSONC": {
+ "prettier": {
+ "allowed": true
+ }
},
"Markdown": {
"format_on_save": "off",
+ "use_on_type_format": false,
"prettier": {
"allowed": true
}
},
"PHP": {
+ "language_servers": ["phpactor", "!intelephense", "..."],
"prettier": {
"allowed": true,
- "plugins": ["@prettier/plugin-php"]
+ "plugins": ["@prettier/plugin-php"],
+ "parser": "php"
}
},
- "Prisma": {
- "tab_size": 2
- },
"Ruby": {
- "language_servers": ["solargraph", "!ruby-lsp", "..."]
+ "language_servers": ["solargraph", "!ruby-lsp", "!rubocop", "..."]
},
"SCSS": {
"prettier": {
@@ -742,6 +819,7 @@
}
},
"TSX": {
+ "language_servers": ["!typescript-language-server", "vtsls", "..."],
"prettier": {
"allowed": true
}
@@ -752,6 +830,7 @@
}
},
"TypeScript": {
+ "language_servers": ["!typescript-language-server", "vtsls", "..."],
"prettier": {
"allowed": true
}
diff --git a/assets/settings/initial_user_settings.json b/assets/settings/initial_user_settings.json
index 75d4a02626336c..705dc30428ca71 100644
--- a/assets/settings/initial_user_settings.json
+++ b/assets/settings/initial_user_settings.json
@@ -4,9 +4,14 @@
// documentation: https://zed.dev/docs/configuring-zed
//
// To see all of Zed's default settings without changing your
-// custom settings, run the `open default settings` command
-// from the command palette or from `Zed` application menu.
+// custom settings, run the `zed: Open Default Settings` command
+// from the command palette
{
"ui_font_size": 16,
- "buffer_font_size": 16
+ "buffer_font_size": 16,
+ "theme": {
+ "mode": "system",
+ "light": "One Light",
+ "dark": "One Dark"
+ }
}
diff --git a/assets/themes/andromeda/andromeda.json b/assets/themes/andromeda/andromeda.json
index 389b0269a17768..8fe6d03a2563e4 100644
--- a/assets/themes/andromeda/andromeda.json
+++ b/assets/themes/andromeda/andromeda.json
@@ -38,6 +38,7 @@
"icon.accent": "#10a793ff",
"status_bar.background": "#262933ff",
"title_bar.background": "#262933ff",
+ "title_bar.inactive_background": "#21242bff",
"toolbar.background": "#1e2025ff",
"tab_bar.background": "#21242bff",
"tab.inactive_background": "#21242bff",
diff --git a/assets/themes/atelier/atelier.json b/assets/themes/atelier/atelier.json
index d8fae1d30d5d0e..b374cbeca42c12 100644
--- a/assets/themes/atelier/atelier.json
+++ b/assets/themes/atelier/atelier.json
@@ -38,6 +38,7 @@
"icon.accent": "#566ddaff",
"status_bar.background": "#3a353fff",
"title_bar.background": "#3a353fff",
+ "title_bar.inactive_background": "#221f26ff",
"toolbar.background": "#19171cff",
"tab_bar.background": "#221f26ff",
"tab.inactive_background": "#221f26ff",
@@ -422,6 +423,7 @@
"icon.accent": "#586cdaff",
"status_bar.background": "#bfbcc5ff",
"title_bar.background": "#bfbcc5ff",
+ "title_bar.inactive_background": "#e6e3ebff",
"toolbar.background": "#efecf4ff",
"tab_bar.background": "#e6e3ebff",
"tab.inactive_background": "#e6e3ebff",
@@ -806,6 +808,7 @@
"icon.accent": "#6684e0ff",
"status_bar.background": "#45433bff",
"title_bar.background": "#45433bff",
+ "title_bar.inactive_background": "#262622ff",
"toolbar.background": "#20201dff",
"tab_bar.background": "#262622ff",
"tab.inactive_background": "#262622ff",
@@ -1190,6 +1193,7 @@
"icon.accent": "#6684dfff",
"status_bar.background": "#cecab4ff",
"title_bar.background": "#cecab4ff",
+ "title_bar.inactive_background": "#eeebd7ff",
"toolbar.background": "#fefbecff",
"tab_bar.background": "#eeebd7ff",
"tab.inactive_background": "#eeebd7ff",
@@ -1574,6 +1578,7 @@
"icon.accent": "#36a165ff",
"status_bar.background": "#424136ff",
"title_bar.background": "#424136ff",
+ "title_bar.inactive_background": "#2c2b23ff",
"toolbar.background": "#22221bff",
"tab_bar.background": "#2c2b23ff",
"tab.inactive_background": "#2c2b23ff",
@@ -1958,6 +1963,7 @@
"icon.accent": "#37a165ff",
"status_bar.background": "#c5c4b9ff",
"title_bar.background": "#c5c4b9ff",
+ "title_bar.inactive_background": "#ebeae3ff",
"toolbar.background": "#f4f3ecff",
"tab_bar.background": "#ebeae3ff",
"tab.inactive_background": "#ebeae3ff",
@@ -2342,6 +2348,7 @@
"icon.accent": "#407ee6ff",
"status_bar.background": "#443c39ff",
"title_bar.background": "#443c39ff",
+ "title_bar.inactive_background": "#27211eff",
"toolbar.background": "#1b1918ff",
"tab_bar.background": "#27211eff",
"tab.inactive_background": "#27211eff",
@@ -2726,6 +2733,7 @@
"icon.accent": "#407ee6ff",
"status_bar.background": "#ccc7c5ff",
"title_bar.background": "#ccc7c5ff",
+ "title_bar.inactive_background": "#e9e6e4ff",
"toolbar.background": "#f0eeedff",
"tab_bar.background": "#e9e6e4ff",
"tab.inactive_background": "#e9e6e4ff",
@@ -3110,6 +3118,7 @@
"icon.accent": "#5169ebff",
"status_bar.background": "#433a43ff",
"title_bar.background": "#433a43ff",
+ "title_bar.inactive_background": "#252025ff",
"toolbar.background": "#1b181bff",
"tab_bar.background": "#252025ff",
"tab.inactive_background": "#252025ff",
@@ -3494,6 +3503,7 @@
"icon.accent": "#5169ebff",
"status_bar.background": "#c6b8c6ff",
"title_bar.background": "#c6b8c6ff",
+ "title_bar.inactive_background": "#e0d5e0ff",
"toolbar.background": "#f7f3f7ff",
"tab_bar.background": "#e0d5e0ff",
"tab.inactive_background": "#e0d5e0ff",
@@ -3878,6 +3888,7 @@
"icon.accent": "#267eadff",
"status_bar.background": "#33444dff",
"title_bar.background": "#33444dff",
+ "title_bar.inactive_background": "#1c2529ff",
"toolbar.background": "#161b1dff",
"tab_bar.background": "#1c2529ff",
"tab.inactive_background": "#1c2529ff",
@@ -4262,6 +4273,7 @@
"icon.accent": "#267eadff",
"status_bar.background": "#a6cadcff",
"title_bar.background": "#a6cadcff",
+ "title_bar.inactive_background": "#cdeaf9ff",
"toolbar.background": "#ebf8ffff",
"tab_bar.background": "#cdeaf9ff",
"tab.inactive_background": "#cdeaf9ff",
@@ -4646,6 +4658,7 @@
"icon.accent": "#7272caff",
"status_bar.background": "#3b3535ff",
"title_bar.background": "#3b3535ff",
+ "title_bar.inactive_background": "#252020ff",
"toolbar.background": "#1b1818ff",
"tab_bar.background": "#252020ff",
"tab.inactive_background": "#252020ff",
@@ -5030,6 +5043,7 @@
"icon.accent": "#7272caff",
"status_bar.background": "#c1bbbbff",
"title_bar.background": "#c1bbbbff",
+ "title_bar.inactive_background": "#ebe3e3ff",
"toolbar.background": "#f4ececff",
"tab_bar.background": "#ebe3e3ff",
"tab.inactive_background": "#ebe3e3ff",
@@ -5414,6 +5428,7 @@
"icon.accent": "#468b8fff",
"status_bar.background": "#353f39ff",
"title_bar.background": "#353f39ff",
+ "title_bar.inactive_background": "#1f2621ff",
"toolbar.background": "#171c19ff",
"tab_bar.background": "#1f2621ff",
"tab.inactive_background": "#1f2621ff",
@@ -5798,6 +5813,7 @@
"icon.accent": "#488b90ff",
"status_bar.background": "#bcc5bfff",
"title_bar.background": "#bcc5bfff",
+ "title_bar.inactive_background": "#e3ebe6ff",
"toolbar.background": "#ecf4eeff",
"tab_bar.background": "#e3ebe6ff",
"tab.inactive_background": "#e3ebe6ff",
@@ -6182,6 +6198,7 @@
"icon.accent": "#3e62f4ff",
"status_bar.background": "#3b453bff",
"title_bar.background": "#3b453bff",
+ "title_bar.inactive_background": "#1f231fff",
"toolbar.background": "#131513ff",
"tab_bar.background": "#1f231fff",
"tab.inactive_background": "#1f231fff",
@@ -6566,6 +6583,7 @@
"icon.accent": "#3e61f4ff",
"status_bar.background": "#b4ceb4ff",
"title_bar.background": "#b4ceb4ff",
+ "title_bar.inactive_background": "#daeedaff",
"toolbar.background": "#f3faf3ff",
"tab_bar.background": "#daeedaff",
"tab.inactive_background": "#daeedaff",
@@ -6950,6 +6968,7 @@
"icon.accent": "#3e8ed0ff",
"status_bar.background": "#3e4769ff",
"title_bar.background": "#3e4769ff",
+ "title_bar.inactive_background": "#262f51ff",
"toolbar.background": "#202646ff",
"tab_bar.background": "#262f51ff",
"tab.inactive_background": "#262f51ff",
@@ -7334,6 +7353,7 @@
"icon.accent": "#3e8fd0ff",
"status_bar.background": "#c1c5d8ff",
"title_bar.background": "#c1c5d8ff",
+ "title_bar.inactive_background": "#e5e8f5ff",
"toolbar.background": "#f5f7ffff",
"tab_bar.background": "#e5e8f5ff",
"tab.inactive_background": "#e5e8f5ff",
diff --git a/assets/themes/ayu/ayu.json b/assets/themes/ayu/ayu.json
index e83d35f2ede364..79ffacdc666cfa 100644
--- a/assets/themes/ayu/ayu.json
+++ b/assets/themes/ayu/ayu.json
@@ -38,6 +38,7 @@
"icon.accent": "#5ac1feff",
"status_bar.background": "#313337ff",
"title_bar.background": "#313337ff",
+ "title_bar.inactive_background": "#1f2127ff",
"toolbar.background": "#0d1016ff",
"tab_bar.background": "#1f2127ff",
"tab.inactive_background": "#1f2127ff",
@@ -407,6 +408,7 @@
"icon.accent": "#3b9ee5ff",
"status_bar.background": "#dcdddeff",
"title_bar.background": "#dcdddeff",
+ "title_bar.inactive_background": "#ececedff",
"toolbar.background": "#fcfcfcff",
"tab_bar.background": "#ececedff",
"tab.inactive_background": "#ececedff",
@@ -776,6 +778,7 @@
"icon.accent": "#72cffeff",
"status_bar.background": "#464a52ff",
"title_bar.background": "#464a52ff",
+ "title_bar.inactive_background": "#353944ff",
"toolbar.background": "#242835ff",
"tab_bar.background": "#353944ff",
"tab.inactive_background": "#353944ff",
diff --git a/assets/themes/gruvbox/gruvbox.json b/assets/themes/gruvbox/gruvbox.json
index d0dd3964574328..d899ff39dfca62 100644
--- a/assets/themes/gruvbox/gruvbox.json
+++ b/assets/themes/gruvbox/gruvbox.json
@@ -47,6 +47,7 @@
"icon.accent": "#83a598ff",
"status_bar.background": "#4c4642ff",
"title_bar.background": "#4c4642ff",
+ "title_bar.inactive_background": "#3a3735ff",
"toolbar.background": "#282828ff",
"tab_bar.background": "#3a3735ff",
"tab.inactive_background": "#3a3735ff",
@@ -430,6 +431,7 @@
"icon.accent": "#83a598ff",
"status_bar.background": "#4c4642ff",
"title_bar.background": "#4c4642ff",
+ "title_bar.inactive_background": "#393634ff",
"toolbar.background": "#1d2021ff",
"tab_bar.background": "#393634ff",
"tab.inactive_background": "#393634ff",
@@ -813,6 +815,7 @@
"icon.accent": "#83a598ff",
"status_bar.background": "#4c4642ff",
"title_bar.background": "#4c4642ff",
+ "title_bar.inactive_background": "#3b3735ff",
"toolbar.background": "#32302fff",
"tab_bar.background": "#3b3735ff",
"tab.inactive_background": "#3b3735ff",
@@ -1196,6 +1199,7 @@
"icon.accent": "#0b6678ff",
"status_bar.background": "#d9c8a4ff",
"title_bar.background": "#d9c8a4ff",
+ "title_bar.inactive_background": "#ecddb4ff",
"toolbar.background": "#fbf1c7ff",
"tab_bar.background": "#ecddb4ff",
"tab.inactive_background": "#ecddb4ff",
@@ -1579,6 +1583,7 @@
"icon.accent": "#0b6678ff",
"status_bar.background": "#d9c8a4ff",
"title_bar.background": "#d9c8a4ff",
+ "title_bar.inactive_background": "#ecddb5ff",
"toolbar.background": "#f9f5d7ff",
"tab_bar.background": "#ecddb5ff",
"tab.inactive_background": "#ecddb5ff",
@@ -1962,6 +1967,7 @@
"icon.accent": "#0b6678ff",
"status_bar.background": "#d9c8a4ff",
"title_bar.background": "#d9c8a4ff",
+ "title_bar.inactive_background": "#ecdcb3ff",
"toolbar.background": "#f2e5bcff",
"tab_bar.background": "#ecdcb3ff",
"tab.inactive_background": "#ecdcb3ff",
diff --git a/assets/themes/one/one.json b/assets/themes/one/one.json
index 6c22473fdd1787..f98b21acac2bea 100644
--- a/assets/themes/one/one.json
+++ b/assets/themes/one/one.json
@@ -15,29 +15,30 @@
"elevated_surface.background": "#2f343eff",
"surface.background": "#2f343eff",
"background": "#3b414dff",
- "element.background": "#2f343eff",
+ "element.background": "#2e343eff",
"element.hover": "#363c46ff",
"element.active": "#454a56ff",
"element.selected": "#454a56ff",
- "element.disabled": "#2f343eff",
+ "element.disabled": "#2e343eff",
"drop_target.background": "#83899480",
"ghost_element.background": "#00000000",
"ghost_element.hover": "#363c46ff",
"ghost_element.active": "#454a56ff",
"ghost_element.selected": "#454a56ff",
- "ghost_element.disabled": "#2f343eff",
+ "ghost_element.disabled": "#2e343eff",
"text": "#c8ccd4ff",
"text.muted": "#838994ff",
- "text.placeholder": "#555a63ff",
- "text.disabled": "#555a63ff",
+ "text.placeholder": "#696B77ff",
+ "text.disabled": "#696B77ff",
"text.accent": "#74ade8ff",
"icon": "#c8ccd4ff",
"icon.muted": "#838994ff",
- "icon.disabled": "#555a63ff",
+ "icon.disabled": "#696B77ff",
"icon.placeholder": "#838994ff",
"icon.accent": "#74ade8ff",
"status_bar.background": "#3b414dff",
"title_bar.background": "#3b414dff",
+ "title_bar.inactive_background": "#2e343eff",
"toolbar.background": "#282c33ff",
"tab_bar.background": "#2f343eff",
"tab.inactive_background": "#2f343eff",
@@ -59,7 +60,7 @@
"editor.highlighted_line.background": "#2f343eff",
"editor.line_number": "#c8ccd459",
"editor.active_line_number": "#c8ccd4ff",
- "editor.invisible": "#555a63ff",
+ "editor.invisible": "#696B77ff",
"editor.wrap_guide": "#c8ccd40d",
"editor.active_wrap_guide": "#c8ccd41a",
"editor.document_highlight.read_background": "#74ade81a",
@@ -94,46 +95,46 @@
"terminal.ansi.dim_white": "#575d65ff",
"link_text.hover": "#74ade8ff",
"conflict": "#dec184ff",
- "conflict.background": "#41321dff",
+ "conflict.background": "#dec1841a",
"conflict.border": "#5d4c2fff",
"created": "#a1c181ff",
- "created.background": "#222e1dff",
+ "created.background": "#a1c1811a",
"created.border": "#38482fff",
"deleted": "#d07277ff",
- "deleted.background": "#301b1bff",
+ "deleted.background": "#d072771a",
"deleted.border": "#4c2b2cff",
"error": "#d07277ff",
- "error.background": "#301b1bff",
+ "error.background": "#d072771a",
"error.border": "#4c2b2cff",
- "hidden": "#555a63ff",
- "hidden.background": "#3b414dff",
+ "hidden": "#696B77ff",
+ "hidden.background": "#696B771a",
"hidden.border": "#414754ff",
"hint": "#5a6f89ff",
- "hint.background": "#18243dff",
+ "hint.background": "#5a6f891a",
"hint.border": "#293b5bff",
- "ignored": "#555a63ff",
- "ignored.background": "#3b414dff",
+ "ignored": "#696B77ff",
+ "ignored.background": "#696B771a",
"ignored.border": "#464b57ff",
"info": "#74ade8ff",
- "info.background": "#18243dff",
+ "info.background": "#74ade81a",
"info.border": "#293b5bff",
"modified": "#dec184ff",
- "modified.background": "#41321dff",
+ "modified.background": "#dec1841a",
"modified.border": "#5d4c2fff",
"predictive": "#5a6a87ff",
- "predictive.background": "#222e1dff",
+ "predictive.background": "#5a6a871a",
"predictive.border": "#38482fff",
"renamed": "#74ade8ff",
- "renamed.background": "#18243dff",
+ "renamed.background": "#74ade81a",
"renamed.border": "#293b5bff",
"success": "#a1c181ff",
- "success.background": "#222e1dff",
+ "success.background": "#a1c1811a",
"success.border": "#38482fff",
"unreachable": "#838994ff",
- "unreachable.background": "#3b414dff",
+ "unreachable.background": "#8389941a",
"unreachable.border": "#464b57ff",
"warning": "#dec184ff",
- "warning.background": "#41321dff",
+ "warning.background": "#dec1841a",
"warning.border": "#5d4c2fff",
"players": [
{
@@ -412,6 +413,7 @@
"icon.accent": "#5c78e2ff",
"status_bar.background": "#dcdcddff",
"title_bar.background": "#dcdcddff",
+ "title_bar.inactive_background": "#ebebecff",
"toolbar.background": "#fafafaff",
"tab_bar.background": "#ebebecff",
"tab.inactive_background": "#ebebecff",
@@ -491,7 +493,7 @@
"info": "#5c78e2ff",
"info.background": "#e2e2faff",
"info.border": "#cbcdf6ff",
- "modified": "#dec184ff",
+ "modified": "#a47a23ff",
"modified.background": "#faf2e6ff",
"modified.border": "#f4e7d1ff",
"predictive": "#9b9ec6ff",
diff --git a/assets/themes/rose_pine/rose_pine.json b/assets/themes/rose_pine/rose_pine.json
index 7d5865fdbec040..99778348ba038d 100644
--- a/assets/themes/rose_pine/rose_pine.json
+++ b/assets/themes/rose_pine/rose_pine.json
@@ -38,6 +38,7 @@
"icon.accent": "#9bced6ff",
"status_bar.background": "#292738ff",
"title_bar.background": "#292738ff",
+ "title_bar.inactive_background": "#1c1b2aff",
"toolbar.background": "#191724ff",
"tab_bar.background": "#1c1b2aff",
"tab.inactive_background": "#1c1b2aff",
@@ -417,6 +418,7 @@
"icon.accent": "#57949fff",
"status_bar.background": "#dcd8d8ff",
"title_bar.background": "#dcd8d8ff",
+ "title_bar.inactive_background": "#fef9f2ff",
"toolbar.background": "#faf4edff",
"tab_bar.background": "#fef9f2ff",
"tab.inactive_background": "#fef9f2ff",
@@ -796,6 +798,7 @@
"icon.accent": "#9bced6ff",
"status_bar.background": "#38354eff",
"title_bar.background": "#38354eff",
+ "title_bar.inactive_background": "#28253cff",
"toolbar.background": "#232136ff",
"tab_bar.background": "#28253cff",
"tab.inactive_background": "#28253cff",
diff --git a/assets/themes/sandcastle/sandcastle.json b/assets/themes/sandcastle/sandcastle.json
index 83f8ef68ddf9ab..12e1e2d2297926 100644
--- a/assets/themes/sandcastle/sandcastle.json
+++ b/assets/themes/sandcastle/sandcastle.json
@@ -38,6 +38,7 @@
"icon.accent": "#518b8bff",
"status_bar.background": "#333944ff",
"title_bar.background": "#333944ff",
+ "title_bar.inactive_background": "#2b3038ff",
"toolbar.background": "#282c33ff",
"tab_bar.background": "#2b3038ff",
"tab.inactive_background": "#2b3038ff",
diff --git a/assets/themes/solarized/solarized.json b/assets/themes/solarized/solarized.json
index 53a4441c9febee..aa4e793e2a79ab 100644
--- a/assets/themes/solarized/solarized.json
+++ b/assets/themes/solarized/solarized.json
@@ -38,6 +38,7 @@
"icon.accent": "#278ad1ff",
"status_bar.background": "#073743ff",
"title_bar.background": "#073743ff",
+ "title_bar.inactive_background": "#04313bff",
"toolbar.background": "#002a35ff",
"tab_bar.background": "#04313bff",
"tab.inactive_background": "#04313bff",
@@ -407,6 +408,7 @@
"icon.accent": "#288bd1ff",
"status_bar.background": "#cfd0c4ff",
"title_bar.background": "#cfd0c4ff",
+ "title_bar.inactive_background": "#f3eddaff",
"toolbar.background": "#fdf6e3ff",
"tab_bar.background": "#f3eddaff",
"tab.inactive_background": "#f3eddaff",
diff --git a/assets/themes/summercamp/summercamp.json b/assets/themes/summercamp/summercamp.json
index 35b101ea383b44..51e9e2d61db6f0 100644
--- a/assets/themes/summercamp/summercamp.json
+++ b/assets/themes/summercamp/summercamp.json
@@ -38,6 +38,7 @@
"icon.accent": "#499befff",
"status_bar.background": "#2a261cff",
"title_bar.background": "#2a261cff",
+ "title_bar.inactive_background": "#231f16ff",
"toolbar.background": "#1b1810ff",
"tab_bar.background": "#231f16ff",
"tab.inactive_background": "#231f16ff",
diff --git a/docker-compose.yml b/compose.yml
similarity index 98%
rename from docker-compose.yml
rename to compose.yml
index af25ed3e6e7576..28f091fb6f04d4 100644
--- a/docker-compose.yml
+++ b/compose.yml
@@ -1,5 +1,3 @@
-version: "3.7"
-
services:
postgres:
image: postgres:15
diff --git a/crates/activity_indicator/src/activity_indicator.rs b/crates/activity_indicator/src/activity_indicator.rs
index b0ff7632786452..d39cb4af479c96 100644
--- a/crates/activity_indicator/src/activity_indicator.rs
+++ b/crates/activity_indicator/src/activity_indicator.rs
@@ -3,22 +3,22 @@ use editor::Editor;
use extension::ExtensionStore;
use futures::StreamExt;
use gpui::{
- actions, svg, AppContext, CursorStyle, EventEmitter, InteractiveElement as _, Model,
- ParentElement as _, Render, SharedString, StatefulInteractiveElement, Styled, View,
- ViewContext, VisualContext as _,
+ actions, anchored, deferred, percentage, Animation, AnimationExt as _, AppContext, CursorStyle,
+ DismissEvent, EventEmitter, InteractiveElement as _, Model, ParentElement as _, Render,
+ SharedString, StatefulInteractiveElement, Styled, Transformation, View, ViewContext,
+ VisualContext as _,
+};
+use language::{
+ LanguageRegistry, LanguageServerBinaryStatus, LanguageServerId, LanguageServerName,
};
-use language::{LanguageRegistry, LanguageServerBinaryStatus, LanguageServerName};
use project::{LanguageServerProgress, Project};
use smallvec::SmallVec;
-use std::{cmp::Reverse, fmt::Write, sync::Arc};
-use ui::prelude::*;
+use std::{cmp::Reverse, fmt::Write, sync::Arc, time::Duration};
+use ui::{prelude::*, ContextMenu};
use workspace::{item::ItemHandle, StatusItemView, Workspace};
actions!(activity_indicator, [ShowErrorMessage]);
-const DOWNLOAD_ICON: &str = "icons/download.svg";
-const WARNING_ICON: &str = "icons/warning.svg";
-
pub enum Event {
ShowError { lsp_name: Arc, error: String },
}
@@ -27,6 +27,7 @@ pub struct ActivityIndicator {
statuses: Vec,
project: Model,
auto_updater: Option>,
+ context_menu: Option>,
}
struct LspStatus {
@@ -35,14 +36,14 @@ struct LspStatus {
}
struct PendingWork<'a> {
- language_server_name: &'a str,
+ language_server_id: LanguageServerId,
progress_token: &'a str,
progress: &'a LanguageServerProgress,
}
#[derive(Default)]
struct Content {
- icon: Option<&'static str>,
+ icon: Option,
message: String,
on_click: Option)>>,
}
@@ -78,6 +79,7 @@ impl ActivityIndicator {
statuses: Default::default(),
project: project.clone(),
auto_updater,
+ context_menu: None,
}
});
@@ -105,6 +107,7 @@ impl ActivityIndicator {
Editor::for_buffer(buffer, Some(project.clone()), cx)
})),
None,
+ true,
cx,
);
})?;
@@ -151,7 +154,7 @@ impl ActivityIndicator {
.read(cx)
.language_server_statuses()
.rev()
- .filter_map(|status| {
+ .filter_map(|(server_id, status)| {
if status.pending_work.is_empty() {
None
} else {
@@ -159,7 +162,7 @@ impl ActivityIndicator {
.pending_work
.iter()
.map(|(token, progress)| PendingWork {
- language_server_name: status.name.as_str(),
+ language_server_id: server_id,
progress_token: token.as_str(),
progress,
})
@@ -175,33 +178,44 @@ impl ActivityIndicator {
// Show any language server has pending activity.
let mut pending_work = self.pending_language_server_work(cx);
if let Some(PendingWork {
- language_server_name,
progress_token,
progress,
+ ..
}) = pending_work.next()
{
- let mut message = language_server_name.to_string();
-
- message.push_str(": ");
- if let Some(progress_message) = progress.message.as_ref() {
- message.push_str(progress_message);
- } else {
- message.push_str(progress_token);
- }
+ let mut message = progress
+ .title
+ .as_deref()
+ .unwrap_or(progress_token)
+ .to_string();
if let Some(percentage) = progress.percentage {
write!(&mut message, " ({}%)", percentage).unwrap();
}
+ if let Some(progress_message) = progress.message.as_ref() {
+ message.push_str(": ");
+ message.push_str(progress_message);
+ }
+
let additional_work_count = pending_work.count();
if additional_work_count > 0 {
write!(&mut message, " + {} more", additional_work_count).unwrap();
}
return Content {
- icon: None,
+ icon: Some(
+ Icon::new(IconName::ArrowCircle)
+ .size(IconSize::Small)
+ .with_animation(
+ "arrow-circle",
+ Animation::new(Duration::from_secs(2)).repeat(),
+ |icon, delta| icon.transform(Transformation::rotate(percentage(delta))),
+ )
+ .into_any_element(),
+ ),
message,
- on_click: None,
+ on_click: Some(Arc::new(Self::toggle_language_server_work_context_menu)),
};
}
@@ -222,7 +236,11 @@ impl ActivityIndicator {
if !downloading.is_empty() {
return Content {
- icon: Some(DOWNLOAD_ICON),
+ icon: Some(
+ Icon::new(IconName::Download)
+ .size(IconSize::Small)
+ .into_any_element(),
+ ),
message: format!("Downloading {}...", downloading.join(", "),),
on_click: None,
};
@@ -230,7 +248,11 @@ impl ActivityIndicator {
if !checking_for_update.is_empty() {
return Content {
- icon: Some(DOWNLOAD_ICON),
+ icon: Some(
+ Icon::new(IconName::Download)
+ .size(IconSize::Small)
+ .into_any_element(),
+ ),
message: format!(
"Checking for updates to {}...",
checking_for_update.join(", "),
@@ -241,7 +263,11 @@ impl ActivityIndicator {
if !failed.is_empty() {
return Content {
- icon: Some(WARNING_ICON),
+ icon: Some(
+ Icon::new(IconName::ExclamationTriangle)
+ .size(IconSize::Small)
+ .into_any_element(),
+ ),
message: format!(
"Failed to download {}. Click to show error.",
failed.join(", "),
@@ -255,7 +281,11 @@ impl ActivityIndicator {
// Show any formatting failure
if let Some(failure) = self.project.read(cx).last_formatting_failure() {
return Content {
- icon: Some(WARNING_ICON),
+ icon: Some(
+ Icon::new(IconName::ExclamationTriangle)
+ .size(IconSize::Small)
+ .into_any_element(),
+ ),
message: format!("Formatting failed: {}. Click to see logs.", failure),
on_click: Some(Arc::new(|_, cx| {
cx.dispatch_action(Box::new(workspace::OpenLog));
@@ -267,17 +297,29 @@ impl ActivityIndicator {
if let Some(updater) = &self.auto_updater {
return match &updater.read(cx).status() {
AutoUpdateStatus::Checking => Content {
- icon: Some(DOWNLOAD_ICON),
+ icon: Some(
+ Icon::new(IconName::Download)
+ .size(IconSize::Small)
+ .into_any_element(),
+ ),
message: "Checking for Zed updates…".to_string(),
on_click: None,
},
AutoUpdateStatus::Downloading => Content {
- icon: Some(DOWNLOAD_ICON),
+ icon: Some(
+ Icon::new(IconName::Download)
+ .size(IconSize::Small)
+ .into_any_element(),
+ ),
message: "Downloading Zed update…".to_string(),
on_click: None,
},
AutoUpdateStatus::Installing => Content {
- icon: Some(DOWNLOAD_ICON),
+ icon: Some(
+ Icon::new(IconName::Download)
+ .size(IconSize::Small)
+ .into_any_element(),
+ ),
message: "Installing Zed update…".to_string(),
on_click: None,
},
@@ -285,14 +327,18 @@ impl ActivityIndicator {
icon: None,
message: "Click to restart and update Zed".to_string(),
on_click: Some(Arc::new({
- let restart = workspace::Restart {
+ let reload = workspace::Reload {
binary_path: Some(binary_path.clone()),
};
- move |_, cx| workspace::restart(&restart, cx)
+ move |_, cx| workspace::reload(&reload, cx)
})),
},
AutoUpdateStatus::Errored => Content {
- icon: Some(WARNING_ICON),
+ icon: Some(
+ Icon::new(IconName::ExclamationTriangle)
+ .size(IconSize::Small)
+ .into_any_element(),
+ ),
message: "Auto update failed".to_string(),
on_click: Some(Arc::new(|this, cx| {
this.dismiss_error_message(&Default::default(), cx)
@@ -307,7 +353,11 @@ impl ActivityIndicator {
{
if let Some(extension_id) = extension_store.outstanding_operations().keys().next() {
return Content {
- icon: Some(DOWNLOAD_ICON),
+ icon: Some(
+ Icon::new(IconName::Download)
+ .size(IconSize::Small)
+ .into_any_element(),
+ ),
message: format!("Updating {extension_id} extension…"),
on_click: None,
};
@@ -316,6 +366,75 @@ impl ActivityIndicator {
Default::default()
}
+
+ fn toggle_language_server_work_context_menu(&mut self, cx: &mut ViewContext) {
+ if self.context_menu.take().is_some() {
+ return;
+ }
+
+ self.build_lsp_work_context_menu(cx);
+ cx.notify();
+ }
+
+ fn build_lsp_work_context_menu(&mut self, cx: &mut ViewContext) {
+ let mut has_work = false;
+ let this = cx.view().downgrade();
+ let context_menu = ContextMenu::build(cx, |mut menu, cx| {
+ for work in self.pending_language_server_work(cx) {
+ has_work = true;
+
+ let this = this.clone();
+ let title = SharedString::from(
+ work.progress
+ .title
+ .as_deref()
+ .unwrap_or(work.progress_token)
+ .to_string(),
+ );
+ if work.progress.is_cancellable {
+ let language_server_id = work.language_server_id;
+ let token = work.progress_token.to_string();
+ menu = menu.custom_entry(
+ move |_| {
+ h_flex()
+ .w_full()
+ .justify_between()
+ .child(Label::new(title.clone()))
+ .child(Icon::new(IconName::XCircle))
+ .into_any_element()
+ },
+ move |cx| {
+ this.update(cx, |this, cx| {
+ this.project.update(cx, |project, cx| {
+ project.cancel_language_server_work(
+ language_server_id,
+ Some(token.clone()),
+ cx,
+ );
+ });
+ this.context_menu.take();
+ })
+ .ok();
+ },
+ );
+ } else {
+ menu = menu.label(title.clone());
+ }
+ }
+ menu
+ });
+
+ if has_work {
+ cx.subscribe(&context_menu, |this, _, _: &DismissEvent, cx| {
+ this.context_menu.take();
+ cx.notify();
+ })
+ .detach();
+ cx.focus_view(&context_menu);
+ self.context_menu = Some(context_menu);
+ cx.notify();
+ }
+ }
}
impl EventEmitter for ActivityIndicator {}
@@ -338,8 +457,17 @@ impl Render for ActivityIndicator {
}
result
- .children(content.icon.map(|icon| svg().path(icon)))
+ .gap_2()
+ .children(content.icon)
.child(Label::new(SharedString::from(content.message)).size(LabelSize::Small))
+ .children(self.context_menu.as_ref().map(|menu| {
+ deferred(
+ anchored()
+ .anchor(gpui::AnchorCorner::BottomLeft)
+ .child(menu.clone()),
+ )
+ .with_priority(1)
+ }))
}
}
diff --git a/crates/anthropic/Cargo.toml b/crates/anthropic/Cargo.toml
index 484a9b3e10f0ed..0ea24d5c0770bf 100644
--- a/crates/anthropic/Cargo.toml
+++ b/crates/anthropic/Cargo.toml
@@ -23,6 +23,7 @@ isahc.workspace = true
schemars = { workspace = true, optional = true }
serde.workspace = true
serde_json.workspace = true
+strum.workspace = true
[dev-dependencies]
tokio.workspace = true
diff --git a/crates/anthropic/src/anthropic.rs b/crates/anthropic/src/anthropic.rs
index 65df4e74dc65bc..c36a7f37fd25cd 100644
--- a/crates/anthropic/src/anthropic.rs
+++ b/crates/anthropic/src/anthropic.rs
@@ -4,13 +4,16 @@ use http::{AsyncBody, HttpClient, Method, Request as HttpRequest};
use isahc::config::Configurable;
use serde::{Deserialize, Serialize};
use std::{convert::TryFrom, time::Duration};
+use strum::EnumIter;
pub const ANTHROPIC_API_URL: &'static str = "https://api.anthropic.com";
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
-#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, EnumIter)]
pub enum Model {
#[default]
+ #[serde(alias = "claude-3-5-sonnet", rename = "claude-3-5-sonnet-20240620")]
+ Claude3_5Sonnet,
#[serde(alias = "claude-3-opus", rename = "claude-3-opus-20240229")]
Claude3Opus,
#[serde(alias = "claude-3-sonnet", rename = "claude-3-sonnet-20240229")]
@@ -21,7 +24,9 @@ pub enum Model {
impl Model {
pub fn from_id(id: &str) -> Result {
- if id.starts_with("claude-3-opus") {
+ if id.starts_with("claude-3-5-sonnet") {
+ Ok(Self::Claude3_5Sonnet)
+ } else if id.starts_with("claude-3-opus") {
Ok(Self::Claude3Opus)
} else if id.starts_with("claude-3-sonnet") {
Ok(Self::Claude3Sonnet)
@@ -34,6 +39,7 @@ impl Model {
pub fn id(&self) -> &'static str {
match self {
+ Model::Claude3_5Sonnet => "claude-3-5-sonnet-20240620",
Model::Claude3Opus => "claude-3-opus-20240229",
Model::Claude3Sonnet => "claude-3-sonnet-20240229",
Model::Claude3Haiku => "claude-3-opus-20240307",
@@ -42,6 +48,7 @@ impl Model {
pub fn display_name(&self) -> &'static str {
match self {
+ Self::Claude3_5Sonnet => "Claude 3.5 Sonnet",
Self::Claude3Opus => "Claude 3 Opus",
Self::Claude3Sonnet => "Claude 3 Sonnet",
Self::Claude3Haiku => "Claude 3 Haiku",
diff --git a/crates/assets/src/assets.rs b/crates/assets/src/assets.rs
index b0a32a9d9cfe5d..f9284bca86b3b9 100644
--- a/crates/assets/src/assets.rs
+++ b/crates/assets/src/assets.rs
@@ -16,9 +16,9 @@ use rust_embed::RustEmbed;
pub struct Assets;
impl AssetSource for Assets {
- fn load(&self, path: &str) -> Result> {
+ fn load(&self, path: &str) -> Result>> {
Self::get(path)
- .map(|f| f.data)
+ .map(|f| Some(f.data))
.ok_or_else(|| anyhow!("could not find asset at path \"{}\"", path))
}
@@ -42,11 +42,23 @@ impl Assets {
let mut embedded_fonts = Vec::new();
for font_path in font_paths {
if font_path.ends_with(".ttf") {
- let font_bytes = cx.asset_source().load(&font_path)?;
+ let font_bytes = cx
+ .asset_source()
+ .load(&font_path)?
+ .expect("Assets should never return None");
embedded_fonts.push(font_bytes);
}
}
cx.text_system().add_fonts(embedded_fonts)
}
+
+ pub fn load_test_fonts(&self, cx: &AppContext) {
+ cx.text_system()
+ .add_fonts(vec![self
+ .load("fonts/plex-mono/ZedPlexMono-Regular.ttf")
+ .unwrap()
+ .unwrap()])
+ .unwrap()
+ }
}
diff --git a/crates/assistant/Cargo.toml b/crates/assistant/Cargo.toml
index 1023296255e54a..e3ddd4e2c7454c 100644
--- a/crates/assistant/Cargo.toml
+++ b/crates/assistant/Cargo.toml
@@ -12,41 +12,62 @@ workspace = true
path = "src/assistant.rs"
doctest = false
+[features]
+test-support = [
+ "editor/test-support",
+ "language/test-support",
+ "project/test-support",
+ "text/test-support",
+]
+
[dependencies]
-anyhow.workspace = true
anthropic = { workspace = true, features = ["schemars"] }
+anyhow.workspace = true
+assets.workspace = true
assistant_slash_command.workspace = true
+async-watch.workspace = true
+breadcrumbs.workspace = true
cargo_toml.workspace = true
chrono.workspace = true
client.workspace = true
+clock.workspace = true
collections.workspace = true
command_palette_hooks.workspace = true
editor.workspace = true
-file_icons.workspace = true
+feature_flags.workspace = true
fs.workspace = true
futures.workspace = true
fuzzy.workspace = true
gpui.workspace = true
+heed.workspace = true
+html_to_markdown.workspace = true
http.workspace = true
+indexed_docs.workspace = true
indoc.workspace = true
language.workspace = true
log.workspace = true
menu.workspace = true
multi_buffer.workspace = true
+ollama = { workspace = true, features = ["schemars"] }
open_ai = { workspace = true, features = ["schemars"] }
ordered-float.workspace = true
parking_lot.workspace = true
+paths.workspace = true
project.workspace = true
regex.workspace = true
rope.workspace = true
schemars.workspace = true
search.workspace = true
+semantic_index.workspace = true
serde.workspace = true
serde_json.workspace = true
settings.workspace = true
+similar.workspace = true
smol.workspace = true
-strsim = "0.11"
+strum.workspace = true
telemetry_events.workspace = true
+terminal.workspace = true
+terminal_view.workspace = true
theme.workspace = true
tiktoken-rs.workspace = true
toml.workspace = true
@@ -55,13 +76,15 @@ util.workspace = true
uuid.workspace = true
workspace.workspace = true
picker.workspace = true
-gray_matter = "0.2.7"
+roxmltree = "0.20.0"
[dev-dependencies]
ctor.workspace = true
editor = { workspace = true, features = ["test-support"] }
env_logger.workspace = true
+language = { workspace = true, features = ["test-support"] }
log.workspace = true
project = { workspace = true, features = ["test-support"] }
rand.workspace = true
+text = { workspace = true, features = ["test-support"] }
unindent.workspace = true
diff --git a/crates/assistant/src/ambient_context.rs b/crates/assistant/src/ambient_context.rs
deleted file mode 100644
index cbb63b6044d487..00000000000000
--- a/crates/assistant/src/ambient_context.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-mod current_project;
-mod recent_buffers;
-
-pub use current_project::*;
-pub use recent_buffers::*;
-
-#[derive(Default)]
-pub struct AmbientContext {
- pub recent_buffers: RecentBuffersContext,
- pub current_project: CurrentProjectContext,
-}
-
-impl AmbientContext {
- pub fn snapshot(&self) -> AmbientContextSnapshot {
- AmbientContextSnapshot {
- recent_buffers: self.recent_buffers.snapshot.clone(),
- }
- }
-}
-
-#[derive(Clone, Default, Debug)]
-pub struct AmbientContextSnapshot {
- pub recent_buffers: RecentBuffersSnapshot,
-}
-
-#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
-pub enum ContextUpdated {
- Updating,
- Disabled,
-}
diff --git a/crates/assistant/src/ambient_context/current_project.rs b/crates/assistant/src/ambient_context/current_project.rs
deleted file mode 100644
index f89a2a88562f5c..00000000000000
--- a/crates/assistant/src/ambient_context/current_project.rs
+++ /dev/null
@@ -1,180 +0,0 @@
-use std::fmt::Write;
-use std::path::{Path, PathBuf};
-use std::sync::Arc;
-use std::time::Duration;
-
-use anyhow::{anyhow, Result};
-use fs::Fs;
-use gpui::{AsyncAppContext, ModelContext, Task, WeakModel};
-use project::{Project, ProjectPath};
-use util::ResultExt;
-
-use crate::ambient_context::ContextUpdated;
-use crate::assistant_panel::Conversation;
-use crate::{LanguageModelRequestMessage, Role};
-
-/// Ambient context about the current project.
-pub struct CurrentProjectContext {
- pub enabled: bool,
- pub message: String,
- pub pending_message: Option>,
-}
-
-#[allow(clippy::derivable_impls)]
-impl Default for CurrentProjectContext {
- fn default() -> Self {
- Self {
- enabled: false,
- message: String::new(),
- pending_message: None,
- }
- }
-}
-
-impl CurrentProjectContext {
- /// Returns the [`CurrentProjectContext`] as a message to the language model.
- pub fn to_message(&self) -> Option {
- self.enabled
- .then(|| LanguageModelRequestMessage {
- role: Role::System,
- content: self.message.clone(),
- })
- .filter(|message| !message.content.is_empty())
- }
-
- /// Updates the [`CurrentProjectContext`] for the given [`Project`].
- pub fn update(
- &mut self,
- fs: Arc,
- project: WeakModel,
- cx: &mut ModelContext,
- ) -> ContextUpdated {
- if !self.enabled {
- self.message.clear();
- self.pending_message = None;
- cx.notify();
- return ContextUpdated::Disabled;
- }
-
- self.pending_message = Some(cx.spawn(|conversation, mut cx| async move {
- const DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
- cx.background_executor().timer(DEBOUNCE_TIMEOUT).await;
-
- let Some(path_to_cargo_toml) = Self::path_to_cargo_toml(project, &mut cx).log_err()
- else {
- return;
- };
-
- let Some(path_to_cargo_toml) = path_to_cargo_toml
- .ok_or_else(|| anyhow!("no Cargo.toml"))
- .log_err()
- else {
- return;
- };
-
- let message_task = cx
- .background_executor()
- .spawn(async move { Self::build_message(fs, &path_to_cargo_toml).await });
-
- if let Some(message) = message_task.await.log_err() {
- conversation
- .update(&mut cx, |conversation, cx| {
- conversation.ambient_context.current_project.message = message;
- conversation.count_remaining_tokens(cx);
- cx.notify();
- })
- .log_err();
- }
- }));
-
- ContextUpdated::Updating
- }
-
- async fn build_message(fs: Arc, path_to_cargo_toml: &Path) -> Result {
- let buffer = fs.load(path_to_cargo_toml).await?;
- let cargo_toml: cargo_toml::Manifest = toml::from_str(&buffer)?;
-
- let mut message = String::new();
- writeln!(message, "You are in a Rust project.")?;
-
- if let Some(workspace) = cargo_toml.workspace {
- writeln!(
- message,
- "The project is a Cargo workspace with the following members:"
- )?;
- for member in workspace.members {
- writeln!(message, "- {member}")?;
- }
-
- if !workspace.default_members.is_empty() {
- writeln!(message, "The default members are:")?;
- for member in workspace.default_members {
- writeln!(message, "- {member}")?;
- }
- }
-
- if !workspace.dependencies.is_empty() {
- writeln!(
- message,
- "The following workspace dependencies are installed:"
- )?;
- for dependency in workspace.dependencies.keys() {
- writeln!(message, "- {dependency}")?;
- }
- }
- } else if let Some(package) = cargo_toml.package {
- writeln!(
- message,
- "The project name is \"{name}\".",
- name = package.name
- )?;
-
- let description = package
- .description
- .as_ref()
- .and_then(|description| description.get().ok().cloned());
- if let Some(description) = description.as_ref() {
- writeln!(message, "It describes itself as \"{description}\".")?;
- }
-
- if !cargo_toml.dependencies.is_empty() {
- writeln!(message, "The following dependencies are installed:")?;
- for dependency in cargo_toml.dependencies.keys() {
- writeln!(message, "- {dependency}")?;
- }
- }
- }
-
- Ok(message)
- }
-
- fn path_to_cargo_toml(
- project: WeakModel,
- cx: &mut AsyncAppContext,
- ) -> Result> {
- cx.update(|cx| {
- let worktree = project.update(cx, |project, _cx| {
- project
- .worktrees()
- .next()
- .ok_or_else(|| anyhow!("no worktree"))
- })??;
-
- let path_to_cargo_toml = worktree.update(cx, |worktree, _cx| {
- let cargo_toml = worktree.entry_for_path("Cargo.toml")?;
- Some(ProjectPath {
- worktree_id: worktree.id(),
- path: cargo_toml.path.clone(),
- })
- });
- let path_to_cargo_toml = path_to_cargo_toml.and_then(|path| {
- project
- .update(cx, |project, cx| project.absolute_path(&path, cx))
- .ok()
- .flatten()
- });
-
- Ok(path_to_cargo_toml)
- })?
- }
-}
diff --git a/crates/assistant/src/ambient_context/recent_buffers.rs b/crates/assistant/src/ambient_context/recent_buffers.rs
deleted file mode 100644
index 056fbd11834d27..00000000000000
--- a/crates/assistant/src/ambient_context/recent_buffers.rs
+++ /dev/null
@@ -1,147 +0,0 @@
-use crate::{assistant_panel::Conversation, LanguageModelRequestMessage, Role};
-use gpui::{ModelContext, Subscription, Task, WeakModel};
-use language::{Buffer, BufferSnapshot, Rope};
-use std::{fmt::Write, path::PathBuf, time::Duration};
-
-use super::ContextUpdated;
-
-pub struct RecentBuffersContext {
- pub enabled: bool,
- pub buffers: Vec,
- pub snapshot: RecentBuffersSnapshot,
- pub pending_message: Option>,
-}
-
-pub struct RecentBuffer {
- pub buffer: WeakModel,
- pub _subscription: Subscription,
-}
-
-impl Default for RecentBuffersContext {
- fn default() -> Self {
- Self {
- enabled: true,
- buffers: Vec::new(),
- snapshot: RecentBuffersSnapshot::default(),
- pending_message: None,
- }
- }
-}
-
-impl RecentBuffersContext {
- pub fn update(&mut self, cx: &mut ModelContext) -> ContextUpdated {
- let source_buffers = self
- .buffers
- .iter()
- .filter_map(|recent| {
- let (full_path, snapshot) = recent
- .buffer
- .read_with(cx, |buffer, cx| {
- (
- buffer.file().map(|file| file.full_path(cx)),
- buffer.snapshot(),
- )
- })
- .ok()?;
- Some(SourceBufferSnapshot {
- full_path,
- model: recent.buffer.clone(),
- snapshot,
- })
- })
- .collect::>();
-
- if !self.enabled || source_buffers.is_empty() {
- self.snapshot.message = Default::default();
- self.snapshot.source_buffers.clear();
- self.pending_message = None;
- cx.notify();
- ContextUpdated::Disabled
- } else {
- self.pending_message = Some(cx.spawn(|this, mut cx| async move {
- const DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
- cx.background_executor().timer(DEBOUNCE_TIMEOUT).await;
-
- let message = if source_buffers.is_empty() {
- Rope::new()
- } else {
- cx.background_executor()
- .spawn({
- let source_buffers = source_buffers.clone();
- async move { message_for_recent_buffers(source_buffers) }
- })
- .await
- };
- this.update(&mut cx, |this, cx| {
- this.ambient_context.recent_buffers.snapshot.source_buffers = source_buffers;
- this.ambient_context.recent_buffers.snapshot.message = message;
- this.count_remaining_tokens(cx);
- cx.notify();
- })
- .ok();
- }));
-
- ContextUpdated::Updating
- }
- }
-
- /// Returns the [`RecentBuffersContext`] as a message to the language model.
- pub fn to_message(&self) -> Option {
- self.enabled
- .then(|| LanguageModelRequestMessage {
- role: Role::System,
- content: self.snapshot.message.to_string(),
- })
- .filter(|message| !message.content.is_empty())
- }
-}
-
-#[derive(Clone, Default, Debug)]
-pub struct RecentBuffersSnapshot {
- pub message: Rope,
- pub source_buffers: Vec,
-}
-
-#[derive(Clone)]
-pub struct SourceBufferSnapshot {
- pub full_path: Option,
- pub model: WeakModel,
- pub snapshot: BufferSnapshot,
-}
-
-impl std::fmt::Debug for SourceBufferSnapshot {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.debug_struct("SourceBufferSnapshot")
- .field("full_path", &self.full_path)
- .field("model (entity id)", &self.model.entity_id())
- .field("snapshot (text)", &self.snapshot.text())
- .finish()
- }
-}
-
-fn message_for_recent_buffers(buffers: Vec) -> Rope {
- let mut message = String::new();
- writeln!(
- message,
- "The following is a list of recent buffers that the user has opened."
- )
- .unwrap();
-
- for buffer in buffers {
- if let Some(path) = buffer.full_path {
- writeln!(message, "```{}", path.display()).unwrap();
- } else {
- writeln!(message, "```untitled").unwrap();
- }
-
- for chunk in buffer.snapshot.chunks(0..buffer.snapshot.len(), false) {
- message.push_str(chunk.text);
- }
- if !message.ends_with('\n') {
- message.push('\n');
- }
- message.push_str("```\n");
- }
-
- Rope::from(message.as_str())
-}
diff --git a/crates/assistant/src/assistant.rs b/crates/assistant/src/assistant.rs
index da1be612c5455c..cf3726485ff490 100644
--- a/crates/assistant/src/assistant.rs
+++ b/crates/assistant/src/assistant.rs
@@ -1,29 +1,42 @@
-mod ambient_context;
pub mod assistant_panel;
pub mod assistant_settings;
-mod codegen;
mod completion_provider;
-mod omit_ranges;
+mod context;
+pub mod context_store;
+mod inline_assistant;
+mod model_selector;
+mod prompt_library;
mod prompts;
-mod saved_conversation;
-mod search;
mod slash_command;
mod streaming_diff;
+mod terminal_inline_assistant;
-use ambient_context::AmbientContextSnapshot;
-pub use assistant_panel::AssistantPanel;
-use assistant_settings::{AnthropicModel, AssistantSettings, OpenAiModel, ZedDotDevModel};
+pub use assistant_panel::{AssistantPanel, AssistantPanelEvent};
+use assistant_settings::{AnthropicModel, AssistantSettings, CloudModel, OllamaModel, OpenAiModel};
+use assistant_slash_command::SlashCommandRegistry;
use client::{proto, Client};
use command_palette_hooks::CommandPaletteFilter;
-pub(crate) use completion_provider::*;
-use gpui::{actions, AppContext, Global, SharedString, UpdateGlobal};
-pub(crate) use saved_conversation::*;
+pub use completion_provider::*;
+pub use context::*;
+pub use context_store::*;
+use fs::Fs;
+use gpui::{actions, impl_actions, AppContext, Global, SharedString, UpdateGlobal};
+use indexed_docs::IndexedDocsRegistry;
+pub(crate) use inline_assistant::*;
+pub(crate) use model_selector::*;
+use semantic_index::{CloudEmbeddingProvider, SemanticIndex};
use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsStore};
+use slash_command::{
+ active_command, default_command, diagnostics_command, docs_command, fetch_command,
+ file_command, now_command, project_command, prompt_command, search_command, symbols_command,
+ tabs_command, term_command,
+};
use std::{
fmt::{self, Display},
sync::Arc,
};
+pub(crate) use streaming_diff::*;
actions!(
assistant,
@@ -32,20 +45,33 @@ actions!(
Split,
CycleMessageRole,
QuoteSelection,
+ InsertIntoEditor,
ToggleFocus,
ResetKey,
- InlineAssist,
InsertActivePrompt,
- ToggleIncludeConversation,
- ToggleHistory,
- ApplyEdit
+ DeployHistory,
+ DeployPromptLibrary,
+ ConfirmCommand,
+ ToggleModelSelector,
+ DebugEditSteps
]
);
-#[derive(
- Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize,
-)]
-struct MessageId(usize);
+#[derive(Clone, Default, Deserialize, PartialEq)]
+pub struct InlineAssist {
+ prompt: Option,
+}
+
+impl_actions!(assistant, [InlineAssist]);
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
+pub struct MessageId(clock::Lamport);
+
+impl MessageId {
+ pub fn as_u64(self) -> u64 {
+ self.0.as_u64()
+ }
+}
#[derive(Clone, Copy, Serialize, Deserialize, Debug, Eq, PartialEq)]
#[serde(rename_all = "lowercase")]
@@ -56,8 +82,26 @@ pub enum Role {
}
impl Role {
- pub fn cycle(&mut self) {
- *self = match self {
+ pub fn from_proto(role: i32) -> Role {
+ match proto::LanguageModelRole::from_i32(role) {
+ Some(proto::LanguageModelRole::LanguageModelUser) => Role::User,
+ Some(proto::LanguageModelRole::LanguageModelAssistant) => Role::Assistant,
+ Some(proto::LanguageModelRole::LanguageModelSystem) => Role::System,
+ Some(proto::LanguageModelRole::LanguageModelTool) => Role::System,
+ None => Role::User,
+ }
+ }
+
+ pub fn to_proto(&self) -> proto::LanguageModelRole {
+ match self {
+ Role::User => proto::LanguageModelRole::LanguageModelUser,
+ Role::Assistant => proto::LanguageModelRole::LanguageModelAssistant,
+ Role::System => proto::LanguageModelRole::LanguageModelSystem,
+ }
+ }
+
+ pub fn cycle(self) -> Role {
+ match self {
Role::User => Role::Assistant,
Role::Assistant => Role::System,
Role::System => Role::User,
@@ -77,14 +121,15 @@ impl Display for Role {
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub enum LanguageModel {
- ZedDotDev(ZedDotDevModel),
+ Cloud(CloudModel),
OpenAi(OpenAiModel),
Anthropic(AnthropicModel),
+ Ollama(OllamaModel),
}
impl Default for LanguageModel {
fn default() -> Self {
- LanguageModel::ZedDotDev(ZedDotDevModel::default())
+ LanguageModel::Cloud(CloudModel::default())
}
}
@@ -93,7 +138,8 @@ impl LanguageModel {
match self {
LanguageModel::OpenAi(model) => format!("openai/{}", model.id()),
LanguageModel::Anthropic(model) => format!("anthropic/{}", model.id()),
- LanguageModel::ZedDotDev(model) => format!("zed.dev/{}", model.id()),
+ LanguageModel::Cloud(model) => format!("zed.dev/{}", model.id()),
+ LanguageModel::Ollama(model) => format!("ollama/{}", model.id()),
}
}
@@ -101,7 +147,8 @@ impl LanguageModel {
match self {
LanguageModel::OpenAi(model) => model.display_name().into(),
LanguageModel::Anthropic(model) => model.display_name().into(),
- LanguageModel::ZedDotDev(model) => model.display_name().into(),
+ LanguageModel::Cloud(model) => model.display_name().into(),
+ LanguageModel::Ollama(model) => model.display_name().into(),
}
}
@@ -109,7 +156,8 @@ impl LanguageModel {
match self {
LanguageModel::OpenAi(model) => model.max_token_count(),
LanguageModel::Anthropic(model) => model.max_token_count(),
- LanguageModel::ZedDotDev(model) => model.max_token_count(),
+ LanguageModel::Cloud(model) => model.max_token_count(),
+ LanguageModel::Ollama(model) => model.max_token_count(),
}
}
@@ -117,7 +165,8 @@ impl LanguageModel {
match self {
LanguageModel::OpenAi(model) => model.id(),
LanguageModel::Anthropic(model) => model.id(),
- LanguageModel::ZedDotDev(model) => model.id(),
+ LanguageModel::Cloud(model) => model.id(),
+ LanguageModel::Ollama(model) => model.id(),
}
}
}
@@ -131,11 +180,7 @@ pub struct LanguageModelRequestMessage {
impl LanguageModelRequestMessage {
pub fn to_proto(&self) -> proto::LanguageModelRequestMessage {
proto::LanguageModelRequestMessage {
- role: match self.role {
- Role::User => proto::LanguageModelRole::LanguageModelUser,
- Role::Assistant => proto::LanguageModelRole::LanguageModelAssistant,
- Role::System => proto::LanguageModelRole::LanguageModelSystem,
- } as i32,
+ role: self.role.to_proto() as i32,
content: self.content.clone(),
tool_calls: Vec::new(),
tool_call_id: None,
@@ -143,7 +188,7 @@ impl LanguageModelRequestMessage {
}
}
-#[derive(Debug, Default, Serialize)]
+#[derive(Debug, Default, Serialize, Deserialize)]
pub struct LanguageModelRequest {
pub model: LanguageModel,
pub messages: Vec,
@@ -162,6 +207,24 @@ impl LanguageModelRequest {
tools: Vec::new(),
}
}
+
+ /// Before we send the request to the server, we can perform fixups on it appropriate to the model.
+ pub fn preprocess(&mut self) {
+ match &self.model {
+ LanguageModel::OpenAi(_) => {}
+ LanguageModel::Anthropic(_) => {}
+ LanguageModel::Ollama(_) => {}
+ LanguageModel::Cloud(model) => match model {
+ CloudModel::Claude3Opus
+ | CloudModel::Claude3Sonnet
+ | CloudModel::Claude3Haiku
+ | CloudModel::Claude3_5Sonnet => {
+ preprocess_anthropic_request(self);
+ }
+ _ => {}
+ },
+ }
+ }
}
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
@@ -184,22 +247,48 @@ pub struct LanguageModelChoiceDelta {
pub finish_reason: Option,
}
-#[derive(Clone, Debug, Serialize, Deserialize)]
-struct MessageMetadata {
- role: Role,
- status: MessageStatus,
- // TODO: Delete this
- #[serde(skip)]
- ambient_context: AmbientContextSnapshot,
-}
-
-#[derive(Clone, Debug, Serialize, Deserialize)]
-enum MessageStatus {
+#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
+pub enum MessageStatus {
Pending,
Done,
Error(SharedString),
}
+impl MessageStatus {
+ pub fn from_proto(status: proto::ContextMessageStatus) -> MessageStatus {
+ match status.variant {
+ Some(proto::context_message_status::Variant::Pending(_)) => MessageStatus::Pending,
+ Some(proto::context_message_status::Variant::Done(_)) => MessageStatus::Done,
+ Some(proto::context_message_status::Variant::Error(error)) => {
+ MessageStatus::Error(error.message.into())
+ }
+ None => MessageStatus::Pending,
+ }
+ }
+
+ pub fn to_proto(&self) -> proto::ContextMessageStatus {
+ match self {
+ MessageStatus::Pending => proto::ContextMessageStatus {
+ variant: Some(proto::context_message_status::Variant::Pending(
+ proto::context_message_status::Pending {},
+ )),
+ },
+ MessageStatus::Done => proto::ContextMessageStatus {
+ variant: Some(proto::context_message_status::Variant::Done(
+ proto::context_message_status::Done {},
+ )),
+ },
+ MessageStatus::Error(message) => proto::ContextMessageStatus {
+ variant: Some(proto::context_message_status::Variant::Error(
+ proto::context_message_status::Error {
+ message: message.to_string(),
+ },
+ )),
+ },
+ }
+ }
+}
+
/// The state pertaining to the Assistant.
#[derive(Default)]
struct Assistant {
@@ -233,12 +322,34 @@ impl Assistant {
}
}
-pub fn init(client: Arc, cx: &mut AppContext) {
+pub fn init(fs: Arc, client: Arc, cx: &mut AppContext) {
cx.set_global(Assistant::default());
AssistantSettings::register(cx);
- completion_provider::init(client, cx);
+
+ cx.spawn(|mut cx| {
+ let client = client.clone();
+ async move {
+ let embedding_provider = CloudEmbeddingProvider::new(client.clone());
+ let semantic_index = SemanticIndex::new(
+ paths::embeddings_dir().join("semantic-index-db.0.mdb"),
+ Arc::new(embedding_provider),
+ &mut cx,
+ )
+ .await?;
+ cx.update(|cx| cx.set_global(semantic_index))
+ }
+ })
+ .detach();
+
+ context_store::init(&client);
+ prompt_library::init(cx);
+ completion_provider::init(client.clone(), cx);
assistant_slash_command::init(cx);
+ register_slash_commands(cx);
assistant_panel::init(cx);
+ inline_assistant::init(fs.clone(), client.telemetry().clone(), cx);
+ terminal_inline_assistant::init(fs.clone(), client.telemetry().clone(), cx);
+ IndexedDocsRegistry::init_global(cx);
CommandPaletteFilter::update_global(cx, |filter, _cx| {
filter.hide_namespace(Assistant::NAMESPACE);
@@ -251,13 +362,47 @@ pub fn init(client: Arc, cx: &mut AppContext) {
cx.observe_global::(|cx| {
Assistant::update_global(cx, |assistant, cx| {
let settings = AssistantSettings::get_global(cx);
-
assistant.set_enabled(settings.enabled, cx);
});
})
.detach();
}
+fn register_slash_commands(cx: &mut AppContext) {
+ let slash_command_registry = SlashCommandRegistry::global(cx);
+ slash_command_registry.register_command(file_command::FileSlashCommand, true);
+ slash_command_registry.register_command(active_command::ActiveSlashCommand, true);
+ slash_command_registry.register_command(symbols_command::OutlineSlashCommand, true);
+ slash_command_registry.register_command(tabs_command::TabsSlashCommand, true);
+ slash_command_registry.register_command(project_command::ProjectSlashCommand, true);
+ slash_command_registry.register_command(search_command::SearchSlashCommand, true);
+ slash_command_registry.register_command(prompt_command::PromptSlashCommand, true);
+ slash_command_registry.register_command(default_command::DefaultSlashCommand, true);
+ slash_command_registry.register_command(term_command::TermSlashCommand, true);
+ slash_command_registry.register_command(now_command::NowSlashCommand, true);
+ slash_command_registry.register_command(diagnostics_command::DiagnosticsSlashCommand, true);
+ slash_command_registry.register_command(docs_command::DocsSlashCommand, true);
+ slash_command_registry.register_command(fetch_command::FetchSlashCommand, false);
+}
+
+pub fn humanize_token_count(count: usize) -> String {
+ match count {
+ 0..=999 => count.to_string(),
+ 1000..=9999 => {
+ let thousands = count / 1000;
+ let hundreds = (count % 1000 + 50) / 100;
+ if hundreds == 0 {
+ format!("{}k", thousands)
+ } else if hundreds == 10 {
+ format!("{}k", thousands + 1)
+ } else {
+ format!("{}.{}k", thousands, hundreds)
+ }
+ }
+ _ => format!("{}k", (count + 500) / 1000),
+ }
+}
+
#[cfg(test)]
#[ctor::ctor]
fn init_logger() {
diff --git a/crates/assistant/src/assistant_panel.rs b/crates/assistant/src/assistant_panel.rs
index 41fc176f28b11a..92bd4b9cbe9832 100644
--- a/crates/assistant/src/assistant_panel.rs
+++ b/crates/assistant/src/assistant_panel.rs
@@ -1,86 +1,82 @@
-use crate::ambient_context::{AmbientContext, ContextUpdated, RecentBuffer};
-use crate::prompts::prompt_library::PromptLibrary;
-use crate::prompts::prompt_manager::PromptManager;
use crate::{
- ambient_context::*,
- assistant_settings::{AssistantDockPosition, AssistantSettings, ZedDotDevModel},
- codegen::{self, Codegen, CodegenKind},
- omit_ranges::text_in_range_omitting_ranges,
- prompts::prompt::generate_content_prompt,
- search::*,
+ assistant_settings::{AssistantDockPosition, AssistantSettings},
+ humanize_token_count,
+ prompt_library::open_prompt_library,
slash_command::{
- current_file_command, file_command, prompt_command, SlashCommandCleanup,
- SlashCommandCompletionProvider, SlashCommandLine, SlashCommandRegistry,
+ default_command::DefaultSlashCommand,
+ docs_command::{DocsSlashCommand, DocsSlashCommandArgs},
+ SlashCommandCompletionProvider, SlashCommandRegistry,
},
- ApplyEdit, Assist, CompletionProvider, CycleMessageRole, InlineAssist, LanguageModel,
- LanguageModelRequest, LanguageModelRequestMessage, MessageId, MessageMetadata, MessageStatus,
- QuoteSelection, ResetKey, Role, SavedConversation, SavedConversationMetadata, SavedMessage,
- Split, ToggleFocus, ToggleHistory, ToggleIncludeConversation,
+ terminal_inline_assistant::TerminalInlineAssistant,
+ Assist, CompletionProvider, ConfirmCommand, Context, ContextEvent, ContextId, ContextStore,
+ CycleMessageRole, DebugEditSteps, DeployHistory, DeployPromptLibrary, EditStep,
+ EditStepOperations, EditSuggestionGroup, InlineAssist, InlineAssistId, InlineAssistant,
+ InsertIntoEditor, MessageStatus, ModelSelector, PendingSlashCommand, PendingSlashCommandStatus,
+ QuoteSelection, RemoteContextMetadata, ResetKey, Role, SavedContextMetadata, Split,
+ ToggleFocus, ToggleModelSelector,
};
use anyhow::{anyhow, Result};
-use client::telemetry::Telemetry;
-use collections::{hash_map, HashMap, HashSet, VecDeque};
-use editor::FoldPlaceholder;
+use assistant_slash_command::{SlashCommand, SlashCommandOutputSection};
+use breadcrumbs::Breadcrumbs;
+use client::proto;
+use collections::{BTreeSet, HashMap, HashSet};
use editor::{
- actions::{FoldAt, MoveDown, MoveUp},
+ actions::{FoldAt, MoveToEndOfLine, Newline, ShowCompletions, UnfoldAt},
display_map::{
- BlockContext, BlockDisposition, BlockId, BlockProperties, BlockStyle, Flap, FlapId,
+ BlockDisposition, BlockProperties, BlockStyle, Crease, CustomBlockId, RenderBlock,
ToDisplayPoint,
},
- scroll::{Autoscroll, AutoscrollStrategy},
- Anchor, Editor, EditorElement, EditorEvent, EditorStyle, MultiBufferSnapshot, RowExt,
- ToOffset as _, ToPoint,
+ scroll::{Autoscroll, AutoscrollStrategy, ScrollAnchor},
+ Anchor, Editor, EditorEvent, ExcerptRange, MultiBuffer, RowExt, ToOffset as _, ToPoint,
};
-use file_icons::FileIcons;
+use editor::{display_map::CreaseId, FoldPlaceholder};
use fs::Fs;
-use futures::StreamExt;
use gpui::{
- canvas, div, point, relative, rems, uniform_list, Action, AnyElement, AnyView, AppContext,
- AsyncAppContext, AsyncWindowContext, AvailableSpace, ClipboardItem, Context, Empty, Entity,
- EventEmitter, FocusHandle, FocusableView, FontStyle, FontWeight, HighlightStyle,
- InteractiveElement, IntoElement, Model, ModelContext, ParentElement, Pixels, Render,
- SharedString, StatefulInteractiveElement, Styled, Subscription, Task, TextStyle,
- UniformListScrollHandle, View, ViewContext, VisualContext, WeakModel, WeakView, WhiteSpace,
- WindowContext,
+ div, percentage, point, Action, Animation, AnimationExt, AnyElement, AnyView, AppContext,
+ AsyncWindowContext, ClipboardItem, Context as _, DismissEvent, Empty, Entity, EventEmitter,
+ FocusHandle, FocusableView, InteractiveElement, IntoElement, Model, ParentElement, Pixels,
+ Render, SharedString, StatefulInteractiveElement, Styled, Subscription, Task, Transformation,
+ UpdateGlobal, View, ViewContext, VisualContext, WeakView, WindowContext,
};
-use language::LspAdapterDelegate;
+use indexed_docs::IndexedDocsStore;
use language::{
- language_settings::SoftWrap, AutoindentMode, Buffer, BufferSnapshot, LanguageRegistry,
- OffsetRangeExt as _, Point, ToOffset as _, ToPoint as _,
+ language_settings::SoftWrap, Buffer, Capability, LanguageRegistry, LspAdapterDelegate, Point,
+ ToOffset,
};
use multi_buffer::MultiBufferRow;
-use parking_lot::Mutex;
-use project::{Project, ProjectLspAdapterDelegate, ProjectTransaction};
+use picker::{Picker, PickerDelegate};
+use project::{Project, ProjectLspAdapterDelegate};
use search::{buffer_search::DivRegistrar, BufferSearchBar};
use settings::Settings;
use std::{
cmp::{self, Ordering},
fmt::Write,
- iter, mem,
ops::Range,
path::PathBuf,
sync::Arc,
- time::{Duration, Instant},
+ time::Duration,
};
-use telemetry_events::AssistantKind;
+use terminal_view::{terminal_panel::TerminalPanel, TerminalView};
use theme::ThemeSettings;
use ui::{
- popover_menu, prelude::*, ButtonLike, ContextMenu, ElevationIndex, KeyBinding, Tab, TabBar,
- Tooltip,
+ prelude::*,
+ utils::{format_distance_from_now, DateTimeType},
+ Avatar, AvatarShape, ButtonLike, ContextMenu, Disclosure, ElevationIndex, KeyBinding, ListItem,
+ ListItemSpacing, PopoverMenu, PopoverMenuHandle, Tooltip,
};
-use util::{paths::CONVERSATIONS_DIR, post_inc, ResultExt, TryFutureExt};
-use uuid::Uuid;
+use util::ResultExt;
use workspace::{
dock::{DockPosition, Panel, PanelEvent},
- searchable::Direction,
- Event as WorkspaceEvent, Save, Toast, ToggleZoom, Toolbar, Workspace,
+ item::{self, BreadcrumbText, FollowableItem, Item, ItemHandle},
+ notifications::NotifyTaskExt,
+ pane::{self, SaveIntent},
+ searchable::{SearchEvent, SearchableItem},
+ Pane, Save, ToggleZoom, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace,
};
-use workspace::{notifications::NotificationId, NewFile};
-
-const MAX_RECENT_BUFFERS: usize = 3;
-const SLASH_COMMAND_DEBOUNCE: Duration = Duration::from_millis(200);
+use workspace::{searchable::SearchableItemHandle, NewFile};
pub fn init(cx: &mut AppContext) {
+ workspace::FollowableViewRegistry::register::(cx);
cx.observe_new_views(
|workspace: &mut Workspace, _cx: &mut ViewContext| {
workspace
@@ -93,180 +89,336 @@ pub fn init(cx: &mut AppContext) {
workspace.toggle_panel_focus::(cx);
})
.register_action(AssistantPanel::inline_assist)
- .register_action(AssistantPanel::cancel_last_inline_assist)
- // .register_action(ConversationEditor::insert_active_prompt)
- .register_action(ConversationEditor::quote_selection);
+ .register_action(ContextEditor::quote_selection)
+ .register_action(ContextEditor::insert_selection);
},
)
.detach();
}
+pub enum AssistantPanelEvent {
+ ContextEdited,
+}
+
pub struct AssistantPanel {
+ pane: View,
workspace: WeakView,
width: Option,
height: Option,
- active_conversation_editor: Option,
- show_saved_conversations: bool,
- saved_conversations: Vec,
- saved_conversations_scroll_handle: UniformListScrollHandle,
- zoomed: bool,
- focus_handle: FocusHandle,
- toolbar: View,
+ project: Model,
+ context_store: Model,
languages: Arc,
- slash_commands: Arc,
- prompt_library: Arc,
fs: Arc,
- telemetry: Arc,
- _subscriptions: Vec,
- next_inline_assist_id: usize,
- pending_inline_assists: HashMap,
- pending_inline_assist_ids_by_editor: HashMap, Vec>,
- include_conversation_in_next_inline_assist: bool,
- inline_prompt_history: VecDeque,
- _watch_saved_conversations: Task>,
- model: LanguageModel,
+ subscriptions: Vec,
authentication_prompt: Option,
+ model_selector_menu_handle: PopoverMenuHandle,
}
-struct ActiveConversationEditor {
- editor: View,
- _subscriptions: Vec,
+#[derive(Clone)]
+enum ContextMetadata {
+ Remote(RemoteContextMetadata),
+ Saved(SavedContextMetadata),
}
-impl AssistantPanel {
- const INLINE_PROMPT_HISTORY_MAX_LEN: usize = 20;
+struct SavedContextPickerDelegate {
+ store: Model,
+ project: Model,
+ matches: Vec,
+ selected_index: usize,
+}
- pub fn load(
- workspace: WeakView,
- cx: AsyncWindowContext,
- ) -> Task>> {
- cx.spawn(|mut cx| async move {
- let fs = workspace.update(&mut cx, |workspace, _| workspace.app_state().fs.clone())?;
- let saved_conversations = SavedConversationMetadata::list(fs.clone())
- .await
- .log_err()
- .unwrap_or_default();
-
- let prompt_library = Arc::new(
- PromptLibrary::load(fs.clone())
- .await
- .log_err()
- .unwrap_or_default(),
- );
+enum SavedContextPickerEvent {
+ Confirmed(ContextMetadata),
+}
- // TODO: deserialize state.
- let workspace_handle = workspace.clone();
- workspace.update(&mut cx, |workspace, cx| {
- cx.new_view::(|cx| {
- const CONVERSATION_WATCH_DURATION: Duration = Duration::from_millis(100);
- let _watch_saved_conversations = cx.spawn(move |this, mut cx| async move {
- let mut events = fs
- .watch(&CONVERSATIONS_DIR, CONVERSATION_WATCH_DURATION)
- .await;
- while events.next().await.is_some() {
- let saved_conversations = SavedConversationMetadata::list(fs.clone())
- .await
- .log_err()
- .unwrap_or_default();
- this.update(&mut cx, |this, cx| {
- this.saved_conversations = saved_conversations;
- cx.notify();
- })
- .ok();
- }
+enum InlineAssistTarget {
+ Editor(View, bool),
+ Terminal(View),
+}
- anyhow::Ok(())
- });
+impl EventEmitter for Picker {}
- let toolbar = cx.new_view(|cx| {
- let mut toolbar = Toolbar::new();
- toolbar.set_can_navigate(false, cx);
- toolbar.add_item(cx.new_view(BufferSearchBar::new), cx);
- toolbar
- });
+impl SavedContextPickerDelegate {
+ fn new(project: Model, store: Model) -> Self {
+ Self {
+ project,
+ store,
+ matches: Vec::new(),
+ selected_index: 0,
+ }
+ }
+}
- let focus_handle = cx.focus_handle();
- let subscriptions = vec![
- cx.on_focus_in(&focus_handle, Self::focus_in),
- cx.on_focus_out(&focus_handle, Self::focus_out),
- cx.observe_global::({
- let mut prev_settings_version =
- CompletionProvider::global(cx).settings_version();
- move |this, cx| {
- this.completion_provider_changed(prev_settings_version, cx);
- prev_settings_version =
- CompletionProvider::global(cx).settings_version();
- }
- }),
- ];
- let model = CompletionProvider::global(cx).default_model();
+impl PickerDelegate for SavedContextPickerDelegate {
+ type ListItem = ListItem;
- cx.observe_global::(|_, cx| {
- cx.notify();
- })
- .detach();
+ fn match_count(&self) -> usize {
+ self.matches.len()
+ }
- let slash_command_registry = SlashCommandRegistry::global(cx);
- let window = cx.window_handle().downcast::();
+ fn selected_index(&self) -> usize {
+ self.selected_index
+ }
- slash_command_registry.register_command(file_command::FileSlashCommand::new(
- workspace.project().clone(),
- ));
- slash_command_registry.register_command(
- prompt_command::PromptSlashCommand::new(prompt_library.clone()),
- );
- if let Some(window) = window {
- slash_command_registry.register_command(
- current_file_command::CurrentFileSlashCommand::new(window),
- );
- }
+ fn set_selected_index(&mut self, ix: usize, _cx: &mut ViewContext>) {
+ self.selected_index = ix;
+ }
- Self {
- workspace: workspace_handle,
- active_conversation_editor: None,
- show_saved_conversations: false,
- saved_conversations,
- saved_conversations_scroll_handle: Default::default(),
- zoomed: false,
- focus_handle,
- toolbar,
- languages: workspace.app_state().languages.clone(),
- slash_commands: slash_command_registry,
- prompt_library,
- fs: workspace.app_state().fs.clone(),
- telemetry: workspace.client().telemetry().clone(),
- width: None,
- height: None,
- _subscriptions: subscriptions,
- next_inline_assist_id: 0,
- pending_inline_assists: Default::default(),
- pending_inline_assist_ids_by_editor: Default::default(),
- include_conversation_in_next_inline_assist: false,
- inline_prompt_history: Default::default(),
- _watch_saved_conversations,
- model,
- authentication_prompt: None,
- }
- })
+ fn placeholder_text(&self, _cx: &mut WindowContext) -> Arc {
+ "Search...".into()
+ }
+
+ fn update_matches(&mut self, query: String, cx: &mut ViewContext>) -> Task<()> {
+ let search = self.store.read(cx).search(query, cx);
+ cx.spawn(|this, mut cx| async move {
+ let matches = search.await;
+ this.update(&mut cx, |this, cx| {
+ let host_contexts = this.delegate.store.read(cx).host_contexts();
+ this.delegate.matches = host_contexts
+ .iter()
+ .cloned()
+ .map(ContextMetadata::Remote)
+ .chain(matches.into_iter().map(ContextMetadata::Saved))
+ .collect();
+ this.delegate.selected_index = 0;
+ cx.notify();
})
+ .ok();
})
}
- fn focus_in(&mut self, cx: &mut ViewContext) {
- self.toolbar
- .update(cx, |toolbar, cx| toolbar.focus_changed(true, cx));
- cx.notify();
- if self.focus_handle.is_focused(cx) {
- if let Some(editor) = self.active_conversation_editor() {
- cx.focus_view(editor);
+ fn confirm(&mut self, _secondary: bool, cx: &mut ViewContext>) {
+ if let Some(metadata) = self.matches.get(self.selected_index) {
+ cx.emit(SavedContextPickerEvent::Confirmed(metadata.clone()));
+ }
+ }
+
+ fn dismissed(&mut self, _cx: &mut ViewContext>) {}
+
+ fn render_match(
+ &self,
+ ix: usize,
+ selected: bool,
+ cx: &mut ViewContext>,
+ ) -> Option {
+ let context = self.matches.get(ix)?;
+ let item = match context {
+ ContextMetadata::Remote(context) => {
+ let host_user = self.project.read(cx).host().and_then(|collaborator| {
+ self.project
+ .read(cx)
+ .user_store()
+ .read(cx)
+ .get_cached_user(collaborator.user_id)
+ });
+ div()
+ .flex()
+ .w_full()
+ .justify_between()
+ .gap_2()
+ .child(
+ h_flex().flex_1().overflow_x_hidden().child(
+ Label::new(context.summary.clone().unwrap_or("New Context".into()))
+ .size(LabelSize::Small),
+ ),
+ )
+ .child(
+ h_flex()
+ .gap_2()
+ .children(if let Some(host_user) = host_user {
+ vec![
+ Avatar::new(host_user.avatar_uri.clone())
+ .shape(AvatarShape::Circle)
+ .into_any_element(),
+ Label::new(format!("Shared by @{}", host_user.github_login))
+ .color(Color::Muted)
+ .size(LabelSize::Small)
+ .into_any_element(),
+ ]
+ } else {
+ vec![Label::new("Shared by host")
+ .color(Color::Muted)
+ .size(LabelSize::Small)
+ .into_any_element()]
+ }),
+ )
}
+ ContextMetadata::Saved(context) => div()
+ .flex()
+ .w_full()
+ .justify_between()
+ .gap_2()
+ .child(
+ h_flex()
+ .flex_1()
+ .child(Label::new(context.title.clone()).size(LabelSize::Small))
+ .overflow_x_hidden(),
+ )
+ .child(
+ Label::new(format_distance_from_now(
+ DateTimeType::Local(context.mtime),
+ false,
+ true,
+ true,
+ ))
+ .color(Color::Muted)
+ .size(LabelSize::Small),
+ ),
+ };
+ Some(
+ ListItem::new(ix)
+ .inset(true)
+ .spacing(ListItemSpacing::Sparse)
+ .selected(selected)
+ .child(item),
+ )
+ }
+}
+
+impl AssistantPanel {
+ pub fn load(
+ workspace: WeakView,
+ cx: AsyncWindowContext,
+ ) -> Task>> {
+ cx.spawn(|mut cx| async move {
+ let context_store = workspace
+ .update(&mut cx, |workspace, cx| {
+ ContextStore::new(workspace.project().clone(), cx)
+ })?
+ .await?;
+ workspace.update(&mut cx, |workspace, cx| {
+ // TODO: deserialize state.
+ cx.new_view(|cx| Self::new(workspace, context_store, cx))
+ })
+ })
+ }
+
+ fn new(
+ workspace: &Workspace,
+ context_store: Model,
+ cx: &mut ViewContext,
+ ) -> Self {
+ let model_selector_menu_handle = PopoverMenuHandle::default();
+ let pane = cx.new_view(|cx| {
+ let mut pane = Pane::new(
+ workspace.weak_handle(),
+ workspace.project().clone(),
+ Default::default(),
+ None,
+ NewFile.boxed_clone(),
+ cx,
+ );
+ pane.set_can_split(false, cx);
+ pane.set_can_navigate(true, cx);
+ pane.display_nav_history_buttons(None);
+ pane.set_should_display_tab_bar(|_| true);
+ pane.set_render_tab_bar_buttons(cx, move |pane, cx| {
+ h_flex()
+ .gap(Spacing::Small.rems(cx))
+ .child(
+ IconButton::new("menu", IconName::Menu)
+ .icon_size(IconSize::Small)
+ .on_click(cx.listener(|pane, _, cx| {
+ let zoom_label = if pane.is_zoomed() {
+ "Zoom Out"
+ } else {
+ "Zoom In"
+ };
+ let menu = ContextMenu::build(cx, |menu, cx| {
+ menu.context(pane.focus_handle(cx))
+ .action("New Context", Box::new(NewFile))
+ .action("History", Box::new(DeployHistory))
+ .action("Prompt Library", Box::new(DeployPromptLibrary))
+ .action(zoom_label, Box::new(ToggleZoom))
+ });
+ cx.subscribe(&menu, |pane, _, _: &DismissEvent, _| {
+ pane.new_item_menu = None;
+ })
+ .detach();
+ pane.new_item_menu = Some(menu);
+ })),
+ )
+ .when_some(pane.new_item_menu.as_ref(), |el, new_item_menu| {
+ el.child(Pane::render_menu_overlay(new_item_menu))
+ })
+ .into_any_element()
+ });
+ pane.toolbar().update(cx, |toolbar, cx| {
+ toolbar.add_item(cx.new_view(|_| Breadcrumbs::new()), cx);
+ toolbar.add_item(
+ cx.new_view(|_| {
+ ContextEditorToolbarItem::new(workspace, model_selector_menu_handle.clone())
+ }),
+ cx,
+ );
+ toolbar.add_item(cx.new_view(BufferSearchBar::new), cx)
+ });
+ pane
+ });
+
+ let subscriptions = vec![
+ cx.observe(&pane, |_, _, cx| cx.notify()),
+ cx.subscribe(&pane, Self::handle_pane_event),
+ cx.observe_global::({
+ let mut prev_settings_version = CompletionProvider::global(cx).settings_version();
+ move |this, cx| {
+ this.completion_provider_changed(prev_settings_version, cx);
+ prev_settings_version = CompletionProvider::global(cx).settings_version();
+ }
+ }),
+ ];
+
+ Self {
+ pane,
+ workspace: workspace.weak_handle(),
+ width: None,
+ height: None,
+ project: workspace.project().clone(),
+ context_store,
+ languages: workspace.app_state().languages.clone(),
+ fs: workspace.app_state().fs.clone(),
+ subscriptions,
+ authentication_prompt: None,
+ model_selector_menu_handle,
}
}
- fn focus_out(&mut self, cx: &mut ViewContext) {
- self.toolbar
- .update(cx, |toolbar, cx| toolbar.focus_changed(false, cx));
- cx.notify();
+ fn handle_pane_event(
+ &mut self,
+ pane: View,
+ event: &pane::Event,
+ cx: &mut ViewContext,
+ ) {
+ match event {
+ pane::Event::Remove => cx.emit(PanelEvent::Close),
+ pane::Event::ZoomIn => cx.emit(PanelEvent::ZoomIn),
+ pane::Event::ZoomOut => cx.emit(PanelEvent::ZoomOut),
+
+ pane::Event::AddItem { item } => {
+ self.workspace
+ .update(cx, |workspace, cx| {
+ item.added_to_pane(workspace, self.pane.clone(), cx)
+ })
+ .ok();
+ }
+
+ pane::Event::ActivateItem { local } => {
+ if *local {
+ self.workspace
+ .update(cx, |workspace, cx| {
+ workspace.unfollow_in_pane(&pane, cx);
+ })
+ .ok();
+ }
+ cx.emit(AssistantPanelEvent::ContextEdited);
+ }
+
+ pane::Event::RemoveItem { .. } => {
+ cx.emit(AssistantPanelEvent::ContextEdited);
+ }
+
+ _ => {}
+ }
}
fn completion_provider_changed(
@@ -277,12 +429,18 @@ impl AssistantPanel {
if self.is_authenticated(cx) {
self.authentication_prompt = None;
- let model = CompletionProvider::global(cx).default_model();
- self.set_model(model, cx);
+ if let Some(editor) = self.active_context_editor(cx) {
+ editor.update(cx, |active_context, cx| {
+ active_context
+ .context
+ .update(cx, |context, cx| context.completion_provider_changed(cx))
+ })
+ }
- if self.active_conversation_editor().is_none() {
- self.new_conversation(cx);
+ if self.active_context_editor(cx).is_none() {
+ self.new_context(cx);
}
+ cx.notify();
} else if self.authentication_prompt.is_none()
|| prev_settings_version != CompletionProvider::global(cx).settings_version()
{
@@ -290,12 +448,13 @@ impl AssistantPanel {
Some(cx.update_global::(|provider, cx| {
provider.authentication_prompt(cx)
}));
+ cx.notify();
}
}
pub fn inline_assist(
workspace: &mut Workspace,
- _: &InlineAssist,
+ action: &InlineAssist,
cx: &mut ViewContext,
) {
let settings = AssistantSettings::get_global(cx);
@@ -303,58 +462,78 @@ impl AssistantPanel {
return;
}
- let Some(assistant) = workspace.panel::(cx) else {
+ let Some(assistant_panel) = workspace.panel::(cx) else {
return;
};
- let conversation_editor =
- assistant
- .read(cx)
- .active_conversation_editor()
- .and_then(|editor| {
- let editor = &editor.read(cx).editor;
- if editor.read(cx).is_focused(cx) {
- Some(editor.clone())
- } else {
- None
- }
- });
-
- let show_include_conversation;
- let active_editor;
- if let Some(conversation_editor) = conversation_editor {
- active_editor = conversation_editor;
- show_include_conversation = false;
- } else if let Some(workspace_editor) = workspace
- .active_item(cx)
- .and_then(|item| item.act_as::(cx))
- {
- active_editor = workspace_editor;
- show_include_conversation = true;
- } else {
+ let Some(inline_assist_target) =
+ Self::resolve_inline_assist_target(workspace, &assistant_panel, cx)
+ else {
return;
};
- let project = workspace.project().clone();
- if assistant.update(cx, |assistant, cx| assistant.is_authenticated(cx)) {
- assistant.update(cx, |assistant, cx| {
- assistant.new_inline_assist(&active_editor, &project, show_include_conversation, cx)
- });
+ let initial_prompt = action.prompt.clone();
+ if assistant_panel.update(cx, |assistant, cx| assistant.is_authenticated(cx)) {
+ match inline_assist_target {
+ InlineAssistTarget::Editor(active_editor, include_context) => {
+ InlineAssistant::update_global(cx, |assistant, cx| {
+ assistant.assist(
+ &active_editor,
+ Some(cx.view().downgrade()),
+ include_context.then_some(&assistant_panel),
+ initial_prompt,
+ cx,
+ )
+ })
+ }
+ InlineAssistTarget::Terminal(active_terminal) => {
+ TerminalInlineAssistant::update_global(cx, |assistant, cx| {
+ assistant.assist(
+ &active_terminal,
+ Some(cx.view().downgrade()),
+ Some(&assistant_panel),
+ initial_prompt,
+ cx,
+ )
+ })
+ }
+ }
} else {
- let assistant = assistant.downgrade();
+ let assistant_panel = assistant_panel.downgrade();
cx.spawn(|workspace, mut cx| async move {
- assistant
+ assistant_panel
.update(&mut cx, |assistant, cx| assistant.authenticate(cx))?
.await?;
- if assistant.update(&mut cx, |assistant, cx| assistant.is_authenticated(cx))? {
- assistant.update(&mut cx, |assistant, cx| {
- assistant.new_inline_assist(
- &active_editor,
- &project,
- show_include_conversation,
- cx,
- )
- })?;
+ if assistant_panel.update(&mut cx, |panel, cx| panel.is_authenticated(cx))? {
+ cx.update(|cx| match inline_assist_target {
+ InlineAssistTarget::Editor(active_editor, include_context) => {
+ let assistant_panel = if include_context {
+ assistant_panel.upgrade()
+ } else {
+ None
+ };
+ InlineAssistant::update_global(cx, |assistant, cx| {
+ assistant.assist(
+ &active_editor,
+ Some(workspace),
+ assistant_panel.as_ref(),
+ initial_prompt,
+ cx,
+ )
+ })
+ }
+ InlineAssistTarget::Terminal(active_terminal) => {
+ TerminalInlineAssistant::update_global(cx, |assistant, cx| {
+ assistant.assist(
+ &active_terminal,
+ Some(workspace),
+ assistant_panel.upgrade().as_ref(),
+ initial_prompt,
+ cx,
+ )
+ })
+ }
+ })?
} else {
workspace.update(&mut cx, |workspace, cx| {
workspace.focus_panel::(cx)
@@ -367,2357 +546,427 @@ impl AssistantPanel {
}
}
- fn new_inline_assist(
- &mut self,
- editor: &View,
- project: &Model,
- show_include_conversation: bool,
- cx: &mut ViewContext,
- ) {
- let selection = editor.read(cx).selections.newest_anchor().clone();
- if selection.start.excerpt_id != selection.end.excerpt_id {
- return;
- }
- let snapshot = editor.read(cx).buffer().read(cx).snapshot(cx);
-
- // Extend the selection to the start and the end of the line.
- let mut point_selection = selection.map(|selection| selection.to_point(&snapshot));
- if point_selection.end > point_selection.start {
- point_selection.start.column = 0;
- // If the selection ends at the start of the line, we don't want to include it.
- if point_selection.end.column == 0 {
- point_selection.end.row -= 1;
+ fn resolve_inline_assist_target(
+ workspace: &mut Workspace,
+ assistant_panel: &View,
+ cx: &mut WindowContext,
+ ) -> Option {
+ if let Some(terminal_panel) = workspace.panel::(cx) {
+ if terminal_panel
+ .read(cx)
+ .focus_handle(cx)
+ .contains_focused(cx)
+ {
+ use feature_flags::FeatureFlagAppExt;
+ if !cx.has_flag::() {
+ return None;
+ }
+
+ if let Some(terminal_view) = terminal_panel
+ .read(cx)
+ .pane()
+ .read(cx)
+ .active_item()
+ .and_then(|t| t.downcast::())
+ {
+ return Some(InlineAssistTarget::Terminal(terminal_view));
+ }
}
- point_selection.end.column = snapshot.line_len(MultiBufferRow(point_selection.end.row));
}
+ let context_editor =
+ assistant_panel
+ .read(cx)
+ .active_context_editor(cx)
+ .and_then(|editor| {
+ let editor = &editor.read(cx).editor;
+ if editor.read(cx).is_focused(cx) {
+ Some(editor.clone())
+ } else {
+ None
+ }
+ });
- let codegen_kind = if point_selection.start == point_selection.end {
- CodegenKind::Generate {
- position: snapshot.anchor_after(point_selection.start),
- }
+ if let Some(context_editor) = context_editor {
+ Some(InlineAssistTarget::Editor(context_editor, false))
+ } else if let Some(workspace_editor) = workspace
+ .active_item(cx)
+ .and_then(|item| item.act_as::(cx))
+ {
+ Some(InlineAssistTarget::Editor(workspace_editor, true))
} else {
- CodegenKind::Transform {
- range: snapshot.anchor_before(point_selection.start)
- ..snapshot.anchor_after(point_selection.end),
- }
- };
-
- let inline_assist_id = post_inc(&mut self.next_inline_assist_id);
- let telemetry = self.telemetry.clone();
+ None
+ }
+ }
- let codegen = cx.new_model(|cx| {
- Codegen::new(
- editor.read(cx).buffer().clone(),
- codegen_kind,
- Some(telemetry),
- cx,
- )
+ fn new_context(&mut self, cx: &mut ViewContext) -> Option> {
+ let context = self.context_store.update(cx, |store, cx| store.create(cx));
+ let workspace = self.workspace.upgrade()?;
+ let lsp_adapter_delegate = workspace.update(cx, |workspace, cx| {
+ make_lsp_adapter_delegate(workspace.project(), cx).log_err()
});
- let measurements = Arc::new(Mutex::new(BlockMeasurements::default()));
- let inline_assistant = cx.new_view(|cx| {
- InlineAssistant::new(
- inline_assist_id,
- measurements.clone(),
- show_include_conversation,
- show_include_conversation && self.include_conversation_in_next_inline_assist,
- self.inline_prompt_history.clone(),
- codegen.clone(),
- cx,
- )
- });
- let block_id = editor.update(cx, |editor, cx| {
- editor.change_selections(None, cx, |selections| {
- selections.select_anchor_ranges([selection.head()..selection.head()])
- });
- editor.insert_blocks(
- [BlockProperties {
- style: BlockStyle::Flex,
- position: snapshot.anchor_before(Point::new(point_selection.head().row, 0)),
- height: 2,
- render: Box::new({
- let inline_assistant = inline_assistant.clone();
- move |cx: &mut BlockContext| {
- *measurements.lock() = BlockMeasurements {
- anchor_x: cx.anchor_x,
- gutter_width: cx.gutter_dimensions.width,
- };
- inline_assistant.clone().into_any_element()
- }
- }),
- disposition: if selection.reversed {
- BlockDisposition::Above
- } else {
- BlockDisposition::Below
- },
- }],
- Some(Autoscroll::Strategy(AutoscrollStrategy::Newest)),
+ let assistant_panel = cx.view().downgrade();
+ let editor = cx.new_view(|cx| {
+ let mut editor = ContextEditor::for_context(
+ context,
+ self.fs.clone(),
+ workspace.clone(),
+ self.project.clone(),
+ lsp_adapter_delegate,
+ assistant_panel,
cx,
- )[0]
+ );
+ editor.insert_default_prompt(cx);
+ editor
});
- self.pending_inline_assists.insert(
- inline_assist_id,
- PendingInlineAssist {
- editor: editor.downgrade(),
- inline_assistant: Some((block_id, inline_assistant.clone())),
- codegen: codegen.clone(),
- project: project.downgrade(),
- _subscriptions: vec![
- cx.subscribe(&inline_assistant, Self::handle_inline_assistant_event),
- cx.subscribe(editor, {
- let inline_assistant = inline_assistant.downgrade();
- move |_, editor, event, cx| {
- if let Some(inline_assistant) = inline_assistant.upgrade() {
- if let EditorEvent::SelectionsChanged { local } = event {
- if *local
- && inline_assistant.focus_handle(cx).contains_focused(cx)
- {
- cx.focus_view(&editor);
- }
- }
- }
- }
- }),
- cx.observe(&codegen, {
- let editor = editor.downgrade();
- move |this, _, cx| {
- if let Some(editor) = editor.upgrade() {
- this.update_highlights_for_editor(&editor, cx);
- }
- }
- }),
- cx.subscribe(&codegen, move |this, codegen, event, cx| match event {
- codegen::Event::Undone => {
- this.finish_inline_assist(inline_assist_id, false, cx)
- }
- codegen::Event::Finished => {
- let pending_assist = if let Some(pending_assist) =
- this.pending_inline_assists.get(&inline_assist_id)
- {
- pending_assist
- } else {
- return;
- };
+ self.show_context(editor.clone(), cx);
+ Some(editor)
+ }
- let error = codegen
- .read(cx)
- .error()
- .map(|error| format!("Inline assistant error: {}", error));
- if let Some(error) = error {
- if pending_assist.inline_assistant.is_none() {
- if let Some(workspace) = this.workspace.upgrade() {
- workspace.update(cx, |workspace, cx| {
- struct InlineAssistantError;
-
- let id =
- NotificationId::identified::(
- inline_assist_id,
- );
-
- workspace.show_toast(Toast::new(id, error), cx);
- })
- }
+ fn show_context(&mut self, context_editor: View, cx: &mut ViewContext) {
+ let focus = self.focus_handle(cx).contains_focused(cx);
+ let prev_len = self.pane.read(cx).items_len();
+ self.pane.update(cx, |pane, cx| {
+ pane.add_item(Box::new(context_editor.clone()), focus, focus, None, cx)
+ });
- this.finish_inline_assist(inline_assist_id, false, cx);
- }
- } else {
- this.finish_inline_assist(inline_assist_id, false, cx);
- }
- }
- }),
- ],
- },
- );
- self.pending_inline_assist_ids_by_editor
- .entry(editor.downgrade())
- .or_default()
- .push(inline_assist_id);
- self.update_highlights_for_editor(editor, cx);
+ if prev_len != self.pane.read(cx).items_len() {
+ self.subscriptions
+ .push(cx.subscribe(&context_editor, Self::handle_context_editor_event));
+ }
+
+ cx.emit(AssistantPanelEvent::ContextEdited);
+ cx.notify();
}
- fn handle_inline_assistant_event(
+ fn handle_context_editor_event(
&mut self,
- inline_assistant: View,
- event: &InlineAssistantEvent,
+ _: View,
+ event: &EditorEvent,
cx: &mut ViewContext,
) {
- let assist_id = inline_assistant.read(cx).id;
match event {
- InlineAssistantEvent::Confirmed {
- prompt,
- include_conversation,
- } => {
- self.confirm_inline_assist(assist_id, prompt, *include_conversation, cx);
- }
- InlineAssistantEvent::Canceled => {
- self.finish_inline_assist(assist_id, true, cx);
- }
- InlineAssistantEvent::Dismissed => {
- self.hide_inline_assist(assist_id, cx);
- }
- InlineAssistantEvent::IncludeConversationToggled {
- include_conversation,
- } => {
- self.include_conversation_in_next_inline_assist = *include_conversation;
- }
+ EditorEvent::TitleChanged { .. } => cx.notify(),
+ EditorEvent::Edited { .. } => cx.emit(AssistantPanelEvent::ContextEdited),
+ _ => {}
}
}
- fn cancel_last_inline_assist(
- workspace: &mut Workspace,
- _: &editor::actions::Cancel,
- cx: &mut ViewContext,
- ) {
- if let Some(panel) = workspace.panel::(cx) {
- if let Some(editor) = workspace
- .active_item(cx)
- .and_then(|item| item.downcast::())
- {
- let handled = panel.update(cx, |panel, cx| {
- if let Some(assist_id) = panel
- .pending_inline_assist_ids_by_editor
- .get(&editor.downgrade())
- .and_then(|assist_ids| assist_ids.last().copied())
- {
- panel.finish_inline_assist(assist_id, true, cx);
- true
- } else {
- false
- }
- });
- if handled {
- return;
- }
- }
- }
+ fn deploy_history(&mut self, _: &DeployHistory, cx: &mut ViewContext) {
+ let history_item_ix = self
+ .pane
+ .read(cx)
+ .items()
+ .position(|item| item.downcast::().is_some());
- cx.propagate();
+ if let Some(history_item_ix) = history_item_ix {
+ self.pane.update(cx, |pane, cx| {
+ pane.activate_item(history_item_ix, true, true, cx);
+ });
+ } else {
+ let assistant_panel = cx.view().downgrade();
+ let history = cx.new_view(|cx| {
+ ContextHistory::new(
+ self.project.clone(),
+ self.context_store.clone(),
+ assistant_panel,
+ cx,
+ )
+ });
+ self.pane.update(cx, |pane, cx| {
+ pane.add_item(Box::new(history), true, true, None, cx);
+ });
+ }
}
- fn finish_inline_assist(&mut self, assist_id: usize, undo: bool, cx: &mut ViewContext) {
- self.hide_inline_assist(assist_id, cx);
+ fn deploy_prompt_library(&mut self, _: &DeployPromptLibrary, cx: &mut ViewContext) {
+ open_prompt_library(self.languages.clone(), cx).detach_and_log_err(cx);
+ }
- if let Some(pending_assist) = self.pending_inline_assists.remove(&assist_id) {
- if let hash_map::Entry::Occupied(mut entry) = self
- .pending_inline_assist_ids_by_editor
- .entry(pending_assist.editor.clone())
- {
- entry.get_mut().retain(|id| *id != assist_id);
- if entry.get().is_empty() {
- entry.remove();
- }
- }
+ fn reset_credentials(&mut self, _: &ResetKey, cx: &mut ViewContext) {
+ CompletionProvider::global(cx)
+ .reset_credentials(cx)
+ .detach_and_log_err(cx);
+ }
- if let Some(editor) = pending_assist.editor.upgrade() {
- self.update_highlights_for_editor(&editor, cx);
+ fn toggle_model_selector(&mut self, _: &ToggleModelSelector, cx: &mut ViewContext) {
+ self.model_selector_menu_handle.toggle(cx);
+ }
- if undo {
- pending_assist
- .codegen
- .update(cx, |codegen, cx| codegen.undo(cx));
- }
- }
- }
+ fn active_context_editor(&self, cx: &AppContext) -> Option> {
+ self.pane
+ .read(cx)
+ .active_item()?
+ .downcast::()
}
- fn hide_inline_assist(&mut self, assist_id: usize, cx: &mut ViewContext) {
- if let Some(pending_assist) = self.pending_inline_assists.get_mut(&assist_id) {
- if let Some(editor) = pending_assist.editor.upgrade() {
- if let Some((block_id, inline_assistant)) = pending_assist.inline_assistant.take() {
- editor.update(cx, |editor, cx| {
- editor.remove_blocks(HashSet::from_iter([block_id]), None, cx);
- if inline_assistant.focus_handle(cx).contains_focused(cx) {
- editor.focus(cx);
- }
- });
- }
- }
- }
+ pub fn active_context(&self, cx: &AppContext) -> Option> {
+ Some(self.active_context_editor(cx)?.read(cx).context.clone())
}
- fn confirm_inline_assist(
+ fn open_saved_context(
&mut self,
- inline_assist_id: usize,
- user_prompt: &str,
- include_conversation: bool,
+ path: PathBuf,
cx: &mut ViewContext,
- ) {
- let conversation = if include_conversation {
- self.active_conversation_editor()
- .map(|editor| editor.read(cx).conversation.clone())
- } else {
- None
- };
-
- let pending_assist =
- if let Some(pending_assist) = self.pending_inline_assists.get_mut(&inline_assist_id) {
- pending_assist
- } else {
- return;
- };
-
- let editor = if let Some(editor) = pending_assist.editor.upgrade() {
- editor
- } else {
- return;
- };
-
- let project = pending_assist.project.clone();
-
- let project_name = project.upgrade().map(|project| {
- project
- .read(cx)
- .worktree_root_names(cx)
- .collect::>()
- .join("/")
+ ) -> Task> {
+ let existing_context = self.pane.read(cx).items().find_map(|item| {
+ item.downcast::()
+ .filter(|editor| editor.read(cx).context.read(cx).path() == Some(&path))
});
-
- self.inline_prompt_history
- .retain(|prompt| prompt != user_prompt);
- self.inline_prompt_history.push_back(user_prompt.into());
- if self.inline_prompt_history.len() > Self::INLINE_PROMPT_HISTORY_MAX_LEN {
- self.inline_prompt_history.pop_front();
+ if let Some(existing_context) = existing_context {
+ return cx.spawn(|this, mut cx| async move {
+ this.update(&mut cx, |this, cx| this.show_context(existing_context, cx))
+ });
}
- let codegen = pending_assist.codegen.clone();
- let snapshot = editor.read(cx).buffer().read(cx).snapshot(cx);
- let range = codegen.read(cx).range();
- let start = snapshot.point_to_buffer_offset(range.start);
- let end = snapshot.point_to_buffer_offset(range.end);
- let (buffer, range) = if let Some((start, end)) = start.zip(end) {
- let (start_buffer, start_buffer_offset) = start;
- let (end_buffer, end_buffer_offset) = end;
- if start_buffer.remote_id() == end_buffer.remote_id() {
- (start_buffer.clone(), start_buffer_offset..end_buffer_offset)
- } else {
- self.finish_inline_assist(inline_assist_id, false, cx);
- return;
- }
- } else {
- self.finish_inline_assist(inline_assist_id, false, cx);
- return;
- };
-
- let language = buffer.language_at(range.start);
- let language_name = if let Some(language) = language.as_ref() {
- if Arc::ptr_eq(language, &language::PLAIN_TEXT) {
- None
- } else {
- Some(language.name())
- }
- } else {
- None
- };
+ let context = self
+ .context_store
+ .update(cx, |store, cx| store.open_local_context(path.clone(), cx));
+ let fs = self.fs.clone();
+ let project = self.project.clone();
+ let workspace = self.workspace.clone();
- // Higher Temperature increases the randomness of model outputs.
- // If Markdown or No Language is Known, increase the randomness for more creative output
- // If Code, decrease temperature to get more deterministic outputs
- let temperature = if let Some(language) = language_name.clone() {
- if language.as_ref() == "Markdown" {
- 1.0
- } else {
- 0.5
- }
- } else {
- 1.0
- };
+ let lsp_adapter_delegate = workspace
+ .update(cx, |workspace, cx| {
+ make_lsp_adapter_delegate(workspace.project(), cx).log_err()
+ })
+ .log_err()
+ .flatten();
- let user_prompt = user_prompt.to_string();
+ cx.spawn(|this, mut cx| async move {
+ let context = context.await?;
+ let assistant_panel = this.clone();
+ this.update(&mut cx, |this, cx| {
+ let workspace = workspace
+ .upgrade()
+ .ok_or_else(|| anyhow!("workspace dropped"))?;
+ let editor = cx.new_view(|cx| {
+ ContextEditor::for_context(
+ context,
+ fs,
+ workspace,
+ project,
+ lsp_adapter_delegate,
+ assistant_panel,
+ cx,
+ )
+ });
+ this.show_context(editor, cx);
+ anyhow::Ok(())
+ })??;
+ Ok(())
+ })
+ }
- let prompt = cx.background_executor().spawn(async move {
- let language_name = language_name.as_deref();
- generate_content_prompt(user_prompt, language_name, buffer, range, project_name)
+ fn open_remote_context(
+ &mut self,
+ id: ContextId,
+ cx: &mut ViewContext,
+ ) -> Task>> {
+ let existing_context = self.pane.read(cx).items().find_map(|item| {
+ item.downcast::()
+ .filter(|editor| *editor.read(cx).context.read(cx).id() == id)
});
-
- let mut messages = Vec::new();
- if let Some(conversation) = conversation {
- let conversation = conversation.read(cx);
- let buffer = conversation.buffer.read(cx);
- messages.extend(
- conversation
- .messages(cx)
- .map(|message| message.to_request_message(buffer)),
- );
+ if let Some(existing_context) = existing_context {
+ return cx.spawn(|this, mut cx| async move {
+ this.update(&mut cx, |this, cx| {
+ this.show_context(existing_context.clone(), cx)
+ })?;
+ Ok(existing_context)
+ });
}
- let model = self.model.clone();
-
- cx.spawn(|_, mut cx| async move {
- // I Don't know if we want to return a ? here.
- let prompt = prompt.await?;
- messages.push(LanguageModelRequestMessage {
- role: Role::User,
- content: prompt,
- });
+ let context = self
+ .context_store
+ .update(cx, |store, cx| store.open_remote_context(id, cx));
+ let fs = self.fs.clone();
+ let workspace = self.workspace.clone();
- let request = LanguageModelRequest {
- model,
- messages,
- stop: vec!["|END|>".to_string()],
- temperature,
- };
+ let lsp_adapter_delegate = workspace
+ .update(cx, |workspace, cx| {
+ make_lsp_adapter_delegate(workspace.project(), cx).log_err()
+ })
+ .log_err()
+ .flatten();
- codegen.update(&mut cx, |codegen, cx| codegen.start(request, cx))?;
- anyhow::Ok(())
+ cx.spawn(|this, mut cx| async move {
+ let context = context.await?;
+ let assistant_panel = this.clone();
+ this.update(&mut cx, |this, cx| {
+ let workspace = workspace
+ .upgrade()
+ .ok_or_else(|| anyhow!("workspace dropped"))?;
+ let editor = cx.new_view(|cx| {
+ ContextEditor::for_context(
+ context,
+ fs,
+ workspace,
+ this.project.clone(),
+ lsp_adapter_delegate,
+ assistant_panel,
+ cx,
+ )
+ });
+ this.show_context(editor.clone(), cx);
+ anyhow::Ok(editor)
+ })?
})
- .detach();
}
- fn update_highlights_for_editor(&self, editor: &View, cx: &mut ViewContext) {
- let mut background_ranges = Vec::new();
- let mut foreground_ranges = Vec::new();
- let empty_inline_assist_ids = Vec::new();
- let inline_assist_ids = self
- .pending_inline_assist_ids_by_editor
- .get(&editor.downgrade())
- .unwrap_or(&empty_inline_assist_ids);
-
- for inline_assist_id in inline_assist_ids {
- if let Some(pending_assist) = self.pending_inline_assists.get(inline_assist_id) {
- let codegen = pending_assist.codegen.read(cx);
- background_ranges.push(codegen.range());
- foreground_ranges.extend(codegen.last_equal_ranges().iter().cloned());
- }
- }
-
- let snapshot = editor.read(cx).buffer().read(cx).snapshot(cx);
- merge_ranges(&mut background_ranges, &snapshot);
- merge_ranges(&mut foreground_ranges, &snapshot);
- editor.update(cx, |editor, cx| {
- if background_ranges.is_empty() {
- editor.clear_background_highlights::(cx);
- } else {
- editor.highlight_background::(
- &background_ranges,
- |theme| theme.editor_active_line_background, // TODO use the appropriate color
- cx,
- );
- }
-
- if foreground_ranges.is_empty() {
- editor.clear_highlights::(cx);
- } else {
- editor.highlight_text::(
- foreground_ranges,
- HighlightStyle {
- fade_out: Some(0.6),
- ..Default::default()
- },
- cx,
- );
- }
- });
+ fn is_authenticated(&mut self, cx: &mut ViewContext) -> bool {
+ CompletionProvider::global(cx).is_authenticated()
}
- fn new_conversation(&mut self, cx: &mut ViewContext) -> Option> {
- let workspace = self.workspace.upgrade()?;
-
- let editor = cx.new_view(|cx| {
- ConversationEditor::new(
- self.model.clone(),
- self.languages.clone(),
- self.slash_commands.clone(),
- self.fs.clone(),
- workspace,
- cx,
- )
- });
-
- self.show_conversation(editor.clone(), cx);
- Some(editor)
+ fn authenticate(&mut self, cx: &mut ViewContext) -> Task> {
+ cx.update_global::(|provider, cx| provider.authenticate(cx))
}
- fn show_conversation(
- &mut self,
- conversation_editor: View,
- cx: &mut ViewContext,
- ) {
- let mut subscriptions = Vec::new();
- subscriptions
- .push(cx.subscribe(&conversation_editor, Self::handle_conversation_editor_event));
+ fn render_signed_in(&mut self, cx: &mut ViewContext) -> impl IntoElement {
+ let mut registrar = DivRegistrar::new(
+ |panel, cx| {
+ panel
+ .pane
+ .read(cx)
+ .toolbar()
+ .read(cx)
+ .item_of_type::()
+ },
+ cx,
+ );
+ BufferSearchBar::register(&mut registrar);
+ let registrar = registrar.into_div();
- let conversation = conversation_editor.read(cx).conversation.clone();
- subscriptions.push(cx.observe(&conversation, |_, _, cx| cx.notify()));
+ v_flex()
+ .key_context("AssistantPanel")
+ .size_full()
+ .on_action(cx.listener(|this, _: &workspace::NewFile, cx| {
+ this.new_context(cx);
+ }))
+ .on_action(cx.listener(AssistantPanel::deploy_history))
+ .on_action(cx.listener(AssistantPanel::deploy_prompt_library))
+ .on_action(cx.listener(AssistantPanel::reset_credentials))
+ .on_action(cx.listener(AssistantPanel::toggle_model_selector))
+ .child(registrar.size_full().child(self.pane.clone()))
+ }
+}
- let editor = conversation_editor.read(cx).editor.clone();
- self.toolbar.update(cx, |toolbar, cx| {
- toolbar.set_active_item(Some(&editor), cx);
- });
- if self.focus_handle.contains_focused(cx) {
- cx.focus_view(&editor);
+impl Render for AssistantPanel {
+ fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement {
+ if let Some(authentication_prompt) = self.authentication_prompt.as_ref() {
+ authentication_prompt.clone().into_any()
+ } else {
+ self.render_signed_in(cx).into_any_element()
}
- self.active_conversation_editor = Some(ActiveConversationEditor {
- editor: conversation_editor,
- _subscriptions: subscriptions,
- });
- self.show_saved_conversations = false;
+ }
+}
- cx.notify();
+impl Panel for AssistantPanel {
+ fn persistent_name() -> &'static str {
+ "AssistantPanel"
}
- fn cycle_model(&mut self, cx: &mut ViewContext) {
- let next_model = match &self.model {
- LanguageModel::OpenAi(model) => LanguageModel::OpenAi(match &model {
- open_ai::Model::ThreePointFiveTurbo => open_ai::Model::Four,
- open_ai::Model::Four => open_ai::Model::FourTurbo,
- open_ai::Model::FourTurbo => open_ai::Model::FourOmni,
- open_ai::Model::FourOmni => open_ai::Model::ThreePointFiveTurbo,
- }),
- LanguageModel::Anthropic(model) => LanguageModel::Anthropic(match &model {
- anthropic::Model::Claude3Opus => anthropic::Model::Claude3Sonnet,
- anthropic::Model::Claude3Sonnet => anthropic::Model::Claude3Haiku,
- anthropic::Model::Claude3Haiku => anthropic::Model::Claude3Opus,
- }),
- LanguageModel::ZedDotDev(model) => LanguageModel::ZedDotDev(match &model {
- ZedDotDevModel::Gpt3Point5Turbo => ZedDotDevModel::Gpt4,
- ZedDotDevModel::Gpt4 => ZedDotDevModel::Gpt4Turbo,
- ZedDotDevModel::Gpt4Turbo => ZedDotDevModel::Gpt4Omni,
- ZedDotDevModel::Gpt4Omni => ZedDotDevModel::Claude3Opus,
- ZedDotDevModel::Claude3Opus => ZedDotDevModel::Claude3Sonnet,
- ZedDotDevModel::Claude3Sonnet => ZedDotDevModel::Claude3Haiku,
- ZedDotDevModel::Claude3Haiku => {
- match CompletionProvider::global(cx).default_model() {
- LanguageModel::ZedDotDev(custom @ ZedDotDevModel::Custom(_)) => custom,
- _ => ZedDotDevModel::Gpt3Point5Turbo,
- }
- }
- ZedDotDevModel::Custom(_) => ZedDotDevModel::Gpt3Point5Turbo,
- }),
- };
+ fn position(&self, cx: &WindowContext) -> DockPosition {
+ match AssistantSettings::get_global(cx).dock {
+ AssistantDockPosition::Left => DockPosition::Left,
+ AssistantDockPosition::Bottom => DockPosition::Bottom,
+ AssistantDockPosition::Right => DockPosition::Right,
+ }
+ }
- self.set_model(next_model, cx);
+ fn position_is_valid(&self, _: DockPosition) -> bool {
+ true
}
- fn set_model(&mut self, model: LanguageModel, cx: &mut ViewContext) {
- self.model = model.clone();
- if let Some(editor) = self.active_conversation_editor() {
- editor.update(cx, |active_conversation, cx| {
- active_conversation
- .conversation
- .update(cx, |conversation, cx| {
- conversation.set_model(model, cx);
- })
- })
- }
- cx.notify();
+ fn set_position(&mut self, position: DockPosition, cx: &mut ViewContext) {
+ settings::update_settings_file::(self.fs.clone(), cx, move |settings| {
+ let dock = match position {
+ DockPosition::Left => AssistantDockPosition::Left,
+ DockPosition::Bottom => AssistantDockPosition::Bottom,
+ DockPosition::Right => AssistantDockPosition::Right,
+ };
+ settings.set_dock(dock);
+ });
}
- fn handle_conversation_editor_event(
- &mut self,
- _: View,
- event: &ConversationEditorEvent,
- cx: &mut ViewContext,
- ) {
- match event {
- ConversationEditorEvent::TabContentChanged => cx.notify(),
+ fn size(&self, cx: &WindowContext) -> Pixels {
+ let settings = AssistantSettings::get_global(cx);
+ match self.position(cx) {
+ DockPosition::Left | DockPosition::Right => {
+ self.width.unwrap_or(settings.default_width)
+ }
+ DockPosition::Bottom => self.height.unwrap_or(settings.default_height),
}
}
- fn toggle_zoom(&mut self, _: &workspace::ToggleZoom, cx: &mut ViewContext) {
- if self.zoomed {
- cx.emit(PanelEvent::ZoomOut)
- } else {
- cx.emit(PanelEvent::ZoomIn)
+ fn set_size(&mut self, size: Option, cx: &mut ViewContext) {
+ match self.position(cx) {
+ DockPosition::Left | DockPosition::Right => self.width = size,
+ DockPosition::Bottom => self.height = size,
}
+ cx.notify();
}
- fn toggle_history(&mut self, _: &ToggleHistory, cx: &mut ViewContext) {
- self.show_saved_conversations = !self.show_saved_conversations;
- cx.notify();
+ fn is_zoomed(&self, cx: &WindowContext) -> bool {
+ self.pane.read(cx).is_zoomed()
}
- fn show_history(&mut self, cx: &mut ViewContext) {
- if !self.show_saved_conversations {
- self.show_saved_conversations = true;
- cx.notify();
- }
+ fn set_zoomed(&mut self, zoomed: bool, cx: &mut ViewContext) {
+ self.pane.update(cx, |pane, cx| pane.set_zoomed(zoomed, cx));
}
- fn deploy(&mut self, action: &search::buffer_search::Deploy, cx: &mut ViewContext) {
- let mut propagate = true;
- if let Some(search_bar) = self.toolbar.read(cx).item_of_type::() {
- search_bar.update(cx, |search_bar, cx| {
- if search_bar.show(cx) {
- search_bar.search_suggested(cx);
- if action.focus {
- let focus_handle = search_bar.focus_handle(cx);
- search_bar.select_query(cx);
- cx.focus(&focus_handle);
+ fn set_active(&mut self, active: bool, cx: &mut ViewContext) {
+ if active {
+ let load_credentials = self.authenticate(cx);
+ cx.spawn(|this, mut cx| async move {
+ load_credentials.await?;
+ this.update(&mut cx, |this, cx| {
+ if this.is_authenticated(cx) && this.active_context_editor(cx).is_none() {
+ this.new_context(cx);
}
- propagate = false
- }
- });
- }
- if propagate {
- cx.propagate();
+ })
+ })
+ .detach_and_log_err(cx);
}
}
- fn handle_editor_cancel(&mut self, _: &editor::actions::Cancel, cx: &mut ViewContext