Compare commits
347 Commits
fix-hard-c
...
lua-syntax
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d6a8b4cfb1 | ||
|
|
264ac61210 | ||
|
|
ad4742a5b8 | ||
|
|
b0d4abb82e | ||
|
|
387ee46c46 | ||
|
|
89d89b8b2d | ||
|
|
f07ae541ad | ||
|
|
ff0bb1f389 | ||
|
|
9c7eee24bc | ||
|
|
ec4719146a | ||
|
|
47f8f891c8 | ||
|
|
d9d3b8847b | ||
|
|
d7b90f4204 | ||
|
|
3e64f38ba0 | ||
|
|
82338e2c47 | ||
|
|
229e853874 | ||
|
|
ed13e05855 | ||
|
|
674fb7621f | ||
|
|
fe18c73a07 | ||
|
|
befacfe8c9 | ||
|
|
54f0a729c2 | ||
|
|
67f9b2b87f | ||
|
|
a4ec0af681 | ||
|
|
886d8c1cab | ||
|
|
ebc5c213a2 | ||
|
|
0a2d938ac5 | ||
|
|
fc01f496a9 | ||
|
|
db28b9bbde | ||
|
|
0453cb2b06 | ||
|
|
85211889e5 | ||
|
|
ad94642e83 | ||
|
|
f4899d92a4 | ||
|
|
6685d85f49 | ||
|
|
161f8a1dd2 | ||
|
|
6cdd7b7390 | ||
|
|
0ec15d6b02 | ||
|
|
909de2ca6f | ||
|
|
f31749c81b | ||
|
|
76a81607de | ||
|
|
7d22059a2f | ||
|
|
6b16a5555e | ||
|
|
7ba2b258de | ||
|
|
cbb535f5eb | ||
|
|
20fc753f2b | ||
|
|
042fc82e99 | ||
|
|
27781a8a60 | ||
|
|
33af6bce55 | ||
|
|
563baf682e | ||
|
|
11b79d0ab9 | ||
|
|
8c4da9fba0 | ||
|
|
1f7fa80166 | ||
|
|
2ac952ee6b | ||
|
|
495612be2e | ||
|
|
1086b282b8 | ||
|
|
ffe2bed1e2 | ||
|
|
88940732ca | ||
|
|
74fc52d5ce | ||
|
|
2a7a4a80c6 | ||
|
|
c03bf1af36 | ||
|
|
922aaa0534 | ||
|
|
fc5ff318e3 | ||
|
|
e7b3b8bf03 | ||
|
|
6faa7cd722 | ||
|
|
0776fa8f31 | ||
|
|
7321c814ce | ||
|
|
ac3cb3df05 | ||
|
|
0bd40da546 | ||
|
|
3bec4eb117 | ||
|
|
bf6cc2697a | ||
|
|
dc3158c8ce | ||
|
|
9e2b7bc5dc | ||
|
|
b774a4b8d1 | ||
|
|
16ab8701a2 | ||
|
|
b2add8c803 | ||
|
|
6635462f7b | ||
|
|
81ff6f7a3c | ||
|
|
669082dbe0 | ||
|
|
d5bc7b9a79 | ||
|
|
8bb2739e28 | ||
|
|
466be14b56 | ||
|
|
95446195af | ||
|
|
b34c0fd71b | ||
|
|
e0060b92cc | ||
|
|
06bcc42652 | ||
|
|
f24c226af8 | ||
|
|
593f3dc1d5 | ||
|
|
61d584db45 | ||
|
|
c37f616c3b | ||
|
|
73ac19958a | ||
|
|
508b9d3b5d | ||
|
|
0a4ff2f475 | ||
|
|
ae6d350334 | ||
|
|
0e44f93178 | ||
|
|
65d92d7278 | ||
|
|
8b5ef2558b | ||
|
|
fec228bb23 | ||
|
|
e00d737196 | ||
|
|
b0dee94126 | ||
|
|
e65471c7a1 | ||
|
|
6713ec8cdf | ||
|
|
48e09c0026 | ||
|
|
3f03d7b023 | ||
|
|
fa96e2259b | ||
|
|
a8a05f208b | ||
|
|
aa1ab50656 | ||
|
|
d115cb1944 | ||
|
|
42571e405f | ||
|
|
2d61a51ded | ||
|
|
a2876f5d3e | ||
|
|
13deaa3f69 | ||
|
|
694afd15c9 | ||
|
|
eb648dd096 | ||
|
|
1c4c568068 | ||
|
|
ec88a6886f | ||
|
|
7fb16977ce | ||
|
|
53b2792844 | ||
|
|
760d08711c | ||
|
|
71866d6314 | ||
|
|
0c2bbb3aa9 | ||
|
|
9d8a163f5b | ||
|
|
8a22a07d14 | ||
|
|
fad4df5e70 | ||
|
|
e4e758db3a | ||
|
|
fc52b43159 | ||
|
|
b445e4ce24 | ||
|
|
508b581215 | ||
|
|
c9aba6c10a | ||
|
|
5740fec9d5 | ||
|
|
22220ed32e | ||
|
|
7440833ff1 | ||
|
|
bb3aef15eb | ||
|
|
ece1818301 | ||
|
|
604eb91a6c | ||
|
|
472dde509f | ||
|
|
212c8f4c31 | ||
|
|
6092918be8 | ||
|
|
a5f96909cb | ||
|
|
b15aa5e018 | ||
|
|
62fb555e18 | ||
|
|
c0ecf8684e | ||
|
|
df7beb4217 | ||
|
|
6f30d5da71 | ||
|
|
b8387c6077 | ||
|
|
c05ce882e9 | ||
|
|
eaf3949614 | ||
|
|
c47305dd7b | ||
|
|
482a45feac | ||
|
|
7ec3702b47 | ||
|
|
91862ddc9f | ||
|
|
eb4fad52df | ||
|
|
541a5c01a4 | ||
|
|
82f793144e | ||
|
|
6eb2ffe77a | ||
|
|
c5632f8c31 | ||
|
|
6856e869fc | ||
|
|
cc3b5c729e | ||
|
|
4e60ebab5e | ||
|
|
e8ef36edcc | ||
|
|
2e98bc17cb | ||
|
|
5c400dac8d | ||
|
|
635b80ed51 | ||
|
|
73ab5abee1 | ||
|
|
1f52aab7c7 | ||
|
|
1732cdb90a | ||
|
|
0625006a9e | ||
|
|
0b96690446 | ||
|
|
bc22690620 | ||
|
|
4eb82c0731 | ||
|
|
fa91379119 | ||
|
|
da2320fb40 | ||
|
|
7bc31a69c3 | ||
|
|
1e4752972f | ||
|
|
91148a72a3 | ||
|
|
878b50c991 | ||
|
|
e7df5ce61c | ||
|
|
da22f21dec | ||
|
|
3505a17452 | ||
|
|
81badd1fe6 | ||
|
|
6dacc751fc | ||
|
|
a0d1555470 | ||
|
|
8ba7b349a5 | ||
|
|
11838cf89e | ||
|
|
84ded96cb2 | ||
|
|
afc61b9527 | ||
|
|
672a472a23 | ||
|
|
9822d9673c | ||
|
|
f0dec2f576 | ||
|
|
9f7c65df44 | ||
|
|
372e485ba8 | ||
|
|
b8fb416892 | ||
|
|
6a1c104522 | ||
|
|
b06da7f7fd | ||
|
|
f80035e0ff | ||
|
|
7664c1cef5 | ||
|
|
967792119b | ||
|
|
be1ac78e11 | ||
|
|
b5a1ae6526 | ||
|
|
d2b49de0e4 | ||
|
|
d694458659 | ||
|
|
7a34dd9888 | ||
|
|
add7ae8052 | ||
|
|
c53020ceaf | ||
|
|
eeac1a9287 | ||
|
|
e83ebd1fab | ||
|
|
afb0fd609b | ||
|
|
b2a685f00a | ||
|
|
089ea5da50 | ||
|
|
b6e8db244c | ||
|
|
6267ab0396 | ||
|
|
d105f04be5 | ||
|
|
5edded5c02 | ||
|
|
78da39e19b | ||
|
|
d82a132477 | ||
|
|
f11357db7c | ||
|
|
6d17546b1a | ||
|
|
60a96ab799 | ||
|
|
1f80f58104 | ||
|
|
bab65011b4 | ||
|
|
c0b6d86c41 | ||
|
|
39728cfc59 | ||
|
|
ebccef1aa4 | ||
|
|
33754f8eac | ||
|
|
dd1ff9b998 | ||
|
|
7f214ed25a | ||
|
|
08539b32d0 | ||
|
|
88baf171c3 | ||
|
|
2f34af7811 | ||
|
|
2978be95d7 | ||
|
|
30568e6dd1 | ||
|
|
a5698a430d | ||
|
|
57659b5552 | ||
|
|
3db18ff053 | ||
|
|
198f56c763 | ||
|
|
d68d858a10 | ||
|
|
7f166298db | ||
|
|
0066071a89 | ||
|
|
e5b6194914 | ||
|
|
23f61d5954 | ||
|
|
0559e1f348 | ||
|
|
014d9dfce1 | ||
|
|
a0aea6ef62 | ||
|
|
278620df33 | ||
|
|
75dbe189bd | ||
|
|
3d7ba7c1c0 | ||
|
|
eebee4ab18 | ||
|
|
3a3621f2d8 | ||
|
|
524e813d20 | ||
|
|
b12b8340de | ||
|
|
7075bd700f | ||
|
|
21fc3c07b6 | ||
|
|
c90f87898a | ||
|
|
796e87ecbc | ||
|
|
3a041cac72 | ||
|
|
86283f4e3d | ||
|
|
8e1003ef59 | ||
|
|
8e891c16f8 | ||
|
|
cea06bc0ce | ||
|
|
45146b6f30 | ||
|
|
bcbb19e06e | ||
|
|
3f168e85c2 | ||
|
|
20440f83e9 | ||
|
|
2d63f7628f | ||
|
|
52f73e0c2d | ||
|
|
980e1b533f | ||
|
|
2ea332421c | ||
|
|
4edecfed3e | ||
|
|
113c471bb0 | ||
|
|
10fef92eea | ||
|
|
3ee4edc404 | ||
|
|
eda233344c | ||
|
|
17a483cb03 | ||
|
|
7b277d2efd | ||
|
|
63cfcc26fb | ||
|
|
53a5145dc8 | ||
|
|
def342e35c | ||
|
|
bbb8d63de0 | ||
|
|
e5b97a5e48 | ||
|
|
e06666759a | ||
|
|
a78f3cfea2 | ||
|
|
0acd556106 | ||
|
|
2f7a62780a | ||
|
|
f1e6b144e8 | ||
|
|
10a4760f90 | ||
|
|
cdd07fdf29 | ||
|
|
8a3fb890b0 | ||
|
|
30af8d0a81 | ||
|
|
ceb7fc2cb2 | ||
|
|
d8694510b5 | ||
|
|
ec7ce41324 | ||
|
|
b2921bd3fd | ||
|
|
64756fa96f | ||
|
|
ff6844300e | ||
|
|
b1b6401ce7 | ||
|
|
07ba7c8c44 | ||
|
|
6516249302 | ||
|
|
fc8218d728 | ||
|
|
a8d56877ee | ||
|
|
dd0de3cfa9 | ||
|
|
198c36811e | ||
|
|
133704a419 | ||
|
|
d1302a7a08 | ||
|
|
2b28b5969f | ||
|
|
bc941bfc97 | ||
|
|
72a9429ef6 | ||
|
|
f020291039 | ||
|
|
4b3a2a33a8 | ||
|
|
1f257f4704 | ||
|
|
f517050548 | ||
|
|
535ba75bc7 | ||
|
|
ee280b0d05 | ||
|
|
a43793493a | ||
|
|
3b3c379852 | ||
|
|
147f407b7a | ||
|
|
822f42e8fe | ||
|
|
7e097d529a | ||
|
|
65f76e6f4d | ||
|
|
918cba4cce | ||
|
|
4067ae4b37 | ||
|
|
084a0233b6 | ||
|
|
04732b23fb | ||
|
|
abc027558a | ||
|
|
4d106a4b0b | ||
|
|
ec4d9ec111 | ||
|
|
10053e2566 | ||
|
|
7a55da58d9 | ||
|
|
5043eaedc4 | ||
|
|
328e4d6278 | ||
|
|
83513bab59 | ||
|
|
b9ca240242 | ||
|
|
5d751cd407 | ||
|
|
ef53f7af22 | ||
|
|
4118f42d61 | ||
|
|
ec56755f9e | ||
|
|
aba89ba12a | ||
|
|
7ff40091d8 | ||
|
|
dabc35b257 | ||
|
|
8f40bcc86c | ||
|
|
3e75a661dd | ||
|
|
a9e753fc07 | ||
|
|
2d6592dcaa | ||
|
|
59a153b2e1 | ||
|
|
10a6cd00e7 | ||
|
|
f6f6980463 | ||
|
|
2e302b1a7c | ||
|
|
17323ed7b2 | ||
|
|
3759e0bf55 | ||
|
|
144d8a1db6 |
51
.github/ISSUE_TEMPLATE/0_git_beta_bug_report.yml
vendored
Normal file
51
.github/ISSUE_TEMPLATE/0_git_beta_bug_report.yml
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
name: Git Beta
|
||||
description: There is a bug related to new Git features in Zed
|
||||
type: "Bug"
|
||||
labels: [git]
|
||||
title: "Git Beta: <a short description of the Git bug>"
|
||||
body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Summary
|
||||
description: Describe the bug with a one line summary, and provide detailed reproduction steps
|
||||
value: |
|
||||
<!-- Please insert a one line summary of the issue below -->
|
||||
|
||||
<!-- Include all steps necessary to reproduce from a clean Zed installation. Be verbose -->
|
||||
Steps to trigger the problem:
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
Actual Behavior:
|
||||
|
||||
Expected Behavior:
|
||||
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: environment
|
||||
attributes:
|
||||
label: Zed Version and System Specs
|
||||
description: 'Open Zed, and in the command palette select "zed: Copy System Specs Into Clipboard"'
|
||||
placeholder: |
|
||||
Output of "zed: Copy System Specs Into Clipboard"
|
||||
validations:
|
||||
required: true
|
||||
- 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: |
|
||||
<details><summary>Zed.log</summary>
|
||||
|
||||
<!-- Click below this line and paste or drag-and-drop your log-->
|
||||
```
|
||||
|
||||
```
|
||||
<!-- Click above this line and paste or drag-and-drop your log--></details>
|
||||
validations:
|
||||
required: false
|
||||
25
.github/ISSUE_TEMPLATE/1_bug_report.yml
vendored
25
.github/ISSUE_TEMPLATE/1_bug_report.yml
vendored
@@ -10,16 +10,39 @@ body:
|
||||
value: |
|
||||
<!-- Please insert a one line summary of the issue below -->
|
||||
|
||||
<!-- Include all steps necessary to reproduce from a clean Zed installation. Be verbose -->
|
||||
SUMMARY_SENTENCE_HERE
|
||||
|
||||
<!-- Be verbose: Include all steps necessary to reproduce from a clean Zed installation. -->
|
||||
<!-- Code snippets are better than images, a repository link that reproduces the issue is ideal. -->
|
||||
|
||||
Steps to trigger the problem:
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
4.
|
||||
|
||||
Actual Behavior:
|
||||
|
||||
Expected Behavior:
|
||||
|
||||
<!--
|
||||
Is there anything additional necessary to reproduce this issue?
|
||||
- settings.json, keymap.json, .editorconfig etc?
|
||||
- Does it happen intermittently or only with specific projects / file types?
|
||||
- Have you found a workaround?
|
||||
|
||||
Did you check your Zed.log to see if there is any relevant details there?
|
||||
- When including large items (videos, screenshots, logs, configs) please wrap with:
|
||||
|
||||
<details><summary>See inside for XXXXYYY</summary>
|
||||
|
||||
```shell
|
||||
code
|
||||
```
|
||||
|
||||
</details>
|
||||
-->
|
||||
|
||||
validations:
|
||||
required: true
|
||||
|
||||
|
||||
28
.github/workflows/ci.yml
vendored
28
.github/workflows/ci.yml
vendored
@@ -109,8 +109,16 @@ jobs:
|
||||
- name: cargo clippy
|
||||
run: ./script/clippy
|
||||
|
||||
- name: Install cargo-machete
|
||||
uses: clechasseur/rs-cargo@8435b10f6e71c2e3d4d3b7573003a8ce4bfc6386 # v2
|
||||
with:
|
||||
command: install
|
||||
args: cargo-machete@0.7.0
|
||||
|
||||
- name: Check unused dependencies
|
||||
uses: bnjbvr/cargo-machete@main
|
||||
uses: clechasseur/rs-cargo@8435b10f6e71c2e3d4d3b7573003a8ce4bfc6386 # v2
|
||||
with:
|
||||
command: machete
|
||||
|
||||
- name: Check licenses
|
||||
run: |
|
||||
@@ -232,7 +240,7 @@ jobs:
|
||||
timeout-minutes: 60
|
||||
name: (Windows) Run Clippy and tests
|
||||
if: github.repository_owner == 'zed-industries'
|
||||
runs-on: hosted-windows-1
|
||||
runs-on: hosted-windows-2
|
||||
steps:
|
||||
# more info here:- https://github.com/rust-lang/cargo/issues/13020
|
||||
- name: Enable longer pathnames for git
|
||||
@@ -265,8 +273,7 @@ jobs:
|
||||
|
||||
- name: cargo clippy
|
||||
working-directory: ${{ env.ZED_WORKSPACE }}
|
||||
# Windows can't run shell scripts, so we need to use `cargo xtask`.
|
||||
run: cargo xtask clippy
|
||||
run: ./script/clippy.ps1
|
||||
|
||||
- name: Run tests
|
||||
uses: ./.github/actions/run_tests_windows
|
||||
@@ -298,8 +305,9 @@ jobs:
|
||||
env:
|
||||
MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
|
||||
MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
|
||||
APPLE_NOTARIZATION_USERNAME: ${{ secrets.APPLE_NOTARIZATION_USERNAME }}
|
||||
APPLE_NOTARIZATION_PASSWORD: ${{ secrets.APPLE_NOTARIZATION_PASSWORD }}
|
||||
APPLE_NOTARIZATION_KEY: ${{ secrets.APPLE_NOTARIZATION_KEY }}
|
||||
APPLE_NOTARIZATION_KEY_ID: ${{ secrets.APPLE_NOTARIZATION_KEY_ID }}
|
||||
APPLE_NOTARIZATION_ISSUER_ID: ${{ secrets.APPLE_NOTARIZATION_ISSUER_ID }}
|
||||
ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
|
||||
ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON: ${{ secrets.ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON }}
|
||||
DIGITALOCEAN_SPACES_ACCESS_KEY: ${{ secrets.DIGITALOCEAN_SPACES_ACCESS_KEY }}
|
||||
@@ -350,14 +358,14 @@ jobs:
|
||||
mv target/x86_64-apple-darwin/release/Zed.dmg target/x86_64-apple-darwin/release/Zed-x86_64.dmg
|
||||
|
||||
- name: Upload app bundle (aarch64) to workflow run if main branch or specific label
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4
|
||||
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # 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.dmg
|
||||
path: target/aarch64-apple-darwin/release/Zed-aarch64.dmg
|
||||
|
||||
- name: Upload app bundle (x86_64) to workflow run if main branch or specific label
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4
|
||||
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # 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 }}-x86_64.dmg
|
||||
@@ -408,7 +416,7 @@ jobs:
|
||||
run: script/bundle-linux
|
||||
|
||||
- name: Upload Linux bundle to workflow run if main branch or specific label
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4
|
||||
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # 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 }}-x86_64-unknown-linux-gnu.tar.gz
|
||||
@@ -456,7 +464,7 @@ jobs:
|
||||
run: script/bundle-linux
|
||||
|
||||
- name: Upload Linux bundle to workflow run if main branch or specific label
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4
|
||||
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # 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
|
||||
|
||||
25
.github/workflows/community_update_all_top_ranking_issues.yml
vendored
Normal file
25
.github/workflows/community_update_all_top_ranking_issues.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
name: Update All Top Ranking Issues
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 */12 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
update_top_ranking_issues:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'zed-industries/zed'
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
- name: Set up uv
|
||||
uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # v3
|
||||
with:
|
||||
version: "latest"
|
||||
enable-cache: true
|
||||
cache-dependency-glob: "script/update_top_ranking_issues/pyproject.toml"
|
||||
- name: Install Python 3.13
|
||||
run: uv python install 3.13
|
||||
- name: Install dependencies
|
||||
run: uv sync --project script/update_top_ranking_issues -p 3.13
|
||||
- name: Run script
|
||||
run: uv run --project script/update_top_ranking_issues script/update_top_ranking_issues/main.py --github-token ${{ secrets.GITHUB_TOKEN }} --issue-reference-number 5393
|
||||
25
.github/workflows/community_update_weekly_top_ranking_issues.yml
vendored
Normal file
25
.github/workflows/community_update_weekly_top_ranking_issues.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
name: Update Weekly Top Ranking Issues
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 15 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
update_top_ranking_issues:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'zed-industries/zed'
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
- name: Set up uv
|
||||
uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # v3
|
||||
with:
|
||||
version: "latest"
|
||||
enable-cache: true
|
||||
cache-dependency-glob: "script/update_top_ranking_issues/pyproject.toml"
|
||||
- name: Install Python 3.13
|
||||
run: uv python install 3.13
|
||||
- name: Install dependencies
|
||||
run: uv sync --project script/update_top_ranking_issues -p 3.13
|
||||
- name: Run script
|
||||
run: uv run --project script/update_top_ranking_issues script/update_top_ranking_issues/main.py --github-token ${{ secrets.GITHUB_TOKEN }} --issue-reference-number 6952 --query-day-interval 7
|
||||
2
.github/workflows/deploy_cloudflare.yml
vendored
2
.github/workflows/deploy_cloudflare.yml
vendored
@@ -65,7 +65,7 @@ jobs:
|
||||
command: deploy .cloudflare/docs-proxy/src/worker.js
|
||||
|
||||
- name: Preserve Wrangler logs
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4
|
||||
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4
|
||||
if: always()
|
||||
with:
|
||||
name: wrangler_logs
|
||||
|
||||
5
.github/workflows/release_nightly.yml
vendored
5
.github/workflows/release_nightly.yml
vendored
@@ -62,8 +62,9 @@ jobs:
|
||||
env:
|
||||
MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
|
||||
MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
|
||||
APPLE_NOTARIZATION_USERNAME: ${{ secrets.APPLE_NOTARIZATION_USERNAME }}
|
||||
APPLE_NOTARIZATION_PASSWORD: ${{ secrets.APPLE_NOTARIZATION_PASSWORD }}
|
||||
APPLE_NOTARIZATION_KEY: ${{ secrets.APPLE_NOTARIZATION_KEY }}
|
||||
APPLE_NOTARIZATION_KEY_ID: ${{ secrets.APPLE_NOTARIZATION_KEY_ID }}
|
||||
APPLE_NOTARIZATION_ISSUER_ID: ${{ secrets.APPLE_NOTARIZATION_ISSUER_ID }}
|
||||
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 }}
|
||||
|
||||
4
.mailmap
4
.mailmap
@@ -21,6 +21,8 @@ Andrei Zvonimir Crnković <andrei@0x7f.dev>
|
||||
Andrei Zvonimir Crnković <andrei@0x7f.dev> <andreicek@0x7f.dev>
|
||||
Antonio Scandurra <me@as-cii.com>
|
||||
Antonio Scandurra <me@as-cii.com> <antonio@zed.dev>
|
||||
Ben Kunkle <ben@zed.dev>
|
||||
Ben Kunkle <ben@zed.dev> <ben.kunkle@gmail.com>
|
||||
Bennet Bo Fenner <bennet@zed.dev>
|
||||
Bennet Bo Fenner <bennet@zed.dev> <53836821+bennetbo@users.noreply.github.com>
|
||||
Bennet Bo Fenner <bennet@zed.dev> <bennetbo@gmx.de>
|
||||
@@ -112,6 +114,8 @@ Sebastijan Kelnerič <sebastijan.kelneric@sebba.dev> <sebastijan.kelneric@vichav
|
||||
Sergey Onufrienko <sergey@onufrienko.com>
|
||||
Shish <webmaster@shishnet.org>
|
||||
Shish <webmaster@shishnet.org> <shish@shishnet.org>
|
||||
Smit Barmase <0xtimsb@gmail.com>
|
||||
Smit Barmase <0xtimsb@gmail.com> <smit@zed.dev>
|
||||
Thorben Kröger <dev@thorben.net>
|
||||
Thorben Kröger <dev@thorben.net> <thorben.kroeger@hexagon.com>
|
||||
Thorsten Ball <thorsten@zed.dev>
|
||||
|
||||
@@ -14,12 +14,12 @@
|
||||
},
|
||||
"JSON": {
|
||||
"tab_size": 2,
|
||||
"preferred_line_length": 100,
|
||||
"preferred_line_length": 120,
|
||||
"formatter": "prettier"
|
||||
},
|
||||
"JSONC": {
|
||||
"tab_size": 2,
|
||||
"preferred_line_length": 100,
|
||||
"preferred_line_length": 120,
|
||||
"formatter": "prettier"
|
||||
},
|
||||
"JavaScript": {
|
||||
|
||||
300
Cargo.lock
generated
300
Cargo.lock
generated
@@ -395,7 +395,6 @@ dependencies = [
|
||||
"language",
|
||||
"language_model",
|
||||
"language_model_selector",
|
||||
"language_models",
|
||||
"languages",
|
||||
"log",
|
||||
"lsp",
|
||||
@@ -406,6 +405,7 @@ dependencies = [
|
||||
"pretty_assertions",
|
||||
"project",
|
||||
"prompt_library",
|
||||
"prompt_store",
|
||||
"proto",
|
||||
"rand 0.8.5",
|
||||
"rope",
|
||||
@@ -463,7 +463,6 @@ dependencies = [
|
||||
"language",
|
||||
"language_model",
|
||||
"language_model_selector",
|
||||
"language_models",
|
||||
"log",
|
||||
"lsp",
|
||||
"markdown",
|
||||
@@ -474,6 +473,7 @@ dependencies = [
|
||||
"picker",
|
||||
"project",
|
||||
"prompt_library",
|
||||
"prompt_store",
|
||||
"proto",
|
||||
"rand 0.8.5",
|
||||
"rope",
|
||||
@@ -492,6 +492,7 @@ dependencies = [
|
||||
"ui",
|
||||
"util",
|
||||
"uuid",
|
||||
"vim_mode_setting",
|
||||
"workspace",
|
||||
"zed_actions",
|
||||
]
|
||||
@@ -518,7 +519,6 @@ dependencies = [
|
||||
"language",
|
||||
"language_model",
|
||||
"language_model_selector",
|
||||
"language_models",
|
||||
"languages",
|
||||
"log",
|
||||
"multi_buffer",
|
||||
@@ -528,7 +528,7 @@ dependencies = [
|
||||
"picker",
|
||||
"pretty_assertions",
|
||||
"project",
|
||||
"prompt_library",
|
||||
"prompt_store",
|
||||
"rand 0.8.5",
|
||||
"regex",
|
||||
"rope",
|
||||
@@ -619,7 +619,7 @@ dependencies = [
|
||||
"log",
|
||||
"pretty_assertions",
|
||||
"project",
|
||||
"prompt_library",
|
||||
"prompt_store",
|
||||
"rope",
|
||||
"schemars",
|
||||
"semantic_index",
|
||||
@@ -644,9 +644,11 @@ dependencies = [
|
||||
"collections",
|
||||
"derive_more",
|
||||
"gpui",
|
||||
"language",
|
||||
"parking_lot",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"ui",
|
||||
"workspace",
|
||||
]
|
||||
|
||||
@@ -1269,6 +1271,30 @@ dependencies = [
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aws-sdk-bedrockruntime"
|
||||
version = "1.74.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6938541d1948a543bca23303fec4cff9c36bf0e63b8fa3ae1b337bcb9d5b81af"
|
||||
dependencies = [
|
||||
"aws-credential-types",
|
||||
"aws-runtime",
|
||||
"aws-smithy-async",
|
||||
"aws-smithy-eventstream",
|
||||
"aws-smithy-http",
|
||||
"aws-smithy-json",
|
||||
"aws-smithy-runtime",
|
||||
"aws-smithy-runtime-api",
|
||||
"aws-smithy-types",
|
||||
"aws-types",
|
||||
"bytes 1.10.0",
|
||||
"fastrand 2.3.0",
|
||||
"http 0.2.12",
|
||||
"once_cell",
|
||||
"regex-lite",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aws-sdk-kinesis"
|
||||
version = "1.61.0"
|
||||
@@ -1598,6 +1624,17 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aws_http_client"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"aws-smithy-runtime-api",
|
||||
"aws-smithy-types",
|
||||
"futures 0.3.31",
|
||||
"http_client",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum"
|
||||
version = "0.6.20"
|
||||
@@ -1727,6 +1764,22 @@ version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
||||
|
||||
[[package]]
|
||||
name = "bedrock"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"aws-sdk-bedrockruntime",
|
||||
"aws-smithy-types",
|
||||
"futures 0.3.31",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"strum",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bigdecimal"
|
||||
version = "0.4.7"
|
||||
@@ -2027,6 +2080,7 @@ name = "buffer_diff"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clock",
|
||||
"ctor",
|
||||
"env_logger 0.11.6",
|
||||
"futures 0.3.31",
|
||||
@@ -2538,9 +2592,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.30"
|
||||
version = "4.5.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92b7b18d71fad5313a1e320fa9897994228ce274b60faa4d694fe0ea89cd9e6d"
|
||||
checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -2548,9 +2602,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.30"
|
||||
version = "4.5.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a35db2071778a7344791a4fb4f95308b5673d219dee3ae348b86642574ecc90c"
|
||||
checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -2605,6 +2659,7 @@ dependencies = [
|
||||
"serde",
|
||||
"tempfile",
|
||||
"util",
|
||||
"windows 0.58.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2785,6 +2840,7 @@ dependencies = [
|
||||
"futures 0.3.31",
|
||||
"git",
|
||||
"git_hosting_providers",
|
||||
"git_ui",
|
||||
"google_ai",
|
||||
"gpui",
|
||||
"hex",
|
||||
@@ -2809,7 +2865,7 @@ dependencies = [
|
||||
"pretty_assertions",
|
||||
"project",
|
||||
"prometheus",
|
||||
"prompt_library",
|
||||
"prompt_store",
|
||||
"prost 0.9.0",
|
||||
"rand 0.8.5",
|
||||
"recent_projects",
|
||||
@@ -2971,7 +3027,6 @@ dependencies = [
|
||||
"collections",
|
||||
"gpui",
|
||||
"linkme",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"theme",
|
||||
]
|
||||
@@ -3052,6 +3107,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"assistant_tool",
|
||||
"async-trait",
|
||||
"collections",
|
||||
"command_palette_hooks",
|
||||
"context_server_settings",
|
||||
@@ -3092,9 +3148,9 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.7.1"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7"
|
||||
checksum = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
@@ -3112,7 +3168,9 @@ dependencies = [
|
||||
"clock",
|
||||
"collections",
|
||||
"command_palette_hooks",
|
||||
"ctor",
|
||||
"editor",
|
||||
"env_logger 0.11.6",
|
||||
"fs",
|
||||
"futures 0.3.31",
|
||||
"gpui",
|
||||
@@ -3120,6 +3178,7 @@ dependencies = [
|
||||
"indoc",
|
||||
"inline_completion",
|
||||
"language",
|
||||
"log",
|
||||
"lsp",
|
||||
"menu",
|
||||
"node_runtime",
|
||||
@@ -3611,9 +3670,19 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ctor"
|
||||
version = "0.3.1"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bba74424191d99c617a172ef126d429f62fe54aba1002c4d36e49403ce4b00a2"
|
||||
checksum = "a7747ac3a66a06f4ee6718686c8ea976d2d05fb30ada93ebd76b3f9aef97257c"
|
||||
dependencies = [
|
||||
"ctor-proc-macro",
|
||||
"dtor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctor-proc-macro"
|
||||
version = "0.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f211af61d8efdd104f96e57adf5e426ba1bc3ed7a4ead616e15e5881fd79c4d"
|
||||
|
||||
[[package]]
|
||||
name = "ctrlc"
|
||||
@@ -3989,6 +4058,21 @@ dependencies = [
|
||||
"phf",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dtor"
|
||||
version = "0.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8bf39a0bfd1f94d62ffdb2802a7e6244c0f34f6ebacf5d4c26547d08cd1d67a5"
|
||||
dependencies = [
|
||||
"dtor-proc-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dtor-proc-macro"
|
||||
version = "0.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7454e41ff9012c00d53cf7f475c5e3afa3b91b7c90568495495e8d9bf47a1055"
|
||||
|
||||
[[package]]
|
||||
name = "dunce"
|
||||
version = "1.0.5"
|
||||
@@ -4043,7 +4127,7 @@ dependencies = [
|
||||
"client",
|
||||
"clock",
|
||||
"collections",
|
||||
"convert_case 0.7.1",
|
||||
"convert_case 0.8.0",
|
||||
"ctor",
|
||||
"db",
|
||||
"emojis",
|
||||
@@ -4228,6 +4312,12 @@ dependencies = [
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_home"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe"
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.10.2"
|
||||
@@ -5286,10 +5376,12 @@ dependencies = [
|
||||
"pretty_assertions",
|
||||
"regex",
|
||||
"rope",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"smol",
|
||||
"sum_tree",
|
||||
"tempfile",
|
||||
"text",
|
||||
"time",
|
||||
"unindent",
|
||||
@@ -5335,8 +5427,11 @@ dependencies = [
|
||||
"anyhow",
|
||||
"buffer_diff",
|
||||
"collections",
|
||||
"component",
|
||||
"ctor",
|
||||
"db",
|
||||
"editor",
|
||||
"env_logger 0.11.6",
|
||||
"feature_flags",
|
||||
"futures 0.3.31",
|
||||
"fuzzy",
|
||||
@@ -5344,6 +5439,9 @@ dependencies = [
|
||||
"gpui",
|
||||
"itertools 0.14.0",
|
||||
"language",
|
||||
"linkify",
|
||||
"linkme",
|
||||
"log",
|
||||
"menu",
|
||||
"multi_buffer",
|
||||
"panel",
|
||||
@@ -5355,10 +5453,12 @@ dependencies = [
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"settings",
|
||||
"smallvec",
|
||||
"strum",
|
||||
"theme",
|
||||
"time",
|
||||
"ui",
|
||||
"unindent",
|
||||
"util",
|
||||
"windows 0.58.0",
|
||||
"workspace",
|
||||
@@ -6950,17 +7050,14 @@ dependencies = [
|
||||
"anthropic",
|
||||
"anyhow",
|
||||
"base64 0.22.1",
|
||||
"client",
|
||||
"collections",
|
||||
"deepseek",
|
||||
"futures 0.3.31",
|
||||
"google_ai",
|
||||
"gpui",
|
||||
"http_client",
|
||||
"image",
|
||||
"lmstudio",
|
||||
"log",
|
||||
"mistral",
|
||||
"ollama",
|
||||
"open_ai",
|
||||
"parking_lot",
|
||||
"proto",
|
||||
@@ -6969,6 +7066,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"smol",
|
||||
"strum",
|
||||
"telemetry_events",
|
||||
"thiserror 1.0.69",
|
||||
"ui",
|
||||
"util",
|
||||
@@ -6995,6 +7093,10 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"anthropic",
|
||||
"anyhow",
|
||||
"aws-config",
|
||||
"aws-credential-types",
|
||||
"aws_http_client",
|
||||
"bedrock",
|
||||
"client",
|
||||
"collections",
|
||||
"copilot",
|
||||
@@ -7006,6 +7108,7 @@ dependencies = [
|
||||
"futures 0.3.31",
|
||||
"google_ai",
|
||||
"gpui",
|
||||
"gpui_tokio",
|
||||
"http_client",
|
||||
"language_model",
|
||||
"lmstudio",
|
||||
@@ -7021,10 +7124,9 @@ dependencies = [
|
||||
"settings",
|
||||
"smol",
|
||||
"strum",
|
||||
"telemetry_events",
|
||||
"theme",
|
||||
"thiserror 1.0.69",
|
||||
"tiktoken-rs",
|
||||
"tokio",
|
||||
"ui",
|
||||
"util",
|
||||
]
|
||||
@@ -7510,9 +7612,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.25"
|
||||
version = "0.4.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
|
||||
checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"value-bag",
|
||||
@@ -7571,6 +7673,25 @@ dependencies = [
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lua-src"
|
||||
version = "547.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1edaf29e3517b49b8b746701e5648ccb5785cde1c119062cbabbc5d5cd115e42"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "luajit-src"
|
||||
version = "210.5.12+a4f56a4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3a8e7962a5368d5f264d045a5a255e90f9aa3fc1941ae15a8d2940d42cac671"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"which 7.0.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lyon"
|
||||
version = "1.0.1"
|
||||
@@ -7883,7 +8004,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collections",
|
||||
"convert_case 0.7.1",
|
||||
"convert_case 0.8.0",
|
||||
"log",
|
||||
"pretty_assertions",
|
||||
"streaming-iterator",
|
||||
@@ -7984,6 +8105,33 @@ dependencies = [
|
||||
"strum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mlua"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3f763c1041eff92ffb5d7169968a327e1ed2ebfe425dac0ee5a35f29082534b"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"either",
|
||||
"mlua-sys",
|
||||
"num-traits",
|
||||
"parking_lot",
|
||||
"rustc-hash 2.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mlua-sys"
|
||||
version = "0.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1901c1a635a22fe9250ffcc4fcc937c16b47c2e9e71adba8784af8bca1f69594"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"lua-src",
|
||||
"luajit-src",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "msvc_spectre_libs"
|
||||
version = "0.1.2"
|
||||
@@ -9262,7 +9410,7 @@ name = "perplexity"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"zed_extension_api 0.2.0",
|
||||
"zed_extension_api 0.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -10237,12 +10385,36 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "prompt_library"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collections",
|
||||
"editor",
|
||||
"gpui",
|
||||
"language",
|
||||
"language_model",
|
||||
"log",
|
||||
"menu",
|
||||
"picker",
|
||||
"prompt_store",
|
||||
"release_channel",
|
||||
"rope",
|
||||
"serde",
|
||||
"settings",
|
||||
"theme",
|
||||
"ui",
|
||||
"util",
|
||||
"workspace",
|
||||
"zed_actions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prompt_store"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"assets",
|
||||
"chrono",
|
||||
"collections",
|
||||
"editor",
|
||||
"fs",
|
||||
"futures 0.3.31",
|
||||
"fuzzy",
|
||||
@@ -10250,23 +10422,14 @@ dependencies = [
|
||||
"handlebars 4.5.0",
|
||||
"heed",
|
||||
"language",
|
||||
"language_model",
|
||||
"log",
|
||||
"menu",
|
||||
"parking_lot",
|
||||
"paths",
|
||||
"picker",
|
||||
"release_channel",
|
||||
"rope",
|
||||
"serde",
|
||||
"settings",
|
||||
"text",
|
||||
"theme",
|
||||
"ui",
|
||||
"util",
|
||||
"uuid",
|
||||
"workspace",
|
||||
"zed_actions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -11720,6 +11883,28 @@ version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152"
|
||||
|
||||
[[package]]
|
||||
name = "scripting_tool"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"assistant_tool",
|
||||
"collections",
|
||||
"gpui",
|
||||
"language",
|
||||
"mlua",
|
||||
"parking_lot",
|
||||
"regex",
|
||||
"rich_text",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"settings",
|
||||
"theme",
|
||||
"ui",
|
||||
"workspace",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scrypt"
|
||||
version = "0.11.0"
|
||||
@@ -11980,18 +12165,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.217"
|
||||
version = "1.0.218"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
|
||||
checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.217"
|
||||
version = "1.0.218"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
|
||||
checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -14504,7 +14689,7 @@ dependencies = [
|
||||
name = "ui_macros"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"convert_case 0.7.1",
|
||||
"convert_case 0.8.0",
|
||||
"linkme",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -14811,6 +14996,8 @@ dependencies = [
|
||||
"multi_buffer",
|
||||
"nvim-rs",
|
||||
"parking_lot",
|
||||
"picker",
|
||||
"project",
|
||||
"project_panel",
|
||||
"regex",
|
||||
"release_channel",
|
||||
@@ -15613,6 +15800,18 @@ dependencies = [
|
||||
"winsafe",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "7.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2774c861e1f072b3aadc02f8ba886c26ad6321567ecc294c935434cad06f1283"
|
||||
dependencies = [
|
||||
"either",
|
||||
"env_home",
|
||||
"rustix",
|
||||
"winsafe",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "whoami"
|
||||
version = "1.5.2"
|
||||
@@ -16667,7 +16866,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zed"
|
||||
version = "0.176.0"
|
||||
version = "0.178.0"
|
||||
dependencies = [
|
||||
"activity_indicator",
|
||||
"anyhow",
|
||||
@@ -16745,7 +16944,7 @@ dependencies = [
|
||||
"project",
|
||||
"project_panel",
|
||||
"project_symbols",
|
||||
"prompt_library",
|
||||
"prompt_store",
|
||||
"proto",
|
||||
"recent_projects",
|
||||
"release_channel",
|
||||
@@ -16753,6 +16952,7 @@ dependencies = [
|
||||
"repl",
|
||||
"reqwest_client",
|
||||
"rope",
|
||||
"scripting_tool",
|
||||
"search",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -16821,7 +17021,7 @@ dependencies = [
|
||||
name = "zed_elixir"
|
||||
version = "0.1.4"
|
||||
dependencies = [
|
||||
"zed_extension_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"zed_extension_api 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -16852,6 +17052,8 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "zed_extension_api"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fd16b8b30a9dc920fc1678ff852f696b5bdf5b5843bc745a128be0aac29859e"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -16860,9 +17062,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zed_extension_api"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fd16b8b30a9dc920fc1678ff852f696b5bdf5b5843bc745a128be0aac29859e"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -16885,7 +17085,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zed_html"
|
||||
version = "0.1.5"
|
||||
version = "0.1.6"
|
||||
dependencies = [
|
||||
"zed_extension_api 0.1.0",
|
||||
]
|
||||
@@ -16948,7 +17148,7 @@ dependencies = [
|
||||
name = "zed_test_extension"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"zed_extension_api 0.2.0",
|
||||
"zed_extension_api 0.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -17130,7 +17330,7 @@ dependencies = [
|
||||
"indoc",
|
||||
"inline_completion",
|
||||
"language",
|
||||
"language_models",
|
||||
"language_model",
|
||||
"log",
|
||||
"menu",
|
||||
"migrator",
|
||||
|
||||
31
Cargo.toml
31
Cargo.toml
@@ -15,6 +15,8 @@ members = [
|
||||
"crates/audio",
|
||||
"crates/auto_update",
|
||||
"crates/auto_update_ui",
|
||||
"crates/aws_http_client",
|
||||
"crates/bedrock",
|
||||
"crates/breadcrumbs",
|
||||
"crates/buffer_diff",
|
||||
"crates/call",
|
||||
@@ -101,6 +103,7 @@ members = [
|
||||
"crates/project_panel",
|
||||
"crates/project_symbols",
|
||||
"crates/prompt_library",
|
||||
"crates/prompt_store",
|
||||
"crates/proto",
|
||||
"crates/recent_projects",
|
||||
"crates/refineable",
|
||||
@@ -114,6 +117,7 @@ members = [
|
||||
"crates/rope",
|
||||
"crates/rpc",
|
||||
"crates/schema_generator",
|
||||
"crates/scripting_tool",
|
||||
"crates/search",
|
||||
"crates/semantic_index",
|
||||
"crates/semantic_version",
|
||||
@@ -218,6 +222,8 @@ assistant_tools = { path = "crates/assistant_tools" }
|
||||
audio = { path = "crates/audio" }
|
||||
auto_update = { path = "crates/auto_update" }
|
||||
auto_update_ui = { path = "crates/auto_update_ui" }
|
||||
aws_http_client = { path = "crates/aws_http_client" }
|
||||
bedrock = { path = "crates/bedrock" }
|
||||
breadcrumbs = { path = "crates/breadcrumbs" }
|
||||
call = { path = "crates/call" }
|
||||
channel = { path = "crates/channel" }
|
||||
@@ -304,6 +310,7 @@ project = { path = "crates/project" }
|
||||
project_panel = { path = "crates/project_panel" }
|
||||
project_symbols = { path = "crates/project_symbols" }
|
||||
prompt_library = { path = "crates/prompt_library" }
|
||||
prompt_store = { path = "crates/prompt_store" }
|
||||
proto = { path = "crates/proto" }
|
||||
recent_projects = { path = "crates/recent_projects" }
|
||||
refineable = { path = "crates/refineable" }
|
||||
@@ -315,6 +322,7 @@ reqwest_client = { path = "crates/reqwest_client" }
|
||||
rich_text = { path = "crates/rich_text" }
|
||||
rope = { path = "crates/rope" }
|
||||
rpc = { path = "crates/rpc" }
|
||||
scripting_tool = { path = "crates/scripting_tool" }
|
||||
search = { path = "crates/search" }
|
||||
semantic_index = { path = "crates/semantic_index" }
|
||||
semantic_version = { path = "crates/semantic_version" }
|
||||
@@ -366,7 +374,7 @@ zeta = { path = "crates/zeta" }
|
||||
#
|
||||
|
||||
aho-corasick = "1.1"
|
||||
alacritty_terminal = { git = "https://github.com/zed-industries/alacritty.git", rev = "03c2907b44b4189aac5fdeaea331f5aab5c7072e"}
|
||||
alacritty_terminal = { git = "https://github.com/zed-industries/alacritty.git", rev = "03c2907b44b4189aac5fdeaea331f5aab5c7072e" }
|
||||
any_vec = "0.14"
|
||||
anyhow = "1.0.86"
|
||||
arrayvec = { version = "0.7.4", features = ["serde"] }
|
||||
@@ -382,6 +390,11 @@ async-trait = "0.1"
|
||||
async-tungstenite = "0.28"
|
||||
async-watch = "0.3.1"
|
||||
async_zip = { version = "0.0.17", features = ["deflate", "deflate64"] }
|
||||
aws-config = { version = "1.5.16", features = ["behavior-version-latest"] }
|
||||
aws-credential-types = { version = "1.2.1", features = ["hardcoded-credentials"] }
|
||||
aws-sdk-bedrockruntime = { version = "1.73.0", features = ["behavior-version-latest"] }
|
||||
aws-smithy-runtime-api = { version = "1.7.3", features = ["http-1x", "client"] }
|
||||
aws-smithy-types = { version = "1.2.13", features = ["http-body-1-x"] }
|
||||
base64 = "0.22"
|
||||
bitflags = "2.6.0"
|
||||
blade-graphics = { git = "https://github.com/kvark/blade", rev = "b16f5c7bd873c7126f48c82c39e7ae64602ae74f" }
|
||||
@@ -396,10 +409,10 @@ chrono = { version = "0.4", features = ["serde"] }
|
||||
clap = { version = "4.4", features = ["derive"] }
|
||||
cocoa = "0.26"
|
||||
cocoa-foundation = "0.2.0"
|
||||
convert_case = "0.7.0"
|
||||
convert_case = "0.8.0"
|
||||
core-foundation = "0.9.3"
|
||||
core-foundation-sys = "0.8.6"
|
||||
ctor = "0.3.0"
|
||||
ctor = "0.4.0"
|
||||
dashmap = "6.0"
|
||||
derive_more = "0.99.17"
|
||||
dirs = "4.0"
|
||||
@@ -442,11 +455,11 @@ livekit = { git = "https://github.com/zed-industries/livekit-rust-sdks", rev = "
|
||||
], default-features = false }
|
||||
log = { version = "0.4.16", features = ["kv_unstable_serde", "serde"] }
|
||||
markup5ever_rcdom = "0.3.0"
|
||||
mlua = { version = "0.10", features = ["lua54", "vendored"] }
|
||||
nanoid = "0.4"
|
||||
nbformat = { version = "0.10.0" }
|
||||
nix = "0.29"
|
||||
num-format = "0.4.4"
|
||||
once_cell = "1.20"
|
||||
ordered-float = "2.1.1"
|
||||
palette = { version = "0.7.5", default-features = false, features = ["std"] }
|
||||
parking_lot = "0.12.1"
|
||||
@@ -535,7 +548,7 @@ tree-sitter-cpp = "0.23"
|
||||
tree-sitter-css = "0.23"
|
||||
tree-sitter-elixir = "0.3"
|
||||
tree-sitter-embedded-template = "0.23.0"
|
||||
tree-sitter-gitcommit = {git = "https://github.com/zed-industries/tree-sitter-git-commit", rev = "88309716a69dd13ab83443721ba6e0b491d37ee9"}
|
||||
tree-sitter-gitcommit = { git = "https://github.com/zed-industries/tree-sitter-git-commit", rev = "88309716a69dd13ab83443721ba6e0b491d37ee9" }
|
||||
tree-sitter-go = "0.23"
|
||||
tree-sitter-go-mod = { git = "https://github.com/camdencheek/tree-sitter-go-mod", rev = "6efb59652d30e0e9cd5f3b3a669afd6f1a926d3c", package = "tree-sitter-gomod" }
|
||||
tree-sitter-gowork = { git = "https://github.com/zed-industries/tree-sitter-go-work", rev = "acb0617bf7f4fda02c6217676cc64acb89536dc7" }
|
||||
@@ -610,6 +623,7 @@ features = [
|
||||
"Win32_Storage_FileSystem",
|
||||
"Win32_System_Com",
|
||||
"Win32_System_Com_StructuredStorage",
|
||||
"Win32_System_Console",
|
||||
"Win32_System_DataExchange",
|
||||
"Win32_System_LibraryLoader",
|
||||
"Win32_System_Memory",
|
||||
@@ -630,7 +644,7 @@ features = [
|
||||
# TODO livekit https://github.com/RustAudio/cpal/pull/891
|
||||
[patch.crates-io]
|
||||
cpal = { git = "https://github.com/zed-industries/cpal", rev = "fd8bc2fd39f1f5fdee5a0690656caff9a26d9d50" }
|
||||
real-async-tls = { git = "https://github.com/zed-industries/async-tls", rev = "1e759a4b5e370f87dc15e40756ac4f8815b61d9d", package = "async-tls"}
|
||||
real-async-tls = { git = "https://github.com/zed-industries/async-tls", rev = "1e759a4b5e370f87dc15e40756ac4f8815b61d9d", package = "async-tls" }
|
||||
|
||||
[profile.dev]
|
||||
split-debuginfo = "unpacked"
|
||||
@@ -700,6 +714,9 @@ debug = "full"
|
||||
lto = false
|
||||
codegen-units = 16
|
||||
|
||||
[workspace.lints.rust]
|
||||
unexpected_cfgs = { level = "allow" }
|
||||
|
||||
[workspace.lints.clippy]
|
||||
dbg_macro = "deny"
|
||||
todo = "deny"
|
||||
@@ -737,4 +754,4 @@ should_implement_trait = { level = "allow" }
|
||||
let_underscore_future = "allow"
|
||||
|
||||
[workspace.metadata.cargo-machete]
|
||||
ignored = ["bindgen", "cbindgen", "prost_build", "serde"]
|
||||
ignored = ["bindgen", "cbindgen", "prost_build", "serde", "component", "linkme"]
|
||||
|
||||
4
assets/icons/ai_bedrock.svg
Normal file
4
assets/icons/ai_bedrock.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="283.6413 127.3453 56 55.9999" width="16px" height="16px">
|
||||
<path d="M 808.592 158.131 C 807.489 158.131 806.592 157.234 806.592 156.131 C 806.592 155.028 807.489 154.131 808.592 154.131 C 809.695 154.131 810.592 155.028 810.592 156.131 C 810.592 157.234 809.695 158.131 808.592 158.131 Z M 776.705 185.039 L 773.457 183.145 L 780.122 178.979 L 779.062 177.283 L 771.505 182.006 L 765.592 178.557 L 765.592 169.666 L 771.147 165.963 L 770.037 164.299 L 764.551 167.956 L 758.592 164.551 L 758.592 159.711 L 765.088 155.999 L 764.096 154.263 L 758.592 157.408 L 758.592 153.711 L 764.592 150.283 L 770.592 153.711 L 770.592 157.565 L 766.077 160.274 L 767.107 161.988 L 771.592 159.297 L 776.077 161.988 L 777.107 160.274 L 772.592 157.565 L 772.592 153.666 L 778.147 149.963 C 778.425 149.777 778.592 149.465 778.592 149.131 L 778.592 142.131 L 776.592 142.131 L 776.592 148.596 L 771.551 151.956 L 765.592 148.551 L 765.592 139.705 L 770.592 136.789 L 770.592 145.131 L 772.592 145.131 L 772.592 135.622 L 776.705 133.223 L 784.592 135.852 L 784.592 164.565 L 770.077 173.274 L 771.107 174.988 L 784.592 166.897 L 784.592 182.41 L 776.705 185.039 Z M 806.592 169.131 C 806.592 170.234 805.695 171.131 804.592 171.131 C 803.489 171.131 802.592 170.234 802.592 169.131 C 802.592 168.028 803.489 167.131 804.592 167.131 C 805.695 167.131 806.592 168.028 806.592 169.131 Z M 796.592 179.131 C 796.592 180.234 795.695 181.131 794.592 181.131 C 793.489 181.131 792.592 180.234 792.592 179.131 C 792.592 178.028 793.489 177.131 794.592 177.131 C 795.695 177.131 796.592 178.028 796.592 179.131 Z M 795.592 139.131 C 795.592 138.028 796.489 137.131 797.592 137.131 C 798.695 137.131 799.592 138.028 799.592 139.131 C 799.592 140.234 798.695 141.131 797.592 141.131 C 796.489 141.131 795.592 140.234 795.592 139.131 Z M 808.592 152.131 C 806.733 152.131 805.181 153.411 804.734 155.131 L 786.592 155.131 L 786.592 150.131 L 797.592 150.131 C 798.145 150.131 798.592 149.683 798.592 149.131 L 798.592 142.989 C 800.312 142.542 801.592 140.989 801.592 139.131 C 801.592 136.925 799.798 135.131 797.592 135.131 C 795.386 135.131 793.592 136.925 793.592 139.131 C 793.592 140.989 794.872 142.542 796.592 142.989 L 796.592 148.131 L 786.592 148.131 L 786.592 135.131 C 786.592 134.7 786.317 134.319 785.908 134.182 L 776.908 131.182 C 776.634 131.092 776.336 131.122 776.088 131.267 L 764.088 138.267 C 763.78 138.446 763.592 138.776 763.592 139.131 L 763.592 148.551 L 757.096 152.263 C 756.784 152.441 756.592 152.772 756.592 153.131 L 756.592 165.131 C 756.592 165.49 756.784 165.821 757.096 165.999 L 763.592 169.711 L 763.592 179.131 C 763.592 179.486 763.78 179.816 764.088 179.995 L 776.088 186.995 C 776.242 187.085 776.417 187.131 776.592 187.131 C 776.698 187.131 776.805 187.114 776.908 187.08 L 785.908 184.08 C 786.317 183.943 786.592 183.562 786.592 183.131 L 786.592 171.131 L 793.592 171.131 L 793.592 175.273 C 791.872 175.72 790.592 177.273 790.592 179.131 C 790.592 181.337 792.386 183.131 794.592 183.131 C 796.798 183.131 798.592 181.337 798.592 179.131 C 798.592 177.273 797.312 175.72 795.592 175.273 L 795.592 170.131 C 795.592 169.579 795.145 169.131 794.592 169.131 L 786.592 169.131 L 786.592 164.131 L 799.092 164.131 L 801.23 166.981 C 800.831 167.603 800.592 168.338 800.592 169.131 C 800.592 171.337 802.386 173.131 804.592 173.131 C 806.798 173.131 808.592 171.337 808.592 169.131 C 808.592 166.925 806.798 165.131 804.592 165.131 C 803.908 165.131 803.274 165.319 802.711 165.623 L 800.392 162.531 C 800.203 162.279 799.906 162.131 799.592 162.131 L 786.592 162.131 L 786.592 157.131 L 804.734 157.131 C 805.181 158.851 806.733 160.131 808.592 160.131 C 810.798 160.131 812.592 158.337 812.592 156.131 C 812.592 153.925 810.798 152.131 808.592 152.131 Z" fill-rule="evenodd" fill-opacity="1" style="" id="object-0" transform="matrix(1, 0, 0, 1, -472.9506530761719, -3.7858259677886963)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
1
assets/icons/cloud.svg
Normal file
1
assets/icons/cloud.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-cloud"><path d="M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z"/></svg>
|
||||
|
After Width: | Height: | Size: 279 B |
6
assets/icons/git_branch_small.svg
Normal file
6
assets/icons/git_branch_small.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.75 3.25C4.02614 3.25 4.25 3.02614 4.25 2.75C4.25 2.47386 4.02614 2.25 3.75 2.25C3.47386 2.25 3.25 2.47386 3.25 2.75C3.25 3.02614 3.47386 3.25 3.75 3.25ZM3.75 4.25C4.57843 4.25 5.25 3.57843 5.25 2.75C5.25 1.92157 4.57843 1.25 3.75 1.25C2.92157 1.25 2.25 1.92157 2.25 2.75C2.25 3.57843 2.92157 4.25 3.75 4.25Z" fill="black"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.25 3.25C8.52614 3.25 8.75 3.02614 8.75 2.75C8.75 2.47386 8.52614 2.25 8.25 2.25C7.97386 2.25 7.75 2.47386 7.75 2.75C7.75 3.02614 7.97386 3.25 8.25 3.25ZM8.25 4.25C9.07843 4.25 9.75 3.57843 9.75 2.75C9.75 1.92157 9.07843 1.25 8.25 1.25C7.42157 1.25 6.75 1.92157 6.75 2.75C6.75 3.57843 7.42157 4.25 8.25 4.25Z" fill="black"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.75 9.75C4.02614 9.75 4.25 9.52614 4.25 9.25C4.25 8.97386 4.02614 8.75 3.75 8.75C3.47386 8.75 3.25 8.97386 3.25 9.25C3.25 9.52614 3.47386 9.75 3.75 9.75ZM3.75 10.75C4.57843 10.75 5.25 10.0784 5.25 9.25C5.25 8.42157 4.57843 7.75 3.75 7.75C2.92157 7.75 2.25 8.42157 2.25 9.25C2.25 10.0784 2.92157 10.75 3.75 10.75Z" fill="black"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.25 3.75H4.25V5.59609C4.67823 5.35824 5.24991 5.25 6 5.25H7.25017C7.5262 5.25 7.75 5.02625 7.75 4.75V3.75H8.75V4.75C8.75 5.57832 8.07871 6.25 7.25017 6.25H6C5.14559 6.25 4.77639 6.41132 4.59684 6.56615C4.42571 6.71373 4.33877 6.92604 4.25 7.30651V8.25H3.25V3.75Z" fill="black"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -1,12 +1,5 @@
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_2131_1193)">
|
||||
<circle cx="7" cy="7" r="6" stroke="black" stroke-width="1.5"/>
|
||||
<path d="M6 10H7M8 10H7M7 10V7.1C7 7.04477 6.95523 7 6.9 7H6" stroke="black" stroke-width="1.5" stroke-linecap="round"/>
|
||||
<circle cx="7" cy="4.5" r="1" fill="black"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_2131_1193">
|
||||
<rect width="14" height="14" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 14C11.3137 14 14 11.3137 14 8C14 4.68629 11.3137 2 8 2C4.68629 2 2 4.68629 2 8C2 11.3137 4.68629 14 8 14Z" stroke="black" stroke-width="1.5"/>
|
||||
<path d="M7 11H8M8 11H9M8 11V8.1C8 8.04477 7.95523 8 7.9 8H7" stroke="black" stroke-width="1.5" stroke-linecap="round"/>
|
||||
<path d="M8 6.5C8.55228 6.5 9 6.05228 9 5.5C9 4.94772 8.55228 4.5 8 4.5C7.44772 4.5 7 4.94772 7 5.5C7 6.05228 7.44772 6.5 8 6.5Z" fill="black"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 479 B After Width: | Height: | Size: 524 B |
4
assets/icons/zed_predict_error.svg
Normal file
4
assets/icons/zed_predict_error.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.6" d="M7.5 8.9V11C5.43097 11 4.56903 11 2.5 11V10.4L7.5 5.6V5H2.5V7.1" stroke="black" stroke-width="1.5"/>
|
||||
<path d="M14 8L10 12M14 12L10 8" stroke="black" stroke-width="1.5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 296 B |
@@ -10,8 +10,8 @@
|
||||
"pagedown": "menu::SelectLast",
|
||||
"ctrl-n": "menu::SelectNext",
|
||||
"tab": "menu::SelectNext",
|
||||
"ctrl-p": "menu::SelectPrev",
|
||||
"shift-tab": "menu::SelectPrev",
|
||||
"ctrl-p": "menu::SelectPrevious",
|
||||
"shift-tab": "menu::SelectPrevious",
|
||||
"enter": "menu::Confirm",
|
||||
"ctrl-enter": "menu::SecondaryConfirm",
|
||||
"ctrl-escape": "menu::Cancel",
|
||||
@@ -38,14 +38,14 @@
|
||||
{
|
||||
"context": "Picker || menu",
|
||||
"bindings": {
|
||||
"up": "menu::SelectPrev",
|
||||
"up": "menu::SelectPrevious",
|
||||
"down": "menu::SelectNext"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "Prompt",
|
||||
"bindings": {
|
||||
"left": "menu::SelectPrev",
|
||||
"left": "menu::SelectPrevious",
|
||||
"right": "menu::SelectNext"
|
||||
}
|
||||
},
|
||||
@@ -57,7 +57,7 @@
|
||||
"backspace": "editor::Backspace",
|
||||
"delete": "editor::Delete",
|
||||
"tab": "editor::Tab",
|
||||
"shift-tab": "editor::TabPrev",
|
||||
"shift-tab": "editor::Backtab",
|
||||
"ctrl-k": "editor::CutToEndOfLine",
|
||||
// "ctrl-t": "editor::Transpose",
|
||||
"ctrl-k ctrl-q": "editor::Rewrap",
|
||||
@@ -84,12 +84,12 @@
|
||||
"pageup": "editor::MovePageUp",
|
||||
"alt-pageup": "editor::PageUp",
|
||||
"shift-pageup": "editor::SelectPageUp",
|
||||
"home": "editor::MoveToBeginningOfLine",
|
||||
"home": ["editor::MoveToBeginningOfLine", { "stop_at_soft_wraps": true, "stop_at_indent": true }],
|
||||
"down": "editor::MoveDown",
|
||||
"pagedown": "editor::MovePageDown",
|
||||
"alt-pagedown": "editor::PageDown",
|
||||
"shift-pagedown": "editor::SelectPageDown",
|
||||
"end": "editor::MoveToEndOfLine",
|
||||
"end": ["editor::MoveToEndOfLine", { "stop_at_soft_wraps": true }],
|
||||
"left": "editor::MoveLeft",
|
||||
"right": "editor::MoveRight",
|
||||
"ctrl-left": "editor::MoveToPreviousWordStart",
|
||||
@@ -107,9 +107,9 @@
|
||||
"ctrl-a": "editor::SelectAll",
|
||||
"ctrl-l": "editor::SelectLine",
|
||||
"ctrl-shift-i": "editor::Format",
|
||||
// "cmd-shift-left": ["editor::SelectToBeginningOfLine", {"stop_at_soft_wraps": true }],
|
||||
// "ctrl-shift-a": ["editor::SelectToBeginningOfLine", { "stop_at_soft_wraps": true }],
|
||||
"shift-home": ["editor::SelectToBeginningOfLine", { "stop_at_soft_wraps": true }],
|
||||
// "cmd-shift-left": ["editor::SelectToBeginningOfLine", {"stop_at_soft_wraps": true, "stop_at_indent": true }],
|
||||
// "ctrl-shift-a": ["editor::SelectToBeginningOfLine", { "stop_at_soft_wraps": true, "stop_at_indent": true }],
|
||||
"shift-home": ["editor::SelectToBeginningOfLine", { "stop_at_soft_wraps": true, "stop_at_indent": true }],
|
||||
// "cmd-shift-right": ["editor::SelectToEndOfLine", { "stop_at_soft_wraps": true }],
|
||||
// "ctrl-shift-e": ["editor::SelectToEndOfLine", { "stop_at_soft_wraps": true }],
|
||||
"shift-end": ["editor::SelectToEndOfLine", { "stop_at_soft_wraps": true }],
|
||||
@@ -118,7 +118,7 @@
|
||||
"ctrl-;": "editor::ToggleLineNumbers",
|
||||
"ctrl-k ctrl-r": "git::Restore",
|
||||
"ctrl-'": "editor::ToggleSelectedDiffHunks",
|
||||
"ctrl-\"": "editor::ExpandAllHunkDiffs",
|
||||
"ctrl-\"": "editor::ExpandAllDiffHunks",
|
||||
"ctrl-i": "editor::ShowSignatureHelp",
|
||||
"alt-g b": "editor::ToggleGitBlame",
|
||||
"menu": "editor::OpenContextMenu",
|
||||
@@ -180,13 +180,13 @@
|
||||
"ctrl-k c": "assistant::CopyCode",
|
||||
"ctrl-shift-e": "project_panel::ToggleFocus",
|
||||
"ctrl-g": "search::SelectNextMatch",
|
||||
"ctrl-shift-g": "search::SelectPrevMatch",
|
||||
"ctrl-shift-g": "search::SelectPreviousMatch",
|
||||
"ctrl-alt-/": "assistant::ToggleModelSelector",
|
||||
"ctrl-k h": "assistant::DeployHistory",
|
||||
"ctrl-k l": "assistant::DeployPromptLibrary",
|
||||
"new": "assistant::NewContext",
|
||||
"ctrl-t": "assistant::NewContext",
|
||||
"ctrl-n": "assistant::NewContext"
|
||||
"new": "assistant::NewChat",
|
||||
"ctrl-t": "assistant::NewChat",
|
||||
"ctrl-n": "assistant::NewChat"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -203,7 +203,7 @@
|
||||
"escape": "buffer_search::Dismiss",
|
||||
"tab": "buffer_search::FocusEditor",
|
||||
"enter": "search::SelectNextMatch",
|
||||
"shift-enter": "search::SelectPrevMatch",
|
||||
"shift-enter": "search::SelectPreviousMatch",
|
||||
"alt-enter": "search::SelectAllMatches",
|
||||
"find": "search::FocusSearch",
|
||||
"ctrl-f": "search::FocusSearch",
|
||||
@@ -272,7 +272,7 @@
|
||||
"alt-8": ["pane::ActivateItem", 7],
|
||||
"alt-9": ["pane::ActivateItem", 8],
|
||||
"alt-0": "pane::ActivateLastItem",
|
||||
"ctrl-pageup": "pane::ActivatePrevItem",
|
||||
"ctrl-pageup": "pane::ActivatePreviousItem",
|
||||
"ctrl-pagedown": "pane::ActivateNextItem",
|
||||
"ctrl-shift-pageup": "pane::SwapItemLeft",
|
||||
"ctrl-shift-pagedown": "pane::SwapItemRight",
|
||||
@@ -290,8 +290,8 @@
|
||||
"forward": "pane::GoForward",
|
||||
"ctrl-alt-g": "search::SelectNextMatch",
|
||||
"f3": "search::SelectNextMatch",
|
||||
"ctrl-alt-shift-g": "search::SelectPrevMatch",
|
||||
"shift-f3": "search::SelectPrevMatch",
|
||||
"ctrl-alt-shift-g": "search::SelectPreviousMatch",
|
||||
"shift-f3": "search::SelectPreviousMatch",
|
||||
"shift-find": "project_search::ToggleFocus",
|
||||
"ctrl-shift-f": "project_search::ToggleFocus",
|
||||
"ctrl-alt-shift-h": "search::ToggleReplace",
|
||||
@@ -334,7 +334,7 @@
|
||||
"ctrl-u": "editor::UndoSelection",
|
||||
"ctrl-shift-u": "editor::RedoSelection",
|
||||
"f8": "editor::GoToDiagnostic",
|
||||
"shift-f8": "editor::GoToPrevDiagnostic",
|
||||
"shift-f8": "editor::GoToPreviousDiagnostic",
|
||||
"f2": "editor::Rename",
|
||||
"f12": "editor::GoToDefinition",
|
||||
"alt-f12": "editor::GoToDefinitionSplit",
|
||||
@@ -368,7 +368,12 @@
|
||||
"ctrl-\\": "pane::SplitRight",
|
||||
"ctrl-k v": "markdown::OpenPreviewToTheSide",
|
||||
"ctrl-shift-v": "markdown::OpenPreview",
|
||||
"ctrl-alt-shift-c": "editor::DisplayCursorNames"
|
||||
"ctrl-alt-shift-c": "editor::DisplayCursorNames",
|
||||
"ctrl-alt-y": "git::ToggleStaged",
|
||||
"alt-y": "git::StageAndNext",
|
||||
"alt-shift-y": "git::UnstageAndNext",
|
||||
"alt-.": "editor::GoToHunk",
|
||||
"alt-,": "editor::GoToPreviousHunk"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -531,8 +536,8 @@
|
||||
{
|
||||
"context": "Editor && (showing_code_actions || showing_completions)",
|
||||
"bindings": {
|
||||
"ctrl-p": "editor::ContextMenuPrev",
|
||||
"up": "editor::ContextMenuPrev",
|
||||
"ctrl-p": "editor::ContextMenuPrevious",
|
||||
"up": "editor::ContextMenuPrevious",
|
||||
"ctrl-n": "editor::ContextMenuNext",
|
||||
"down": "editor::ContextMenuNext",
|
||||
"pageup": "editor::ContextMenuFirst",
|
||||
@@ -560,7 +565,7 @@
|
||||
"ctrl-alt-enter": "editor::OpenExcerptsSplit",
|
||||
"ctrl-shift-e": "pane::RevealInProjectPanel",
|
||||
"ctrl-f8": "editor::GoToHunk",
|
||||
"ctrl-shift-f8": "editor::GoToPrevHunk",
|
||||
"ctrl-shift-f8": "editor::GoToPreviousHunk",
|
||||
"ctrl-enter": "assistant::InlineAssist",
|
||||
"ctrl-:": "editor::ToggleInlayHints"
|
||||
}
|
||||
@@ -601,18 +606,35 @@
|
||||
"ctrl-n": "assistant2::NewThread",
|
||||
"new": "assistant2::NewThread",
|
||||
"ctrl-shift-h": "assistant2::OpenHistory",
|
||||
"ctrl-alt-/": "assistant2::ToggleModelSelector",
|
||||
"ctrl-alt-/": "assistant::ToggleModelSelector",
|
||||
"ctrl-shift-a": "assistant2::ToggleContextPicker",
|
||||
"ctrl-e": "assistant2::ChatMode",
|
||||
"ctrl-alt-e": "assistant2::RemoveAllContext"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "AssistantPanel2 && prompt_editor",
|
||||
"use_key_equivalents": true,
|
||||
"bindings": {
|
||||
"cmd-n": "assistant2::NewPromptEditor",
|
||||
"cmd-alt-t": "assistant2::NewThread"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "MessageEditor > Editor",
|
||||
"bindings": {
|
||||
"enter": "assistant2::Chat"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "EditMessageEditor > Editor",
|
||||
"use_key_equivalents": true,
|
||||
"bindings": {
|
||||
"escape": "menu::Cancel",
|
||||
"enter": "menu::Confirm",
|
||||
"alt-enter": "editor::Newline"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "ContextStrip",
|
||||
"bindings": {
|
||||
@@ -657,7 +679,7 @@
|
||||
"alt-ctrl-r": "outline_panel::RevealInFileManager",
|
||||
"space": "outline_panel::Open",
|
||||
"shift-down": "menu::SelectNext",
|
||||
"shift-up": "menu::SelectPrev",
|
||||
"shift-up": "menu::SelectPrevious",
|
||||
"alt-enter": "editor::OpenExcerpts",
|
||||
"ctrl-alt-enter": "editor::OpenExcerptsSplit"
|
||||
}
|
||||
@@ -695,7 +717,7 @@
|
||||
"shift-find": "project_panel::NewSearchInDirectory",
|
||||
"ctrl-shift-f": "project_panel::NewSearchInDirectory",
|
||||
"shift-down": "menu::SelectNext",
|
||||
"shift-up": "menu::SelectPrev",
|
||||
"shift-up": "menu::SelectPrevious",
|
||||
"escape": "menu::Cancel"
|
||||
}
|
||||
},
|
||||
@@ -705,16 +727,10 @@
|
||||
"space": "project_panel::Open"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "GitPanel && !CommitEditor",
|
||||
"bindings": {
|
||||
"escape": "git_panel::Close"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "GitPanel && ChangesList",
|
||||
"bindings": {
|
||||
"up": "menu::SelectPrev",
|
||||
"up": "menu::SelectPrevious",
|
||||
"down": "menu::SelectNext",
|
||||
"enter": "menu::Confirm",
|
||||
"space": "git::ToggleStaged",
|
||||
@@ -722,16 +738,31 @@
|
||||
"ctrl-shift-space": "git::UnstageAll",
|
||||
"tab": "git_panel::FocusEditor",
|
||||
"shift-tab": "git_panel::FocusEditor",
|
||||
"escape": "git_panel::ToggleFocus"
|
||||
"escape": "git_panel::ToggleFocus",
|
||||
"ctrl-enter": "git::ShowCommitEditor",
|
||||
"alt-enter": "menu::SecondaryConfirm"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "GitCommit > Editor",
|
||||
"bindings": {
|
||||
"enter": "editor::Newline",
|
||||
"ctrl-enter": "git::Commit"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "GitDiff > Editor",
|
||||
"bindings": {
|
||||
"ctrl-enter": "git::ShowCommitEditor"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "GitPanel > Editor",
|
||||
"bindings": {
|
||||
"escape": "git_panel::FocusChanges",
|
||||
"ctrl-enter": "git::Commit",
|
||||
"tab": "git_panel::FocusChanges",
|
||||
"shift-tab": "git_panel::FocusChanges",
|
||||
"ctrl-enter": "git::Commit",
|
||||
"alt-up": "git_panel::FocusChanges"
|
||||
}
|
||||
},
|
||||
@@ -757,6 +788,9 @@
|
||||
{
|
||||
"context": "Picker > Editor",
|
||||
"bindings": {
|
||||
"escape": "menu::Cancel",
|
||||
"up": "menu::SelectPrevious",
|
||||
"down": "menu::SelectNext",
|
||||
"tab": "picker::ConfirmCompletion",
|
||||
"alt-enter": ["picker::ConfirmInput", { "secondary": false }]
|
||||
}
|
||||
@@ -770,7 +804,7 @@
|
||||
{
|
||||
"context": "FileFinder || (FileFinder > Picker > Editor) || (FileFinder > Picker > menu)",
|
||||
"bindings": {
|
||||
"ctrl-shift-p": "file_finder::SelectPrev",
|
||||
"ctrl-shift-p": "file_finder::SelectPrevious",
|
||||
"ctrl-j": "pane::SplitDown",
|
||||
"ctrl-k": "pane::SplitUp",
|
||||
"ctrl-h": "pane::SplitLeft",
|
||||
@@ -780,8 +814,8 @@
|
||||
{
|
||||
"context": "TabSwitcher",
|
||||
"bindings": {
|
||||
"ctrl-shift-tab": "menu::SelectPrev",
|
||||
"ctrl-up": "menu::SelectPrev",
|
||||
"ctrl-shift-tab": "menu::SelectPrevious",
|
||||
"ctrl-up": "menu::SelectPrevious",
|
||||
"ctrl-down": "menu::SelectNext",
|
||||
"ctrl-backspace": "tab_switcher::CloseSelectedItem"
|
||||
}
|
||||
@@ -813,6 +847,7 @@
|
||||
"pagedown": ["terminal::SendKeystroke", "pagedown"],
|
||||
"escape": ["terminal::SendKeystroke", "escape"],
|
||||
"enter": ["terminal::SendKeystroke", "enter"],
|
||||
"ctrl-b": ["terminal::SendKeystroke", "ctrl-b"],
|
||||
"ctrl-c": ["terminal::SendKeystroke", "ctrl-c"],
|
||||
"shift-pageup": "terminal::ScrollPageUp",
|
||||
"shift-pagedown": "terminal::ScrollPageDown",
|
||||
|
||||
@@ -1,4 +1,15 @@
|
||||
[
|
||||
// Moved before Standard macOS bindings so that `cmd-w` is not the last binding for
|
||||
// `workspace::CloseWindow` and displayed/intercepted by macOS
|
||||
{
|
||||
"context": "PromptLibrary",
|
||||
"use_key_equivalents": true,
|
||||
"bindings": {
|
||||
"cmd-n": "prompt_library::NewPrompt",
|
||||
"cmd-shift-s": "prompt_library::ToggleDefaultPrompt",
|
||||
"cmd-w": "workspace::CloseWindow"
|
||||
}
|
||||
},
|
||||
// Standard macOS bindings
|
||||
{
|
||||
"use_key_equivalents": true,
|
||||
@@ -14,19 +25,19 @@
|
||||
"tab": "menu::SelectNext",
|
||||
"ctrl-n": "menu::SelectNext",
|
||||
"down": "menu::SelectNext",
|
||||
"shift-tab": "menu::SelectPrev",
|
||||
"ctrl-p": "menu::SelectPrev",
|
||||
"up": "menu::SelectPrev",
|
||||
"shift-tab": "menu::SelectPrevious",
|
||||
"ctrl-p": "menu::SelectPrevious",
|
||||
"up": "menu::SelectPrevious",
|
||||
"enter": "menu::Confirm",
|
||||
"ctrl-enter": "menu::SecondaryConfirm",
|
||||
"cmd-enter": "menu::SecondaryConfirm",
|
||||
"ctrl-escape": "menu::Cancel",
|
||||
"cmd-escape": "menu::Cancel",
|
||||
"ctrl-c": "menu::Cancel",
|
||||
"escape": "menu::Cancel",
|
||||
"alt-shift-enter": "menu::Restart",
|
||||
"cmd-shift-w": "workspace::CloseWindow",
|
||||
"shift-escape": "workspace::ToggleZoom",
|
||||
"cmd-escape": "menu::Cancel",
|
||||
"cmd-o": "workspace::Open",
|
||||
"cmd-=": ["zed::IncreaseBufferFontSize", { "persist": false }],
|
||||
"cmd-+": ["zed::IncreaseBufferFontSize", { "persist": false }],
|
||||
@@ -54,7 +65,7 @@
|
||||
"ctrl-d": "editor::Delete",
|
||||
"delete": "editor::Delete",
|
||||
"tab": "editor::Tab",
|
||||
"shift-tab": "editor::TabPrev",
|
||||
"shift-tab": "editor::Backtab",
|
||||
"ctrl-t": "editor::Transpose",
|
||||
"ctrl-k": "editor::KillRingCut",
|
||||
"ctrl-y": "editor::KillRingYank",
|
||||
@@ -91,12 +102,12 @@
|
||||
"ctrl-l": "editor::ScrollCursorCenter",
|
||||
"alt-left": "editor::MoveToPreviousWordStart",
|
||||
"alt-right": "editor::MoveToNextWordEnd",
|
||||
"cmd-left": "editor::MoveToBeginningOfLine",
|
||||
"ctrl-a": "editor::MoveToBeginningOfLine",
|
||||
"home": "editor::MoveToBeginningOfLine",
|
||||
"cmd-right": "editor::MoveToEndOfLine",
|
||||
"ctrl-e": "editor::MoveToEndOfLine",
|
||||
"end": "editor::MoveToEndOfLine",
|
||||
"cmd-left": ["editor::MoveToBeginningOfLine", { "stop_at_soft_wraps": true, "stop_at_indent": true }],
|
||||
"ctrl-a": ["editor::MoveToBeginningOfLine", { "stop_at_soft_wraps": false, "stop_at_indent": true }],
|
||||
"home": ["editor::MoveToBeginningOfLine", { "stop_at_soft_wraps": true, "stop_at_indent": true }],
|
||||
"cmd-right": ["editor::MoveToEndOfLine", { "stop_at_soft_wraps": true }],
|
||||
"ctrl-e": ["editor::MoveToEndOfLine", { "stop_at_soft_wraps": false }],
|
||||
"end": ["editor::MoveToEndOfLine", { "stop_at_soft_wraps": true }],
|
||||
"cmd-up": "editor::MoveToStartOfExcerpt",
|
||||
"cmd-down": "editor::MoveToEndOfExcerpt",
|
||||
"cmd-home": "editor::MoveToBeginning", // Typed via `cmd-fn-left`
|
||||
@@ -118,9 +129,10 @@
|
||||
"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 }],
|
||||
"alt-shift-o": "editor::OrganizeImports",
|
||||
"cmd-shift-left": ["editor::SelectToBeginningOfLine", { "stop_at_soft_wraps": true, "stop_at_indent": true }],
|
||||
"shift-home": ["editor::SelectToBeginningOfLine", { "stop_at_soft_wraps": true, "stop_at_indent": true }],
|
||||
"ctrl-shift-a": ["editor::SelectToBeginningOfLine", { "stop_at_soft_wraps": true, "stop_at_indent": 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 }],
|
||||
@@ -133,7 +145,7 @@
|
||||
"cmd-y": "git::StageAndNext",
|
||||
"cmd-shift-y": "git::UnstageAndNext",
|
||||
"cmd-'": "editor::ToggleSelectedDiffHunks",
|
||||
"cmd-\"": "editor::ExpandAllHunkDiffs",
|
||||
"cmd-\"": "editor::ExpandAllDiffHunks",
|
||||
"cmd-alt-g b": "editor::ToggleGitBlame",
|
||||
"cmd-i": "editor::ShowSignatureHelp",
|
||||
"ctrl-f12": "editor::GoToDeclaration",
|
||||
@@ -207,12 +219,12 @@
|
||||
"cmd-k c": "assistant::CopyCode",
|
||||
"cmd-shift-e": "project_panel::ToggleFocus",
|
||||
"cmd-g": "search::SelectNextMatch",
|
||||
"cmd-shift-g": "search::SelectPrevMatch",
|
||||
"cmd-shift-g": "search::SelectPreviousMatch",
|
||||
"cmd-alt-/": "assistant::ToggleModelSelector",
|
||||
"cmd-k h": "assistant::DeployHistory",
|
||||
"cmd-k l": "assistant::DeployPromptLibrary",
|
||||
"cmd-t": "assistant::NewContext",
|
||||
"cmd-n": "assistant::NewContext"
|
||||
"cmd-t": "assistant::NewChat",
|
||||
"cmd-n": "assistant::NewChat"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -238,12 +250,20 @@
|
||||
"cmd-n": "assistant2::NewThread",
|
||||
"cmd-alt-p": "assistant2::NewPromptEditor",
|
||||
"cmd-shift-h": "assistant2::OpenHistory",
|
||||
"cmd-alt-/": "assistant2::ToggleModelSelector",
|
||||
"cmd-alt-/": "assistant::ToggleModelSelector",
|
||||
"cmd-shift-a": "assistant2::ToggleContextPicker",
|
||||
"cmd-e": "assistant2::ChatMode",
|
||||
"cmd-alt-e": "assistant2::RemoveAllContext"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "AssistantPanel2 && prompt_editor",
|
||||
"use_key_equivalents": true,
|
||||
"bindings": {
|
||||
"cmd-n": "assistant2::NewPromptEditor",
|
||||
"cmd-alt-t": "assistant2::NewThread"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "MessageEditor > Editor",
|
||||
"use_key_equivalents": true,
|
||||
@@ -251,6 +271,15 @@
|
||||
"enter": "assistant2::Chat"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "EditMessageEditor > Editor",
|
||||
"use_key_equivalents": true,
|
||||
"bindings": {
|
||||
"escape": "menu::Cancel",
|
||||
"enter": "menu::Confirm",
|
||||
"alt-enter": "editor::Newline"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "ContextStrip",
|
||||
"use_key_equivalents": true,
|
||||
@@ -269,15 +298,6 @@
|
||||
"backspace": "assistant2::RemoveSelectedThread"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "PromptLibrary",
|
||||
"use_key_equivalents": true,
|
||||
"bindings": {
|
||||
"cmd-n": "prompt_library::NewPrompt",
|
||||
"cmd-shift-s": "prompt_library::ToggleDefaultPrompt",
|
||||
"cmd-w": "workspace::CloseWindow"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "BufferSearchBar",
|
||||
"use_key_equivalents": true,
|
||||
@@ -285,7 +305,7 @@
|
||||
"escape": "buffer_search::Dismiss",
|
||||
"tab": "buffer_search::FocusEditor",
|
||||
"enter": "search::SelectNextMatch",
|
||||
"shift-enter": "search::SelectPrevMatch",
|
||||
"shift-enter": "search::SelectPreviousMatch",
|
||||
"alt-enter": "search::SelectAllMatches",
|
||||
"cmd-f": "search::FocusSearch",
|
||||
"cmd-alt-f": "search::ToggleReplace",
|
||||
@@ -352,8 +372,8 @@
|
||||
"context": "Pane",
|
||||
"use_key_equivalents": true,
|
||||
"bindings": {
|
||||
"alt-cmd-left": "pane::ActivatePrevItem",
|
||||
"cmd-{": "pane::ActivatePrevItem",
|
||||
"alt-cmd-left": "pane::ActivatePreviousItem",
|
||||
"cmd-{": "pane::ActivatePreviousItem",
|
||||
"alt-cmd-right": "pane::ActivateNextItem",
|
||||
"cmd-}": "pane::ActivateNextItem",
|
||||
"ctrl-shift-pageup": "pane::SwapItemLeft",
|
||||
@@ -367,7 +387,7 @@
|
||||
"cmd-k cmd-w": ["pane::CloseAllItems", { "close_pinned": false }],
|
||||
"cmd-f": "project_search::ToggleFocus",
|
||||
"cmd-g": "search::SelectNextMatch",
|
||||
"cmd-shift-g": "search::SelectPrevMatch",
|
||||
"cmd-shift-g": "search::SelectPreviousMatch",
|
||||
"cmd-shift-h": "search::ToggleReplace",
|
||||
"cmd-alt-l": "search::ToggleSelection",
|
||||
"alt-enter": "search::SelectAllMatches",
|
||||
@@ -407,7 +427,7 @@
|
||||
"cmd-u": "editor::UndoSelection",
|
||||
"cmd-shift-u": "editor::RedoSelection",
|
||||
"f8": "editor::GoToDiagnostic",
|
||||
"shift-f8": "editor::GoToPrevDiagnostic",
|
||||
"shift-f8": "editor::GoToPreviousDiagnostic",
|
||||
"f2": "editor::Rename",
|
||||
"f12": "editor::GoToDefinition",
|
||||
"alt-f12": "editor::GoToDefinitionSplit",
|
||||
@@ -613,8 +633,8 @@
|
||||
"context": "Editor && (showing_code_actions || showing_completions)",
|
||||
"use_key_equivalents": true,
|
||||
"bindings": {
|
||||
"up": "editor::ContextMenuPrev",
|
||||
"ctrl-p": "editor::ContextMenuPrev",
|
||||
"up": "editor::ContextMenuPrevious",
|
||||
"ctrl-p": "editor::ContextMenuPrevious",
|
||||
"down": "editor::ContextMenuNext",
|
||||
"ctrl-n": "editor::ContextMenuNext",
|
||||
"pageup": "editor::ContextMenuFirst",
|
||||
@@ -640,7 +660,7 @@
|
||||
"cmd-alt-enter": "editor::OpenExcerptsSplit",
|
||||
"cmd-shift-e": "pane::RevealInProjectPanel",
|
||||
"cmd-f8": "editor::GoToHunk",
|
||||
"cmd-shift-f8": "editor::GoToPrevHunk",
|
||||
"cmd-shift-f8": "editor::GoToPreviousHunk",
|
||||
"ctrl-enter": "assistant::InlineAssist",
|
||||
"ctrl-:": "editor::ToggleInlayHints"
|
||||
}
|
||||
@@ -658,7 +678,7 @@
|
||||
"use_key_equivalents": true,
|
||||
"bindings": {
|
||||
"cmd-shift-a": "assistant2::ToggleContextPicker",
|
||||
"cmd-alt-/": "assistant2::ToggleModelSelector",
|
||||
"cmd-alt-/": "assistant::ToggleModelSelector",
|
||||
"cmd-alt-e": "assistant2::RemoveAllContext",
|
||||
"ctrl-[": "assistant::CyclePreviousInlineAssist",
|
||||
"ctrl-]": "assistant::CycleNextInlineAssist"
|
||||
@@ -683,7 +703,7 @@
|
||||
"alt-cmd-r": "outline_panel::RevealInFileManager",
|
||||
"space": "outline_panel::Open",
|
||||
"shift-down": "menu::SelectNext",
|
||||
"shift-up": "menu::SelectPrev",
|
||||
"shift-up": "menu::SelectPrevious",
|
||||
"alt-enter": "editor::OpenExcerpts",
|
||||
"cmd-alt-enter": "editor::OpenExcerptsSplit"
|
||||
}
|
||||
@@ -713,7 +733,7 @@
|
||||
"cmd-alt-backspace": ["project_panel::Delete", { "skip_prompt": false }],
|
||||
"cmd-shift-f": "project_panel::NewSearchInDirectory",
|
||||
"shift-down": "menu::SelectNext",
|
||||
"shift-up": "menu::SelectPrev",
|
||||
"shift-up": "menu::SelectPrevious",
|
||||
"escape": "menu::Cancel"
|
||||
}
|
||||
},
|
||||
@@ -728,7 +748,7 @@
|
||||
"context": "GitPanel && ChangesList",
|
||||
"use_key_equivalents": true,
|
||||
"bindings": {
|
||||
"up": "menu::SelectPrev",
|
||||
"up": "menu::SelectPrevious",
|
||||
"down": "menu::SelectNext",
|
||||
"cmd-up": "menu::SelectFirst",
|
||||
"cmd-down": "menu::SelectLast",
|
||||
@@ -739,15 +759,15 @@
|
||||
"alt-down": "git_panel::FocusEditor",
|
||||
"tab": "git_panel::FocusEditor",
|
||||
"shift-tab": "git_panel::FocusEditor",
|
||||
"escape": "git_panel::ToggleFocus"
|
||||
"escape": "git_panel::ToggleFocus",
|
||||
"cmd-enter": "git::ShowCommitEditor"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "GitCommit > Editor",
|
||||
"context": "GitDiff > Editor",
|
||||
"use_key_equivalents": true,
|
||||
"bindings": {
|
||||
"enter": "editor::Newline",
|
||||
"cmd-enter": "git::Commit"
|
||||
"cmd-enter": "git::ShowCommitEditor"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -761,6 +781,14 @@
|
||||
"alt-up": "git_panel::FocusChanges"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "GitCommit > Editor",
|
||||
"use_key_equivalents": true,
|
||||
"bindings": {
|
||||
"enter": "editor::Newline",
|
||||
"cmd-enter": "git::Commit"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "CollabPanel && not_editing",
|
||||
"use_key_equivalents": true,
|
||||
@@ -787,6 +815,9 @@
|
||||
"context": "Picker > Editor",
|
||||
"use_key_equivalents": true,
|
||||
"bindings": {
|
||||
"escape": "menu::Cancel",
|
||||
"up": "menu::SelectPrevious",
|
||||
"down": "menu::SelectNext",
|
||||
"tab": "picker::ConfirmCompletion",
|
||||
"alt-enter": ["picker::ConfirmInput", { "secondary": false }],
|
||||
"cmd-alt-enter": ["picker::ConfirmInput", { "secondary": true }]
|
||||
@@ -803,7 +834,7 @@
|
||||
"context": "FileFinder || (FileFinder > Picker > Editor) || (FileFinder > Picker > menu)",
|
||||
"use_key_equivalents": true,
|
||||
"bindings": {
|
||||
"cmd-shift-p": "file_finder::SelectPrev",
|
||||
"cmd-shift-p": "file_finder::SelectPrevious",
|
||||
"cmd-j": "pane::SplitDown",
|
||||
"cmd-k": "pane::SplitUp",
|
||||
"cmd-h": "pane::SplitLeft",
|
||||
@@ -814,8 +845,8 @@
|
||||
"context": "TabSwitcher",
|
||||
"use_key_equivalents": true,
|
||||
"bindings": {
|
||||
"ctrl-shift-tab": "menu::SelectPrev",
|
||||
"ctrl-up": "menu::SelectPrev",
|
||||
"ctrl-shift-tab": "menu::SelectPrevious",
|
||||
"ctrl-up": "menu::SelectPrevious",
|
||||
"ctrl-down": "menu::SelectNext",
|
||||
"ctrl-backspace": "tab_switcher::CloseSelectedItem"
|
||||
}
|
||||
@@ -831,6 +862,7 @@
|
||||
"cmd-k": "terminal::Clear",
|
||||
"cmd-n": "workspace::NewTerminal",
|
||||
"ctrl-enter": "assistant::InlineAssist",
|
||||
"ctrl-_": null, // emacs undo
|
||||
// Some nice conveniences
|
||||
"cmd-backspace": ["terminal::SendText", "\u0015"],
|
||||
"cmd-right": ["terminal::SendText", "\u0005"],
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
"context": "BufferSearchBar",
|
||||
"bindings": {
|
||||
"ctrl-f3": "search::SelectNextMatch", // find-and-replace:find-next-selected
|
||||
"ctrl-shift-f3": "search::SelectPrevMatch" // find-and-replace:find-previous-selected
|
||||
"ctrl-shift-f3": "search::SelectPreviousMatch" // find-and-replace:find-previous-selected
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"ctrl-e": ["editor::MoveToEndOfLine", { "stop_at_soft_wraps": false }], // move-end-of-line
|
||||
"shift-home": ["editor::SelectToBeginningOfLine", { "stop_at_soft_wraps": false }], // move-beginning-of-line
|
||||
"shift-end": ["editor::SelectToEndOfLine", { "stop_at_soft_wraps": false }], // move-end-of-line
|
||||
"alt-m": ["editor::MoveToBeginningOfLine", { "stop_at_soft_wraps": false, "stop_at_indent": true }], // back-to-indentation
|
||||
"alt-f": "editor::MoveToNextSubwordEnd", // forward-word
|
||||
"alt-b": "editor::MoveToPreviousSubwordStart", // backward-word
|
||||
"alt-u": "editor::ConvertToUpperCase", // upcase-word
|
||||
@@ -48,6 +49,8 @@
|
||||
"ctrl-_": "editor::Undo", // undo
|
||||
"ctrl-/": "editor::Undo", // undo
|
||||
"ctrl-x u": "editor::Undo", // undo
|
||||
"alt-{": "editor::MoveToStartOfParagraph", // backward-paragraph
|
||||
"alt-}": "editor::MoveToEndOfParagraph", // forward-paragraph
|
||||
"ctrl-v": "editor::MovePageDown", // scroll-up
|
||||
"alt-v": "editor::MovePageUp", // scroll-down
|
||||
"ctrl-x [": "editor::MoveToBeginning", // beginning-of-buffer
|
||||
@@ -119,7 +122,7 @@
|
||||
"context": "BufferSearchBar > Editor",
|
||||
"bindings": {
|
||||
"ctrl-s": "search::SelectNextMatch",
|
||||
"ctrl-r": "search::SelectPrevMatch",
|
||||
"ctrl-r": "search::SelectPreviousMatch",
|
||||
"ctrl-g": "buffer_search::Dismiss"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"bindings": {
|
||||
"ctrl-alt-s": "zed::OpenSettings",
|
||||
"ctrl-{": "pane::ActivatePrevItem",
|
||||
"ctrl-{": "pane::ActivatePreviousItem",
|
||||
"ctrl-}": "pane::ActivateNextItem"
|
||||
}
|
||||
},
|
||||
@@ -41,9 +41,9 @@
|
||||
"ctrl-shift-b": "editor::GoToTypeDefinition",
|
||||
"ctrl-alt-shift-b": "editor::GoToTypeDefinitionSplit",
|
||||
"f2": "editor::GoToDiagnostic",
|
||||
"shift-f2": "editor::GoToPrevDiagnostic",
|
||||
"shift-f2": "editor::GoToPreviousDiagnostic",
|
||||
"ctrl-alt-shift-down": "editor::GoToHunk",
|
||||
"ctrl-alt-shift-up": "editor::GoToPrevHunk",
|
||||
"ctrl-alt-shift-up": "editor::GoToPreviousHunk",
|
||||
"ctrl-alt-z": "git::Restore",
|
||||
"ctrl-home": "editor::MoveToBeginning",
|
||||
"ctrl-end": "editor::MoveToEnd",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
[
|
||||
{
|
||||
"bindings": {
|
||||
"ctrl-{": "pane::ActivatePrevItem",
|
||||
"ctrl-{": "pane::ActivatePreviousItem",
|
||||
"ctrl-}": "pane::ActivateNextItem",
|
||||
"ctrl-pageup": "pane::ActivatePrevItem",
|
||||
"ctrl-pageup": "pane::ActivatePreviousItem",
|
||||
"ctrl-pagedown": "pane::ActivateNextItem",
|
||||
"ctrl-1": ["workspace::ActivatePane", 0],
|
||||
"ctrl-2": ["workspace::ActivatePane", 1],
|
||||
@@ -44,7 +44,7 @@
|
||||
"shift-f12": "editor::FindAllReferences",
|
||||
"ctrl-shift-f12": "editor::FindAllReferences",
|
||||
"ctrl-.": "editor::GoToHunk",
|
||||
"ctrl-,": "editor::GoToPrevHunk",
|
||||
"ctrl-,": "editor::GoToPreviousHunk",
|
||||
"ctrl-k ctrl-u": "editor::ConvertToUpperCase",
|
||||
"ctrl-k ctrl-l": "editor::ConvertToLowerCase",
|
||||
"shift-alt-m": "markdown::OpenPreviewToTheSide",
|
||||
@@ -62,7 +62,7 @@
|
||||
"context": "Pane",
|
||||
"bindings": {
|
||||
"f4": "search::SelectNextMatch",
|
||||
"shift-f4": "search::SelectPrevMatch",
|
||||
"shift-f4": "search::SelectPreviousMatch",
|
||||
"alt-1": ["pane::ActivateItem", 0],
|
||||
"alt-2": ["pane::ActivateItem", 1],
|
||||
"alt-3": ["pane::ActivateItem", 2],
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
"context": "BufferSearchBar",
|
||||
"bindings": {
|
||||
"cmd-f3": "search::SelectNextMatch",
|
||||
"cmd-shift-f3": "search::SelectPrevMatch"
|
||||
"cmd-shift-f3": "search::SelectPreviousMatch"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"ctrl-e": ["editor::MoveToEndOfLine", { "stop_at_soft_wraps": false }], // move-end-of-line
|
||||
"shift-home": ["editor::SelectToBeginningOfLine", { "stop_at_soft_wraps": false }], // move-beginning-of-line
|
||||
"shift-end": ["editor::SelectToEndOfLine", { "stop_at_soft_wraps": false }], // move-end-of-line
|
||||
"alt-m": ["editor::MoveToBeginningOfLine", { "stop_at_soft_wraps": false, "stop_at_indent": true }], // back-to-indentation
|
||||
"alt-f": "editor::MoveToNextSubwordEnd", // forward-word
|
||||
"alt-b": "editor::MoveToPreviousSubwordStart", // backward-word
|
||||
"alt-u": "editor::ConvertToUpperCase", // upcase-word
|
||||
@@ -48,6 +49,8 @@
|
||||
"ctrl-_": "editor::Undo", // undo
|
||||
"ctrl-/": "editor::Undo", // undo
|
||||
"ctrl-x u": "editor::Undo", // undo
|
||||
"alt-{": "editor::MoveToStartOfParagraph", // backward-paragraph
|
||||
"alt-}": "editor::MoveToEndOfParagraph", // forward-paragraph
|
||||
"ctrl-v": "editor::MovePageDown", // scroll-up
|
||||
"alt-v": "editor::MovePageUp", // scroll-down
|
||||
"ctrl-x [": "editor::MoveToBeginning", // beginning-of-buffer
|
||||
@@ -119,7 +122,7 @@
|
||||
"context": "BufferSearchBar > Editor",
|
||||
"bindings": {
|
||||
"ctrl-s": "search::SelectNextMatch",
|
||||
"ctrl-r": "search::SelectPrevMatch",
|
||||
"ctrl-r": "search::SelectPreviousMatch",
|
||||
"ctrl-g": "buffer_search::Dismiss"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[
|
||||
{
|
||||
"bindings": {
|
||||
"cmd-{": "pane::ActivatePrevItem",
|
||||
"cmd-{": "pane::ActivatePreviousItem",
|
||||
"cmd-}": "pane::ActivateNextItem"
|
||||
}
|
||||
},
|
||||
@@ -39,9 +39,9 @@
|
||||
"cmd-shift-b": "editor::GoToTypeDefinition",
|
||||
"cmd-alt-shift-b": "editor::GoToTypeDefinitionSplit",
|
||||
"f2": "editor::GoToDiagnostic",
|
||||
"shift-f2": "editor::GoToPrevDiagnostic",
|
||||
"shift-f2": "editor::GoToPreviousDiagnostic",
|
||||
"ctrl-alt-shift-down": "editor::GoToHunk",
|
||||
"ctrl-alt-shift-up": "editor::GoToPrevHunk",
|
||||
"ctrl-alt-shift-up": "editor::GoToPreviousHunk",
|
||||
"cmd-home": "editor::MoveToBeginning",
|
||||
"cmd-end": "editor::MoveToEnd",
|
||||
"cmd-shift-home": "editor::SelectToBeginning",
|
||||
@@ -61,7 +61,7 @@
|
||||
{
|
||||
"context": "BufferSearchBar > Editor",
|
||||
"bindings": {
|
||||
"shift-enter": "search::SelectPrevMatch"
|
||||
"shift-enter": "search::SelectPreviousMatch"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
[
|
||||
{
|
||||
"bindings": {
|
||||
"cmd-{": "pane::ActivatePrevItem",
|
||||
"cmd-{": "pane::ActivatePreviousItem",
|
||||
"cmd-}": "pane::ActivateNextItem",
|
||||
"ctrl-pageup": "pane::ActivatePrevItem",
|
||||
"ctrl-pageup": "pane::ActivatePreviousItem",
|
||||
"ctrl-pagedown": "pane::ActivateNextItem",
|
||||
"ctrl-1": ["workspace::ActivatePane", 0],
|
||||
"ctrl-2": ["workspace::ActivatePane", 1],
|
||||
@@ -45,7 +45,7 @@
|
||||
"ctrl-alt-cmd-down": "editor::GoToDefinitionSplit",
|
||||
"alt-shift-cmd-down": "editor::FindAllReferences",
|
||||
"ctrl-.": "editor::GoToHunk",
|
||||
"ctrl-,": "editor::GoToPrevHunk",
|
||||
"ctrl-,": "editor::GoToPreviousHunk",
|
||||
"cmd-k cmd-u": "editor::ConvertToUpperCase",
|
||||
"cmd-k cmd-l": "editor::ConvertToLowerCase",
|
||||
"cmd-shift-j": "editor::JoinLines",
|
||||
@@ -64,7 +64,7 @@
|
||||
"context": "Pane",
|
||||
"bindings": {
|
||||
"f4": "search::SelectNextMatch",
|
||||
"shift-f4": "search::SelectPrevMatch",
|
||||
"shift-f4": "search::SelectPreviousMatch",
|
||||
"cmd-1": ["pane::ActivateItem", 0],
|
||||
"cmd-2": ["pane::ActivateItem", 1],
|
||||
"cmd-3": ["pane::ActivateItem", 2],
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
"context": "BufferSearchBar",
|
||||
"bindings": {
|
||||
"ctrl-s": "search::SelectNextMatch",
|
||||
"ctrl-shift-s": "search::SelectPrevMatch"
|
||||
"ctrl-shift-s": "search::SelectPreviousMatch"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
"tab": "menu::SelectNext",
|
||||
"ctrl-n": "menu::SelectNext",
|
||||
"down": "menu::SelectNext",
|
||||
"shift-tab": "menu::SelectPrev",
|
||||
"ctrl-p": "menu::SelectPrev",
|
||||
"up": "menu::SelectPrev",
|
||||
"shift-tab": "menu::SelectPrevious",
|
||||
"ctrl-p": "menu::SelectPrevious",
|
||||
"up": "menu::SelectPrevious",
|
||||
"enter": "menu::Confirm",
|
||||
"ctrl-enter": "menu::SecondaryConfirm",
|
||||
"cmd-enter": "menu::SecondaryConfirm",
|
||||
|
||||
@@ -62,9 +62,9 @@
|
||||
"g /": "pane::DeploySearch",
|
||||
"?": ["vim::Search", { "backwards": true }],
|
||||
"*": "vim::MoveToNext",
|
||||
"#": "vim::MoveToPrev",
|
||||
"#": "vim::MoveToPrevious",
|
||||
"n": "vim::MoveToNextMatch",
|
||||
"shift-n": "vim::MoveToPrevMatch",
|
||||
"shift-n": "vim::MoveToPreviousMatch",
|
||||
"%": "vim::Matching",
|
||||
"] }": ["vim::UnmatchedForward", { "char": "}" }],
|
||||
"[ {": ["vim::UnmatchedBackward", { "char": "{" }],
|
||||
@@ -106,7 +106,7 @@
|
||||
"g g": "vim::StartOfDocument",
|
||||
"g h": "editor::Hover",
|
||||
"g t": "pane::ActivateNextItem",
|
||||
"g shift-t": "pane::ActivatePrevItem",
|
||||
"g shift-t": "pane::ActivatePreviousItem",
|
||||
"g d": "editor::GoToDefinition",
|
||||
"g shift-d": "editor::GoToDeclaration",
|
||||
"g y": "editor::GoToTypeDefinition",
|
||||
@@ -126,7 +126,7 @@
|
||||
"g shift-a": "editor::FindAllReferences", // zed specific
|
||||
"g space": "editor::OpenExcerpts", // zed specific
|
||||
"g *": ["vim::MoveToNext", { "partial_word": true }],
|
||||
"g #": ["vim::MoveToPrev", { "partial_word": true }],
|
||||
"g #": ["vim::MoveToPrevious", { "partial_word": true }],
|
||||
"g j": ["vim::Down", { "display_lines": true }],
|
||||
"g down": ["vim::Down", { "display_lines": true }],
|
||||
"g k": ["vim::Up", { "display_lines": true }],
|
||||
@@ -138,7 +138,7 @@
|
||||
"g ^": ["vim::FirstNonWhitespace", { "display_lines": true }],
|
||||
"g v": "vim::RestoreVisualSelection",
|
||||
"g ]": "editor::GoToDiagnostic",
|
||||
"g [": "editor::GoToPrevDiagnostic",
|
||||
"g [": "editor::GoToPreviousDiagnostic",
|
||||
"g i": "vim::InsertAtPrevious",
|
||||
"g ,": "vim::ChangeListNewer",
|
||||
"g ;": "vim::ChangeListOlder",
|
||||
@@ -231,15 +231,15 @@
|
||||
"g w": "vim::PushRewrap",
|
||||
"g q": "vim::PushRewrap",
|
||||
"ctrl-pagedown": "pane::ActivateNextItem",
|
||||
"ctrl-pageup": "pane::ActivatePrevItem",
|
||||
"ctrl-pageup": "pane::ActivatePreviousItem",
|
||||
"insert": "vim::InsertBefore",
|
||||
// tree-sitter related commands
|
||||
"[ x": "vim::SelectLargerSyntaxNode",
|
||||
"] x": "vim::SelectSmallerSyntaxNode",
|
||||
"] d": "editor::GoToDiagnostic",
|
||||
"[ d": "editor::GoToPrevDiagnostic",
|
||||
"[ d": "editor::GoToPreviousDiagnostic",
|
||||
"] c": "editor::GoToHunk",
|
||||
"[ c": "editor::GoToPrevHunk",
|
||||
"[ c": "editor::GoToPreviousHunk",
|
||||
"g c": "vim::PushToggleComments"
|
||||
}
|
||||
},
|
||||
@@ -272,7 +272,7 @@
|
||||
"shift-s": "vim::SubstituteLine",
|
||||
"~": "vim::ChangeCase",
|
||||
"*": ["vim::MoveToNext", { "partial_word": true }],
|
||||
"#": ["vim::MoveToPrev", { "partial_word": true }],
|
||||
"#": ["vim::MoveToPrevious", { "partial_word": true }],
|
||||
"ctrl-a": "vim::Increment",
|
||||
"ctrl-x": "vim::Decrement",
|
||||
"g ctrl-a": ["vim::Increment", { "step": true }],
|
||||
@@ -437,6 +437,7 @@
|
||||
"context": "vim_operator == c",
|
||||
"bindings": {
|
||||
"c": "vim::CurrentLine",
|
||||
"x": "vim::Exchange",
|
||||
"d": "editor::Rename", // zed specific
|
||||
"s": ["vim::PushChangeSurrounds", {}]
|
||||
}
|
||||
@@ -447,7 +448,10 @@
|
||||
"d": "vim::CurrentLine",
|
||||
"s": "vim::PushDeleteSurrounds",
|
||||
"o": "editor::ToggleSelectedDiffHunks", // "d o"
|
||||
"p": "git::Restore" // "d p"
|
||||
"shift-o": "git::ToggleStaged",
|
||||
"p": "git::Restore", // "d p"
|
||||
"u": "git::StageAndNext", // "d u"
|
||||
"shift-u": "git::UnstageAndNext" // "d shift-u"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -523,6 +527,19 @@
|
||||
"c": "vim::CurrentLine"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "vim_operator == gr",
|
||||
"bindings": {
|
||||
"r": "vim::CurrentLine"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "vim_operator == cx",
|
||||
"bindings": {
|
||||
"x": "vim::CurrentLine",
|
||||
"c": "vim::ClearExchange"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "vim_mode == literal",
|
||||
"bindings": {
|
||||
@@ -606,8 +623,8 @@
|
||||
"ctrl-w =": "vim::ResetPaneSizes",
|
||||
"ctrl-w g t": "pane::ActivateNextItem",
|
||||
"ctrl-w ctrl-g t": "pane::ActivateNextItem",
|
||||
"ctrl-w g shift-t": "pane::ActivatePrevItem",
|
||||
"ctrl-w ctrl-g shift-t": "pane::ActivatePrevItem",
|
||||
"ctrl-w g shift-t": "pane::ActivatePreviousItem",
|
||||
"ctrl-w ctrl-g shift-t": "pane::ActivatePreviousItem",
|
||||
"ctrl-w w": "workspace::ActivateNextPane",
|
||||
"ctrl-w ctrl-w": "workspace::ActivateNextPane",
|
||||
"ctrl-w p": "workspace::ActivatePreviousPane",
|
||||
@@ -650,7 +667,7 @@
|
||||
"escape": "project_panel::ToggleFocus",
|
||||
"h": "project_panel::CollapseSelectedEntry",
|
||||
"j": "menu::SelectNext",
|
||||
"k": "menu::SelectPrev",
|
||||
"k": "menu::SelectPrevious",
|
||||
"l": "project_panel::ExpandSelectedEntry",
|
||||
"o": "project_panel::OpenPermanent",
|
||||
"shift-d": "project_panel::Delete",
|
||||
@@ -676,7 +693,7 @@
|
||||
"context": "OutlinePanel && not_editing",
|
||||
"bindings": {
|
||||
"j": "menu::SelectNext",
|
||||
"k": "menu::SelectPrev",
|
||||
"k": "menu::SelectPrevious",
|
||||
"shift-g": "menu::SelectLast",
|
||||
"g g": "menu::SelectFirst"
|
||||
}
|
||||
@@ -685,7 +702,7 @@
|
||||
"context": "GitPanel && ChangesList",
|
||||
"use_key_equivalents": true,
|
||||
"bindings": {
|
||||
"k": "menu::SelectPrev",
|
||||
"k": "menu::SelectPrevious",
|
||||
"j": "menu::SelectNext",
|
||||
"g g": "menu::SelectFirst",
|
||||
"shift-g": "menu::SelectLast",
|
||||
|
||||
@@ -150,8 +150,6 @@
|
||||
//
|
||||
// Default: not set, defaults to "bar"
|
||||
"cursor_shape": null,
|
||||
// Determines whether the mouse cursor is hidden when typing in an editor or input box.
|
||||
"hide_mouse_while_typing": true,
|
||||
// How to highlight the current line in the editor.
|
||||
//
|
||||
// 1. Don't highlight the current line:
|
||||
@@ -178,8 +176,8 @@
|
||||
"show_completion_documentation": true,
|
||||
// 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.
|
||||
// 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": false,
|
||||
// Whether to show wrap guides (vertical rulers) in the editor.
|
||||
// Setting this to true will show a guide at the 'preferred_line_length' value
|
||||
@@ -300,11 +298,11 @@
|
||||
// - "information": show only errors, warnings, and information
|
||||
// - "all" or true: show all diagnostics
|
||||
"diagnostics": "all",
|
||||
/// Forcefully enable or disable the scrollbar for each axis
|
||||
// Forcefully enable or disable the scrollbar for each axis
|
||||
"axes": {
|
||||
/// When false, forcefully disables the horizontal scrollbar. Otherwise, obey other settings.
|
||||
// When false, forcefully disables the horizontal scrollbar. Otherwise, obey other settings.
|
||||
"horizontal": true,
|
||||
/// When false, forcefully disables the vertical scrollbar. Otherwise, obey other settings.
|
||||
// When false, forcefully disables the vertical scrollbar. Otherwise, obey other settings.
|
||||
"vertical": true
|
||||
}
|
||||
},
|
||||
@@ -330,24 +328,24 @@
|
||||
"folds": true
|
||||
},
|
||||
"indent_guides": {
|
||||
/// Whether to show indent guides in the editor.
|
||||
// Whether to show indent guides in the editor.
|
||||
"enabled": true,
|
||||
/// The width of the indent guides in pixels, between 1 and 10.
|
||||
// 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.
|
||||
// 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:
|
||||
// Determines how indent guides are colored.
|
||||
// This setting can take the following three values:
|
||||
///
|
||||
/// 1. "disabled"
|
||||
/// 2. "fixed"
|
||||
/// 3. "indent_aware"
|
||||
// 1. "disabled"
|
||||
// 2. "fixed"
|
||||
// 3. "indent_aware"
|
||||
"coloring": "fixed",
|
||||
/// Determines how indent guide backgrounds are colored.
|
||||
/// This setting can take the following two values:
|
||||
// Determines how indent guide backgrounds are colored.
|
||||
// This setting can take the following two values:
|
||||
///
|
||||
/// 1. "disabled"
|
||||
/// 2. "indent_aware"
|
||||
// 1. "disabled"
|
||||
// 2. "indent_aware"
|
||||
"background_coloring": "disabled"
|
||||
},
|
||||
// Whether the editor will scroll beyond the last line.
|
||||
@@ -381,6 +379,9 @@
|
||||
// 3. Never populate the search query
|
||||
// "never"
|
||||
"seed_search_query_from_cursor": "always",
|
||||
// When enabled, automatically adjusts search case sensitivity based on your query.
|
||||
// If your search query contains any uppercase letters, the search becomes case-sensitive;
|
||||
// if it contains only lowercase letters, the search becomes case-insensitive.
|
||||
"use_smartcase_search": false,
|
||||
// Inlay hint related settings
|
||||
"inlay_hints": {
|
||||
@@ -400,7 +401,16 @@
|
||||
"edit_debounce_ms": 700,
|
||||
// Time to wait after scrolling the buffer, before requesting the hints,
|
||||
// set to 0 to disable debouncing.
|
||||
"scroll_debounce_ms": 50
|
||||
"scroll_debounce_ms": 50,
|
||||
/// A set of modifiers which, when pressed, will toggle the visibility of inlay hints.
|
||||
/// If the set if empty or not all the modifiers specified are pressed, inlay hints will not be toggled.
|
||||
"toggle_on_modifiers_press": {
|
||||
"control": false,
|
||||
"shift": false,
|
||||
"alt": false,
|
||||
"platform": false,
|
||||
"function": false
|
||||
}
|
||||
},
|
||||
"project_panel": {
|
||||
// Whether to show the project panel button in the status bar
|
||||
@@ -426,32 +436,32 @@
|
||||
// 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": true,
|
||||
/// Scrollbar-related settings
|
||||
// Scrollbar-related settings
|
||||
"scrollbar": {
|
||||
/// When to show the scrollbar in the project panel.
|
||||
/// This setting can take five values:
|
||||
// When to show the scrollbar in the project panel.
|
||||
// This setting can take five values:
|
||||
///
|
||||
/// 1. null (default): Inherit editor settings
|
||||
/// 2. Show the scrollbar if there's important information or
|
||||
/// follow the system's configured behavior (default):
|
||||
/// "auto"
|
||||
/// 3. Match the system's configured behavior:
|
||||
/// "system"
|
||||
/// 4. Always show the scrollbar:
|
||||
/// "always"
|
||||
/// 5. Never show the scrollbar:
|
||||
/// "never"
|
||||
// 1. null (default): Inherit editor settings
|
||||
// 2. Show the scrollbar if there's important information or
|
||||
// follow the system's configured behavior (default):
|
||||
// "auto"
|
||||
// 3. Match the system's configured behavior:
|
||||
// "system"
|
||||
// 4. Always show the scrollbar:
|
||||
// "always"
|
||||
// 5. Never show the scrollbar:
|
||||
// "never"
|
||||
"show": null
|
||||
},
|
||||
/// Which files containing diagnostic errors/warnings to mark in the project panel.
|
||||
/// This setting can take the following three values:
|
||||
// Which files containing diagnostic errors/warnings to mark in the project panel.
|
||||
// This setting can take the following three values:
|
||||
///
|
||||
/// 1. Do not mark any files:
|
||||
/// "off"
|
||||
/// 2. Only mark files with errors:
|
||||
/// "errors"
|
||||
/// 3. Mark files with errors and warnings:
|
||||
/// "all"
|
||||
// 1. Do not mark any files:
|
||||
// "off"
|
||||
// 2. Only mark files with errors:
|
||||
// "errors"
|
||||
// 3. Mark files with errors and warnings:
|
||||
// "all"
|
||||
"show_diagnostics": "all",
|
||||
// Settings related to indent guides in the project panel.
|
||||
"indent_guides": {
|
||||
@@ -484,8 +494,8 @@
|
||||
// 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.
|
||||
// Whether to fold directories automatically
|
||||
// when a directory has only one directory inside.
|
||||
"auto_fold_dirs": true,
|
||||
// Settings related to indent guides in the outline panel.
|
||||
"indent_guides": {
|
||||
@@ -498,21 +508,21 @@
|
||||
// "never"
|
||||
"show": "always"
|
||||
},
|
||||
/// Scrollbar-related settings
|
||||
// Scrollbar-related settings
|
||||
"scrollbar": {
|
||||
/// When to show the scrollbar in the project panel.
|
||||
/// This setting can take five values:
|
||||
// When to show the scrollbar in the project panel.
|
||||
// This setting can take five values:
|
||||
///
|
||||
/// 1. null (default): Inherit editor settings
|
||||
/// 2. Show the scrollbar if there's important information or
|
||||
/// follow the system's configured behavior (default):
|
||||
/// "auto"
|
||||
/// 3. Match the system's configured behavior:
|
||||
/// "system"
|
||||
/// 4. Always show the scrollbar:
|
||||
/// "always"
|
||||
/// 5. Never show the scrollbar:
|
||||
/// "never"
|
||||
// 1. null (default): Inherit editor settings
|
||||
// 2. Show the scrollbar if there's important information or
|
||||
// follow the system's configured behavior (default):
|
||||
// "auto"
|
||||
// 3. Match the system's configured behavior:
|
||||
// "system"
|
||||
// 4. Always show the scrollbar:
|
||||
// "always"
|
||||
// 5. Never show the scrollbar:
|
||||
// "never"
|
||||
"show": null
|
||||
}
|
||||
},
|
||||
@@ -583,7 +593,7 @@
|
||||
// The provider to use.
|
||||
"provider": "zed.dev",
|
||||
// The model to use.
|
||||
"model": "claude-3-5-sonnet"
|
||||
"model": "claude-3-5-sonnet-latest"
|
||||
}
|
||||
},
|
||||
// The settings for slash commands.
|
||||
@@ -630,7 +640,7 @@
|
||||
"show": true,
|
||||
// Whether or not to show the navigation history buttons.
|
||||
"show_nav_history_buttons": true,
|
||||
/// Whether or not to show the tab bar buttons.
|
||||
// Whether or not to show the tab bar buttons.
|
||||
"show_tab_bar_buttons": true
|
||||
},
|
||||
// Settings related to the editor's tabs
|
||||
@@ -638,11 +648,19 @@
|
||||
// Show git status colors in the editor tabs.
|
||||
"git_status": false,
|
||||
// Position of the close button on the editor tabs.
|
||||
// One of: ["right", "left", "hidden"]
|
||||
"close_position": "right",
|
||||
// Whether to show the file icon for a tab.
|
||||
"file_icons": false,
|
||||
// Whether to always show the close button on tabs.
|
||||
"always_show_close_button": false,
|
||||
// Controls the appearance behavior of the tab's close button.
|
||||
//
|
||||
// 1. Show it just upon hovering the tab. (default)
|
||||
// "hover"
|
||||
// 2. Show it persistently.
|
||||
// "always"
|
||||
// 3. Never show it, even if hovering it.
|
||||
// "hidden"
|
||||
"show_close_button": "hover",
|
||||
// What to do after closing the current tab.
|
||||
//
|
||||
// 1. Activate the tab that was open previously (default)
|
||||
@@ -652,16 +670,16 @@
|
||||
// 3. Activate the left neighbour tab if present
|
||||
// "left_neighbour"
|
||||
"activate_on_close": "history",
|
||||
/// Which files containing diagnostic errors/warnings to mark in the tabs.
|
||||
/// Diagnostics are only shown when file icons are also active.
|
||||
/// This setting only works when can take the following three values:
|
||||
// Which files containing diagnostic errors/warnings to mark in the tabs.
|
||||
// Diagnostics are only shown when file icons are also active.
|
||||
// This setting only works when can take the following three values:
|
||||
///
|
||||
/// 1. Do not mark any files:
|
||||
/// "off"
|
||||
/// 2. Only mark files with errors:
|
||||
/// "errors"
|
||||
/// 3. Mark files with errors and warnings:
|
||||
/// "all"
|
||||
// 1. Do not mark any files:
|
||||
// "off"
|
||||
// 2. Only mark files with errors:
|
||||
// "errors"
|
||||
// 3. Mark files with errors and warnings:
|
||||
// "all"
|
||||
"show_diagnostics": "off"
|
||||
},
|
||||
// Settings related to preview tabs.
|
||||
@@ -819,7 +837,15 @@
|
||||
//
|
||||
// The minimum column number to show the inline blame information at
|
||||
// "min_column": 0
|
||||
}
|
||||
},
|
||||
// How git hunks are displayed visually in the editor.
|
||||
// This setting can take two values:
|
||||
//
|
||||
// 1. Show unstaged hunks with a transparent background (default):
|
||||
// "hunk_style": "transparent"
|
||||
// 2. Show unstaged hunks with a pattern background:
|
||||
// "hunk_style": "pattern"
|
||||
"hunk_style": "transparent"
|
||||
},
|
||||
// Configuration for how direnv configuration should be loaded. May take 2 values:
|
||||
// 1. Load direnv configuration using `direnv export json` directly.
|
||||
@@ -831,22 +857,19 @@
|
||||
// A list of globs representing files that edit predictions should be disabled for.
|
||||
// There's a sensible default list of globs already included.
|
||||
// Any addition to this list will be merged with the default list.
|
||||
"disabled_globs": [
|
||||
"**/.env*",
|
||||
"**/*.pem",
|
||||
"**/*.key",
|
||||
"**/*.cert",
|
||||
"**/*.crt",
|
||||
"**/.dev.vars",
|
||||
"**/secrets.yml"
|
||||
],
|
||||
// Globs are matched relative to the worktree root,
|
||||
// except when starting with a slash (/) or equivalent in Windows.
|
||||
"disabled_globs": ["**/.env*", "**/*.pem", "**/*.key", "**/*.cert", "**/*.crt", "**/.dev.vars", "**/secrets.yml"],
|
||||
// When to show edit predictions previews in buffer.
|
||||
// This setting takes two possible values:
|
||||
// 1. Display inline when there are no language server completions available.
|
||||
// "mode": "eager_preview"
|
||||
// 2. Display inline when holding modifier key (alt by default).
|
||||
// "mode": "auto"
|
||||
"mode": "eager_preview"
|
||||
// 1. Display predictions inline when there are no language server completions available.
|
||||
// "mode": "eager"
|
||||
// 2. Display predictions inline only when holding a modifier key (alt by default).
|
||||
// "mode": "subtle"
|
||||
"mode": "eager",
|
||||
// Whether edit predictions are enabled in the assistant panel.
|
||||
// This setting has no effect if globally disabled.
|
||||
"enabled_in_assistant": true
|
||||
},
|
||||
// Settings specific to journaling
|
||||
"journal": {
|
||||
@@ -982,21 +1005,21 @@
|
||||
// Example: `echo -e "\e]2;New Title\007";`
|
||||
"breadcrumbs": true
|
||||
},
|
||||
/// Scrollbar-related settings
|
||||
// Scrollbar-related settings
|
||||
"scrollbar": {
|
||||
/// When to show the scrollbar in the terminal.
|
||||
/// This setting can take five values:
|
||||
// When to show the scrollbar in the terminal.
|
||||
// This setting can take five values:
|
||||
///
|
||||
/// 1. null (default): Inherit editor settings
|
||||
/// 2. Show the scrollbar if there's important information or
|
||||
/// follow the system's configured behavior (default):
|
||||
/// "auto"
|
||||
/// 3. Match the system's configured behavior:
|
||||
/// "system"
|
||||
/// 4. Always show the scrollbar:
|
||||
/// "always"
|
||||
/// 5. Never show the scrollbar:
|
||||
/// "never"
|
||||
// 1. null (default): Inherit editor settings
|
||||
// 2. Show the scrollbar if there's important information or
|
||||
// follow the system's configured behavior (default):
|
||||
// "auto"
|
||||
// 3. Match the system's configured behavior:
|
||||
// "system"
|
||||
// 4. Always show the scrollbar:
|
||||
// "always"
|
||||
// 5. Never show the scrollbar:
|
||||
// "never"
|
||||
"show": null
|
||||
}
|
||||
// Set the terminal's font size. If this option is not included,
|
||||
@@ -1015,7 +1038,7 @@
|
||||
// "max_scroll_history_lines": 10000,
|
||||
},
|
||||
"code_actions_on_format": {},
|
||||
/// Settings related to running tasks.
|
||||
// Settings related to running tasks.
|
||||
"tasks": {
|
||||
"variables": {}
|
||||
},
|
||||
@@ -1036,20 +1059,20 @@
|
||||
"JSONC": ["**/.zed/**/*.json", "**/zed/**/*.json", "**/Zed/**/*.json", "**/.vscode/**/*.json"],
|
||||
"Shell Script": [".env.*"]
|
||||
},
|
||||
/// By default use a recent system version of node, or install our own.
|
||||
/// You can override this to use a version of node that is not in $PATH with:
|
||||
/// {
|
||||
/// "node": {
|
||||
/// "path": "/path/to/node"
|
||||
/// "npm_path": "/path/to/npm" (defaults to node_path/../npm)
|
||||
/// }
|
||||
/// }
|
||||
/// or to ensure Zed always downloads and installs an isolated version of node:
|
||||
/// {
|
||||
/// "node": {
|
||||
/// "ignore_system_version": true,
|
||||
/// }
|
||||
/// NOTE: changing this setting currently requires restarting Zed.
|
||||
// By default use a recent system version of node, or install our own.
|
||||
// You can override this to use a version of node that is not in $PATH with:
|
||||
// {
|
||||
// "node": {
|
||||
// "path": "/path/to/node"
|
||||
// "npm_path": "/path/to/npm" (defaults to node_path/../npm)
|
||||
// }
|
||||
// }
|
||||
// or to ensure Zed always downloads and installs an isolated version of node:
|
||||
// {
|
||||
// "node": {
|
||||
// "ignore_system_version": true,
|
||||
// }
|
||||
// NOTE: changing this setting currently requires restarting Zed.
|
||||
"node": {},
|
||||
// The extensions that Zed should automatically install on startup.
|
||||
//
|
||||
@@ -1095,6 +1118,7 @@
|
||||
"tab_size": 2
|
||||
},
|
||||
"Diff": {
|
||||
"show_edit_predictions": false,
|
||||
"remove_trailing_whitespace_on_save": false,
|
||||
"ensure_final_newline_on_save": false
|
||||
},
|
||||
@@ -1297,6 +1321,7 @@
|
||||
},
|
||||
// Vim settings
|
||||
"vim": {
|
||||
"default_mode": "normal",
|
||||
"toggle_relative_line_numbers": false,
|
||||
"use_system_clipboard": "always",
|
||||
"use_multiline_find": false,
|
||||
|
||||
@@ -379,7 +379,7 @@
|
||||
"font_weight": null
|
||||
},
|
||||
"variable": {
|
||||
"color": "#83a598ff",
|
||||
"color": "#ebdbb2ff",
|
||||
"font_style": null,
|
||||
"font_weight": null
|
||||
},
|
||||
@@ -767,7 +767,7 @@
|
||||
"font_weight": null
|
||||
},
|
||||
"variable": {
|
||||
"color": "#83a598ff",
|
||||
"color": "#ebdbb2ff",
|
||||
"font_style": null,
|
||||
"font_weight": null
|
||||
},
|
||||
@@ -1155,7 +1155,7 @@
|
||||
"font_weight": null
|
||||
},
|
||||
"variable": {
|
||||
"color": "#83a598ff",
|
||||
"color": "#ebdbb2ff",
|
||||
"font_style": null,
|
||||
"font_weight": null
|
||||
},
|
||||
@@ -1543,7 +1543,7 @@
|
||||
"font_weight": null
|
||||
},
|
||||
"variable": {
|
||||
"color": "#066578ff",
|
||||
"color": "#282828ff",
|
||||
"font_style": null,
|
||||
"font_weight": null
|
||||
},
|
||||
@@ -1931,7 +1931,7 @@
|
||||
"font_weight": null
|
||||
},
|
||||
"variable": {
|
||||
"color": "#066578ff",
|
||||
"color": "#282828ff",
|
||||
"font_style": null,
|
||||
"font_weight": null
|
||||
},
|
||||
@@ -2319,7 +2319,7 @@
|
||||
"font_weight": null
|
||||
},
|
||||
"variable": {
|
||||
"color": "#066578ff",
|
||||
"color": "#282828ff",
|
||||
"font_style": null,
|
||||
"font_weight": null
|
||||
},
|
||||
|
||||
@@ -365,7 +365,7 @@
|
||||
"font_weight": null
|
||||
},
|
||||
"variable": {
|
||||
"color": "#dce0e5ff",
|
||||
"color": "#acb2beff",
|
||||
"font_style": null,
|
||||
"font_weight": null
|
||||
},
|
||||
|
||||
@@ -30,6 +30,8 @@ pub enum Model {
|
||||
#[default]
|
||||
#[serde(rename = "claude-3-5-sonnet", alias = "claude-3-5-sonnet-latest")]
|
||||
Claude3_5Sonnet,
|
||||
#[serde(rename = "claude-3-7-sonnet", alias = "claude-3-7-sonnet-latest")]
|
||||
Claude3_7Sonnet,
|
||||
#[serde(rename = "claude-3-5-haiku", alias = "claude-3-5-haiku-latest")]
|
||||
Claude3_5Haiku,
|
||||
#[serde(rename = "claude-3-opus", alias = "claude-3-opus-latest")]
|
||||
@@ -59,6 +61,8 @@ impl Model {
|
||||
pub fn from_id(id: &str) -> Result<Self> {
|
||||
if id.starts_with("claude-3-5-sonnet") {
|
||||
Ok(Self::Claude3_5Sonnet)
|
||||
} else if id.starts_with("claude-3-7-sonnet") {
|
||||
Ok(Self::Claude3_7Sonnet)
|
||||
} else if id.starts_with("claude-3-5-haiku") {
|
||||
Ok(Self::Claude3_5Haiku)
|
||||
} else if id.starts_with("claude-3-opus") {
|
||||
@@ -75,6 +79,7 @@ impl Model {
|
||||
pub fn id(&self) -> &str {
|
||||
match self {
|
||||
Model::Claude3_5Sonnet => "claude-3-5-sonnet-latest",
|
||||
Model::Claude3_7Sonnet => "claude-3-7-sonnet-latest",
|
||||
Model::Claude3_5Haiku => "claude-3-5-haiku-latest",
|
||||
Model::Claude3Opus => "claude-3-opus-latest",
|
||||
Model::Claude3Sonnet => "claude-3-sonnet-20240229",
|
||||
@@ -85,6 +90,7 @@ impl Model {
|
||||
|
||||
pub fn display_name(&self) -> &str {
|
||||
match self {
|
||||
Self::Claude3_7Sonnet => "Claude 3.7 Sonnet",
|
||||
Self::Claude3_5Sonnet => "Claude 3.5 Sonnet",
|
||||
Self::Claude3_5Haiku => "Claude 3.5 Haiku",
|
||||
Self::Claude3Opus => "Claude 3 Opus",
|
||||
@@ -98,13 +104,14 @@ impl Model {
|
||||
|
||||
pub fn cache_configuration(&self) -> Option<AnthropicModelCacheConfiguration> {
|
||||
match self {
|
||||
Self::Claude3_5Sonnet | Self::Claude3_5Haiku | Self::Claude3Haiku => {
|
||||
Some(AnthropicModelCacheConfiguration {
|
||||
min_total_token: 2_048,
|
||||
should_speculate: true,
|
||||
max_cache_anchors: 4,
|
||||
})
|
||||
}
|
||||
Self::Claude3_5Sonnet
|
||||
| Self::Claude3_5Haiku
|
||||
| Self::Claude3_7Sonnet
|
||||
| Self::Claude3Haiku => Some(AnthropicModelCacheConfiguration {
|
||||
min_total_token: 2_048,
|
||||
should_speculate: true,
|
||||
max_cache_anchors: 4,
|
||||
}),
|
||||
Self::Custom {
|
||||
cache_configuration,
|
||||
..
|
||||
@@ -117,6 +124,7 @@ impl Model {
|
||||
match self {
|
||||
Self::Claude3_5Sonnet
|
||||
| Self::Claude3_5Haiku
|
||||
| Self::Claude3_7Sonnet
|
||||
| Self::Claude3Opus
|
||||
| Self::Claude3Sonnet
|
||||
| Self::Claude3Haiku => 200_000,
|
||||
@@ -127,7 +135,7 @@ impl Model {
|
||||
pub fn max_output_tokens(&self) -> u32 {
|
||||
match self {
|
||||
Self::Claude3Opus | Self::Claude3Sonnet | Self::Claude3Haiku => 4_096,
|
||||
Self::Claude3_5Sonnet | Self::Claude3_5Haiku => 8_192,
|
||||
Self::Claude3_5Sonnet | Self::Claude3_7Sonnet | Self::Claude3_5Haiku => 8_192,
|
||||
Self::Custom {
|
||||
max_output_tokens, ..
|
||||
} => max_output_tokens.unwrap_or(4_096),
|
||||
@@ -137,6 +145,7 @@ impl Model {
|
||||
pub fn default_temperature(&self) -> f32 {
|
||||
match self {
|
||||
Self::Claude3_5Sonnet
|
||||
| Self::Claude3_7Sonnet
|
||||
| Self::Claude3_5Haiku
|
||||
| Self::Claude3Opus
|
||||
| Self::Claude3Sonnet
|
||||
|
||||
@@ -43,7 +43,6 @@ indoc.workspace = true
|
||||
language.workspace = true
|
||||
language_model.workspace = true
|
||||
language_model_selector.workspace = true
|
||||
language_models.workspace = true
|
||||
log.workspace = true
|
||||
lsp.workspace = true
|
||||
menu.workspace = true
|
||||
@@ -52,6 +51,7 @@ parking_lot.workspace = true
|
||||
paths.workspace = true
|
||||
project.workspace = true
|
||||
prompt_library.workspace = true
|
||||
prompt_store.workspace = true
|
||||
proto.workspace = true
|
||||
rope.workspace = true
|
||||
schemars.workspace = true
|
||||
|
||||
@@ -19,7 +19,7 @@ use gpui::{actions, App, Global, UpdateGlobal};
|
||||
use language_model::{
|
||||
LanguageModelId, LanguageModelProviderId, LanguageModelRegistry, LanguageModelResponseMessage,
|
||||
};
|
||||
use prompt_library::PromptBuilder;
|
||||
use prompt_store::PromptBuilder;
|
||||
use semantic_index::{CloudEmbeddingProvider, SemanticDb};
|
||||
use serde::Deserialize;
|
||||
use settings::{Settings, SettingsStore};
|
||||
@@ -33,7 +33,7 @@ actions!(
|
||||
[
|
||||
InsertActivePrompt,
|
||||
DeployHistory,
|
||||
NewContext,
|
||||
NewChat,
|
||||
CycleNextInlineAssist,
|
||||
CyclePreviousInlineAssist
|
||||
]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::assistant_configuration::{ConfigurationView, ConfigurationViewEvent};
|
||||
use crate::{
|
||||
terminal_inline_assistant::TerminalInlineAssistant, DeployHistory, InlineAssistant, NewContext,
|
||||
terminal_inline_assistant::TerminalInlineAssistant, DeployHistory, InlineAssistant, NewChat,
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use assistant_context_editor::{
|
||||
@@ -24,7 +24,8 @@ use language_model::{
|
||||
AuthenticateError, LanguageModelProviderId, LanguageModelRegistry, ZED_CLOUD_PROVIDER_ID,
|
||||
};
|
||||
use project::Project;
|
||||
use prompt_library::{open_prompt_library, PromptBuilder, PromptLibrary};
|
||||
use prompt_library::{open_prompt_library, PromptLibrary};
|
||||
use prompt_store::PromptBuilder;
|
||||
use search::{buffer_search::DivRegistrar, BufferSearchBar};
|
||||
use settings::{update_settings_file, Settings};
|
||||
use smol::stream::StreamExt;
|
||||
@@ -129,7 +130,7 @@ impl AssistantPanel {
|
||||
workspace.project().clone(),
|
||||
Default::default(),
|
||||
None,
|
||||
NewContext.boxed_clone(),
|
||||
NewChat.boxed_clone(),
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
@@ -228,12 +229,12 @@ impl AssistantPanel {
|
||||
IconButton::new("new-chat", IconName::Plus)
|
||||
.icon_size(IconSize::Small)
|
||||
.on_click(cx.listener(|_, _, window, cx| {
|
||||
window.dispatch_action(NewContext.boxed_clone(), cx)
|
||||
window.dispatch_action(NewChat.boxed_clone(), cx)
|
||||
}))
|
||||
.tooltip(move |window, cx| {
|
||||
Tooltip::for_action_in(
|
||||
"New Chat",
|
||||
&NewContext,
|
||||
&NewChat,
|
||||
&focus_handle,
|
||||
window,
|
||||
cx,
|
||||
@@ -256,7 +257,7 @@ impl AssistantPanel {
|
||||
let focus_handle = _pane.focus_handle(cx);
|
||||
Some(ContextMenu::build(window, cx, move |menu, _, _| {
|
||||
menu.context(focus_handle.clone())
|
||||
.action("New Chat", Box::new(NewContext))
|
||||
.action("New Chat", Box::new(NewChat))
|
||||
.action("History", Box::new(DeployHistory))
|
||||
.action("Prompt Library", Box::new(DeployPromptLibrary))
|
||||
.action("Configure", Box::new(ShowConfiguration))
|
||||
@@ -760,7 +761,7 @@ impl AssistantPanel {
|
||||
|
||||
pub fn create_new_context(
|
||||
workspace: &mut Workspace,
|
||||
_: &NewContext,
|
||||
_: &NewChat,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Workspace>,
|
||||
) {
|
||||
@@ -978,7 +979,7 @@ impl AssistantPanel {
|
||||
.active_provider()
|
||||
.map_or(true, |p| p.id() != provider.id())
|
||||
{
|
||||
if let Some(model) = provider.provided_models(cx).first().cloned() {
|
||||
if let Some(model) = provider.default_model(cx) {
|
||||
update_settings_file::<AssistantSettings>(
|
||||
this.fs.clone(),
|
||||
cx,
|
||||
@@ -1206,7 +1207,7 @@ impl Render for AssistantPanel {
|
||||
v_flex()
|
||||
.key_context("AssistantPanel")
|
||||
.size_full()
|
||||
.on_action(cx.listener(|this, _: &NewContext, window, cx| {
|
||||
.on_action(cx.listener(|this, _: &NewChat, window, cx| {
|
||||
this.new_context(window, cx);
|
||||
}))
|
||||
.on_action(cx.listener(|this, _: &ShowConfiguration, window, cx| {
|
||||
|
||||
@@ -32,15 +32,14 @@ use gpui::{
|
||||
};
|
||||
use language::{line_diff, Buffer, IndentKind, Point, Selection, TransactionId};
|
||||
use language_model::{
|
||||
LanguageModel, LanguageModelRegistry, LanguageModelRequest, LanguageModelRequestMessage,
|
||||
LanguageModelTextStream, Role,
|
||||
report_assistant_event, LanguageModel, LanguageModelRegistry, LanguageModelRequest,
|
||||
LanguageModelRequestMessage, LanguageModelTextStream, Role,
|
||||
};
|
||||
use language_model_selector::{LanguageModelSelector, LanguageModelSelectorPopoverMenu};
|
||||
use language_models::report_assistant_event;
|
||||
use language_model_selector::inline_language_model_selector;
|
||||
use multi_buffer::MultiBufferRow;
|
||||
use parking_lot::Mutex;
|
||||
use project::{CodeAction, ProjectTransaction};
|
||||
use prompt_library::PromptBuilder;
|
||||
use prompt_store::PromptBuilder;
|
||||
use rope::Rope;
|
||||
use settings::{update_settings_file, Settings, SettingsStore};
|
||||
use smol::future::FutureExt;
|
||||
@@ -1426,7 +1425,6 @@ enum PromptEditorEvent {
|
||||
struct PromptEditor {
|
||||
id: InlineAssistId,
|
||||
editor: Entity<Editor>,
|
||||
language_model_selector: Entity<LanguageModelSelector>,
|
||||
edited_since_done: bool,
|
||||
gutter_dimensions: Arc<Mutex<GutterDimensions>>,
|
||||
prompt_history: VecDeque<String>,
|
||||
@@ -1440,6 +1438,7 @@ struct PromptEditor {
|
||||
_token_count_subscriptions: Vec<Subscription>,
|
||||
workspace: Option<WeakEntity<Workspace>>,
|
||||
show_rate_limit_notice: bool,
|
||||
fs: Arc<dyn Fs>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
@@ -1568,6 +1567,7 @@ impl Render for PromptEditor {
|
||||
]
|
||||
}
|
||||
});
|
||||
let fs_clone = self.fs.clone();
|
||||
|
||||
h_flex()
|
||||
.key_context("PromptEditor")
|
||||
@@ -1590,29 +1590,13 @@ impl Render for PromptEditor {
|
||||
.w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0))
|
||||
.justify_center()
|
||||
.gap_2()
|
||||
.child(LanguageModelSelectorPopoverMenu::new(
|
||||
self.language_model_selector.clone(),
|
||||
IconButton::new("context", IconName::SettingsAlt)
|
||||
.shape(IconButtonShape::Square)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted),
|
||||
move |window, cx| {
|
||||
Tooltip::with_meta(
|
||||
format!(
|
||||
"Using {}",
|
||||
LanguageModelRegistry::read_global(cx)
|
||||
.active_model()
|
||||
.map(|model| model.name().0)
|
||||
.unwrap_or_else(|| "No model selected".into()),
|
||||
),
|
||||
None,
|
||||
"Change Model",
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
},
|
||||
gpui::Corner::TopRight,
|
||||
))
|
||||
.child(inline_language_model_selector(move |model, cx| {
|
||||
update_settings_file::<AssistantSettings>(
|
||||
fs_clone.clone(),
|
||||
cx,
|
||||
move |settings, _| settings.set_model(model.clone()),
|
||||
);
|
||||
}))
|
||||
.map(|el| {
|
||||
let CodegenStatus::Error(error) = self.codegen.read(cx).status(cx) else {
|
||||
return el;
|
||||
@@ -1725,21 +1709,8 @@ impl PromptEditor {
|
||||
|
||||
let mut this = Self {
|
||||
id,
|
||||
fs,
|
||||
editor: prompt_editor,
|
||||
language_model_selector: cx.new(|cx| {
|
||||
let fs = fs.clone();
|
||||
LanguageModelSelector::new(
|
||||
move |model, cx| {
|
||||
update_settings_file::<AssistantSettings>(
|
||||
fs.clone(),
|
||||
cx,
|
||||
move |settings, _| settings.set_model(model.clone()),
|
||||
);
|
||||
},
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
}),
|
||||
edited_since_done: false,
|
||||
gutter_dimensions,
|
||||
prompt_history,
|
||||
|
||||
@@ -16,11 +16,11 @@ use gpui::{
|
||||
};
|
||||
use language::Buffer;
|
||||
use language_model::{
|
||||
LanguageModelRegistry, LanguageModelRequest, LanguageModelRequestMessage, Role,
|
||||
report_assistant_event, LanguageModelRegistry, LanguageModelRequest,
|
||||
LanguageModelRequestMessage, Role,
|
||||
};
|
||||
use language_model_selector::{LanguageModelSelector, LanguageModelSelectorPopoverMenu};
|
||||
use language_models::report_assistant_event;
|
||||
use prompt_library::PromptBuilder;
|
||||
use language_model_selector::inline_language_model_selector;
|
||||
use prompt_store::PromptBuilder;
|
||||
use settings::{update_settings_file, Settings};
|
||||
use std::{
|
||||
cmp,
|
||||
@@ -487,9 +487,9 @@ enum PromptEditorEvent {
|
||||
|
||||
struct PromptEditor {
|
||||
id: TerminalInlineAssistId,
|
||||
fs: Arc<dyn Fs>,
|
||||
height_in_lines: u8,
|
||||
editor: Entity<Editor>,
|
||||
language_model_selector: Entity<LanguageModelSelector>,
|
||||
edited_since_done: bool,
|
||||
prompt_history: VecDeque<String>,
|
||||
prompt_history_ix: Option<usize>,
|
||||
@@ -506,7 +506,7 @@ struct PromptEditor {
|
||||
impl EventEmitter<PromptEditorEvent> for PromptEditor {}
|
||||
|
||||
impl Render for PromptEditor {
|
||||
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let status = &self.codegen.read(cx).status;
|
||||
let buttons = match status {
|
||||
CodegenStatus::Idle => {
|
||||
@@ -624,6 +624,8 @@ impl Render for PromptEditor {
|
||||
}
|
||||
};
|
||||
|
||||
let fs_clone = self.fs.clone();
|
||||
|
||||
h_flex()
|
||||
.bg(cx.theme().colors().editor_background)
|
||||
.border_y_1()
|
||||
@@ -641,29 +643,13 @@ impl Render for PromptEditor {
|
||||
.w_12()
|
||||
.justify_center()
|
||||
.gap_2()
|
||||
.child(LanguageModelSelectorPopoverMenu::new(
|
||||
self.language_model_selector.clone(),
|
||||
IconButton::new("context", IconName::SettingsAlt)
|
||||
.shape(IconButtonShape::Square)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted),
|
||||
move |window, cx| {
|
||||
Tooltip::with_meta(
|
||||
format!(
|
||||
"Using {}",
|
||||
LanguageModelRegistry::read_global(cx)
|
||||
.active_model()
|
||||
.map(|model| model.name().0)
|
||||
.unwrap_or_else(|| "No model selected".into()),
|
||||
),
|
||||
None,
|
||||
"Change Model",
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
},
|
||||
gpui::Corner::TopRight,
|
||||
))
|
||||
.child(inline_language_model_selector(move |model, cx| {
|
||||
update_settings_file::<AssistantSettings>(
|
||||
fs_clone.clone(),
|
||||
cx,
|
||||
move |settings, _| settings.set_model(model.clone()),
|
||||
);
|
||||
}))
|
||||
.children(
|
||||
if let CodegenStatus::Error(error) = &self.codegen.read(cx).status {
|
||||
let error_message = SharedString::from(error.to_string());
|
||||
@@ -741,22 +727,9 @@ impl PromptEditor {
|
||||
|
||||
let mut this = Self {
|
||||
id,
|
||||
fs,
|
||||
height_in_lines: 1,
|
||||
editor: prompt_editor,
|
||||
language_model_selector: cx.new(|cx| {
|
||||
let fs = fs.clone();
|
||||
LanguageModelSelector::new(
|
||||
move |model, cx| {
|
||||
update_settings_file::<AssistantSettings>(
|
||||
fs.clone(),
|
||||
cx,
|
||||
move |settings, _| settings.set_model(model.clone()),
|
||||
);
|
||||
},
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
}),
|
||||
edited_since_done: false,
|
||||
prompt_history,
|
||||
prompt_history_ix: None,
|
||||
@@ -1073,7 +1046,10 @@ pub enum CodegenEvent {
|
||||
|
||||
impl EventEmitter<CodegenEvent> for Codegen {}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
const CLEAR_INPUT: &str = "\x15";
|
||||
#[cfg(target_os = "windows")]
|
||||
const CLEAR_INPUT: &str = "\x03";
|
||||
const CARRIAGE_RETURN: &str = "\x0d";
|
||||
|
||||
struct TerminalTransaction {
|
||||
|
||||
@@ -46,7 +46,6 @@ itertools.workspace = true
|
||||
language.workspace = true
|
||||
language_model.workspace = true
|
||||
language_model_selector.workspace = true
|
||||
language_models.workspace = true
|
||||
log.workspace = true
|
||||
lsp.workspace = true
|
||||
markdown.workspace = true
|
||||
@@ -57,6 +56,7 @@ paths.workspace = true
|
||||
picker.workspace = true
|
||||
project.workspace = true
|
||||
prompt_library.workspace = true
|
||||
prompt_store.workspace = true
|
||||
proto.workspace = true
|
||||
rope.workspace = true
|
||||
serde.workspace = true
|
||||
@@ -74,6 +74,7 @@ time_format.workspace = true
|
||||
ui.workspace = true
|
||||
util.workspace = true
|
||||
uuid.workspace = true
|
||||
vim_mode_setting.workspace = true
|
||||
workspace.workspace = true
|
||||
zed_actions.workspace = true
|
||||
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use assistant_tool::ToolWorkingSet;
|
||||
use assistant_tool::{ToolRegistry, ToolWorkingSet};
|
||||
use collections::HashMap;
|
||||
use editor::{Editor, MultiBuffer};
|
||||
use gpui::{
|
||||
list, AbsoluteLength, AnyElement, App, DefiniteLength, EdgesRefinement, Empty, Entity, Length,
|
||||
ListAlignment, ListOffset, ListState, StyleRefinement, Subscription, TextStyleRefinement,
|
||||
UnderlineStyle, WeakEntity,
|
||||
list, AbsoluteLength, AnyElement, App, ClickEvent, DefiniteLength, EdgesRefinement, Empty,
|
||||
Entity, Focusable, Length, ListAlignment, ListOffset, ListState, StyleRefinement, Subscription,
|
||||
Task, TextStyleRefinement, UnderlineStyle, WeakEntity,
|
||||
};
|
||||
use language::LanguageRegistry;
|
||||
use language_model::Role;
|
||||
use language::{Buffer, Language, LanguageRegistry};
|
||||
use language_model::{LanguageModelRegistry, LanguageModelToolUseId, Role};
|
||||
use markdown::{Markdown, MarkdownStyle};
|
||||
use settings::Settings as _;
|
||||
use std::sync::Arc;
|
||||
use theme::ThemeSettings;
|
||||
use ui::prelude::*;
|
||||
use ui::{prelude::*, Disclosure, KeyBinding};
|
||||
use util::ResultExt as _;
|
||||
use workspace::Workspace;
|
||||
|
||||
use crate::thread::{MessageId, Thread, ThreadError, ThreadEvent};
|
||||
use crate::thread::{MessageId, RequestKind, Thread, ThreadError, ThreadEvent};
|
||||
use crate::thread_store::ThreadStore;
|
||||
use crate::tool_use::{ToolUse, ToolUseStatus};
|
||||
use crate::ui::ContextPill;
|
||||
|
||||
pub struct ActiveThread {
|
||||
@@ -25,13 +27,21 @@ pub struct ActiveThread {
|
||||
tools: Arc<ToolWorkingSet>,
|
||||
thread_store: Entity<ThreadStore>,
|
||||
thread: Entity<Thread>,
|
||||
save_thread_task: Option<Task<()>>,
|
||||
messages: Vec<MessageId>,
|
||||
list_state: ListState,
|
||||
rendered_messages_by_id: HashMap<MessageId, Entity<Markdown>>,
|
||||
editing_message: Option<(MessageId, EditMessageState)>,
|
||||
expanded_tool_uses: HashMap<LanguageModelToolUseId, bool>,
|
||||
last_error: Option<ThreadError>,
|
||||
lua_language: Option<Arc<Language>>, // Used for syntax highlighting in the Lua script tool
|
||||
_subscriptions: Vec<Subscription>,
|
||||
}
|
||||
|
||||
struct EditMessageState {
|
||||
editor: Entity<Editor>,
|
||||
}
|
||||
|
||||
impl ActiveThread {
|
||||
pub fn new(
|
||||
thread: Entity<Thread>,
|
||||
@@ -53,19 +63,36 @@ impl ActiveThread {
|
||||
tools,
|
||||
thread_store,
|
||||
thread: thread.clone(),
|
||||
save_thread_task: None,
|
||||
messages: Vec::new(),
|
||||
rendered_messages_by_id: HashMap::default(),
|
||||
expanded_tool_uses: HashMap::default(),
|
||||
list_state: ListState::new(0, ListAlignment::Bottom, px(1024.), {
|
||||
let this = cx.entity().downgrade();
|
||||
move |ix, _: &mut Window, cx: &mut App| {
|
||||
this.update(cx, |this, cx| this.render_message(ix, cx))
|
||||
move |ix, window: &mut Window, cx: &mut App| {
|
||||
this.update(cx, |this, cx| this.render_message(ix, window, cx))
|
||||
.unwrap()
|
||||
}
|
||||
}),
|
||||
editing_message: None,
|
||||
last_error: None,
|
||||
lua_language: None,
|
||||
_subscriptions: subscriptions,
|
||||
};
|
||||
|
||||
// Initialize the Lua language in the background, for syntax highlighting.
|
||||
let language_registry = this.language_registry.clone();
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
if let Ok(lua_language) = language_registry.language_for_name("Lua").await {
|
||||
this.update(&mut cx, |this, _| {
|
||||
this.lua_language = Some(lua_language);
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok::<_, anyhow::Error>(())
|
||||
})
|
||||
.detach();
|
||||
|
||||
for message in thread.read(cx).messages().cloned().collect::<Vec<_>>() {
|
||||
this.push_message(&message.id, message.text.clone(), window, cx);
|
||||
}
|
||||
@@ -114,6 +141,44 @@ impl ActiveThread {
|
||||
self.messages.push(*id);
|
||||
self.list_state.splice(old_len..old_len, 1);
|
||||
|
||||
let markdown = self.render_markdown(text.into(), window, cx);
|
||||
self.rendered_messages_by_id.insert(*id, markdown);
|
||||
self.list_state.scroll_to(ListOffset {
|
||||
item_ix: old_len,
|
||||
offset_in_item: Pixels(0.0),
|
||||
});
|
||||
}
|
||||
|
||||
fn edited_message(
|
||||
&mut self,
|
||||
id: &MessageId,
|
||||
text: String,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let Some(index) = self.messages.iter().position(|message_id| message_id == id) else {
|
||||
return;
|
||||
};
|
||||
self.list_state.splice(index..index + 1, 1);
|
||||
let markdown = self.render_markdown(text.into(), window, cx);
|
||||
self.rendered_messages_by_id.insert(*id, markdown);
|
||||
}
|
||||
|
||||
fn deleted_message(&mut self, id: &MessageId) {
|
||||
let Some(index) = self.messages.iter().position(|message_id| message_id == id) else {
|
||||
return;
|
||||
};
|
||||
self.messages.remove(index);
|
||||
self.list_state.splice(index..index + 1, 0);
|
||||
self.rendered_messages_by_id.remove(id);
|
||||
}
|
||||
|
||||
fn render_markdown(
|
||||
&self,
|
||||
text: SharedString,
|
||||
window: &Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Entity<Markdown> {
|
||||
let theme_settings = ThemeSettings::get_global(cx);
|
||||
let colors = cx.theme().colors();
|
||||
let ui_font_size = TextSize::Default.rems(cx);
|
||||
@@ -131,6 +196,8 @@ impl ActiveThread {
|
||||
base_text_style: text_style,
|
||||
syntax: cx.theme().syntax().clone(),
|
||||
selection_background_color: cx.theme().players().local().selection,
|
||||
code_block_overflow_x_scroll: true,
|
||||
table_overflow_x_scroll: true,
|
||||
code_block: StyleRefinement {
|
||||
margin: EdgesRefinement {
|
||||
top: Some(Length::Definite(rems(0.).into())),
|
||||
@@ -177,20 +244,15 @@ impl ActiveThread {
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let markdown = cx.new(|cx| {
|
||||
cx.new(|cx| {
|
||||
Markdown::new(
|
||||
text.into(),
|
||||
text,
|
||||
markdown_style,
|
||||
Some(self.language_registry.clone()),
|
||||
None,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
self.rendered_messages_by_id.insert(*id, markdown);
|
||||
self.list_state.scroll_to(ListOffset {
|
||||
item_ix: old_len,
|
||||
offset_in_item: Pixels(0.0),
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
fn handle_thread_event(
|
||||
@@ -205,11 +267,7 @@ impl ActiveThread {
|
||||
self.last_error = Some(error.clone());
|
||||
}
|
||||
ThreadEvent::StreamedCompletion | ThreadEvent::SummaryChanged => {
|
||||
self.thread_store
|
||||
.update(cx, |thread_store, cx| {
|
||||
thread_store.save_thread(&self.thread, cx)
|
||||
})
|
||||
.detach_and_log_err(cx);
|
||||
self.save_thread(cx);
|
||||
}
|
||||
ThreadEvent::StreamedAssistantText(message_id, text) => {
|
||||
if let Some(markdown) = self.rendered_messages_by_id.get_mut(&message_id) {
|
||||
@@ -228,18 +286,31 @@ impl ActiveThread {
|
||||
self.push_message(message_id, message_text, window, cx);
|
||||
}
|
||||
|
||||
self.thread_store
|
||||
.update(cx, |thread_store, cx| {
|
||||
thread_store.save_thread(&self.thread, cx)
|
||||
})
|
||||
.detach_and_log_err(cx);
|
||||
self.save_thread(cx);
|
||||
cx.notify();
|
||||
}
|
||||
ThreadEvent::MessageEdited(message_id) => {
|
||||
if let Some(message_text) = self
|
||||
.thread
|
||||
.read(cx)
|
||||
.message(*message_id)
|
||||
.map(|message| message.text.clone())
|
||||
{
|
||||
self.edited_message(message_id, message_text, window, cx);
|
||||
}
|
||||
|
||||
self.save_thread(cx);
|
||||
cx.notify();
|
||||
}
|
||||
ThreadEvent::MessageDeleted(message_id) => {
|
||||
self.deleted_message(message_id);
|
||||
self.save_thread(cx);
|
||||
cx.notify();
|
||||
}
|
||||
ThreadEvent::UsePendingTools => {
|
||||
let pending_tool_uses = self
|
||||
.thread
|
||||
.read(cx)
|
||||
let thread = self.thread.read(cx);
|
||||
let thread_id = thread.id().0.clone();
|
||||
let pending_tool_uses = thread
|
||||
.pending_tool_uses()
|
||||
.into_iter()
|
||||
.filter(|tool_use| tool_use.status.is_idle())
|
||||
@@ -248,24 +319,175 @@ impl ActiveThread {
|
||||
|
||||
for tool_use in pending_tool_uses {
|
||||
if let Some(tool) = self.tools.tool(&tool_use.name, cx) {
|
||||
let task = tool.run(tool_use.input, self.workspace.clone(), window, cx);
|
||||
let task = tool.run(
|
||||
tool_use.input,
|
||||
thread_id.clone(),
|
||||
self.workspace.clone(),
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
|
||||
self.thread.update(cx, |thread, cx| {
|
||||
thread.insert_tool_output(
|
||||
tool_use.assistant_message_id,
|
||||
tool_use.id.clone(),
|
||||
task,
|
||||
cx,
|
||||
);
|
||||
thread.insert_tool_output(tool_use.id.clone(), task, cx);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
ThreadEvent::ToolFinished { .. } => {
|
||||
let all_tools_finished = self
|
||||
.thread
|
||||
.read(cx)
|
||||
.pending_tool_uses()
|
||||
.into_iter()
|
||||
.all(|tool_use| tool_use.status.is_error());
|
||||
if all_tools_finished {
|
||||
let model_registry = LanguageModelRegistry::read_global(cx);
|
||||
if let Some(model) = model_registry.active_model() {
|
||||
self.thread.update(cx, |thread, cx| {
|
||||
// Insert a user message to contain the tool results.
|
||||
thread.insert_user_message(
|
||||
// TODO: Sending up a user message without any content results in the model sending back
|
||||
// responses that also don't have any content. We currently don't handle this case well,
|
||||
// so for now we provide some text to keep the model on track.
|
||||
"Here are the tool results.",
|
||||
Vec::new(),
|
||||
cx,
|
||||
);
|
||||
thread.send_to_model(model, RequestKind::Chat, true, cx);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
ThreadEvent::ToolFinished { .. } => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_message(&self, ix: usize, cx: &mut Context<Self>) -> AnyElement {
|
||||
/// Spawns a task to save the active thread.
|
||||
///
|
||||
/// Only one task to save the thread will be in flight at a time.
|
||||
fn save_thread(&mut self, cx: &mut Context<Self>) {
|
||||
let thread = self.thread.clone();
|
||||
self.save_thread_task = Some(cx.spawn(|this, mut cx| async move {
|
||||
let task = this
|
||||
.update(&mut cx, |this, cx| {
|
||||
this.thread_store
|
||||
.update(cx, |thread_store, cx| thread_store.save_thread(&thread, cx))
|
||||
})
|
||||
.ok();
|
||||
|
||||
if let Some(task) = task {
|
||||
task.await.log_err();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
fn start_editing_message(
|
||||
&mut self,
|
||||
message_id: MessageId,
|
||||
message_text: String,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let buffer = cx.new(|cx| {
|
||||
MultiBuffer::singleton(cx.new(|cx| Buffer::local(message_text.clone(), cx)), cx)
|
||||
});
|
||||
let editor = cx.new(|cx| {
|
||||
let mut editor = Editor::new(
|
||||
editor::EditorMode::AutoHeight { max_lines: 8 },
|
||||
buffer,
|
||||
None,
|
||||
false,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
editor.focus_handle(cx).focus(window);
|
||||
editor.move_to_end(&editor::actions::MoveToEnd, window, cx);
|
||||
editor
|
||||
});
|
||||
self.editing_message = Some((
|
||||
message_id,
|
||||
EditMessageState {
|
||||
editor: editor.clone(),
|
||||
},
|
||||
));
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn cancel_editing_message(&mut self, _: &menu::Cancel, _: &mut Window, cx: &mut Context<Self>) {
|
||||
self.editing_message.take();
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn confirm_editing_message(
|
||||
&mut self,
|
||||
_: &menu::Confirm,
|
||||
_: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let Some((message_id, state)) = self.editing_message.take() else {
|
||||
return;
|
||||
};
|
||||
let edited_text = state.editor.read(cx).text(cx);
|
||||
self.thread.update(cx, |thread, cx| {
|
||||
thread.edit_message(message_id, Role::User, edited_text, cx);
|
||||
for message_id in self.messages_after(message_id) {
|
||||
thread.delete_message(*message_id, cx);
|
||||
}
|
||||
});
|
||||
|
||||
let provider = LanguageModelRegistry::read_global(cx).active_provider();
|
||||
if provider
|
||||
.as_ref()
|
||||
.map_or(false, |provider| provider.must_accept_terms(cx))
|
||||
{
|
||||
cx.notify();
|
||||
return;
|
||||
}
|
||||
let model_registry = LanguageModelRegistry::read_global(cx);
|
||||
let Some(model) = model_registry.active_model() else {
|
||||
return;
|
||||
};
|
||||
|
||||
self.thread.update(cx, |thread, cx| {
|
||||
thread.send_to_model(model, RequestKind::Chat, false, cx)
|
||||
});
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn last_user_message(&self, cx: &Context<Self>) -> Option<MessageId> {
|
||||
self.messages
|
||||
.iter()
|
||||
.rev()
|
||||
.find(|message_id| {
|
||||
self.thread
|
||||
.read(cx)
|
||||
.message(**message_id)
|
||||
.map_or(false, |message| message.role == Role::User)
|
||||
})
|
||||
.cloned()
|
||||
}
|
||||
|
||||
fn messages_after(&self, message_id: MessageId) -> &[MessageId] {
|
||||
self.messages
|
||||
.iter()
|
||||
.position(|id| *id == message_id)
|
||||
.map(|index| &self.messages[index + 1..])
|
||||
.unwrap_or(&[])
|
||||
}
|
||||
|
||||
fn handle_cancel_click(&mut self, _: &ClickEvent, window: &mut Window, cx: &mut Context<Self>) {
|
||||
self.cancel_editing_message(&menu::Cancel, window, cx);
|
||||
}
|
||||
|
||||
fn handle_regenerate_click(
|
||||
&mut self,
|
||||
_: &ClickEvent,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.confirm_editing_message(&menu::Confirm, window, cx);
|
||||
}
|
||||
|
||||
fn render_message(&self, ix: usize, window: &mut Window, cx: &mut Context<Self>) -> AnyElement {
|
||||
let message_id = self.messages[ix];
|
||||
let Some(message) = self.thread.read(cx).message(message_id) else {
|
||||
return Empty.into_any();
|
||||
@@ -276,10 +498,36 @@ impl ActiveThread {
|
||||
};
|
||||
|
||||
let context = self.thread.read(cx).context_for_message(message_id);
|
||||
let tool_uses = self.thread.read(cx).tool_uses_for_message(message_id);
|
||||
let colors = cx.theme().colors();
|
||||
|
||||
// Don't render user messages that are just there for returning tool results.
|
||||
if message.role == Role::User && self.thread.read(cx).message_has_tool_results(message_id) {
|
||||
return Empty.into_any();
|
||||
}
|
||||
|
||||
let allow_editing_message =
|
||||
message.role == Role::User && self.last_user_message(cx) == Some(message_id);
|
||||
|
||||
let edit_message_editor = self
|
||||
.editing_message
|
||||
.as_ref()
|
||||
.filter(|(id, _)| *id == message_id)
|
||||
.map(|(_, state)| state.editor.clone());
|
||||
|
||||
let message_content = v_flex()
|
||||
.child(div().p_2p5().text_ui(cx).child(markdown.clone()))
|
||||
.child(
|
||||
if let Some(edit_message_editor) = edit_message_editor.clone() {
|
||||
div()
|
||||
.key_context("EditMessageEditor")
|
||||
.on_action(cx.listener(Self::cancel_editing_message))
|
||||
.on_action(cx.listener(Self::confirm_editing_message))
|
||||
.p_2p5()
|
||||
.child(edit_message_editor)
|
||||
} else {
|
||||
div().p_2p5().text_ui(cx).child(markdown.clone())
|
||||
},
|
||||
)
|
||||
.when_some(context, |parent, context| {
|
||||
if !context.is_empty() {
|
||||
parent.child(
|
||||
@@ -309,7 +557,8 @@ impl ActiveThread {
|
||||
.child(
|
||||
h_flex()
|
||||
.py_1()
|
||||
.px_2()
|
||||
.pl_2()
|
||||
.pr_1()
|
||||
.bg(colors.editor_foreground.opacity(0.05))
|
||||
.border_b_1()
|
||||
.border_color(colors.border)
|
||||
@@ -328,11 +577,91 @@ impl ActiveThread {
|
||||
.size(LabelSize::Small)
|
||||
.color(Color::Muted),
|
||||
),
|
||||
)
|
||||
.when_some(
|
||||
edit_message_editor.clone(),
|
||||
|this, edit_message_editor| {
|
||||
let focus_handle = edit_message_editor.focus_handle(cx);
|
||||
this.child(
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.child(
|
||||
Button::new("cancel-edit-message", "Cancel")
|
||||
.label_size(LabelSize::Small)
|
||||
.key_binding(
|
||||
KeyBinding::for_action_in(
|
||||
&menu::Cancel,
|
||||
&focus_handle,
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
.map(|kb| kb.size(rems_from_px(12.))),
|
||||
)
|
||||
.on_click(
|
||||
cx.listener(Self::handle_cancel_click),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
Button::new(
|
||||
"confirm-edit-message",
|
||||
"Regenerate",
|
||||
)
|
||||
.label_size(LabelSize::Small)
|
||||
.key_binding(
|
||||
KeyBinding::for_action_in(
|
||||
&menu::Confirm,
|
||||
&focus_handle,
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
.map(|kb| kb.size(rems_from_px(12.))),
|
||||
)
|
||||
.on_click(
|
||||
cx.listener(Self::handle_regenerate_click),
|
||||
),
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
.when(
|
||||
edit_message_editor.is_none() && allow_editing_message,
|
||||
|this| {
|
||||
this.child(
|
||||
Button::new("edit-message", "Edit")
|
||||
.label_size(LabelSize::Small)
|
||||
.on_click(cx.listener({
|
||||
let message_text = message.text.clone();
|
||||
move |this, _, window, cx| {
|
||||
this.start_editing_message(
|
||||
message_id,
|
||||
message_text.clone(),
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
})),
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
.child(message_content),
|
||||
),
|
||||
Role::Assistant => div().id(("message-container", ix)).child(message_content),
|
||||
Role::Assistant => div()
|
||||
.id(("message-container", ix))
|
||||
.child(message_content)
|
||||
.map(|parent| {
|
||||
if tool_uses.is_empty() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
parent.child(
|
||||
v_flex().children(
|
||||
tool_uses
|
||||
.into_iter()
|
||||
.map(|tool_use| self.render_tool_use(tool_use, cx)),
|
||||
),
|
||||
)
|
||||
}),
|
||||
Role::System => div().id(("message-container", ix)).py_1().px_2().child(
|
||||
v_flex()
|
||||
.bg(colors.editor_background)
|
||||
@@ -343,6 +672,110 @@ impl ActiveThread {
|
||||
|
||||
styled_message.into_any()
|
||||
}
|
||||
|
||||
fn render_tool_use(&self, tool_use: ToolUse, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let tool = ToolRegistry::global(cx).tool(&tool_use.name);
|
||||
let is_open = self
|
||||
.expanded_tool_uses
|
||||
.get(&tool_use.id)
|
||||
.copied()
|
||||
.unwrap_or_default();
|
||||
|
||||
div().px_2p5().child(
|
||||
v_flex()
|
||||
.gap_1()
|
||||
.rounded_lg()
|
||||
.border_1()
|
||||
.border_color(cx.theme().colors().border)
|
||||
.child(
|
||||
h_flex()
|
||||
.justify_between()
|
||||
.py_0p5()
|
||||
.pl_1()
|
||||
.pr_2()
|
||||
.bg(cx.theme().colors().editor_foreground.opacity(0.02))
|
||||
.when(is_open, |element| element.border_b_1().rounded_t(px(6.)))
|
||||
.when(!is_open, |element| element.rounded(px(6.)))
|
||||
.border_color(cx.theme().colors().border)
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.child(Disclosure::new("tool-use-disclosure", is_open).on_click(
|
||||
cx.listener({
|
||||
let tool_use_id = tool_use.id.clone();
|
||||
move |this, _event, _window, _cx| {
|
||||
let is_open = this
|
||||
.expanded_tool_uses
|
||||
.entry(tool_use_id.clone())
|
||||
.or_insert(false);
|
||||
|
||||
*is_open = !*is_open;
|
||||
}
|
||||
}),
|
||||
))
|
||||
.child(Label::new(tool_use.name)),
|
||||
)
|
||||
.child(
|
||||
Label::new(match tool_use.status {
|
||||
ToolUseStatus::Pending => "Pending",
|
||||
ToolUseStatus::Running => "Running",
|
||||
ToolUseStatus::Finished(_) => "Finished",
|
||||
ToolUseStatus::Error(_) => "Error",
|
||||
})
|
||||
.size(LabelSize::XSmall)
|
||||
.buffer_font(cx),
|
||||
),
|
||||
)
|
||||
.map(|parent| {
|
||||
if !is_open {
|
||||
return parent;
|
||||
}
|
||||
|
||||
parent.child(
|
||||
v_flex()
|
||||
.child(
|
||||
v_flex()
|
||||
.gap_0p5()
|
||||
.py_1()
|
||||
.px_2p5()
|
||||
.border_b_1()
|
||||
.border_color(cx.theme().colors().border)
|
||||
.bg(cx.theme().colors().editor_background)
|
||||
.child(match tool.clone() {
|
||||
Some(tool) => tool.render_input(
|
||||
tool_use.input,
|
||||
self.lua_language.clone(),
|
||||
cx,
|
||||
),
|
||||
None => {
|
||||
assistant_tool::default_render_input(tool_use.input)
|
||||
}
|
||||
}),
|
||||
)
|
||||
.map(|parent| match tool_use.status {
|
||||
ToolUseStatus::Finished(output) => parent.child(
|
||||
v_flex()
|
||||
.gap_0p5()
|
||||
.py_1()
|
||||
.px_2p5()
|
||||
.bg(cx.theme().colors().editor_background)
|
||||
.child(match tool {
|
||||
Some(tool) => tool.render_output(output, cx),
|
||||
None => assistant_tool::default_render_output(output),
|
||||
}),
|
||||
),
|
||||
ToolUseStatus::Error(err) => parent.child(
|
||||
v_flex().gap_0p5().py_1().px_2p5().child(match tool {
|
||||
Some(tool) => tool.render_error(err, cx),
|
||||
None => assistant_tool::default_render_output(err),
|
||||
}),
|
||||
),
|
||||
ToolUseStatus::Pending | ToolUseStatus::Running => parent,
|
||||
}),
|
||||
)
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for ActiveThread {
|
||||
|
||||
@@ -16,6 +16,7 @@ mod terminal_inline_assistant;
|
||||
mod thread;
|
||||
mod thread_history;
|
||||
mod thread_store;
|
||||
mod tool_use;
|
||||
mod ui;
|
||||
|
||||
use std::sync::Arc;
|
||||
@@ -26,7 +27,7 @@ use command_palette_hooks::CommandPaletteFilter;
|
||||
use feature_flags::{Assistant2FeatureFlag, FeatureFlagAppExt};
|
||||
use fs::Fs;
|
||||
use gpui::{actions, App};
|
||||
use prompt_library::PromptBuilder;
|
||||
use prompt_store::PromptBuilder;
|
||||
use settings::Settings as _;
|
||||
|
||||
pub use crate::assistant_panel::{AssistantPanel, ConcreteAssistantPanelDelegate};
|
||||
@@ -38,7 +39,6 @@ actions!(
|
||||
NewThread,
|
||||
NewPromptEditor,
|
||||
ToggleContextPicker,
|
||||
ToggleModelSelector,
|
||||
RemoveAllContext,
|
||||
OpenHistory,
|
||||
OpenConfiguration,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use collections::HashMap;
|
||||
use gpui::{AnyView, App, EventEmitter, FocusHandle, Focusable, Subscription};
|
||||
use gpui::{Action, AnyView, App, EventEmitter, FocusHandle, Focusable, Subscription};
|
||||
use language_model::{LanguageModelProvider, LanguageModelProviderId, LanguageModelRegistry};
|
||||
use ui::{prelude::*, Divider, DividerColor, ElevationIndex};
|
||||
use zed_actions::assistant::DeployPromptLibrary;
|
||||
@@ -158,8 +158,16 @@ impl Render for AssistantConfiguration {
|
||||
.child(
|
||||
v_flex()
|
||||
.p(DynamicSpacing::Base16.rems(cx))
|
||||
.gap_1()
|
||||
.child(Headline::new("Prompt Library").size(HeadlineSize::Small))
|
||||
.gap_2()
|
||||
.child(
|
||||
v_flex()
|
||||
.gap_0p5()
|
||||
.child(Headline::new("Prompt Library").size(HeadlineSize::Small))
|
||||
.child(
|
||||
Label::new("Create reusable prompts and tag which ones you want sent in every LLM interaction.")
|
||||
.color(Color::Muted),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
Button::new("open-prompt-library", "Open Prompt Library")
|
||||
.style(ButtonStyle::Filled)
|
||||
@@ -168,8 +176,8 @@ impl Render for AssistantConfiguration {
|
||||
.icon(IconName::Book)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_position(IconPosition::Start)
|
||||
.on_click(|_event, _window, cx| {
|
||||
cx.dispatch_action(&DeployPromptLibrary)
|
||||
.on_click(|_event, window, cx| {
|
||||
window.dispatch_action(DeployPromptLibrary.boxed_clone(), cx)
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -1,87 +1,50 @@
|
||||
use assistant_settings::AssistantSettings;
|
||||
use fs::Fs;
|
||||
use gpui::{Entity, FocusHandle, SharedString};
|
||||
use language_model::LanguageModelRegistry;
|
||||
use language_model_selector::{LanguageModelSelector, LanguageModelSelectorPopoverMenu};
|
||||
use gpui::FocusHandle;
|
||||
use language_model_selector::{assistant_language_model_selector, LanguageModelSelector};
|
||||
use settings::update_settings_file;
|
||||
use std::sync::Arc;
|
||||
use ui::{prelude::*, ButtonLike, PopoverMenuHandle, Tooltip};
|
||||
|
||||
use crate::ToggleModelSelector;
|
||||
use ui::{prelude::*, PopoverMenuHandle};
|
||||
|
||||
pub struct AssistantModelSelector {
|
||||
selector: Entity<LanguageModelSelector>,
|
||||
menu_handle: PopoverMenuHandle<LanguageModelSelector>,
|
||||
focus_handle: FocusHandle,
|
||||
fs: Arc<dyn Fs>,
|
||||
}
|
||||
|
||||
impl AssistantModelSelector {
|
||||
pub(crate) fn new(
|
||||
fs: Arc<dyn Fs>,
|
||||
menu_handle: PopoverMenuHandle<LanguageModelSelector>,
|
||||
focus_handle: FocusHandle,
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
_window: &mut Window,
|
||||
_cx: &mut App,
|
||||
) -> Self {
|
||||
Self {
|
||||
selector: cx.new(|cx| {
|
||||
let fs = fs.clone();
|
||||
LanguageModelSelector::new(
|
||||
move |model, cx| {
|
||||
update_settings_file::<AssistantSettings>(
|
||||
fs.clone(),
|
||||
cx,
|
||||
move |settings, _cx| settings.set_model(model.clone()),
|
||||
);
|
||||
},
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
}),
|
||||
menu_handle,
|
||||
fs,
|
||||
focus_handle,
|
||||
menu_handle: PopoverMenuHandle::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle(&self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
self.menu_handle.toggle(window, cx);
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for AssistantModelSelector {
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let active_model = LanguageModelRegistry::read_global(cx).active_model();
|
||||
let focus_handle = self.focus_handle.clone();
|
||||
let model_name = match active_model {
|
||||
Some(model) => model.name().0,
|
||||
_ => SharedString::from("No model selected"),
|
||||
};
|
||||
|
||||
LanguageModelSelectorPopoverMenu::new(
|
||||
self.selector.clone(),
|
||||
ButtonLike::new("active-model")
|
||||
.style(ButtonStyle::Subtle)
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_0p5()
|
||||
.child(
|
||||
Label::new(model_name)
|
||||
.size(LabelSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.child(
|
||||
Icon::new(IconName::ChevronDown)
|
||||
.color(Color::Muted)
|
||||
.size(IconSize::XSmall),
|
||||
),
|
||||
),
|
||||
move |window, cx| {
|
||||
Tooltip::for_action_in(
|
||||
"Change Model",
|
||||
&ToggleModelSelector,
|
||||
&focus_handle,
|
||||
window,
|
||||
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let fs_clone = self.fs.clone();
|
||||
assistant_language_model_selector(
|
||||
self.focus_handle.clone(),
|
||||
Some(self.menu_handle.clone()),
|
||||
cx,
|
||||
move |model, cx| {
|
||||
update_settings_file::<AssistantSettings>(
|
||||
fs_clone.clone(),
|
||||
cx,
|
||||
)
|
||||
move |settings, _| settings.set_model(model.clone()),
|
||||
);
|
||||
},
|
||||
gpui::Corner::BottomRight,
|
||||
)
|
||||
.with_handle(self.menu_handle.clone())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,13 +14,15 @@ use client::zed_urls;
|
||||
use editor::Editor;
|
||||
use fs::Fs;
|
||||
use gpui::{
|
||||
prelude::*, px, svg, Action, AnyElement, App, AsyncWindowContext, Corner, Entity, EventEmitter,
|
||||
FocusHandle, Focusable, FontWeight, Pixels, Subscription, Task, UpdateGlobal, WeakEntity,
|
||||
prelude::*, Action, AnyElement, App, AsyncWindowContext, Corner, Entity, EventEmitter,
|
||||
FocusHandle, Focusable, FontWeight, KeyContext, Pixels, Subscription, Task, UpdateGlobal,
|
||||
WeakEntity,
|
||||
};
|
||||
use language::LanguageRegistry;
|
||||
use language_model::{LanguageModelProviderTosView, LanguageModelRegistry};
|
||||
use project::Project;
|
||||
use prompt_library::{open_prompt_library, PromptBuilder, PromptLibrary};
|
||||
use prompt_library::{open_prompt_library, PromptLibrary};
|
||||
use prompt_store::PromptBuilder;
|
||||
use settings::{update_settings_file, Settings};
|
||||
use time::UtcOffset;
|
||||
use ui::{prelude::*, ContextMenu, KeyBinding, PopoverMenu, PopoverMenuHandle, Tab, Tooltip};
|
||||
@@ -431,7 +433,7 @@ impl AssistantPanel {
|
||||
active_provider.id() != provider.id()
|
||||
})
|
||||
{
|
||||
if let Some(model) = provider.provided_models(cx).first().cloned() {
|
||||
if let Some(model) = provider.default_model(cx) {
|
||||
update_settings_file::<AssistantSettings>(
|
||||
self.fs.clone(),
|
||||
cx,
|
||||
@@ -458,6 +460,12 @@ impl AssistantPanel {
|
||||
pub(crate) fn active_context_editor(&self) -> Option<Entity<ContextEditor>> {
|
||||
self.context_editor.clone()
|
||||
}
|
||||
|
||||
pub(crate) fn delete_context(&mut self, path: PathBuf, cx: &mut Context<Self>) {
|
||||
self.context_store
|
||||
.update(cx, |this, cx| this.delete_local_context(path, cx))
|
||||
.detach_and_log_err(cx);
|
||||
}
|
||||
}
|
||||
|
||||
impl Focusable for AssistantPanel {
|
||||
@@ -590,7 +598,6 @@ impl AssistantPanel {
|
||||
|
||||
h_flex()
|
||||
.id("assistant-toolbar")
|
||||
.px(DynamicSpacing::Base08.rems(cx))
|
||||
.h(Tab::container_height(cx))
|
||||
.flex_none()
|
||||
.justify_between()
|
||||
@@ -598,72 +605,86 @@ impl AssistantPanel {
|
||||
.bg(cx.theme().colors().tab_bar_background)
|
||||
.border_b_1()
|
||||
.border_color(cx.theme().colors().border)
|
||||
.child(
|
||||
div()
|
||||
.id("title")
|
||||
.overflow_x_scroll()
|
||||
.px(DynamicSpacing::Base08.rems(cx))
|
||||
.child(Label::new(title).truncate()),
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
.w_full()
|
||||
.gap_1()
|
||||
.justify_between()
|
||||
.child(Label::new(title))
|
||||
.h_full()
|
||||
.pl_2()
|
||||
.gap_2()
|
||||
.bg(cx.theme().colors().tab_bar_background)
|
||||
.children(if matches!(self.active_view, ActiveView::PromptEditor) {
|
||||
self.context_editor
|
||||
.as_ref()
|
||||
.and_then(|editor| render_remaining_tokens(editor, cx))
|
||||
} else {
|
||||
None
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
.h_full()
|
||||
.pl_1p5()
|
||||
.border_l_1()
|
||||
.border_color(cx.theme().colors().border)
|
||||
.gap(DynamicSpacing::Base02.rems(cx))
|
||||
})
|
||||
.child(
|
||||
PopoverMenu::new("assistant-toolbar-new-popover-menu")
|
||||
.trigger_with_tooltip(
|
||||
IconButton::new("new", IconName::Plus)
|
||||
.icon_size(IconSize::Small)
|
||||
.style(ButtonStyle::Subtle),
|
||||
Tooltip::text("New…"),
|
||||
)
|
||||
.anchor(Corner::TopRight)
|
||||
.with_handle(self.new_item_context_menu_handle.clone())
|
||||
.menu(move |window, cx| {
|
||||
Some(ContextMenu::build(window, cx, |menu, _window, _cx| {
|
||||
menu.action("New Thread", NewThread.boxed_clone())
|
||||
.action("New Prompt Editor", NewPromptEditor.boxed_clone())
|
||||
}))
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
IconButton::new("open-history", IconName::HistoryRerun)
|
||||
.icon_size(IconSize::Small)
|
||||
.style(ButtonStyle::Subtle)
|
||||
.tooltip({
|
||||
let focus_handle = self.focus_handle(cx);
|
||||
move |window, cx| {
|
||||
Tooltip::for_action_in(
|
||||
"History",
|
||||
&OpenHistory,
|
||||
&focus_handle,
|
||||
window,
|
||||
cx,
|
||||
h_flex()
|
||||
.h_full()
|
||||
.px(DynamicSpacing::Base08.rems(cx))
|
||||
.border_l_1()
|
||||
.border_color(cx.theme().colors().border)
|
||||
.gap(DynamicSpacing::Base02.rems(cx))
|
||||
.child(
|
||||
PopoverMenu::new("assistant-toolbar-new-popover-menu")
|
||||
.trigger_with_tooltip(
|
||||
IconButton::new("new", IconName::Plus)
|
||||
.icon_size(IconSize::Small)
|
||||
.style(ButtonStyle::Subtle),
|
||||
Tooltip::text("New…"),
|
||||
)
|
||||
}
|
||||
})
|
||||
.on_click(move |_event, window, cx| {
|
||||
window.dispatch_action(OpenHistory.boxed_clone(), cx);
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
IconButton::new("configure-assistant", IconName::Settings)
|
||||
.icon_size(IconSize::Small)
|
||||
.style(ButtonStyle::Subtle)
|
||||
.tooltip(Tooltip::text("Assistant Settings"))
|
||||
.on_click(move |_event, window, cx| {
|
||||
window.dispatch_action(OpenConfiguration.boxed_clone(), cx);
|
||||
}),
|
||||
.anchor(Corner::TopRight)
|
||||
.with_handle(self.new_item_context_menu_handle.clone())
|
||||
.menu(move |window, cx| {
|
||||
Some(ContextMenu::build(
|
||||
window,
|
||||
cx,
|
||||
|menu, _window, _cx| {
|
||||
menu.action("New Thread", NewThread.boxed_clone())
|
||||
.action(
|
||||
"New Prompt Editor",
|
||||
NewPromptEditor.boxed_clone(),
|
||||
)
|
||||
},
|
||||
))
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
IconButton::new("open-history", IconName::HistoryRerun)
|
||||
.icon_size(IconSize::Small)
|
||||
.style(ButtonStyle::Subtle)
|
||||
.tooltip({
|
||||
let focus_handle = self.focus_handle(cx);
|
||||
move |window, cx| {
|
||||
Tooltip::for_action_in(
|
||||
"History",
|
||||
&OpenHistory,
|
||||
&focus_handle,
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
}
|
||||
})
|
||||
.on_click(move |_event, window, cx| {
|
||||
window.dispatch_action(OpenHistory.boxed_clone(), cx);
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
IconButton::new("configure-assistant", IconName::Settings)
|
||||
.icon_size(IconSize::Small)
|
||||
.style(ButtonStyle::Subtle)
|
||||
.tooltip(Tooltip::text("Assistant Settings"))
|
||||
.on_click(move |_event, window, cx| {
|
||||
window.dispatch_action(OpenConfiguration.boxed_clone(), cx);
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -705,12 +726,11 @@ impl AssistantPanel {
|
||||
) -> impl IntoElement {
|
||||
let recent_history = self
|
||||
.history_store
|
||||
.update(cx, |this, cx| this.recent_entries(3, cx));
|
||||
.update(cx, |this, cx| this.recent_entries(6, cx));
|
||||
|
||||
let create_welcome_heading = || {
|
||||
h_flex()
|
||||
.w_full()
|
||||
.justify_center()
|
||||
.child(Headline::new("Welcome to the Assistant Panel").size(HeadlineSize::Small))
|
||||
};
|
||||
|
||||
@@ -718,36 +738,27 @@ impl AssistantPanel {
|
||||
let no_error = configuration_error.is_none();
|
||||
|
||||
v_flex()
|
||||
.gap_2()
|
||||
.child(
|
||||
v_flex().w_full().child(
|
||||
svg()
|
||||
.path("icons/logo_96.svg")
|
||||
.text_color(cx.theme().colors().text)
|
||||
.w(px(40.))
|
||||
.h(px(40.))
|
||||
.mx_auto()
|
||||
.mb_4(),
|
||||
),
|
||||
)
|
||||
.p_1p5()
|
||||
.size_full()
|
||||
.justify_end()
|
||||
.gap_1()
|
||||
.map(|parent| {
|
||||
match configuration_error {
|
||||
Some(ConfigurationError::ProviderNotAuthenticated)
|
||||
| Some(ConfigurationError::NoProvider) => {
|
||||
parent.child(
|
||||
v_flex()
|
||||
.px_1p5()
|
||||
.gap_0p5()
|
||||
.child(create_welcome_heading())
|
||||
.child(
|
||||
h_flex().mb_2().w_full().justify_center().child(
|
||||
Label::new(
|
||||
"To start using the assistant, configure at least one LLM provider.",
|
||||
)
|
||||
.color(Color::Muted),
|
||||
),
|
||||
Label::new(
|
||||
"To start using the assistant, configure at least one LLM provider.",
|
||||
)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.child(
|
||||
h_flex().w_full().justify_center().child(
|
||||
h_flex().mt_1().w_full().child(
|
||||
Button::new("open-configuration", "Configure a Provider")
|
||||
.size(ButtonSize::Compact)
|
||||
.icon(Some(IconName::Sliders))
|
||||
@@ -761,7 +772,7 @@ impl AssistantPanel {
|
||||
)
|
||||
}
|
||||
Some(ConfigurationError::ProviderPendingTermsAcceptance(provider)) => parent
|
||||
.child(v_flex().gap_0p5().child(create_welcome_heading()).children(
|
||||
.child(v_flex().px_1p5().gap_0p5().child(create_welcome_heading()).children(
|
||||
provider.render_accept_terms(
|
||||
LanguageModelProviderTosView::ThreadEmptyState,
|
||||
cx,
|
||||
@@ -772,21 +783,40 @@ impl AssistantPanel {
|
||||
})
|
||||
.when(recent_history.is_empty() && no_error, |parent| {
|
||||
parent.child(v_flex().gap_0p5().child(create_welcome_heading()).child(
|
||||
h_flex().w_full().justify_center().child(
|
||||
Label::new("Start typing to chat with your codebase").color(Color::Muted),
|
||||
),
|
||||
Label::new("Start typing to chat with your codebase").color(Color::Muted),
|
||||
))
|
||||
})
|
||||
.when(!recent_history.is_empty(), |parent| {
|
||||
parent
|
||||
.child(
|
||||
h_flex().w_full().justify_center().child(
|
||||
Label::new("Recent Threads:")
|
||||
.size(LabelSize::Small)
|
||||
.color(Color::Muted),
|
||||
),
|
||||
h_flex()
|
||||
.pl_1p5()
|
||||
.pb_1()
|
||||
.w_full()
|
||||
.justify_between()
|
||||
.border_b_1()
|
||||
.border_color(cx.theme().colors().border_variant)
|
||||
.child(
|
||||
Label::new("Past Interactions")
|
||||
.size(LabelSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.child(
|
||||
Button::new("view-history", "View All")
|
||||
.style(ButtonStyle::Subtle)
|
||||
.label_size(LabelSize::Small)
|
||||
.key_binding(KeyBinding::for_action_in(
|
||||
&OpenHistory,
|
||||
&self.focus_handle(cx),
|
||||
window,
|
||||
cx,
|
||||
))
|
||||
.on_click(move |_event, window, cx| {
|
||||
window.dispatch_action(OpenHistory.boxed_clone(), cx);
|
||||
}),
|
||||
),
|
||||
)
|
||||
.child(v_flex().mx_auto().w_4_5().gap_2().children(
|
||||
.child(v_flex().gap_1().children(
|
||||
recent_history.into_iter().map(|entry| {
|
||||
// TODO: Add keyboard navigation.
|
||||
match entry {
|
||||
@@ -801,22 +831,6 @@ impl AssistantPanel {
|
||||
}
|
||||
}),
|
||||
))
|
||||
.child(
|
||||
h_flex().w_full().justify_center().child(
|
||||
Button::new("view-all-past-threads", "View All Past Threads")
|
||||
.style(ButtonStyle::Subtle)
|
||||
.label_size(LabelSize::Small)
|
||||
.key_binding(KeyBinding::for_action_in(
|
||||
&OpenHistory,
|
||||
&self.focus_handle(cx),
|
||||
window,
|
||||
cx,
|
||||
))
|
||||
.on_click(move |_event, window, cx| {
|
||||
window.dispatch_action(OpenHistory.boxed_clone(), cx);
|
||||
}),
|
||||
),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -980,12 +994,21 @@ impl AssistantPanel {
|
||||
)
|
||||
.into_any()
|
||||
}
|
||||
|
||||
fn key_context(&self) -> KeyContext {
|
||||
let mut key_context = KeyContext::new_with_defaults();
|
||||
key_context.add("AssistantPanel2");
|
||||
if matches!(self.active_view, ActiveView::PromptEditor) {
|
||||
key_context.add("prompt_editor");
|
||||
}
|
||||
key_context
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for AssistantPanel {
|
||||
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
v_flex()
|
||||
.key_context("AssistantPanel2")
|
||||
.key_context(self.key_context())
|
||||
.justify_between()
|
||||
.size_full()
|
||||
.on_action(cx.listener(Self::cancel))
|
||||
|
||||
@@ -9,13 +9,12 @@ use futures::{channel::mpsc, future::LocalBoxFuture, join, SinkExt, Stream, Stre
|
||||
use gpui::{App, AppContext as _, Context, Entity, EventEmitter, Subscription, Task};
|
||||
use language::{line_diff, Buffer, IndentKind, Point, TransactionId};
|
||||
use language_model::{
|
||||
LanguageModel, LanguageModelRegistry, LanguageModelRequest, LanguageModelRequestMessage,
|
||||
LanguageModelTextStream, Role,
|
||||
report_assistant_event, LanguageModel, LanguageModelRegistry, LanguageModelRequest,
|
||||
LanguageModelRequestMessage, LanguageModelTextStream, Role,
|
||||
};
|
||||
use language_models::report_assistant_event;
|
||||
use multi_buffer::MultiBufferRow;
|
||||
use parking_lot::Mutex;
|
||||
use prompt_library::PromptBuilder;
|
||||
use prompt_store::PromptBuilder;
|
||||
use rope::Rope;
|
||||
use smol::future::FutureExt;
|
||||
use std::{
|
||||
|
||||
@@ -24,12 +24,11 @@ use gpui::{
|
||||
UpdateGlobal, WeakEntity, Window,
|
||||
};
|
||||
use language::{Buffer, Point, Selection, TransactionId};
|
||||
use language_model::LanguageModelRegistry;
|
||||
use language_models::report_assistant_event;
|
||||
use language_model::{report_assistant_event, LanguageModelRegistry};
|
||||
use multi_buffer::MultiBufferRow;
|
||||
use parking_lot::Mutex;
|
||||
use project::{CodeAction, ProjectTransaction};
|
||||
use prompt_library::PromptBuilder;
|
||||
use prompt_store::PromptBuilder;
|
||||
use settings::{Settings, SettingsStore};
|
||||
use telemetry_events::{AssistantEvent, AssistantKind, AssistantPhase};
|
||||
use terminal_view::{terminal_panel::TerminalPanel, TerminalView};
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::context_strip::{ContextStrip, ContextStripEvent, SuggestContextKind};
|
||||
use crate::terminal_codegen::TerminalCodegen;
|
||||
use crate::thread_store::ThreadStore;
|
||||
use crate::{CycleNextInlineAssist, CyclePreviousInlineAssist};
|
||||
use crate::{RemoveAllContext, ToggleContextPicker, ToggleModelSelector};
|
||||
use crate::{RemoveAllContext, ToggleContextPicker};
|
||||
use client::ErrorExt;
|
||||
use collections::VecDeque;
|
||||
use editor::{
|
||||
@@ -20,7 +20,7 @@ use gpui::{
|
||||
EventEmitter, FocusHandle, Focusable, FontWeight, Subscription, TextStyle, WeakEntity, Window,
|
||||
};
|
||||
use language_model::{LanguageModel, LanguageModelRegistry};
|
||||
use language_model_selector::LanguageModelSelector;
|
||||
use language_model_selector::ToggleModelSelector;
|
||||
use parking_lot::Mutex;
|
||||
use settings::Settings;
|
||||
use std::cmp;
|
||||
@@ -40,7 +40,6 @@ pub struct PromptEditor<T> {
|
||||
context_strip: Entity<ContextStrip>,
|
||||
context_picker_menu_handle: PopoverMenuHandle<ContextPicker>,
|
||||
model_selector: Entity<AssistantModelSelector>,
|
||||
model_selector_menu_handle: PopoverMenuHandle<LanguageModelSelector>,
|
||||
edited_since_done: bool,
|
||||
prompt_history: VecDeque<String>,
|
||||
prompt_history_ix: Option<usize>,
|
||||
@@ -104,7 +103,10 @@ impl<T: 'static> Render for PromptEditor<T> {
|
||||
.items_start()
|
||||
.cursor(CursorStyle::Arrow)
|
||||
.on_action(cx.listener(Self::toggle_context_picker))
|
||||
.on_action(cx.listener(Self::toggle_model_selector))
|
||||
.on_action(cx.listener(|this, _: &ToggleModelSelector, window, cx| {
|
||||
this.model_selector
|
||||
.update(cx, |model_selector, cx| model_selector.toggle(window, cx));
|
||||
}))
|
||||
.on_action(cx.listener(Self::confirm))
|
||||
.on_action(cx.listener(Self::cancel))
|
||||
.on_action(cx.listener(Self::move_up))
|
||||
@@ -347,15 +349,6 @@ impl<T: 'static> PromptEditor<T> {
|
||||
self.context_picker_menu_handle.toggle(window, cx);
|
||||
}
|
||||
|
||||
fn toggle_model_selector(
|
||||
&mut self,
|
||||
_: &ToggleModelSelector,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.model_selector_menu_handle.toggle(window, cx);
|
||||
}
|
||||
|
||||
pub fn remove_all_context(
|
||||
&mut self,
|
||||
_: &RemoveAllContext,
|
||||
@@ -864,7 +857,6 @@ impl PromptEditor<BufferCodegen> {
|
||||
editor
|
||||
});
|
||||
let context_picker_menu_handle = PopoverMenuHandle::default();
|
||||
let model_selector_menu_handle = PopoverMenuHandle::default();
|
||||
|
||||
let context_strip = cx.new(|cx| {
|
||||
ContextStrip::new(
|
||||
@@ -888,15 +880,8 @@ impl PromptEditor<BufferCodegen> {
|
||||
context_strip,
|
||||
context_picker_menu_handle,
|
||||
model_selector: cx.new(|cx| {
|
||||
AssistantModelSelector::new(
|
||||
fs,
|
||||
model_selector_menu_handle.clone(),
|
||||
prompt_editor.focus_handle(cx),
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
AssistantModelSelector::new(fs, prompt_editor.focus_handle(cx), window, cx)
|
||||
}),
|
||||
model_selector_menu_handle,
|
||||
edited_since_done: false,
|
||||
prompt_history,
|
||||
prompt_history_ix: None,
|
||||
@@ -1020,7 +1005,6 @@ impl PromptEditor<TerminalCodegen> {
|
||||
editor
|
||||
});
|
||||
let context_picker_menu_handle = PopoverMenuHandle::default();
|
||||
let model_selector_menu_handle = PopoverMenuHandle::default();
|
||||
|
||||
let context_strip = cx.new(|cx| {
|
||||
ContextStrip::new(
|
||||
@@ -1044,15 +1028,8 @@ impl PromptEditor<TerminalCodegen> {
|
||||
context_strip,
|
||||
context_picker_menu_handle,
|
||||
model_selector: cx.new(|cx| {
|
||||
AssistantModelSelector::new(
|
||||
fs,
|
||||
model_selector_menu_handle.clone(),
|
||||
prompt_editor.focus_handle(cx),
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
AssistantModelSelector::new(fs, prompt_editor.focus_handle(cx), window, cx)
|
||||
}),
|
||||
model_selector_menu_handle,
|
||||
edited_since_done: false,
|
||||
prompt_history,
|
||||
prompt_history_ix: None,
|
||||
|
||||
@@ -7,16 +7,18 @@ use gpui::{
|
||||
pulsating_between, Animation, AnimationExt, App, DismissEvent, Entity, Focusable, Subscription,
|
||||
TextStyle, WeakEntity,
|
||||
};
|
||||
use language_model::{LanguageModelRegistry, LanguageModelRequestTool};
|
||||
use language_model_selector::LanguageModelSelector;
|
||||
use language_model::LanguageModelRegistry;
|
||||
use language_model_selector::ToggleModelSelector;
|
||||
use rope::Point;
|
||||
use settings::Settings;
|
||||
use std::time::Duration;
|
||||
use text::Bias;
|
||||
use theme::{get_ui_font_size, ThemeSettings};
|
||||
use theme::ThemeSettings;
|
||||
use ui::{
|
||||
prelude::*, ButtonLike, KeyBinding, PopoverMenu, PopoverMenuHandle, Switch, TintColor, Tooltip,
|
||||
prelude::*, ButtonLike, KeyBinding, PlatformStyle, PopoverMenu, PopoverMenuHandle, Switch,
|
||||
TintColor, Tooltip,
|
||||
};
|
||||
use vim_mode_setting::VimModeSetting;
|
||||
use workspace::Workspace;
|
||||
|
||||
use crate::assistant_model_selector::AssistantModelSelector;
|
||||
@@ -25,7 +27,7 @@ use crate::context_store::{refresh_context_store_text, ContextStore};
|
||||
use crate::context_strip::{ContextStrip, ContextStripEvent, SuggestContextKind};
|
||||
use crate::thread::{RequestKind, Thread};
|
||||
use crate::thread_store::ThreadStore;
|
||||
use crate::{Chat, ChatMode, RemoveAllContext, ToggleContextPicker, ToggleModelSelector};
|
||||
use crate::{Chat, ChatMode, RemoveAllContext, ToggleContextPicker};
|
||||
|
||||
pub struct MessageEditor {
|
||||
thread: Entity<Thread>,
|
||||
@@ -36,7 +38,6 @@ pub struct MessageEditor {
|
||||
inline_context_picker: Entity<ContextPicker>,
|
||||
inline_context_picker_menu_handle: PopoverMenuHandle<ContextPicker>,
|
||||
model_selector: Entity<AssistantModelSelector>,
|
||||
model_selector_menu_handle: PopoverMenuHandle<LanguageModelSelector>,
|
||||
use_tools: bool,
|
||||
_subscriptions: Vec<Subscription>,
|
||||
}
|
||||
@@ -53,7 +54,6 @@ impl MessageEditor {
|
||||
let context_store = cx.new(|_cx| ContextStore::new(workspace.clone()));
|
||||
let context_picker_menu_handle = PopoverMenuHandle::default();
|
||||
let inline_context_picker_menu_handle = PopoverMenuHandle::default();
|
||||
let model_selector_menu_handle = PopoverMenuHandle::default();
|
||||
|
||||
let editor = cx.new(|cx| {
|
||||
let mut editor = Editor::auto_height(10, window, cx);
|
||||
@@ -106,30 +106,13 @@ impl MessageEditor {
|
||||
context_picker_menu_handle,
|
||||
inline_context_picker,
|
||||
inline_context_picker_menu_handle,
|
||||
model_selector: cx.new(|cx| {
|
||||
AssistantModelSelector::new(
|
||||
fs,
|
||||
model_selector_menu_handle.clone(),
|
||||
editor.focus_handle(cx),
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
}),
|
||||
model_selector_menu_handle,
|
||||
model_selector: cx
|
||||
.new(|cx| AssistantModelSelector::new(fs, editor.focus_handle(cx), window, cx)),
|
||||
use_tools: false,
|
||||
_subscriptions: subscriptions,
|
||||
}
|
||||
}
|
||||
|
||||
fn toggle_model_selector(
|
||||
&mut self,
|
||||
_: &ToggleModelSelector,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.model_selector_menu_handle.toggle(window, cx)
|
||||
}
|
||||
|
||||
fn toggle_chat_mode(&mut self, _: &ChatMode, _window: &mut Window, cx: &mut Context<Self>) {
|
||||
self.use_tools = !self.use_tools;
|
||||
cx.notify();
|
||||
@@ -205,22 +188,7 @@ impl MessageEditor {
|
||||
.update(&mut cx, |thread, cx| {
|
||||
let context = context_store.read(cx).snapshot(cx).collect::<Vec<_>>();
|
||||
thread.insert_user_message(user_message, context, cx);
|
||||
let mut request = thread.to_completion_request(request_kind, cx);
|
||||
|
||||
if use_tools {
|
||||
request.tools = thread
|
||||
.tools()
|
||||
.tools(cx)
|
||||
.into_iter()
|
||||
.map(|tool| LanguageModelRequestTool {
|
||||
name: tool.name(),
|
||||
description: tool.description(),
|
||||
input_schema: tool.input_schema(),
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
|
||||
thread.stream_completion(request, model, cx)
|
||||
thread.send_to_model(model, request_kind, use_tools, cx);
|
||||
})
|
||||
.ok();
|
||||
})
|
||||
@@ -309,7 +277,6 @@ impl Render for MessageEditor {
|
||||
let inline_context_picker = self.inline_context_picker.clone();
|
||||
let bg_color = cx.theme().colors().editor_background;
|
||||
let is_streaming_completion = self.thread.read(cx).is_streaming();
|
||||
let button_width = px(64.);
|
||||
let is_model_selected = self.is_model_selected(cx);
|
||||
let is_editor_empty = self.is_editor_empty(cx);
|
||||
let submit_label_color = if is_editor_empty {
|
||||
@@ -318,10 +285,23 @@ impl Render for MessageEditor {
|
||||
Color::Default
|
||||
};
|
||||
|
||||
let vim_mode_enabled = VimModeSetting::get_global(cx).0;
|
||||
let platform = PlatformStyle::platform();
|
||||
let linux = platform == PlatformStyle::Linux;
|
||||
let windows = platform == PlatformStyle::Windows;
|
||||
let button_width = if linux || windows || vim_mode_enabled {
|
||||
px(92.)
|
||||
} else {
|
||||
px(64.)
|
||||
};
|
||||
|
||||
v_flex()
|
||||
.key_context("MessageEditor")
|
||||
.on_action(cx.listener(Self::chat))
|
||||
.on_action(cx.listener(Self::toggle_model_selector))
|
||||
.on_action(cx.listener(|this, _: &ToggleModelSelector, window, cx| {
|
||||
this.model_selector
|
||||
.update(cx, |model_selector, cx| model_selector.toggle(window, cx));
|
||||
}))
|
||||
.on_action(cx.listener(Self::toggle_context_picker))
|
||||
.on_action(cx.listener(Self::remove_all_context))
|
||||
.on_action(cx.listener(Self::move_up))
|
||||
@@ -333,7 +313,7 @@ impl Render for MessageEditor {
|
||||
.child(self.context_strip.clone())
|
||||
.child(
|
||||
v_flex()
|
||||
.gap_4()
|
||||
.gap_5()
|
||||
.child({
|
||||
let settings = ThemeSettings::get_global(cx);
|
||||
let text_style = TextStyle {
|
||||
@@ -369,7 +349,7 @@ impl Render for MessageEditor {
|
||||
.anchor(gpui::Corner::BottomLeft)
|
||||
.offset(gpui::Point {
|
||||
x: px(0.0),
|
||||
y: (-get_ui_font_size(cx) * 2) - px(4.0),
|
||||
y: (-ThemeSettings::get_global(cx).ui_font_size(cx) * 2) - px(4.0),
|
||||
})
|
||||
.with_handle(self.inline_context_picker_menu_handle.clone()),
|
||||
)
|
||||
|
||||
@@ -2,8 +2,7 @@ use crate::inline_prompt_editor::CodegenStatus;
|
||||
use client::telemetry::Telemetry;
|
||||
use futures::{channel::mpsc, SinkExt, StreamExt};
|
||||
use gpui::{App, AppContext as _, Context, Entity, EventEmitter, Task};
|
||||
use language_model::{LanguageModelRegistry, LanguageModelRequest};
|
||||
use language_models::report_assistant_event;
|
||||
use language_model::{report_assistant_event, LanguageModelRegistry, LanguageModelRequest};
|
||||
use std::{sync::Arc, time::Instant};
|
||||
use telemetry_events::{AssistantEvent, AssistantKind, AssistantPhase};
|
||||
use terminal::Terminal;
|
||||
@@ -156,7 +155,10 @@ pub enum CodegenEvent {
|
||||
Finished,
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
pub const CLEAR_INPUT: &str = "\x15";
|
||||
#[cfg(target_os = "windows")]
|
||||
pub const CLEAR_INPUT: &str = "\x03";
|
||||
const CARRIAGE_RETURN: &str = "\x0d";
|
||||
|
||||
struct TerminalTransaction {
|
||||
|
||||
@@ -13,10 +13,10 @@ use fs::Fs;
|
||||
use gpui::{App, Entity, Focusable, Global, Subscription, UpdateGlobal, WeakEntity};
|
||||
use language::Buffer;
|
||||
use language_model::{
|
||||
LanguageModelRegistry, LanguageModelRequest, LanguageModelRequestMessage, Role,
|
||||
report_assistant_event, LanguageModelRegistry, LanguageModelRequest,
|
||||
LanguageModelRequestMessage, Role,
|
||||
};
|
||||
use language_models::report_assistant_event;
|
||||
use prompt_library::PromptBuilder;
|
||||
use prompt_store::PromptBuilder;
|
||||
use std::sync::Arc;
|
||||
use telemetry_events::{AssistantEvent, AssistantKind, AssistantPhase};
|
||||
use terminal_view::TerminalView;
|
||||
|
||||
@@ -4,29 +4,31 @@ use anyhow::Result;
|
||||
use assistant_tool::ToolWorkingSet;
|
||||
use chrono::{DateTime, Utc};
|
||||
use collections::{BTreeMap, HashMap, HashSet};
|
||||
use futures::future::Shared;
|
||||
use futures::{FutureExt as _, StreamExt as _};
|
||||
use futures::StreamExt as _;
|
||||
use gpui::{App, Context, EventEmitter, SharedString, Task};
|
||||
use language_model::{
|
||||
LanguageModel, LanguageModelCompletionEvent, LanguageModelRegistry, LanguageModelRequest,
|
||||
LanguageModelRequestMessage, LanguageModelToolResult, LanguageModelToolUse,
|
||||
LanguageModelToolUseId, MessageContent, Role, StopReason,
|
||||
LanguageModelRequestMessage, LanguageModelRequestTool, LanguageModelToolResult,
|
||||
LanguageModelToolUseId, MaxMonthlySpendReachedError, MessageContent, PaymentRequiredError,
|
||||
Role, StopReason,
|
||||
};
|
||||
use language_models::provider::cloud::{MaxMonthlySpendReachedError, PaymentRequiredError};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use util::{post_inc, TryFutureExt as _};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::context::{attach_context_to_message, ContextId, ContextSnapshot};
|
||||
use crate::thread_store::SavedThread;
|
||||
use crate::tool_use::{PendingToolUse, ToolUse, ToolUseState};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum RequestKind {
|
||||
Chat,
|
||||
/// Used when summarizing a thread.
|
||||
Summarize,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Serialize, Deserialize)]
|
||||
pub struct ThreadId(Arc<str>);
|
||||
pub struct ThreadId(pub Arc<str>);
|
||||
|
||||
impl ThreadId {
|
||||
pub fn new() -> Self {
|
||||
@@ -41,7 +43,7 @@ impl std::fmt::Display for ThreadId {
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Serialize, Deserialize)]
|
||||
pub struct MessageId(usize);
|
||||
pub struct MessageId(pub(crate) usize);
|
||||
|
||||
impl MessageId {
|
||||
fn post_inc(&mut self) -> Self {
|
||||
@@ -70,9 +72,7 @@ pub struct Thread {
|
||||
completion_count: usize,
|
||||
pending_completions: Vec<PendingCompletion>,
|
||||
tools: Arc<ToolWorkingSet>,
|
||||
tool_uses_by_message: HashMap<MessageId, Vec<LanguageModelToolUse>>,
|
||||
tool_results_by_message: HashMap<MessageId, Vec<LanguageModelToolResult>>,
|
||||
pending_tool_uses_by_id: HashMap<LanguageModelToolUseId, PendingToolUse>,
|
||||
tool_use: ToolUseState,
|
||||
}
|
||||
|
||||
impl Thread {
|
||||
@@ -89,9 +89,7 @@ impl Thread {
|
||||
completion_count: 0,
|
||||
pending_completions: Vec::new(),
|
||||
tools,
|
||||
tool_uses_by_message: HashMap::default(),
|
||||
tool_results_by_message: HashMap::default(),
|
||||
pending_tool_uses_by_id: HashMap::default(),
|
||||
tool_use: ToolUseState::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +99,14 @@ impl Thread {
|
||||
tools: Arc<ToolWorkingSet>,
|
||||
_cx: &mut Context<Self>,
|
||||
) -> Self {
|
||||
let next_message_id = MessageId(saved.messages.len());
|
||||
let next_message_id = MessageId(
|
||||
saved
|
||||
.messages
|
||||
.last()
|
||||
.map(|message| message.id.0 + 1)
|
||||
.unwrap_or(0),
|
||||
);
|
||||
let tool_use = ToolUseState::from_saved_messages(&saved.messages);
|
||||
|
||||
Self {
|
||||
id,
|
||||
@@ -123,9 +128,7 @@ impl Thread {
|
||||
completion_count: 0,
|
||||
pending_completions: Vec::new(),
|
||||
tools,
|
||||
tool_uses_by_message: HashMap::default(),
|
||||
tool_results_by_message: HashMap::default(),
|
||||
pending_tool_uses_by_id: HashMap::default(),
|
||||
tool_use,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,7 +190,19 @@ impl Thread {
|
||||
}
|
||||
|
||||
pub fn pending_tool_uses(&self) -> Vec<&PendingToolUse> {
|
||||
self.pending_tool_uses_by_id.values().collect()
|
||||
self.tool_use.pending_tool_uses()
|
||||
}
|
||||
|
||||
pub fn tool_uses_for_message(&self, id: MessageId) -> Vec<ToolUse> {
|
||||
self.tool_use.tool_uses_for_message(id)
|
||||
}
|
||||
|
||||
pub fn tool_results_for_message(&self, id: MessageId) -> Vec<&LanguageModelToolResult> {
|
||||
self.tool_use.tool_results_for_message(id)
|
||||
}
|
||||
|
||||
pub fn message_has_tool_results(&self, message_id: MessageId) -> bool {
|
||||
self.tool_use.message_has_tool_results(message_id)
|
||||
}
|
||||
|
||||
pub fn insert_user_message(
|
||||
@@ -220,6 +235,34 @@ impl Thread {
|
||||
id
|
||||
}
|
||||
|
||||
pub fn edit_message(
|
||||
&mut self,
|
||||
id: MessageId,
|
||||
new_role: Role,
|
||||
new_text: String,
|
||||
cx: &mut Context<Self>,
|
||||
) -> bool {
|
||||
let Some(message) = self.messages.iter_mut().find(|message| message.id == id) else {
|
||||
return false;
|
||||
};
|
||||
message.role = new_role;
|
||||
message.text = new_text;
|
||||
self.touch_updated_at();
|
||||
cx.emit(ThreadEvent::MessageEdited(id));
|
||||
true
|
||||
}
|
||||
|
||||
pub fn delete_message(&mut self, id: MessageId, cx: &mut Context<Self>) -> bool {
|
||||
let Some(index) = self.messages.iter().position(|message| message.id == id) else {
|
||||
return false;
|
||||
};
|
||||
self.messages.remove(index);
|
||||
self.context_by_message.remove(&id);
|
||||
self.touch_updated_at();
|
||||
cx.emit(ThreadEvent::MessageDeleted(id));
|
||||
true
|
||||
}
|
||||
|
||||
/// Returns the representation of this [`Thread`] in a textual form.
|
||||
///
|
||||
/// This is the representation we use when attaching a thread as context to another thread.
|
||||
@@ -241,9 +284,34 @@ impl Thread {
|
||||
text
|
||||
}
|
||||
|
||||
pub fn send_to_model(
|
||||
&mut self,
|
||||
model: Arc<dyn LanguageModel>,
|
||||
request_kind: RequestKind,
|
||||
use_tools: bool,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let mut request = self.to_completion_request(request_kind, cx);
|
||||
|
||||
if use_tools {
|
||||
request.tools = self
|
||||
.tools()
|
||||
.tools(cx)
|
||||
.into_iter()
|
||||
.map(|tool| LanguageModelRequestTool {
|
||||
name: tool.name(),
|
||||
description: tool.description(),
|
||||
input_schema: tool.input_schema(),
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
|
||||
self.stream_completion(request, model, cx);
|
||||
}
|
||||
|
||||
pub fn to_completion_request(
|
||||
&self,
|
||||
_request_kind: RequestKind,
|
||||
request_kind: RequestKind,
|
||||
_cx: &App,
|
||||
) -> LanguageModelRequest {
|
||||
let mut request = LanguageModelRequest {
|
||||
@@ -265,12 +333,13 @@ impl Thread {
|
||||
content: Vec::new(),
|
||||
cache: false,
|
||||
};
|
||||
|
||||
if let Some(tool_results) = self.tool_results_by_message.get(&message.id) {
|
||||
for tool_result in tool_results {
|
||||
request_message
|
||||
.content
|
||||
.push(MessageContent::ToolResult(tool_result.clone()));
|
||||
match request_kind {
|
||||
RequestKind::Chat => {
|
||||
self.tool_use
|
||||
.attach_tool_results(message.id, &mut request_message);
|
||||
}
|
||||
RequestKind::Summarize => {
|
||||
// We don't care about tool use during summarization.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,11 +349,13 @@ impl Thread {
|
||||
.push(MessageContent::Text(message.text.clone()));
|
||||
}
|
||||
|
||||
if let Some(tool_uses) = self.tool_uses_by_message.get(&message.id) {
|
||||
for tool_use in tool_uses {
|
||||
request_message
|
||||
.content
|
||||
.push(MessageContent::ToolUse(tool_use.clone()));
|
||||
match request_kind {
|
||||
RequestKind::Chat => {
|
||||
self.tool_use
|
||||
.attach_tool_uses(message.id, &mut request_message);
|
||||
}
|
||||
RequestKind::Summarize => {
|
||||
// We don't care about tool use during summarization.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,21 +431,8 @@ impl Thread {
|
||||
.rfind(|message| message.role == Role::Assistant)
|
||||
{
|
||||
thread
|
||||
.tool_uses_by_message
|
||||
.entry(last_assistant_message.id)
|
||||
.or_default()
|
||||
.push(tool_use.clone());
|
||||
|
||||
thread.pending_tool_uses_by_id.insert(
|
||||
tool_use.id.clone(),
|
||||
PendingToolUse {
|
||||
assistant_message_id: last_assistant_message.id,
|
||||
id: tool_use.id,
|
||||
name: tool_use.name,
|
||||
input: tool_use.input,
|
||||
status: PendingToolUseStatus::Idle,
|
||||
},
|
||||
);
|
||||
.tool_use
|
||||
.request_tool_use(last_assistant_message.id, tool_use);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -451,7 +509,7 @@ impl Thread {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut request = self.to_completion_request(RequestKind::Chat, cx);
|
||||
let mut request = self.to_completion_request(RequestKind::Summarize, cx);
|
||||
request.messages.push(LanguageModelRequestMessage {
|
||||
role: Role::User,
|
||||
content: vec![
|
||||
@@ -494,7 +552,6 @@ impl Thread {
|
||||
|
||||
pub fn insert_tool_output(
|
||||
&mut self,
|
||||
assistant_message_id: MessageId,
|
||||
tool_use_id: LanguageModelToolUseId,
|
||||
output: Task<Result<String>>,
|
||||
cx: &mut Context<Self>,
|
||||
@@ -505,50 +562,18 @@ impl Thread {
|
||||
let output = output.await;
|
||||
thread
|
||||
.update(&mut cx, |thread, cx| {
|
||||
// The tool use was requested by an Assistant message,
|
||||
// so we want to attach the tool results to the next
|
||||
// user message.
|
||||
let next_user_message = MessageId(assistant_message_id.0 + 1);
|
||||
thread
|
||||
.tool_use
|
||||
.insert_tool_output(tool_use_id.clone(), output);
|
||||
|
||||
let tool_results = thread
|
||||
.tool_results_by_message
|
||||
.entry(next_user_message)
|
||||
.or_default();
|
||||
|
||||
match output {
|
||||
Ok(output) => {
|
||||
tool_results.push(LanguageModelToolResult {
|
||||
tool_use_id: tool_use_id.to_string(),
|
||||
content: output,
|
||||
is_error: false,
|
||||
});
|
||||
|
||||
cx.emit(ThreadEvent::ToolFinished { tool_use_id });
|
||||
}
|
||||
Err(err) => {
|
||||
tool_results.push(LanguageModelToolResult {
|
||||
tool_use_id: tool_use_id.to_string(),
|
||||
content: err.to_string(),
|
||||
is_error: true,
|
||||
});
|
||||
|
||||
if let Some(tool_use) =
|
||||
thread.pending_tool_uses_by_id.get_mut(&tool_use_id)
|
||||
{
|
||||
tool_use.status = PendingToolUseStatus::Error(err.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
cx.emit(ThreadEvent::ToolFinished { tool_use_id });
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(tool_use) = self.pending_tool_uses_by_id.get_mut(&tool_use_id) {
|
||||
tool_use.status = PendingToolUseStatus::Running {
|
||||
_task: insert_output_task.shared(),
|
||||
};
|
||||
}
|
||||
self.tool_use
|
||||
.run_pending_tool(tool_use_id, insert_output_task);
|
||||
}
|
||||
|
||||
/// Cancels the last pending completion, if there are any pending.
|
||||
@@ -576,6 +601,8 @@ pub enum ThreadEvent {
|
||||
StreamedCompletion,
|
||||
StreamedAssistantText(MessageId, String),
|
||||
MessageAdded(MessageId),
|
||||
MessageEdited(MessageId),
|
||||
MessageDeleted(MessageId),
|
||||
SummaryChanged,
|
||||
UsePendingTools,
|
||||
ToolFinished {
|
||||
@@ -590,26 +617,3 @@ struct PendingCompletion {
|
||||
id: usize,
|
||||
_task: Task<()>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PendingToolUse {
|
||||
pub id: LanguageModelToolUseId,
|
||||
/// The ID of the Assistant message in which the tool use was requested.
|
||||
pub assistant_message_id: MessageId,
|
||||
pub name: String,
|
||||
pub input: serde_json::Value,
|
||||
pub status: PendingToolUseStatus,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PendingToolUseStatus {
|
||||
Idle,
|
||||
Running { _task: Shared<Task<()>> },
|
||||
Error(#[allow(unused)] String),
|
||||
}
|
||||
|
||||
impl PendingToolUseStatus {
|
||||
pub fn is_idle(&self) -> bool {
|
||||
matches!(self, PendingToolUseStatus::Idle)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,9 +33,9 @@ impl ThreadHistory {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn select_prev(
|
||||
pub fn select_previous(
|
||||
&mut self,
|
||||
_: &menu::SelectPrev,
|
||||
_: &menu::SelectPrevious,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
@@ -134,7 +134,13 @@ impl ThreadHistory {
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
HistoryEntry::Context(_context) => {}
|
||||
HistoryEntry::Context(context) => {
|
||||
self.assistant_panel
|
||||
.update(cx, |this, cx| {
|
||||
this.delete_context(context.path.clone(), cx);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
cx.notify();
|
||||
@@ -160,7 +166,7 @@ impl Render for ThreadHistory {
|
||||
.overflow_y_scroll()
|
||||
.size_full()
|
||||
.p_1()
|
||||
.on_action(cx.listener(Self::select_prev))
|
||||
.on_action(cx.listener(Self::select_previous))
|
||||
.on_action(cx.listener(Self::select_next))
|
||||
.on_action(cx.listener(Self::select_first))
|
||||
.on_action(cx.listener(Self::select_last))
|
||||
@@ -248,18 +254,28 @@ impl RenderOnce for PastThread {
|
||||
);
|
||||
|
||||
ListItem::new(SharedString::from(self.thread.id.to_string()))
|
||||
.outlined()
|
||||
.rounded()
|
||||
.toggle_state(self.selected)
|
||||
.start_slot(
|
||||
Icon::new(IconName::MessageCircle)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.spacing(ListItemSpacing::Sparse)
|
||||
.child(Label::new(summary).size(LabelSize::Small).text_ellipsis())
|
||||
.start_slot(
|
||||
div()
|
||||
.max_w_4_5()
|
||||
.child(Label::new(summary).size(LabelSize::Small).truncate()),
|
||||
)
|
||||
.end_slot(
|
||||
h_flex()
|
||||
.gap_1p5()
|
||||
.child(
|
||||
Label::new("Thread")
|
||||
.color(Color::Muted)
|
||||
.size(LabelSize::XSmall),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.size(px(3.))
|
||||
.rounded_full()
|
||||
.bg(cx.theme().colors().text_disabled),
|
||||
)
|
||||
.child(
|
||||
Label::new(thread_timestamp)
|
||||
.color(Color::Muted)
|
||||
@@ -334,21 +350,50 @@ impl RenderOnce for PastContext {
|
||||
ListItem::new(SharedString::from(
|
||||
self.context.path.to_string_lossy().to_string(),
|
||||
))
|
||||
.outlined()
|
||||
.rounded()
|
||||
.toggle_state(self.selected)
|
||||
.start_slot(
|
||||
Icon::new(IconName::Code)
|
||||
.size(IconSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.spacing(ListItemSpacing::Sparse)
|
||||
.child(Label::new(summary).size(LabelSize::Small).text_ellipsis())
|
||||
.start_slot(
|
||||
div()
|
||||
.max_w_4_5()
|
||||
.child(Label::new(summary).size(LabelSize::Small).truncate()),
|
||||
)
|
||||
.end_slot(
|
||||
h_flex().gap_1p5().child(
|
||||
Label::new(context_timestamp)
|
||||
.color(Color::Muted)
|
||||
.size(LabelSize::XSmall),
|
||||
),
|
||||
h_flex()
|
||||
.gap_1p5()
|
||||
.child(
|
||||
Label::new("Prompt Editor")
|
||||
.color(Color::Muted)
|
||||
.size(LabelSize::XSmall),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.size(px(3.))
|
||||
.rounded_full()
|
||||
.bg(cx.theme().colors().text_disabled),
|
||||
)
|
||||
.child(
|
||||
Label::new(context_timestamp)
|
||||
.color(Color::Muted)
|
||||
.size(LabelSize::XSmall),
|
||||
)
|
||||
.child(
|
||||
IconButton::new("delete", IconName::TrashAlt)
|
||||
.shape(IconButtonShape::Square)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.tooltip(Tooltip::text("Delete Prompt Editor"))
|
||||
.on_click({
|
||||
let assistant_panel = self.assistant_panel.clone();
|
||||
let path = self.context.path.clone();
|
||||
move |_event, _window, cx| {
|
||||
assistant_panel
|
||||
.update(cx, |this, cx| {
|
||||
this.delete_context(path.clone(), cx);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}),
|
||||
),
|
||||
)
|
||||
.on_click({
|
||||
let assistant_panel = self.assistant_panel.clone();
|
||||
|
||||
@@ -12,9 +12,9 @@ use futures::FutureExt as _;
|
||||
use gpui::{
|
||||
prelude::*, App, BackgroundExecutor, Context, Entity, Global, ReadGlobal, SharedString, Task,
|
||||
};
|
||||
use heed::types::SerdeBincode;
|
||||
use heed::types::{SerdeBincode, SerdeJson};
|
||||
use heed::Database;
|
||||
use language_model::Role;
|
||||
use language_model::{LanguageModelToolUseId, Role};
|
||||
use project::Project;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use util::ResultExt as _;
|
||||
@@ -113,6 +113,24 @@ impl ThreadStore {
|
||||
id: message.id,
|
||||
role: message.role,
|
||||
text: message.text.clone(),
|
||||
tool_uses: thread
|
||||
.tool_uses_for_message(message.id)
|
||||
.into_iter()
|
||||
.map(|tool_use| SavedToolUse {
|
||||
id: tool_use.id,
|
||||
name: tool_use.name,
|
||||
input: tool_use.input,
|
||||
})
|
||||
.collect(),
|
||||
tool_results: thread
|
||||
.tool_results_for_message(message.id)
|
||||
.into_iter()
|
||||
.map(|tool_result| SavedToolResult {
|
||||
tool_use_id: tool_result.tool_use_id.clone(),
|
||||
is_error: tool_result.is_error,
|
||||
content: tool_result.content.clone(),
|
||||
})
|
||||
.collect(),
|
||||
})
|
||||
.collect(),
|
||||
};
|
||||
@@ -239,11 +257,29 @@ pub struct SavedThread {
|
||||
pub messages: Vec<SavedMessage>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct SavedMessage {
|
||||
pub id: MessageId,
|
||||
pub role: Role,
|
||||
pub text: String,
|
||||
#[serde(default)]
|
||||
pub tool_uses: Vec<SavedToolUse>,
|
||||
#[serde(default)]
|
||||
pub tool_results: Vec<SavedToolResult>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct SavedToolUse {
|
||||
pub id: LanguageModelToolUseId,
|
||||
pub name: SharedString,
|
||||
pub input: serde_json::Value,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct SavedToolResult {
|
||||
pub tool_use_id: LanguageModelToolUseId,
|
||||
pub is_error: bool,
|
||||
pub content: Arc<str>,
|
||||
}
|
||||
|
||||
struct GlobalThreadsDatabase(
|
||||
@@ -255,7 +291,7 @@ impl Global for GlobalThreadsDatabase {}
|
||||
pub(crate) struct ThreadsDatabase {
|
||||
executor: BackgroundExecutor,
|
||||
env: heed::Env,
|
||||
threads: Database<SerdeBincode<ThreadId>, SerdeBincode<SavedThread>>,
|
||||
threads: Database<SerdeBincode<ThreadId>, SerdeJson<SavedThread>>,
|
||||
}
|
||||
|
||||
impl ThreadsDatabase {
|
||||
@@ -270,7 +306,7 @@ impl ThreadsDatabase {
|
||||
let database_future = executor
|
||||
.spawn({
|
||||
let executor = executor.clone();
|
||||
let database_path = paths::support_dir().join("threads/threads-db.0.mdb");
|
||||
let database_path = paths::support_dir().join("threads/threads-db.1.mdb");
|
||||
async move { ThreadsDatabase::new(database_path, executor) }
|
||||
})
|
||||
.then(|result| future::ready(result.map(Arc::new).map_err(Arc::new)))
|
||||
|
||||
291
crates/assistant2/src/tool_use.rs
Normal file
291
crates/assistant2/src/tool_use.rs
Normal file
@@ -0,0 +1,291 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::Result;
|
||||
use collections::HashMap;
|
||||
use futures::future::Shared;
|
||||
use futures::FutureExt as _;
|
||||
use gpui::{SharedString, Task};
|
||||
use language_model::{
|
||||
LanguageModelRequestMessage, LanguageModelToolResult, LanguageModelToolUse,
|
||||
LanguageModelToolUseId, MessageContent, Role,
|
||||
};
|
||||
|
||||
use crate::thread::MessageId;
|
||||
use crate::thread_store::SavedMessage;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ToolUse {
|
||||
pub id: LanguageModelToolUseId,
|
||||
pub name: SharedString,
|
||||
pub status: ToolUseStatus,
|
||||
pub input: serde_json::Value,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ToolUseStatus {
|
||||
Pending,
|
||||
Running,
|
||||
Finished(SharedString),
|
||||
Error(SharedString),
|
||||
}
|
||||
|
||||
pub struct ToolUseState {
|
||||
tool_uses_by_assistant_message: HashMap<MessageId, Vec<LanguageModelToolUse>>,
|
||||
tool_uses_by_user_message: HashMap<MessageId, Vec<LanguageModelToolUseId>>,
|
||||
tool_results: HashMap<LanguageModelToolUseId, LanguageModelToolResult>,
|
||||
pending_tool_uses_by_id: HashMap<LanguageModelToolUseId, PendingToolUse>,
|
||||
}
|
||||
|
||||
impl ToolUseState {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
tool_uses_by_assistant_message: HashMap::default(),
|
||||
tool_uses_by_user_message: HashMap::default(),
|
||||
tool_results: HashMap::default(),
|
||||
pending_tool_uses_by_id: HashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_saved_messages(messages: &[SavedMessage]) -> Self {
|
||||
let mut this = Self::new();
|
||||
|
||||
for message in messages {
|
||||
match message.role {
|
||||
Role::Assistant => {
|
||||
if !message.tool_uses.is_empty() {
|
||||
this.tool_uses_by_assistant_message.insert(
|
||||
message.id,
|
||||
message
|
||||
.tool_uses
|
||||
.iter()
|
||||
.map(|tool_use| LanguageModelToolUse {
|
||||
id: tool_use.id.clone(),
|
||||
name: tool_use.name.clone().into(),
|
||||
input: tool_use.input.clone(),
|
||||
})
|
||||
.collect(),
|
||||
);
|
||||
}
|
||||
}
|
||||
Role::User => {
|
||||
if !message.tool_results.is_empty() {
|
||||
let tool_uses_by_user_message = this
|
||||
.tool_uses_by_user_message
|
||||
.entry(message.id)
|
||||
.or_default();
|
||||
|
||||
for tool_result in &message.tool_results {
|
||||
let tool_use_id = tool_result.tool_use_id.clone();
|
||||
|
||||
tool_uses_by_user_message.push(tool_use_id.clone());
|
||||
this.tool_results.insert(
|
||||
tool_use_id.clone(),
|
||||
LanguageModelToolResult {
|
||||
tool_use_id,
|
||||
is_error: tool_result.is_error,
|
||||
content: tool_result.content.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Role::System => {}
|
||||
}
|
||||
}
|
||||
|
||||
this
|
||||
}
|
||||
|
||||
pub fn pending_tool_uses(&self) -> Vec<&PendingToolUse> {
|
||||
self.pending_tool_uses_by_id.values().collect()
|
||||
}
|
||||
|
||||
pub fn tool_uses_for_message(&self, id: MessageId) -> Vec<ToolUse> {
|
||||
let Some(tool_uses_for_message) = &self.tool_uses_by_assistant_message.get(&id) else {
|
||||
return Vec::new();
|
||||
};
|
||||
|
||||
let mut tool_uses = Vec::new();
|
||||
|
||||
for tool_use in tool_uses_for_message.iter() {
|
||||
let tool_result = self.tool_results.get(&tool_use.id);
|
||||
|
||||
let status = (|| {
|
||||
if let Some(tool_result) = tool_result {
|
||||
return if tool_result.is_error {
|
||||
ToolUseStatus::Error(tool_result.content.clone().into())
|
||||
} else {
|
||||
ToolUseStatus::Finished(tool_result.content.clone().into())
|
||||
};
|
||||
}
|
||||
|
||||
if let Some(pending_tool_use) = self.pending_tool_uses_by_id.get(&tool_use.id) {
|
||||
return match pending_tool_use.status {
|
||||
PendingToolUseStatus::Idle => ToolUseStatus::Pending,
|
||||
PendingToolUseStatus::Running { .. } => ToolUseStatus::Running,
|
||||
PendingToolUseStatus::Error(ref err) => {
|
||||
ToolUseStatus::Error(err.clone().into())
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ToolUseStatus::Pending
|
||||
})();
|
||||
|
||||
tool_uses.push(ToolUse {
|
||||
id: tool_use.id.clone(),
|
||||
name: tool_use.name.clone().into(),
|
||||
input: tool_use.input.clone(),
|
||||
status,
|
||||
})
|
||||
}
|
||||
|
||||
tool_uses
|
||||
}
|
||||
|
||||
pub fn tool_results_for_message(&self, message_id: MessageId) -> Vec<&LanguageModelToolResult> {
|
||||
let empty = Vec::new();
|
||||
|
||||
self.tool_uses_by_user_message
|
||||
.get(&message_id)
|
||||
.unwrap_or(&empty)
|
||||
.iter()
|
||||
.filter_map(|tool_use_id| self.tool_results.get(&tool_use_id))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn message_has_tool_results(&self, message_id: MessageId) -> bool {
|
||||
self.tool_uses_by_user_message
|
||||
.get(&message_id)
|
||||
.map_or(false, |results| !results.is_empty())
|
||||
}
|
||||
|
||||
pub fn request_tool_use(
|
||||
&mut self,
|
||||
assistant_message_id: MessageId,
|
||||
tool_use: LanguageModelToolUse,
|
||||
) {
|
||||
self.tool_uses_by_assistant_message
|
||||
.entry(assistant_message_id)
|
||||
.or_default()
|
||||
.push(tool_use.clone());
|
||||
|
||||
// The tool use is being requested by the Assistant, so we want to
|
||||
// attach the tool results to the next user message.
|
||||
let next_user_message_id = MessageId(assistant_message_id.0 + 1);
|
||||
self.tool_uses_by_user_message
|
||||
.entry(next_user_message_id)
|
||||
.or_default()
|
||||
.push(tool_use.id.clone());
|
||||
|
||||
self.pending_tool_uses_by_id.insert(
|
||||
tool_use.id.clone(),
|
||||
PendingToolUse {
|
||||
assistant_message_id,
|
||||
id: tool_use.id,
|
||||
name: tool_use.name,
|
||||
input: tool_use.input,
|
||||
status: PendingToolUseStatus::Idle,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
pub fn run_pending_tool(&mut self, tool_use_id: LanguageModelToolUseId, task: Task<()>) {
|
||||
if let Some(tool_use) = self.pending_tool_uses_by_id.get_mut(&tool_use_id) {
|
||||
tool_use.status = PendingToolUseStatus::Running {
|
||||
_task: task.shared(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_tool_output(
|
||||
&mut self,
|
||||
tool_use_id: LanguageModelToolUseId,
|
||||
output: Result<String>,
|
||||
) {
|
||||
match output {
|
||||
Ok(output) => {
|
||||
self.tool_results.insert(
|
||||
tool_use_id.clone(),
|
||||
LanguageModelToolResult {
|
||||
tool_use_id: tool_use_id.clone(),
|
||||
content: output.into(),
|
||||
is_error: false,
|
||||
},
|
||||
);
|
||||
self.pending_tool_uses_by_id.remove(&tool_use_id);
|
||||
}
|
||||
Err(err) => {
|
||||
self.tool_results.insert(
|
||||
tool_use_id.clone(),
|
||||
LanguageModelToolResult {
|
||||
tool_use_id: tool_use_id.clone(),
|
||||
content: err.to_string().into(),
|
||||
is_error: true,
|
||||
},
|
||||
);
|
||||
|
||||
if let Some(tool_use) = self.pending_tool_uses_by_id.get_mut(&tool_use_id) {
|
||||
tool_use.status = PendingToolUseStatus::Error(err.to_string().into());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn attach_tool_uses(
|
||||
&self,
|
||||
message_id: MessageId,
|
||||
request_message: &mut LanguageModelRequestMessage,
|
||||
) {
|
||||
if let Some(tool_uses) = self.tool_uses_by_assistant_message.get(&message_id) {
|
||||
for tool_use in tool_uses {
|
||||
request_message
|
||||
.content
|
||||
.push(MessageContent::ToolUse(tool_use.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn attach_tool_results(
|
||||
&self,
|
||||
message_id: MessageId,
|
||||
request_message: &mut LanguageModelRequestMessage,
|
||||
) {
|
||||
if let Some(tool_uses) = self.tool_uses_by_user_message.get(&message_id) {
|
||||
for tool_use_id in tool_uses {
|
||||
if let Some(tool_result) = self.tool_results.get(tool_use_id) {
|
||||
request_message
|
||||
.content
|
||||
.push(MessageContent::ToolResult(tool_result.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PendingToolUse {
|
||||
pub id: LanguageModelToolUseId,
|
||||
/// The ID of the Assistant message in which the tool use was requested.
|
||||
pub assistant_message_id: MessageId,
|
||||
pub name: Arc<str>,
|
||||
pub input: serde_json::Value,
|
||||
pub status: PendingToolUseStatus,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PendingToolUseStatus {
|
||||
Idle,
|
||||
Running { _task: Shared<Task<()>> },
|
||||
Error(#[allow(unused)] Arc<str>),
|
||||
}
|
||||
|
||||
impl PendingToolUseStatus {
|
||||
pub fn is_idle(&self) -> bool {
|
||||
matches!(self, PendingToolUseStatus::Idle)
|
||||
}
|
||||
|
||||
pub fn is_error(&self) -> bool {
|
||||
matches!(self, PendingToolUseStatus::Error(_))
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,6 @@ indexed_docs.workspace = true
|
||||
language.workspace = true
|
||||
language_model.workspace = true
|
||||
language_model_selector.workspace = true
|
||||
language_models.workspace = true
|
||||
log.workspace = true
|
||||
multi_buffer.workspace = true
|
||||
open_ai.workspace = true
|
||||
@@ -38,7 +37,7 @@ parking_lot.workspace = true
|
||||
paths.workspace = true
|
||||
picker.workspace = true
|
||||
project.workspace = true
|
||||
prompt_library.workspace = true
|
||||
prompt_store.workspace = true
|
||||
regex.workspace = true
|
||||
rope.workspace = true
|
||||
rpc.workspace = true
|
||||
|
||||
@@ -19,18 +19,15 @@ use gpui::{
|
||||
};
|
||||
use language::{AnchorRangeExt, Bias, Buffer, LanguageRegistry, OffsetRangeExt, Point, ToOffset};
|
||||
use language_model::{
|
||||
LanguageModel, LanguageModelCacheConfiguration, LanguageModelCompletionEvent,
|
||||
LanguageModelImage, LanguageModelRegistry, LanguageModelRequest, LanguageModelRequestMessage,
|
||||
LanguageModelToolUseId, MessageContent, Role, StopReason,
|
||||
};
|
||||
use language_models::{
|
||||
provider::cloud::{MaxMonthlySpendReachedError, PaymentRequiredError},
|
||||
report_assistant_event,
|
||||
report_assistant_event, LanguageModel, LanguageModelCacheConfiguration,
|
||||
LanguageModelCompletionEvent, LanguageModelImage, LanguageModelRegistry, LanguageModelRequest,
|
||||
LanguageModelRequestMessage, LanguageModelToolUseId, MaxMonthlySpendReachedError,
|
||||
MessageContent, PaymentRequiredError, Role, StopReason,
|
||||
};
|
||||
use open_ai::Model as OpenAiModel;
|
||||
use paths::contexts_dir;
|
||||
use project::Project;
|
||||
use prompt_library::PromptBuilder;
|
||||
use prompt_store::PromptBuilder;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use smallvec::SmallVec;
|
||||
use std::{
|
||||
|
||||
@@ -20,7 +20,7 @@ use language_model::{LanguageModelCacheConfiguration, LanguageModelRegistry, Rol
|
||||
use parking_lot::Mutex;
|
||||
use pretty_assertions::assert_eq;
|
||||
use project::Project;
|
||||
use prompt_library::PromptBuilder;
|
||||
use prompt_store::PromptBuilder;
|
||||
use rand::prelude::*;
|
||||
use serde_json::json;
|
||||
use settings::SettingsStore;
|
||||
@@ -671,7 +671,7 @@ async fn test_slash_commands(cx: &mut TestAppContext) {
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_workflow_step_parsing(cx: &mut TestAppContext) {
|
||||
cx.update(prompt_library::init);
|
||||
cx.update(prompt_store::init);
|
||||
let mut settings_store = cx.update(SettingsStore::test);
|
||||
cx.update(|cx| {
|
||||
settings_store
|
||||
|
||||
@@ -29,19 +29,24 @@ use gpui::{
|
||||
WeakEntity,
|
||||
};
|
||||
use indexed_docs::IndexedDocsStore;
|
||||
use language::{language_settings::SoftWrap, BufferSnapshot, LspAdapterDelegate, ToOffset};
|
||||
use language::{
|
||||
language_settings::{all_language_settings, SoftWrap},
|
||||
BufferSnapshot, LspAdapterDelegate, ToOffset,
|
||||
};
|
||||
use language_model::{
|
||||
LanguageModelImage, LanguageModelProvider, LanguageModelProviderTosView, LanguageModelRegistry,
|
||||
Role,
|
||||
};
|
||||
use language_model_selector::{LanguageModelSelector, LanguageModelSelectorPopoverMenu};
|
||||
use language_model_selector::{
|
||||
assistant_language_model_selector, LanguageModelSelector, ToggleModelSelector,
|
||||
};
|
||||
use multi_buffer::MultiBufferRow;
|
||||
use picker::Picker;
|
||||
use project::lsp_store::LocalLspAdapterDelegate;
|
||||
use project::{Project, Worktree};
|
||||
use rope::Point;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{update_settings_file, Settings};
|
||||
use settings::{update_settings_file, Settings, SettingsStore};
|
||||
use std::{any::TypeId, borrow::Cow, cmp, ops::Range, path::PathBuf, sync::Arc, time::Duration};
|
||||
use text::SelectionGoal;
|
||||
use ui::{
|
||||
@@ -49,7 +54,7 @@ use ui::{
|
||||
Tooltip,
|
||||
};
|
||||
use util::{maybe, ResultExt};
|
||||
use workspace::searchable::SearchableItemHandle;
|
||||
use workspace::searchable::{Direction, SearchableItemHandle};
|
||||
use workspace::{
|
||||
item::{self, FollowableItem, Item, ItemHandle},
|
||||
notifications::NotificationId,
|
||||
@@ -77,7 +82,6 @@ actions!(
|
||||
InsertIntoEditor,
|
||||
QuoteSelection,
|
||||
Split,
|
||||
ToggleModelSelector,
|
||||
]
|
||||
);
|
||||
|
||||
@@ -193,8 +197,7 @@ pub struct ContextEditor {
|
||||
// the file is opened. In order to keep the worktree alive for the duration of the
|
||||
// context editor, we keep a reference here.
|
||||
dragged_file_worktrees: Vec<Entity<Worktree>>,
|
||||
language_model_selector: Entity<LanguageModelSelector>,
|
||||
language_model_selector_menu_handle: PopoverMenuHandle<LanguageModelSelector>,
|
||||
language_model_selector: PopoverMenuHandle<LanguageModelSelector>,
|
||||
}
|
||||
|
||||
pub const DEFAULT_TAB_TITLE: &str = "New Chat";
|
||||
@@ -230,6 +233,13 @@ impl ContextEditor {
|
||||
editor.set_completion_provider(Some(Box::new(completion_provider)));
|
||||
editor.set_menu_inline_completions_policy(MenuInlineCompletionsPolicy::Never);
|
||||
editor.set_collaboration_hub(Box::new(project.clone()));
|
||||
|
||||
let show_edit_predictions = all_language_settings(None, cx)
|
||||
.edit_predictions
|
||||
.enabled_in_assistant;
|
||||
|
||||
editor.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
|
||||
|
||||
editor
|
||||
});
|
||||
|
||||
@@ -238,24 +248,9 @@ impl ContextEditor {
|
||||
cx.subscribe_in(&context, window, Self::handle_context_event),
|
||||
cx.subscribe_in(&editor, window, Self::handle_editor_event),
|
||||
cx.subscribe_in(&editor, window, Self::handle_editor_search_event),
|
||||
cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
|
||||
];
|
||||
|
||||
let fs_clone = fs.clone();
|
||||
let language_model_selector = cx.new(|cx| {
|
||||
LanguageModelSelector::new(
|
||||
move |model, cx| {
|
||||
update_settings_file::<AssistantSettings>(
|
||||
fs_clone.clone(),
|
||||
cx,
|
||||
move |settings, _| settings.set_model(model.clone()),
|
||||
);
|
||||
},
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
let language_model_selector_menu_handle = PopoverMenuHandle::default();
|
||||
let sections = context.read(cx).slash_command_output_sections().to_vec();
|
||||
let patch_ranges = context.read(cx).patch_ranges().collect::<Vec<_>>();
|
||||
let slash_commands = context.read(cx).slash_commands().clone();
|
||||
@@ -280,8 +275,7 @@ impl ContextEditor {
|
||||
show_accept_terms: false,
|
||||
slash_menu_handle: Default::default(),
|
||||
dragged_file_worktrees: Vec::new(),
|
||||
language_model_selector,
|
||||
language_model_selector_menu_handle,
|
||||
language_model_selector: PopoverMenuHandle::default(),
|
||||
};
|
||||
this.update_message_headers(cx);
|
||||
this.update_image_blocks(cx);
|
||||
@@ -290,6 +284,16 @@ impl ContextEditor {
|
||||
this
|
||||
}
|
||||
|
||||
fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
self.editor.update(cx, |editor, cx| {
|
||||
let show_edit_predictions = all_language_settings(None, cx)
|
||||
.edit_predictions
|
||||
.enabled_in_assistant;
|
||||
|
||||
editor.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn context(&self) -> &Entity<AssistantContext> {
|
||||
&self.context
|
||||
}
|
||||
@@ -1087,7 +1091,7 @@ impl ContextEditor {
|
||||
patch: AssistantPatch,
|
||||
mut cx: AsyncWindowContext,
|
||||
) -> Result<()> {
|
||||
let project = this.update(&mut cx, |this, _| this.project.clone())?;
|
||||
let project = this.read_with(&cx, |this, _| this.project.clone())?;
|
||||
let resolved_patch = patch.resolve(project.clone(), &mut cx).await;
|
||||
|
||||
let editor = cx.new_window_entity(|window, cx| {
|
||||
@@ -1112,7 +1116,7 @@ impl ContextEditor {
|
||||
editor
|
||||
})?;
|
||||
|
||||
this.update_in(&mut cx, |this, window, cx| {
|
||||
this.update(&mut cx, |this, _| {
|
||||
if let Some(patch_state) = this.patches.get_mut(&patch.range) {
|
||||
patch_state.editor = Some(PatchEditorState {
|
||||
editor: editor.downgrade(),
|
||||
@@ -1120,19 +1124,12 @@ impl ContextEditor {
|
||||
});
|
||||
patch_state.update_task.take();
|
||||
}
|
||||
|
||||
this.workspace
|
||||
.update(cx, |workspace, cx| {
|
||||
workspace.add_item_to_active_pane(
|
||||
Box::new(editor.clone()),
|
||||
None,
|
||||
false,
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.log_err();
|
||||
})?;
|
||||
this.read_with(&cx, |this, _| this.workspace.clone())?
|
||||
.update_in(&mut cx, |workspace, window, cx| {
|
||||
workspace.add_item_to_active_pane(Box::new(editor.clone()), None, false, window, cx)
|
||||
})
|
||||
.log_err();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1234,8 +1231,8 @@ impl ContextEditor {
|
||||
.px_1()
|
||||
.mr_0p5()
|
||||
.border_1()
|
||||
.border_color(theme::color_alpha(colors.border_variant, 0.6))
|
||||
.bg(theme::color_alpha(colors.element_background, 0.6))
|
||||
.border_color(colors.border_variant.alpha(0.6))
|
||||
.bg(colors.element_background.alpha(0.6))
|
||||
.child("esc"),
|
||||
)
|
||||
.child("to cancel")
|
||||
@@ -1514,15 +1511,11 @@ impl ContextEditor {
|
||||
|
||||
(!text.is_empty()).then_some((text, true))
|
||||
} else {
|
||||
let anchor = context_editor.selections.newest_anchor();
|
||||
let text = context_editor
|
||||
.buffer()
|
||||
.read(cx)
|
||||
.read(cx)
|
||||
.text_for_range(anchor.range())
|
||||
.collect::<String>();
|
||||
let selection = context_editor.selections.newest_adjusted(cx);
|
||||
let buffer = context_editor.buffer().read(cx).snapshot(cx);
|
||||
let selected_text = buffer.text_for_range(selection.range()).collect::<String>();
|
||||
|
||||
(!text.is_empty()).then_some((text, false))
|
||||
(!selected_text.is_empty()).then_some((selected_text, false))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1777,23 +1770,16 @@ impl ContextEditor {
|
||||
&mut self,
|
||||
cx: &mut Context<Self>,
|
||||
) -> (String, CopyMetadata, Vec<text::Selection<usize>>) {
|
||||
let (snapshot, selection, creases) = self.editor.update(cx, |editor, cx| {
|
||||
let mut selection = editor.selections.newest::<Point>(cx);
|
||||
let (selection, creases) = self.editor.update(cx, |editor, cx| {
|
||||
let mut selection = editor.selections.newest_adjusted(cx);
|
||||
let snapshot = editor.buffer().read(cx).snapshot(cx);
|
||||
|
||||
let is_entire_line = selection.is_empty() || editor.selections.line_mode;
|
||||
if is_entire_line {
|
||||
selection.start = Point::new(selection.start.row, 0);
|
||||
selection.end =
|
||||
cmp::min(snapshot.max_point(), Point::new(selection.start.row + 1, 0));
|
||||
selection.goal = SelectionGoal::None;
|
||||
}
|
||||
selection.goal = SelectionGoal::None;
|
||||
|
||||
let selection_start = snapshot.point_to_offset(selection.start);
|
||||
|
||||
(
|
||||
snapshot.clone(),
|
||||
selection.clone(),
|
||||
selection.map(|point| snapshot.point_to_offset(point)),
|
||||
editor.display_map.update(cx, |display_map, cx| {
|
||||
display_map
|
||||
.snapshot(cx)
|
||||
@@ -1833,7 +1819,6 @@ impl ContextEditor {
|
||||
)
|
||||
});
|
||||
|
||||
let selection = selection.map(|point| snapshot.point_to_offset(point));
|
||||
let context = self.context.read(cx);
|
||||
|
||||
let mut text = String::new();
|
||||
@@ -2043,15 +2028,6 @@ impl ContextEditor {
|
||||
});
|
||||
}
|
||||
|
||||
fn toggle_model_selector(
|
||||
&mut self,
|
||||
_: &ToggleModelSelector,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.language_model_selector_menu_handle.toggle(window, cx);
|
||||
}
|
||||
|
||||
fn save(&mut self, _: &Save, _window: &mut Window, cx: &mut Context<Self>) {
|
||||
self.context.update(cx, |context, cx| {
|
||||
context.save(Some(Duration::from_millis(500)), self.fs.clone(), cx)
|
||||
@@ -2399,46 +2375,6 @@ impl ContextEditor {
|
||||
)
|
||||
}
|
||||
|
||||
fn render_language_model_selector(&self, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let active_model = LanguageModelRegistry::read_global(cx).active_model();
|
||||
let focus_handle = self.editor().focus_handle(cx).clone();
|
||||
let model_name = match active_model {
|
||||
Some(model) => model.name().0,
|
||||
None => SharedString::from("No model selected"),
|
||||
};
|
||||
|
||||
LanguageModelSelectorPopoverMenu::new(
|
||||
self.language_model_selector.clone(),
|
||||
ButtonLike::new("active-model")
|
||||
.style(ButtonStyle::Subtle)
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_0p5()
|
||||
.child(
|
||||
Label::new(model_name)
|
||||
.size(LabelSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.child(
|
||||
Icon::new(IconName::ChevronDown)
|
||||
.color(Color::Muted)
|
||||
.size(IconSize::XSmall),
|
||||
),
|
||||
),
|
||||
move |window, cx| {
|
||||
Tooltip::for_action_in(
|
||||
"Change Model",
|
||||
&ToggleModelSelector,
|
||||
&focus_handle,
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
},
|
||||
gpui::Corner::BottomLeft,
|
||||
)
|
||||
.with_handle(self.language_model_selector_menu_handle.clone())
|
||||
}
|
||||
|
||||
fn render_last_error(&self, cx: &mut Context<Self>) -> Option<AnyElement> {
|
||||
let last_error = self.last_error.as_ref()?;
|
||||
|
||||
@@ -2882,7 +2818,9 @@ impl Render for ContextEditor {
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let fs_clone = self.fs.clone();
|
||||
|
||||
let language_model_selector = self.language_model_selector.clone();
|
||||
v_flex()
|
||||
.key_context("ContextEditor")
|
||||
.capture_action(cx.listener(ContextEditor::cancel))
|
||||
@@ -2895,7 +2833,9 @@ impl Render for ContextEditor {
|
||||
.on_action(cx.listener(ContextEditor::edit))
|
||||
.on_action(cx.listener(ContextEditor::assist))
|
||||
.on_action(cx.listener(ContextEditor::split))
|
||||
.on_action(cx.listener(ContextEditor::toggle_model_selector))
|
||||
.on_action(move |_: &ToggleModelSelector, window, cx| {
|
||||
language_model_selector.toggle(window, cx);
|
||||
})
|
||||
.size_full()
|
||||
.children(self.render_notice(cx))
|
||||
.child(
|
||||
@@ -2933,11 +2873,18 @@ impl Render for ContextEditor {
|
||||
.gap_1()
|
||||
.child(self.render_inject_context_menu(cx))
|
||||
.child(ui::Divider::vertical())
|
||||
.child(
|
||||
div()
|
||||
.pl_0p5()
|
||||
.child(self.render_language_model_selector(cx)),
|
||||
),
|
||||
.child(div().pl_0p5().child(assistant_language_model_selector(
|
||||
self.editor().focus_handle(cx),
|
||||
Some(self.language_model_selector.clone()),
|
||||
cx,
|
||||
move |model, cx| {
|
||||
update_settings_file::<AssistantSettings>(
|
||||
fs_clone.clone(),
|
||||
cx,
|
||||
move |settings, _| settings.set_model(model.clone()),
|
||||
);
|
||||
},
|
||||
))),
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
@@ -3113,12 +3060,13 @@ impl SearchableItem for ContextEditor {
|
||||
|
||||
fn active_match_index(
|
||||
&mut self,
|
||||
direction: Direction,
|
||||
matches: &[Self::Match],
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Option<usize> {
|
||||
self.editor.update(cx, |editor, cx| {
|
||||
editor.active_match_index(matches, window, cx)
|
||||
editor.active_match_index(direction, matches, window, cx)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,14 +9,14 @@ use clock::ReplicaId;
|
||||
use collections::HashMap;
|
||||
use context_server::manager::ContextServerManager;
|
||||
use context_server::ContextServerFactoryRegistry;
|
||||
use fs::Fs;
|
||||
use fs::{Fs, RemoveOptions};
|
||||
use futures::StreamExt;
|
||||
use fuzzy::StringMatchCandidate;
|
||||
use gpui::{App, AppContext as _, AsyncApp, Context, Entity, EventEmitter, Task, WeakEntity};
|
||||
use language::LanguageRegistry;
|
||||
use paths::contexts_dir;
|
||||
use project::Project;
|
||||
use prompt_library::PromptBuilder;
|
||||
use prompt_store::PromptBuilder;
|
||||
use regex::Regex;
|
||||
use rpc::AnyProtoClient;
|
||||
use std::sync::LazyLock;
|
||||
@@ -475,6 +475,38 @@ impl ContextStore {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn delete_local_context(
|
||||
&mut self,
|
||||
path: PathBuf,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
let fs = self.fs.clone();
|
||||
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
fs.remove_file(
|
||||
&path,
|
||||
RemoveOptions {
|
||||
recursive: false,
|
||||
ignore_if_not_exists: true,
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.contexts.retain(|context| {
|
||||
context
|
||||
.upgrade()
|
||||
.and_then(|context| context.read(cx).path())
|
||||
!= Some(&path)
|
||||
});
|
||||
this.contexts_metadata
|
||||
.retain(|context| context.path != path);
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn loaded_context_for_path(&self, path: &Path, cx: &App) -> Option<Entity<AssistantContext>> {
|
||||
self.contexts.iter().find_map(|context| {
|
||||
let context = context.upgrade()?;
|
||||
|
||||
@@ -207,24 +207,31 @@ impl PickerDelegate for SlashCommandDelegate {
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_1p5()
|
||||
.child(Icon::new(info.icon).size(IconSize::XSmall))
|
||||
.child(div().font_buffer(cx).child({
|
||||
.child(
|
||||
Icon::new(info.icon)
|
||||
.size(IconSize::XSmall)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.child({
|
||||
let mut label = format!("{}", info.name);
|
||||
if let Some(args) = info.args.as_ref().filter(|_| selected)
|
||||
{
|
||||
label.push_str(&args);
|
||||
}
|
||||
Label::new(label).single_line().size(LabelSize::Small)
|
||||
}))
|
||||
Label::new(label)
|
||||
.single_line()
|
||||
.size(LabelSize::Small)
|
||||
.buffer_font(cx)
|
||||
})
|
||||
.children(info.args.clone().filter(|_| !selected).map(
|
||||
|args| {
|
||||
div()
|
||||
.font_buffer(cx)
|
||||
.child(
|
||||
Label::new(args)
|
||||
.single_line()
|
||||
.size(LabelSize::Small)
|
||||
.color(Color::Muted),
|
||||
.color(Color::Muted)
|
||||
.buffer_font(cx),
|
||||
)
|
||||
.visible_on_hover(format!(
|
||||
"command-entry-label-{ix}"
|
||||
@@ -236,7 +243,7 @@ impl PickerDelegate for SlashCommandDelegate {
|
||||
Label::new(info.description.clone())
|
||||
.size(LabelSize::Small)
|
||||
.color(Color::Muted)
|
||||
.text_ellipsis(),
|
||||
.truncate(),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -294,10 +301,9 @@ where
|
||||
.gap_1p5()
|
||||
.child(Icon::new(IconName::Plus).size(IconSize::XSmall))
|
||||
.child(
|
||||
div().font_buffer(cx).child(
|
||||
Label::new("create-your-command")
|
||||
.size(LabelSize::Small),
|
||||
),
|
||||
Label::new("create-your-command")
|
||||
.size(LabelSize::Small)
|
||||
.buffer_font(cx),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
@@ -341,7 +347,7 @@ where
|
||||
.anchor(gpui::Corner::BottomLeft)
|
||||
.offset(gpui::Point {
|
||||
x: px(0.0),
|
||||
y: px(-16.0),
|
||||
y: px(-2.0),
|
||||
})
|
||||
.when_some(handle, |this, handle| this.with_handle(handle))
|
||||
}
|
||||
|
||||
@@ -359,6 +359,7 @@ fn providers_schema(_: &mut schemars::gen::SchemaGenerator) -> schemars::schema:
|
||||
schemars::schema::SchemaObject {
|
||||
enum_values: Some(vec![
|
||||
"anthropic".into(),
|
||||
"bedrock".into(),
|
||||
"google".into(),
|
||||
"lmstudio".into(),
|
||||
"ollama".into(),
|
||||
@@ -512,7 +513,7 @@ mod tests {
|
||||
AssistantSettings::get_global(cx).default_model,
|
||||
LanguageModelSelection {
|
||||
provider: "zed.dev".into(),
|
||||
model: "claude-3-5-sonnet".into(),
|
||||
model: "claude-3-5-sonnet-latest".into(),
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
@@ -32,7 +32,7 @@ language.workspace = true
|
||||
language_model.workspace = true
|
||||
log.workspace = true
|
||||
project.workspace = true
|
||||
prompt_library.workspace = true
|
||||
prompt_store.workspace = true
|
||||
rope.workspace = true
|
||||
schemars.workspace = true
|
||||
semantic_index.workspace = true
|
||||
|
||||
@@ -5,7 +5,7 @@ use assistant_slash_command::{
|
||||
};
|
||||
use gpui::{Task, WeakEntity};
|
||||
use language::{BufferSnapshot, LspAdapterDelegate};
|
||||
use prompt_library::PromptStore;
|
||||
use prompt_store::PromptStore;
|
||||
use std::{
|
||||
fmt::Write,
|
||||
sync::{atomic::AtomicBool, Arc},
|
||||
@@ -21,11 +21,11 @@ impl SlashCommand for DefaultSlashCommand {
|
||||
}
|
||||
|
||||
fn description(&self) -> String {
|
||||
"insert default prompt".into()
|
||||
"Insert default prompt".into()
|
||||
}
|
||||
|
||||
fn menu_text(&self) -> String {
|
||||
"Insert Default Prompt".into()
|
||||
self.description()
|
||||
}
|
||||
|
||||
fn requires_argument(&self) -> bool {
|
||||
|
||||
@@ -13,7 +13,7 @@ use feature_flags::FeatureFlag;
|
||||
use gpui::{App, Task, WeakEntity};
|
||||
use language::{Anchor, CodeLabel, LspAdapterDelegate};
|
||||
use language_model::{LanguageModelRegistry, LanguageModelTool};
|
||||
use prompt_library::PromptBuilder;
|
||||
use prompt_store::PromptBuilder;
|
||||
use schemars::JsonSchema;
|
||||
use semantic_index::SemanticDb;
|
||||
use serde::Deserialize;
|
||||
|
||||
@@ -5,7 +5,7 @@ use assistant_slash_command::{
|
||||
};
|
||||
use gpui::{Task, WeakEntity};
|
||||
use language::{BufferSnapshot, LspAdapterDelegate};
|
||||
use prompt_library::PromptStore;
|
||||
use prompt_store::PromptStore;
|
||||
use std::sync::{atomic::AtomicBool, Arc};
|
||||
use ui::prelude::*;
|
||||
use workspace::Workspace;
|
||||
|
||||
@@ -16,7 +16,9 @@ anyhow.workspace = true
|
||||
collections.workspace = true
|
||||
derive_more.workspace = true
|
||||
gpui.workspace = true
|
||||
language.workspace = true
|
||||
parking_lot.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
workspace.workspace = true
|
||||
ui.workspace = true
|
||||
|
||||
@@ -4,7 +4,16 @@ mod tool_working_set;
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::Result;
|
||||
use gpui::AnyElement;
|
||||
use gpui::IntoElement;
|
||||
use gpui::{App, Task, WeakEntity, Window};
|
||||
use language::Language;
|
||||
use ui::div;
|
||||
use ui::Label;
|
||||
use ui::LabelCommon;
|
||||
use ui::LabelSize;
|
||||
use ui::ParentElement;
|
||||
use ui::SharedString;
|
||||
use workspace::Workspace;
|
||||
|
||||
pub use crate::tool_registry::*;
|
||||
@@ -31,8 +40,52 @@ pub trait Tool: 'static + Send + Sync {
|
||||
fn run(
|
||||
self: Arc<Self>,
|
||||
input: serde_json::Value,
|
||||
thread_id: Arc<str>,
|
||||
workspace: WeakEntity<Workspace>,
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
) -> Task<Result<String>>;
|
||||
|
||||
/// Renders the tool's input when the user expands it.
|
||||
fn render_input(
|
||||
self: Arc<Self>,
|
||||
input: serde_json::Value,
|
||||
_lua_language: Option<Arc<Language>>,
|
||||
_cx: &mut App,
|
||||
) -> AnyElement {
|
||||
default_render_input(input)
|
||||
}
|
||||
|
||||
/// Renders the tool's output when the user expands it.
|
||||
fn render_output(self: Arc<Self>, output: SharedString, _cx: &mut App) -> AnyElement {
|
||||
default_render_output(output)
|
||||
}
|
||||
|
||||
/// Renders the tool's error message when the user expands it.
|
||||
fn render_error(self: Arc<Self>, err: SharedString, _cx: &mut App) -> AnyElement {
|
||||
default_render_error(err)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default_render_input(input: serde_json::Value) -> AnyElement {
|
||||
div()
|
||||
.child(Label::new("Input:").size(LabelSize::Small))
|
||||
.child(Label::new(
|
||||
serde_json::to_string_pretty(&input).unwrap_or_default(),
|
||||
))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
pub fn default_render_output(output: SharedString) -> AnyElement {
|
||||
div()
|
||||
.child(Label::new("Result:").size(LabelSize::Small))
|
||||
.child(Label::new(output))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
pub fn default_render_error(err: SharedString) -> AnyElement {
|
||||
div()
|
||||
.child(Label::new("Error:").size(LabelSize::Small))
|
||||
.child(Label::new(err))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use assistant_tool::Tool;
|
||||
use chrono::{Local, Utc};
|
||||
use gpui::{App, Task, WeakEntity, Window};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
@@ -17,7 +16,7 @@ pub enum Timezone {
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct FileToolInput {
|
||||
pub struct NowToolInput {
|
||||
/// The timezone to use for the datetime.
|
||||
timezone: Timezone,
|
||||
}
|
||||
@@ -34,18 +33,19 @@ impl Tool for NowTool {
|
||||
}
|
||||
|
||||
fn input_schema(&self) -> serde_json::Value {
|
||||
let schema = schemars::schema_for!(FileToolInput);
|
||||
let schema = schemars::schema_for!(NowToolInput);
|
||||
serde_json::to_value(&schema).unwrap()
|
||||
}
|
||||
|
||||
fn run(
|
||||
self: Arc<Self>,
|
||||
input: serde_json::Value,
|
||||
_thread_id: Arc<str>,
|
||||
_workspace: WeakEntity<workspace::Workspace>,
|
||||
_window: &mut Window,
|
||||
_cx: &mut App,
|
||||
) -> Task<Result<String>> {
|
||||
let input: FileToolInput = match serde_json::from_value(input) {
|
||||
let input: NowToolInput = match serde_json::from_value(input) {
|
||||
Ok(input) => input,
|
||||
Err(err) => return Task::ready(Err(anyhow!(err))),
|
||||
};
|
||||
|
||||
@@ -141,19 +141,20 @@ pub fn notify_if_app_was_updated(cx: &mut App) {
|
||||
cx,
|
||||
move |cx| {
|
||||
let workspace_handle = cx.entity().downgrade();
|
||||
cx.new(|_cx| {
|
||||
MessageNotification::new(format!("Updated to {app_name} {}", version))
|
||||
.primary_message("View Release Notes")
|
||||
.primary_on_click(move |window, cx| {
|
||||
if let Some(workspace) = workspace_handle.upgrade() {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
crate::view_release_notes_locally(
|
||||
workspace, window, cx,
|
||||
);
|
||||
})
|
||||
}
|
||||
cx.emit(DismissEvent);
|
||||
})
|
||||
cx.new(|cx| {
|
||||
MessageNotification::new(
|
||||
format!("Updated to {app_name} {}", version),
|
||||
cx,
|
||||
)
|
||||
.primary_message("View Release Notes")
|
||||
.primary_on_click(move |window, cx| {
|
||||
if let Some(workspace) = workspace_handle.upgrade() {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
crate::view_release_notes_locally(workspace, window, cx);
|
||||
})
|
||||
}
|
||||
cx.emit(DismissEvent);
|
||||
})
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
22
crates/aws_http_client/Cargo.toml
Normal file
22
crates/aws_http_client/Cargo.toml
Normal file
@@ -0,0 +1,22 @@
|
||||
[package]
|
||||
name = "aws_http_client"
|
||||
version = "0.1.0"
|
||||
edition.workspace = true
|
||||
publish.workspace = true
|
||||
license = "GPL-3.0-or-later"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[lib]
|
||||
path = "src/aws_http_client.rs"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
aws-smithy-runtime-api.workspace = true
|
||||
aws-smithy-types.workspace = true
|
||||
futures.workspace = true
|
||||
http_client.workspace = true
|
||||
tokio = { workspace = true, features = ["rt", "rt-multi-thread"] }
|
||||
1
crates/aws_http_client/LICENSE-GPL
Symbolic link
1
crates/aws_http_client/LICENSE-GPL
Symbolic link
@@ -0,0 +1 @@
|
||||
../../LICENSE-GPL
|
||||
118
crates/aws_http_client/src/aws_http_client.rs
Normal file
118
crates/aws_http_client/src/aws_http_client.rs
Normal file
@@ -0,0 +1,118 @@
|
||||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
|
||||
use aws_smithy_runtime_api::client::http::{
|
||||
HttpClient as AwsClient, HttpConnector as AwsConnector,
|
||||
HttpConnectorFuture as AwsConnectorFuture, HttpConnectorFuture, HttpConnectorSettings,
|
||||
SharedHttpConnector,
|
||||
};
|
||||
use aws_smithy_runtime_api::client::orchestrator::{HttpRequest as AwsHttpRequest, HttpResponse};
|
||||
use aws_smithy_runtime_api::client::result::ConnectorError;
|
||||
use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents;
|
||||
use aws_smithy_runtime_api::http::StatusCode;
|
||||
use aws_smithy_types::body::SdkBody;
|
||||
use futures::AsyncReadExt;
|
||||
use http_client::{AsyncBody, Inner};
|
||||
use http_client::{HttpClient, Request};
|
||||
use tokio::runtime::Handle;
|
||||
|
||||
struct AwsHttpConnector {
|
||||
client: Arc<dyn HttpClient>,
|
||||
handle: Handle,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for AwsHttpConnector {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("AwsHttpConnector").finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl AwsConnector for AwsHttpConnector {
|
||||
fn call(&self, request: AwsHttpRequest) -> AwsConnectorFuture {
|
||||
let req = match request.try_into_http1x() {
|
||||
Ok(req) => req,
|
||||
Err(err) => {
|
||||
return HttpConnectorFuture::ready(Err(ConnectorError::other(err.into(), None)))
|
||||
}
|
||||
};
|
||||
|
||||
let (parts, body) = req.into_parts();
|
||||
|
||||
let response = self
|
||||
.client
|
||||
.send(Request::from_parts(parts, convert_to_async_body(body)));
|
||||
|
||||
let handle = self.handle.clone();
|
||||
|
||||
HttpConnectorFuture::new(async move {
|
||||
let response = match response.await {
|
||||
Ok(response) => response,
|
||||
Err(err) => return Err(ConnectorError::other(err.into(), None)),
|
||||
};
|
||||
let (parts, body) = response.into_parts();
|
||||
let body = convert_to_sdk_body(body, handle).await;
|
||||
|
||||
Ok(HttpResponse::new(
|
||||
StatusCode::try_from(parts.status.as_u16()).unwrap(),
|
||||
body,
|
||||
))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AwsHttpClient {
|
||||
client: Arc<dyn HttpClient>,
|
||||
handler: Handle,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for AwsHttpClient {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("AwsHttpClient").finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl AwsHttpClient {
|
||||
pub fn new(client: Arc<dyn HttpClient>, handle: Handle) -> Self {
|
||||
Self {
|
||||
client,
|
||||
handler: handle,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AwsClient for AwsHttpClient {
|
||||
fn http_connector(
|
||||
&self,
|
||||
_settings: &HttpConnectorSettings,
|
||||
_components: &RuntimeComponents,
|
||||
) -> SharedHttpConnector {
|
||||
SharedHttpConnector::new(AwsHttpConnector {
|
||||
client: self.client.clone(),
|
||||
handle: self.handler.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn convert_to_sdk_body(body: AsyncBody, handle: Handle) -> SdkBody {
|
||||
match body.0 {
|
||||
Inner::Empty => SdkBody::empty(),
|
||||
Inner::Bytes(bytes) => SdkBody::from(bytes.into_inner()),
|
||||
Inner::AsyncReader(mut reader) => {
|
||||
let buffer = handle.spawn(async move {
|
||||
let mut buffer = Vec::new();
|
||||
let _ = reader.read_to_end(&mut buffer).await;
|
||||
buffer
|
||||
});
|
||||
|
||||
SdkBody::from(buffer.await.unwrap_or_default())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert_to_async_body(body: SdkBody) -> AsyncBody {
|
||||
match body.bytes() {
|
||||
Some(bytes) => AsyncBody::from((*bytes).to_vec()),
|
||||
None => AsyncBody::empty(),
|
||||
}
|
||||
}
|
||||
28
crates/bedrock/Cargo.toml
Normal file
28
crates/bedrock/Cargo.toml
Normal file
@@ -0,0 +1,28 @@
|
||||
[package]
|
||||
name = "bedrock"
|
||||
version = "0.1.0"
|
||||
edition.workspace = true
|
||||
publish.workspace = true
|
||||
license = "GPL-3.0-or-later"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[lib]
|
||||
path = "src/bedrock.rs"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
schemars = ["dep:schemars"]
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
aws-sdk-bedrockruntime = { workspace = true, features = ["behavior-version-latest"] }
|
||||
aws-smithy-types = {workspace = true}
|
||||
futures.workspace = true
|
||||
schemars = { workspace = true, optional = true }
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
strum.workspace = true
|
||||
thiserror.workspace = true
|
||||
tokio = { workspace = true, features = ["rt", "rt-multi-thread"] }
|
||||
1
crates/bedrock/LICENSE-GPL
Symbolic link
1
crates/bedrock/LICENSE-GPL
Symbolic link
@@ -0,0 +1 @@
|
||||
../../LICENSE-GPL
|
||||
166
crates/bedrock/src/bedrock.rs
Normal file
166
crates/bedrock/src/bedrock.rs
Normal file
@@ -0,0 +1,166 @@
|
||||
mod models;
|
||||
|
||||
use std::pin::Pin;
|
||||
|
||||
use anyhow::{anyhow, Context, Error, Result};
|
||||
use aws_sdk_bedrockruntime as bedrock;
|
||||
pub use aws_sdk_bedrockruntime as bedrock_client;
|
||||
pub use aws_sdk_bedrockruntime::types::{
|
||||
ContentBlock as BedrockInnerContent, SpecificToolChoice as BedrockSpecificTool,
|
||||
ToolChoice as BedrockToolChoice, ToolInputSchema as BedrockToolInputSchema,
|
||||
ToolSpecification as BedrockTool,
|
||||
};
|
||||
use aws_smithy_types::{Document, Number as AwsNumber};
|
||||
pub use bedrock::operation::converse_stream::ConverseStreamInput as BedrockStreamingRequest;
|
||||
pub use bedrock::types::{
|
||||
ContentBlock as BedrockRequestContent, ConversationRole as BedrockRole,
|
||||
ConverseOutput as BedrockResponse, ConverseStreamOutput as BedrockStreamingResponse,
|
||||
Message as BedrockMessage, ResponseStream as BedrockResponseStream,
|
||||
};
|
||||
use futures::stream::{self, BoxStream, Stream};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::{Number, Value};
|
||||
use thiserror::Error;
|
||||
|
||||
pub use crate::models::*;
|
||||
|
||||
pub async fn complete(
|
||||
client: &bedrock::Client,
|
||||
request: Request,
|
||||
) -> Result<BedrockResponse, BedrockError> {
|
||||
let response = bedrock::Client::converse(client)
|
||||
.model_id(request.model.clone())
|
||||
.set_messages(request.messages.into())
|
||||
.send()
|
||||
.await
|
||||
.context("failed to send request to Bedrock");
|
||||
|
||||
match response {
|
||||
Ok(output) => output
|
||||
.output
|
||||
.ok_or_else(|| BedrockError::Other(anyhow!("no output"))),
|
||||
Err(err) => Err(BedrockError::Other(err)),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn stream_completion(
|
||||
client: bedrock::Client,
|
||||
request: Request,
|
||||
handle: tokio::runtime::Handle,
|
||||
) -> Result<BoxStream<'static, Result<BedrockStreamingResponse, BedrockError>>, Error> {
|
||||
handle
|
||||
.spawn(async move {
|
||||
let response = bedrock::Client::converse_stream(&client)
|
||||
.model_id(request.model.clone())
|
||||
.set_messages(request.messages.into())
|
||||
.send()
|
||||
.await;
|
||||
|
||||
match response {
|
||||
Ok(output) => {
|
||||
let stream: Pin<
|
||||
Box<
|
||||
dyn Stream<Item = Result<BedrockStreamingResponse, BedrockError>>
|
||||
+ Send,
|
||||
>,
|
||||
> = Box::pin(stream::unfold(output.stream, |mut stream| async move {
|
||||
match stream.recv().await {
|
||||
Ok(Some(output)) => Some((Ok(output), stream)),
|
||||
Ok(None) => None,
|
||||
Err(err) => {
|
||||
Some((
|
||||
// TODO: Figure out how we can capture Throttling Exceptions
|
||||
Err(BedrockError::ClientError(anyhow!(
|
||||
"{:?}",
|
||||
aws_sdk_bedrockruntime::error::DisplayErrorContext(err)
|
||||
))),
|
||||
stream,
|
||||
))
|
||||
}
|
||||
}
|
||||
}));
|
||||
Ok(stream)
|
||||
}
|
||||
Err(err) => Err(anyhow!(
|
||||
"{:?}",
|
||||
aws_sdk_bedrockruntime::error::DisplayErrorContext(err)
|
||||
)),
|
||||
}
|
||||
})
|
||||
.await
|
||||
.map_err(|err| anyhow!("failed to spawn task: {err:?}"))?
|
||||
}
|
||||
|
||||
pub fn aws_document_to_value(document: &Document) -> Value {
|
||||
match document {
|
||||
Document::Null => Value::Null,
|
||||
Document::Bool(value) => Value::Bool(*value),
|
||||
Document::Number(value) => match *value {
|
||||
AwsNumber::PosInt(value) => Value::Number(Number::from(value)),
|
||||
AwsNumber::NegInt(value) => Value::Number(Number::from(value)),
|
||||
AwsNumber::Float(value) => Value::Number(Number::from_f64(value).unwrap()),
|
||||
},
|
||||
Document::String(value) => Value::String(value.clone()),
|
||||
Document::Array(array) => Value::Array(array.iter().map(aws_document_to_value).collect()),
|
||||
Document::Object(map) => Value::Object(
|
||||
map.iter()
|
||||
.map(|(key, value)| (key.clone(), aws_document_to_value(value)))
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn value_to_aws_document(value: &Value) -> Document {
|
||||
match value {
|
||||
Value::Null => Document::Null,
|
||||
Value::Bool(value) => Document::Bool(*value),
|
||||
Value::Number(value) => {
|
||||
if let Some(value) = value.as_u64() {
|
||||
Document::Number(AwsNumber::PosInt(value))
|
||||
} else if let Some(value) = value.as_i64() {
|
||||
Document::Number(AwsNumber::NegInt(value))
|
||||
} else if let Some(value) = value.as_f64() {
|
||||
Document::Number(AwsNumber::Float(value))
|
||||
} else {
|
||||
Document::Null
|
||||
}
|
||||
}
|
||||
Value::String(value) => Document::String(value.clone()),
|
||||
Value::Array(array) => Document::Array(array.iter().map(value_to_aws_document).collect()),
|
||||
Value::Object(map) => Document::Object(
|
||||
map.iter()
|
||||
.map(|(key, value)| (key.clone(), value_to_aws_document(value)))
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Request {
|
||||
pub model: String,
|
||||
pub max_tokens: u32,
|
||||
pub messages: Vec<BedrockMessage>,
|
||||
pub tools: Vec<BedrockTool>,
|
||||
pub tool_choice: Option<BedrockToolChoice>,
|
||||
pub system: Option<String>,
|
||||
pub metadata: Option<Metadata>,
|
||||
pub stop_sequences: Vec<String>,
|
||||
pub temperature: Option<f32>,
|
||||
pub top_k: Option<u32>,
|
||||
pub top_p: Option<f32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Metadata {
|
||||
pub user_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum BedrockError {
|
||||
#[error("client error: {0}")]
|
||||
ClientError(anyhow::Error),
|
||||
#[error("extension error: {0}")]
|
||||
ExtensionError(anyhow::Error),
|
||||
#[error(transparent)]
|
||||
Other(#[from] anyhow::Error),
|
||||
}
|
||||
207
crates/bedrock/src/models.rs
Normal file
207
crates/bedrock/src/models.rs
Normal file
@@ -0,0 +1,207 @@
|
||||
use anyhow::anyhow;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum::EnumIter;
|
||||
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, EnumIter)]
|
||||
pub enum Model {
|
||||
// Anthropic models (already included)
|
||||
#[default]
|
||||
#[serde(rename = "claude-3-5-sonnet-v2", alias = "claude-3-5-sonnet-latest")]
|
||||
Claude3_5Sonnet,
|
||||
#[serde(rename = "claude-3-7-sonnet", alias = "claude-3-7-sonnet-latest")]
|
||||
Claude3_7Sonnet,
|
||||
#[serde(rename = "claude-3-opus", alias = "claude-3-opus-latest")]
|
||||
Claude3Opus,
|
||||
#[serde(rename = "claude-3-sonnet", alias = "claude-3-sonnet-latest")]
|
||||
Claude3Sonnet,
|
||||
#[serde(rename = "claude-3-5-haiku", alias = "claude-3-5-haiku-latest")]
|
||||
Claude3_5Haiku,
|
||||
// Amazon Nova Models
|
||||
AmazonNovaLite,
|
||||
AmazonNovaMicro,
|
||||
AmazonNovaPro,
|
||||
// AI21 models
|
||||
AI21J2GrandeInstruct,
|
||||
AI21J2JumboInstruct,
|
||||
AI21J2Mid,
|
||||
AI21J2MidV1,
|
||||
AI21J2Ultra,
|
||||
AI21J2UltraV1_8k,
|
||||
AI21J2UltraV1,
|
||||
AI21JambaInstructV1,
|
||||
AI21Jamba15LargeV1,
|
||||
AI21Jamba15MiniV1,
|
||||
// Cohere models
|
||||
CohereCommandTextV14_4k,
|
||||
CohereCommandRV1,
|
||||
CohereCommandRPlusV1,
|
||||
CohereCommandLightTextV14_4k,
|
||||
// Meta models
|
||||
MetaLlama38BInstructV1,
|
||||
MetaLlama370BInstructV1,
|
||||
MetaLlama318BInstructV1_128k,
|
||||
MetaLlama318BInstructV1,
|
||||
MetaLlama3170BInstructV1_128k,
|
||||
MetaLlama3170BInstructV1,
|
||||
MetaLlama3211BInstructV1,
|
||||
MetaLlama3290BInstructV1,
|
||||
MetaLlama321BInstructV1,
|
||||
MetaLlama323BInstructV1,
|
||||
// Mistral models
|
||||
MistralMistral7BInstructV0,
|
||||
MistralMixtral8x7BInstructV0,
|
||||
MistralMistralLarge2402V1,
|
||||
MistralMistralSmall2402V1,
|
||||
#[serde(rename = "custom")]
|
||||
Custom {
|
||||
name: String,
|
||||
max_tokens: usize,
|
||||
/// The name displayed in the UI, such as in the assistant panel model dropdown menu.
|
||||
display_name: Option<String>,
|
||||
max_output_tokens: Option<u32>,
|
||||
default_temperature: Option<f32>,
|
||||
},
|
||||
}
|
||||
|
||||
impl Model {
|
||||
pub fn from_id(id: &str) -> anyhow::Result<Self> {
|
||||
if id.starts_with("claude-3-5-sonnet-v2") {
|
||||
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)
|
||||
} else if id.starts_with("claude-3-5-haiku") {
|
||||
Ok(Self::Claude3_5Haiku)
|
||||
} else if id.starts_with("claude-3-7-sonnet") {
|
||||
Ok(Self::Claude3_7Sonnet)
|
||||
} else {
|
||||
Err(anyhow!("invalid model id"))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn id(&self) -> &str {
|
||||
match self {
|
||||
Model::Claude3_5Sonnet => "us.anthropic.claude-3-5-sonnet-20241022-v2:0",
|
||||
Model::Claude3Opus => "us.anthropic.claude-3-opus-20240229-v1:0",
|
||||
Model::Claude3Sonnet => "us.anthropic.claude-3-sonnet-20240229-v1:0",
|
||||
Model::Claude3_5Haiku => "us.anthropic.claude-3-5-haiku-20241022-v1:0",
|
||||
Model::Claude3_7Sonnet => "us.anthropic.claude-3-7-sonnet-20250219-v1:0",
|
||||
Model::AmazonNovaLite => "us.amazon.nova-lite-v1:0",
|
||||
Model::AmazonNovaMicro => "us.amazon.nova-micro-v1:0",
|
||||
Model::AmazonNovaPro => "us.amazon.nova-pro-v1:0",
|
||||
Model::AI21J2GrandeInstruct => "ai21.j2-grande-instruct",
|
||||
Model::AI21J2JumboInstruct => "ai21.j2-jumbo-instruct",
|
||||
Model::AI21J2Mid => "ai21.j2-mid",
|
||||
Model::AI21J2MidV1 => "ai21.j2-mid-v1",
|
||||
Model::AI21J2Ultra => "ai21.j2-ultra",
|
||||
Model::AI21J2UltraV1_8k => "ai21.j2-ultra-v1:0:8k",
|
||||
Model::AI21J2UltraV1 => "ai21.j2-ultra-v1",
|
||||
Model::AI21JambaInstructV1 => "ai21.jamba-instruct-v1:0",
|
||||
Model::AI21Jamba15LargeV1 => "ai21.jamba-1-5-large-v1:0",
|
||||
Model::AI21Jamba15MiniV1 => "ai21.jamba-1-5-mini-v1:0",
|
||||
Model::CohereCommandTextV14_4k => "cohere.command-text-v14:7:4k",
|
||||
Model::CohereCommandRV1 => "cohere.command-r-v1:0",
|
||||
Model::CohereCommandRPlusV1 => "cohere.command-r-plus-v1:0",
|
||||
Model::CohereCommandLightTextV14_4k => "cohere.command-light-text-v14:7:4k",
|
||||
Model::MetaLlama38BInstructV1 => "meta.llama3-8b-instruct-v1:0",
|
||||
Model::MetaLlama370BInstructV1 => "meta.llama3-70b-instruct-v1:0",
|
||||
Model::MetaLlama318BInstructV1_128k => "meta.llama3-1-8b-instruct-v1:0:128k",
|
||||
Model::MetaLlama318BInstructV1 => "meta.llama3-1-8b-instruct-v1:0",
|
||||
Model::MetaLlama3170BInstructV1_128k => "meta.llama3-1-70b-instruct-v1:0:128k",
|
||||
Model::MetaLlama3170BInstructV1 => "meta.llama3-1-70b-instruct-v1:0",
|
||||
Model::MetaLlama3211BInstructV1 => "meta.llama3-2-11b-instruct-v1:0",
|
||||
Model::MetaLlama3290BInstructV1 => "meta.llama3-2-90b-instruct-v1:0",
|
||||
Model::MetaLlama321BInstructV1 => "meta.llama3-2-1b-instruct-v1:0",
|
||||
Model::MetaLlama323BInstructV1 => "meta.llama3-2-3b-instruct-v1:0",
|
||||
Model::MistralMistral7BInstructV0 => "mistral.mistral-7b-instruct-v0:2",
|
||||
Model::MistralMixtral8x7BInstructV0 => "mistral.mixtral-8x7b-instruct-v0:1",
|
||||
Model::MistralMistralLarge2402V1 => "mistral.mistral-large-2402-v1:0",
|
||||
Model::MistralMistralSmall2402V1 => "mistral.mistral-small-2402-v1:0",
|
||||
Self::Custom { name, .. } => name,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn display_name(&self) -> &str {
|
||||
match self {
|
||||
Self::Claude3_5Sonnet => "Claude 3.5 Sonnet v2",
|
||||
Self::Claude3Opus => "Claude 3 Opus",
|
||||
Self::Claude3Sonnet => "Claude 3 Sonnet",
|
||||
Self::Claude3_5Haiku => "Claude 3.5 Haiku",
|
||||
Self::Claude3_7Sonnet => "Claude 3.7 Sonnet",
|
||||
Self::AmazonNovaLite => "Amazon Nova Lite",
|
||||
Self::AmazonNovaMicro => "Amazon Nova Micro",
|
||||
Self::AmazonNovaPro => "Amazon Nova Pro",
|
||||
Self::AI21J2GrandeInstruct => "AI21 Jurassic2 Grande Instruct",
|
||||
Self::AI21J2JumboInstruct => "AI21 Jurassic2 Jumbo Instruct",
|
||||
Self::AI21J2Mid => "AI21 Jurassic2 Mid",
|
||||
Self::AI21J2MidV1 => "AI21 Jurassic2 Mid V1",
|
||||
Self::AI21J2Ultra => "AI21 Jurassic2 Ultra",
|
||||
Self::AI21J2UltraV1_8k => "AI21 Jurassic2 Ultra V1 8K",
|
||||
Self::AI21J2UltraV1 => "AI21 Jurassic2 Ultra V1",
|
||||
Self::AI21JambaInstructV1 => "AI21 Jamba Instruct",
|
||||
Self::AI21Jamba15LargeV1 => "AI21 Jamba 1.5 Large",
|
||||
Self::AI21Jamba15MiniV1 => "AI21 Jamba 1.5 Mini",
|
||||
Self::CohereCommandTextV14_4k => "Cohere Command Text V14 4K",
|
||||
Self::CohereCommandRV1 => "Cohere Command R V1",
|
||||
Self::CohereCommandRPlusV1 => "Cohere Command R Plus V1",
|
||||
Self::CohereCommandLightTextV14_4k => "Cohere Command Light Text V14 4K",
|
||||
Self::MetaLlama38BInstructV1 => "Meta Llama 3 8B Instruct V1",
|
||||
Self::MetaLlama370BInstructV1 => "Meta Llama 3 70B Instruct V1",
|
||||
Self::MetaLlama318BInstructV1_128k => "Meta Llama 3 1.8B Instruct V1 128K",
|
||||
Self::MetaLlama318BInstructV1 => "Meta Llama 3 1.8B Instruct V1",
|
||||
Self::MetaLlama3170BInstructV1_128k => "Meta Llama 3 1 70B Instruct V1 128K",
|
||||
Self::MetaLlama3170BInstructV1 => "Meta Llama 3 1 70B Instruct V1",
|
||||
Self::MetaLlama3211BInstructV1 => "Meta Llama 3 2 11B Instruct V1",
|
||||
Self::MetaLlama3290BInstructV1 => "Meta Llama 3 2 90B Instruct V1",
|
||||
Self::MetaLlama321BInstructV1 => "Meta Llama 3 2 1B Instruct V1",
|
||||
Self::MetaLlama323BInstructV1 => "Meta Llama 3 2 3B Instruct V1",
|
||||
Self::MistralMistral7BInstructV0 => "Mistral 7B Instruct V0",
|
||||
Self::MistralMixtral8x7BInstructV0 => "Mistral Mixtral 8x7B Instruct V0",
|
||||
Self::MistralMistralLarge2402V1 => "Mistral Large 2402 V1",
|
||||
Self::MistralMistralSmall2402V1 => "Mistral Small 2402 V1",
|
||||
Self::Custom {
|
||||
display_name, name, ..
|
||||
} => display_name.as_deref().unwrap_or(name),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn max_token_count(&self) -> usize {
|
||||
match self {
|
||||
Self::Claude3_5Sonnet
|
||||
| Self::Claude3Opus
|
||||
| Self::Claude3Sonnet
|
||||
| Self::Claude3_5Haiku
|
||||
| Self::Claude3_7Sonnet => 200_000,
|
||||
Self::Custom { max_tokens, .. } => *max_tokens,
|
||||
_ => 200_000,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn max_output_tokens(&self) -> u32 {
|
||||
match self {
|
||||
Self::Claude3Opus | Self::Claude3Sonnet | Self::Claude3_5Haiku => 4_096,
|
||||
Self::Claude3_5Sonnet => 8_192,
|
||||
Self::Custom {
|
||||
max_output_tokens, ..
|
||||
} => max_output_tokens.unwrap_or(4_096),
|
||||
_ => 4_096,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default_temperature(&self) -> f32 {
|
||||
match self {
|
||||
Self::Claude3_5Sonnet
|
||||
| Self::Claude3Opus
|
||||
| Self::Claude3Sonnet
|
||||
| Self::Claude3_5Haiku
|
||||
| Self::Claude3_7Sonnet => 1.0,
|
||||
Self::Custom {
|
||||
default_temperature,
|
||||
..
|
||||
} => default_temperature.unwrap_or(1.0),
|
||||
_ => 1.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,8 +81,8 @@ impl Render for Breadcrumbs {
|
||||
}
|
||||
text_style.color = Color::Muted.color(cx);
|
||||
|
||||
StyledText::new(segment.text.replace('\n', ""))
|
||||
.with_highlights(&text_style, segment.highlights.unwrap_or_default())
|
||||
StyledText::new(segment.text.replace('\n', "⏎"))
|
||||
.with_default_highlights(&text_style, segment.highlights.unwrap_or_default())
|
||||
.into_any()
|
||||
});
|
||||
let breadcrumbs = Itertools::intersperse_with(highlighted_segments, || {
|
||||
|
||||
@@ -16,6 +16,7 @@ test-support = []
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
clock.workspace = true
|
||||
futures.workspace = true
|
||||
git2.workspace = true
|
||||
gpui.workspace = true
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -48,7 +48,7 @@ pub struct ChannelPathsInsertGuard<'a> {
|
||||
channels_by_id: &'a mut BTreeMap<ChannelId, Arc<Channel>>,
|
||||
}
|
||||
|
||||
impl<'a> ChannelPathsInsertGuard<'a> {
|
||||
impl ChannelPathsInsertGuard<'_> {
|
||||
pub fn insert(&mut self, channel_proto: proto::Channel) -> bool {
|
||||
let mut ret = false;
|
||||
let parent_path = channel_proto
|
||||
@@ -86,7 +86,7 @@ impl<'a> ChannelPathsInsertGuard<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for ChannelPathsInsertGuard<'a> {
|
||||
impl Drop for ChannelPathsInsertGuard<'_> {
|
||||
fn drop(&mut self) {
|
||||
self.channels_ordered.sort_by(|a, b| {
|
||||
let a = channel_path_sorting_key(*a, self.channels_by_id);
|
||||
|
||||
@@ -33,10 +33,13 @@ util.workspace = true
|
||||
tempfile.workspace = true
|
||||
|
||||
[target.'cfg(any(target_os = "linux", target_os = "freebsd"))'.dependencies]
|
||||
exec.workspace = true
|
||||
exec.workspace = true
|
||||
fork.workspace = true
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
core-foundation.workspace = true
|
||||
core-services = "0.2"
|
||||
plist = "1.3"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
windows.workspace = true
|
||||
|
||||
@@ -521,30 +521,115 @@ mod flatpak {
|
||||
}
|
||||
}
|
||||
|
||||
// todo("windows")
|
||||
#[cfg(target_os = "windows")]
|
||||
mod windows {
|
||||
use anyhow::Context;
|
||||
use release_channel::app_identifier;
|
||||
use windows::{
|
||||
core::HSTRING,
|
||||
Win32::{
|
||||
Foundation::{CloseHandle, GetLastError, ERROR_ALREADY_EXISTS, GENERIC_WRITE},
|
||||
Storage::FileSystem::{
|
||||
CreateFileW, WriteFile, FILE_FLAGS_AND_ATTRIBUTES, FILE_SHARE_MODE, OPEN_EXISTING,
|
||||
},
|
||||
System::Threading::CreateMutexW,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::{Detect, InstalledApp};
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::ExitStatus;
|
||||
|
||||
struct App;
|
||||
fn check_single_instance() -> bool {
|
||||
let mutex = unsafe {
|
||||
CreateMutexW(
|
||||
None,
|
||||
false,
|
||||
&HSTRING::from(format!("{}-Instance-Mutex", app_identifier())),
|
||||
)
|
||||
.expect("Unable to create instance sync event")
|
||||
};
|
||||
let last_err = unsafe { GetLastError() };
|
||||
let _ = unsafe { CloseHandle(mutex) };
|
||||
last_err != ERROR_ALREADY_EXISTS
|
||||
}
|
||||
|
||||
struct App(PathBuf);
|
||||
|
||||
impl InstalledApp for App {
|
||||
fn zed_version_string(&self) -> String {
|
||||
unimplemented!()
|
||||
format!(
|
||||
"Zed {}{}{} – {}",
|
||||
if *release_channel::RELEASE_CHANNEL_NAME == "stable" {
|
||||
"".to_string()
|
||||
} else {
|
||||
format!("{} ", *release_channel::RELEASE_CHANNEL_NAME)
|
||||
},
|
||||
option_env!("RELEASE_VERSION").unwrap_or_default(),
|
||||
match option_env!("ZED_COMMIT_SHA") {
|
||||
Some(commit_sha) => format!(" {commit_sha} "),
|
||||
None => "".to_string(),
|
||||
},
|
||||
self.0.display(),
|
||||
)
|
||||
}
|
||||
fn launch(&self, _ipc_url: String) -> anyhow::Result<()> {
|
||||
unimplemented!()
|
||||
|
||||
fn launch(&self, ipc_url: String) -> anyhow::Result<()> {
|
||||
if check_single_instance() {
|
||||
std::process::Command::new(self.0.clone())
|
||||
.arg(ipc_url)
|
||||
.spawn()?;
|
||||
} else {
|
||||
unsafe {
|
||||
let pipe = CreateFileW(
|
||||
&HSTRING::from(format!("\\\\.\\pipe\\{}-Named-Pipe", app_identifier())),
|
||||
GENERIC_WRITE.0,
|
||||
FILE_SHARE_MODE::default(),
|
||||
None,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAGS_AND_ATTRIBUTES::default(),
|
||||
None,
|
||||
)?;
|
||||
let message = ipc_url.as_bytes();
|
||||
let mut bytes_written = 0;
|
||||
WriteFile(pipe, Some(message), Some(&mut bytes_written), None)?;
|
||||
CloseHandle(pipe)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn run_foreground(&self, _ipc_url: String) -> io::Result<ExitStatus> {
|
||||
unimplemented!()
|
||||
|
||||
fn run_foreground(&self, ipc_url: String) -> io::Result<ExitStatus> {
|
||||
std::process::Command::new(self.0.clone())
|
||||
.arg(ipc_url)
|
||||
.arg("--foreground")
|
||||
.spawn()?
|
||||
.wait()
|
||||
}
|
||||
}
|
||||
|
||||
impl Detect {
|
||||
pub fn detect(_path: Option<&Path>) -> anyhow::Result<impl InstalledApp> {
|
||||
Ok(App)
|
||||
pub fn detect(path: Option<&Path>) -> anyhow::Result<impl InstalledApp> {
|
||||
let path = if let Some(path) = path {
|
||||
path.to_path_buf().canonicalize()?
|
||||
} else {
|
||||
let cli = std::env::current_exe()?;
|
||||
let dir = cli.parent().context("no parent path for cli")?;
|
||||
|
||||
// ../Zed.exe is the standard, lib/zed is for MSYS2, ./zed.exe is for the target
|
||||
// directory in development builds.
|
||||
let possible_locations = ["../Zed.exe", "../lib/zed/zed-editor.exe", "./zed.exe"];
|
||||
possible_locations
|
||||
.iter()
|
||||
.find_map(|p| dir.join(p).canonicalize().ok().filter(|path| path != &cli))
|
||||
.context(format!(
|
||||
"could not find any of: {}",
|
||||
possible_locations.join(", ")
|
||||
))?
|
||||
};
|
||||
|
||||
Ok(App(path))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,6 +97,7 @@ extension.workspace = true
|
||||
file_finder.workspace = true
|
||||
fs = { workspace = true, features = ["test-support"] }
|
||||
git = { workspace = true, features = ["test-support"] }
|
||||
git_ui = { workspace = true, features = ["test-support"] }
|
||||
git_hosting_providers.workspace = true
|
||||
gpui = { workspace = true, features = ["test-support"] }
|
||||
hyper.workspace = true
|
||||
@@ -110,7 +111,7 @@ node_runtime.workspace = true
|
||||
notifications = { workspace = true, features = ["test-support"] }
|
||||
pretty_assertions.workspace = true
|
||||
project = { workspace = true, features = ["test-support"] }
|
||||
prompt_library.workspace = true
|
||||
prompt_store.workspace = true
|
||||
recent_projects = { workspace = true }
|
||||
release_channel.workspace = true
|
||||
remote = { workspace = true, features = ["test-support"] }
|
||||
|
||||
@@ -202,7 +202,7 @@ impl Database {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_known_extension_versions<'a>(&self) -> Result<HashMap<String, Vec<String>>> {
|
||||
pub async fn get_known_extension_versions(&self) -> Result<HashMap<String, Vec<String>>> {
|
||||
self.transaction(|tx| async move {
|
||||
let mut extension_external_ids_by_id = HashMap::default();
|
||||
|
||||
|
||||
@@ -256,6 +256,7 @@ async fn perform_completion(
|
||||
// so that users can use the new version, without having to update Zed.
|
||||
request.model = match model.as_str() {
|
||||
"claude-3-5-sonnet" => anthropic::Model::Claude3_5Sonnet.id().to_string(),
|
||||
"claude-3-7-sonnet" => anthropic::Model::Claude3_7Sonnet.id().to_string(),
|
||||
"claude-3-opus" => anthropic::Model::Claude3Opus.id().to_string(),
|
||||
"claude-3-haiku" => anthropic::Model::Claude3Haiku.id().to_string(),
|
||||
"claude-3-sonnet" => anthropic::Model::Claude3Sonnet.id().to_string(),
|
||||
@@ -450,19 +451,15 @@ async fn check_usage_limit(
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let user_id = UserId::from_proto(claims.user_id);
|
||||
let model = state.db.model(provider, model_name)?;
|
||||
let usage = state
|
||||
.db
|
||||
.get_usage(
|
||||
UserId::from_proto(claims.user_id),
|
||||
provider,
|
||||
model_name,
|
||||
Utc::now(),
|
||||
)
|
||||
.await?;
|
||||
let free_tier = claims.free_tier_monthly_spending_limit();
|
||||
|
||||
if usage.spending_this_month >= free_tier {
|
||||
let spending_this_month = state
|
||||
.db
|
||||
.get_user_spending_for_month(user_id, Utc::now())
|
||||
.await?;
|
||||
if spending_this_month >= free_tier {
|
||||
if !claims.has_llm_subscription {
|
||||
return Err(Error::http(
|
||||
StatusCode::PAYMENT_REQUIRED,
|
||||
@@ -470,7 +467,8 @@ async fn check_usage_limit(
|
||||
));
|
||||
}
|
||||
|
||||
if (usage.spending_this_month - free_tier) >= Cents(claims.max_monthly_spend_in_cents) {
|
||||
let monthly_spend = spending_this_month.saturating_sub(free_tier);
|
||||
if monthly_spend >= Cents(claims.max_monthly_spend_in_cents) {
|
||||
return Err(Error::Http(
|
||||
StatusCode::FORBIDDEN,
|
||||
"Maximum spending limit reached for this month.".to_string(),
|
||||
@@ -495,6 +493,11 @@ async fn check_usage_limit(
|
||||
model.max_tokens_per_minute as usize / users_in_recent_minutes;
|
||||
let per_user_max_tokens_per_day = model.max_tokens_per_day as usize / users_in_recent_days;
|
||||
|
||||
let usage = state
|
||||
.db
|
||||
.get_usage(user_id, provider, model_name, Utc::now())
|
||||
.await?;
|
||||
|
||||
let checks = [
|
||||
(
|
||||
usage.requests_this_minute,
|
||||
|
||||
@@ -27,7 +27,7 @@ fn authorize_access_to_model(
|
||||
}
|
||||
|
||||
if provider == LanguageModelProvider::Anthropic {
|
||||
if model == "claude-3-5-sonnet" {
|
||||
if model == "claude-3-5-sonnet" || model == "claude-3-7-sonnet" {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
||||
@@ -328,6 +328,7 @@ impl Server {
|
||||
.add_request_handler(forward_mutating_project_request::<proto::PrepareRename>)
|
||||
.add_request_handler(forward_mutating_project_request::<proto::PerformRename>)
|
||||
.add_request_handler(forward_mutating_project_request::<proto::ReloadBuffers>)
|
||||
.add_request_handler(forward_mutating_project_request::<proto::ApplyCodeActionKind>)
|
||||
.add_request_handler(forward_mutating_project_request::<proto::FormatBuffers>)
|
||||
.add_request_handler(forward_mutating_project_request::<proto::CreateProjectEntry>)
|
||||
.add_request_handler(forward_mutating_project_request::<proto::RenameProjectEntry>)
|
||||
@@ -392,9 +393,13 @@ impl Server {
|
||||
.add_request_handler(forward_mutating_project_request::<proto::OpenContext>)
|
||||
.add_request_handler(forward_mutating_project_request::<proto::CreateContext>)
|
||||
.add_request_handler(forward_mutating_project_request::<proto::SynchronizeContexts>)
|
||||
.add_request_handler(forward_mutating_project_request::<proto::Push>)
|
||||
.add_request_handler(forward_mutating_project_request::<proto::Pull>)
|
||||
.add_request_handler(forward_mutating_project_request::<proto::Fetch>)
|
||||
.add_request_handler(forward_mutating_project_request::<proto::Stage>)
|
||||
.add_request_handler(forward_mutating_project_request::<proto::Unstage>)
|
||||
.add_request_handler(forward_mutating_project_request::<proto::Commit>)
|
||||
.add_request_handler(forward_read_only_project_request::<proto::GetRemotes>)
|
||||
.add_request_handler(forward_read_only_project_request::<proto::GitShow>)
|
||||
.add_request_handler(forward_read_only_project_request::<proto::GitReset>)
|
||||
.add_request_handler(forward_read_only_project_request::<proto::GitCheckoutFiles>)
|
||||
@@ -971,7 +976,7 @@ impl Server {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deref for ConnectionPoolGuard<'a> {
|
||||
impl Deref for ConnectionPoolGuard<'_> {
|
||||
type Target = ConnectionPool;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
@@ -979,13 +984,13 @@ impl<'a> Deref for ConnectionPoolGuard<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DerefMut for ConnectionPoolGuard<'a> {
|
||||
impl DerefMut for ConnectionPoolGuard<'_> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.guard
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for ConnectionPoolGuard<'a> {
|
||||
impl Drop for ConnectionPoolGuard<'_> {
|
||||
fn drop(&mut self) {
|
||||
#[cfg(test)]
|
||||
self.check_invariants();
|
||||
|
||||
@@ -13,6 +13,7 @@ mod channel_message_tests;
|
||||
mod channel_tests;
|
||||
mod editor_tests;
|
||||
mod following_tests;
|
||||
mod git_tests;
|
||||
mod integration_tests;
|
||||
mod notification_tests;
|
||||
mod random_channel_buffer_tests;
|
||||
|
||||
@@ -1537,6 +1537,7 @@ async fn test_mutual_editor_inlay_hint_cache_update(
|
||||
show_parameter_hints: false,
|
||||
show_other_hints: true,
|
||||
show_background: false,
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
});
|
||||
});
|
||||
@@ -1552,6 +1553,7 @@ async fn test_mutual_editor_inlay_hint_cache_update(
|
||||
show_parameter_hints: false,
|
||||
show_other_hints: true,
|
||||
show_background: false,
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
});
|
||||
});
|
||||
@@ -1770,6 +1772,7 @@ async fn test_inlay_hint_refresh_is_forwarded(
|
||||
show_parameter_hints: false,
|
||||
show_other_hints: false,
|
||||
show_background: false,
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
});
|
||||
});
|
||||
@@ -1785,6 +1788,7 @@ async fn test_inlay_hint_refresh_is_forwarded(
|
||||
show_parameter_hints: true,
|
||||
show_other_hints: true,
|
||||
show_background: false,
|
||||
toggle_on_modifiers_press: None,
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
130
crates/collab/src/tests/git_tests.rs
Normal file
130
crates/collab/src/tests/git_tests.rs
Normal file
@@ -0,0 +1,130 @@
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use call::ActiveCall;
|
||||
use git::status::{FileStatus, StatusCode, TrackedStatus};
|
||||
use git_ui::project_diff::ProjectDiff;
|
||||
use gpui::{TestAppContext, VisualTestContext};
|
||||
use project::ProjectPath;
|
||||
use serde_json::json;
|
||||
use workspace::Workspace;
|
||||
|
||||
//
|
||||
use crate::tests::TestServer;
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_project_diff(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) {
|
||||
let mut server = TestServer::start(cx_a.background_executor.clone()).await;
|
||||
let client_a = server.create_client(cx_a, "user_a").await;
|
||||
let client_b = server.create_client(cx_b, "user_b").await;
|
||||
cx_a.set_name("cx_a");
|
||||
cx_b.set_name("cx_b");
|
||||
|
||||
server
|
||||
.create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
|
||||
.await;
|
||||
|
||||
client_a
|
||||
.fs()
|
||||
.insert_tree(
|
||||
"/a",
|
||||
json!({
|
||||
".git": {},
|
||||
"changed.txt": "after\n",
|
||||
"unchanged.txt": "unchanged\n",
|
||||
"created.txt": "created\n",
|
||||
"secret.pem": "secret-changed\n",
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
client_a.fs().set_git_content_for_repo(
|
||||
Path::new("/a/.git"),
|
||||
&[
|
||||
("changed.txt".into(), "before\n".to_string(), None),
|
||||
("unchanged.txt".into(), "unchanged\n".to_string(), None),
|
||||
("deleted.txt".into(), "deleted\n".to_string(), None),
|
||||
("secret.pem".into(), "shh\n".to_string(), None),
|
||||
],
|
||||
);
|
||||
let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
|
||||
let active_call_a = cx_a.read(ActiveCall::global);
|
||||
let project_id = active_call_a
|
||||
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
cx_b.update(editor::init);
|
||||
cx_b.update(git_ui::init);
|
||||
let project_b = client_b.join_remote_project(project_id, cx_b).await;
|
||||
let workspace_b = cx_b.add_window(|window, cx| {
|
||||
Workspace::new(
|
||||
None,
|
||||
project_b.clone(),
|
||||
client_b.app_state.clone(),
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
let cx_b = &mut VisualTestContext::from_window(*workspace_b, cx_b);
|
||||
let workspace_b = workspace_b.root(cx_b).unwrap();
|
||||
|
||||
cx_b.update(|window, cx| {
|
||||
window
|
||||
.focused(cx)
|
||||
.unwrap()
|
||||
.dispatch_action(&git_ui::project_diff::Diff, window, cx)
|
||||
});
|
||||
let diff = workspace_b.update(cx_b, |workspace, cx| {
|
||||
workspace.active_item(cx).unwrap().act_as::<ProjectDiff>(cx)
|
||||
});
|
||||
let diff = diff.unwrap();
|
||||
cx_b.run_until_parked();
|
||||
|
||||
diff.update(cx_b, |diff, cx| {
|
||||
assert_eq!(
|
||||
diff.excerpt_paths(cx),
|
||||
vec!["changed.txt", "deleted.txt", "created.txt"]
|
||||
);
|
||||
});
|
||||
|
||||
client_a
|
||||
.fs()
|
||||
.insert_tree(
|
||||
"/a",
|
||||
json!({
|
||||
".git": {},
|
||||
"changed.txt": "before\n",
|
||||
"unchanged.txt": "changed\n",
|
||||
"created.txt": "created\n",
|
||||
"secret.pem": "secret-changed\n",
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
client_a.fs().recalculate_git_status(Path::new("/a/.git"));
|
||||
cx_b.run_until_parked();
|
||||
|
||||
project_b.update(cx_b, |project, cx| {
|
||||
let project_path = ProjectPath {
|
||||
worktree_id,
|
||||
path: Arc::from(PathBuf::from("unchanged.txt")),
|
||||
};
|
||||
let status = project.project_path_git_status(&project_path, cx);
|
||||
assert_eq!(
|
||||
status.unwrap(),
|
||||
FileStatus::Tracked(TrackedStatus {
|
||||
worktree_status: StatusCode::Modified,
|
||||
index_status: StatusCode::Unmodified,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
diff.update(cx_b, |diff, cx| {
|
||||
assert_eq!(
|
||||
diff.excerpt_paths(cx),
|
||||
vec!["deleted.txt", "unchanged.txt", "created.txt"]
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -14,7 +14,7 @@ use client::{User, RECEIVE_TIMEOUT};
|
||||
use collections::{HashMap, HashSet};
|
||||
use fs::{FakeFs, Fs as _, RemoveOptions};
|
||||
use futures::{channel::mpsc, StreamExt as _};
|
||||
use prompt_library::PromptBuilder;
|
||||
use prompt_store::PromptBuilder;
|
||||
|
||||
use git::status::{FileStatus, StatusCode, TrackedStatus, UnmergedStatus, UnmergedStatusCode};
|
||||
use gpui::{
|
||||
@@ -6354,7 +6354,7 @@ async fn test_preview_tabs(cx: &mut TestAppContext) {
|
||||
// Open item 1 as preview
|
||||
workspace
|
||||
.update_in(cx, |workspace, window, cx| {
|
||||
workspace.open_path_preview(path_1.clone(), None, true, true, window, cx)
|
||||
workspace.open_path_preview(path_1.clone(), None, true, true, true, window, cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
@@ -6375,7 +6375,7 @@ async fn test_preview_tabs(cx: &mut TestAppContext) {
|
||||
// Open item 2 as preview
|
||||
workspace
|
||||
.update_in(cx, |workspace, window, cx| {
|
||||
workspace.open_path_preview(path_2.clone(), None, true, true, window, cx)
|
||||
workspace.open_path_preview(path_2.clone(), None, true, true, true, window, cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
@@ -6507,7 +6507,7 @@ async fn test_preview_tabs(cx: &mut TestAppContext) {
|
||||
// Open item 2 as preview in right pane
|
||||
workspace
|
||||
.update_in(cx, |workspace, window, cx| {
|
||||
workspace.open_path_preview(path_2.clone(), None, true, true, window, cx)
|
||||
workspace.open_path_preview(path_2.clone(), None, true, true, true, window, cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
@@ -6545,7 +6545,7 @@ async fn test_preview_tabs(cx: &mut TestAppContext) {
|
||||
// Open item 2 as preview in left pane
|
||||
workspace
|
||||
.update_in(cx, |workspace, window, cx| {
|
||||
workspace.open_path_preview(path_2.clone(), None, true, true, window, cx)
|
||||
workspace.open_path_preview(path_2.clone(), None, true, true, true, window, cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -17,7 +17,7 @@ use gpui::{
|
||||
ListState, MouseDownEvent, ParentElement, Pixels, Point, PromptLevel, Render, SharedString,
|
||||
Styled, Subscription, Task, TextStyle, WeakEntity, Window,
|
||||
};
|
||||
use menu::{Cancel, Confirm, SecondaryConfirm, SelectNext, SelectPrev};
|
||||
use menu::{Cancel, Confirm, SecondaryConfirm, SelectNext, SelectPrevious};
|
||||
use project::{Fs, Project};
|
||||
use rpc::{
|
||||
proto::{self, ChannelVisibility, PeerId},
|
||||
@@ -1430,7 +1430,7 @@ impl CollabPanel {
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn select_prev(&mut self, _: &SelectPrev, _: &mut Window, cx: &mut Context<Self>) {
|
||||
fn select_previous(&mut self, _: &SelectPrevious, _: &mut Window, cx: &mut Context<Self>) {
|
||||
let ix = self.selection.take().unwrap_or(0);
|
||||
if ix > 0 {
|
||||
self.selection = Some(ix - 1);
|
||||
@@ -2878,7 +2878,7 @@ impl Render for CollabPanel {
|
||||
.key_context("CollabPanel")
|
||||
.on_action(cx.listener(CollabPanel::cancel))
|
||||
.on_action(cx.listener(CollabPanel::select_next))
|
||||
.on_action(cx.listener(CollabPanel::select_prev))
|
||||
.on_action(cx.listener(CollabPanel::select_previous))
|
||||
.on_action(cx.listener(CollabPanel::confirm))
|
||||
.on_action(cx.listener(CollabPanel::insert_space))
|
||||
.on_action(cx.listener(CollabPanel::remove_selected_channel))
|
||||
|
||||
@@ -22,7 +22,7 @@ use ui::{
|
||||
h_flex, prelude::*, v_flex, Avatar, Button, Icon, IconButton, IconName, Label, Tab, Tooltip,
|
||||
};
|
||||
use util::{ResultExt, TryFutureExt};
|
||||
use workspace::notifications::NotificationId;
|
||||
use workspace::notifications::{Notification as WorkspaceNotification, NotificationId};
|
||||
use workspace::{
|
||||
dock::{DockPosition, Panel, PanelEvent},
|
||||
Workspace,
|
||||
@@ -570,11 +570,12 @@ impl NotificationPanel {
|
||||
workspace.dismiss_notification(&id, cx);
|
||||
workspace.show_notification(id, cx, |cx| {
|
||||
let workspace = cx.entity().downgrade();
|
||||
cx.new(|_| NotificationToast {
|
||||
cx.new(|cx| NotificationToast {
|
||||
notification_id,
|
||||
actor,
|
||||
text,
|
||||
workspace,
|
||||
focus_handle: cx.focus_handle(),
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -771,8 +772,17 @@ pub struct NotificationToast {
|
||||
actor: Option<Arc<User>>,
|
||||
text: String,
|
||||
workspace: WeakEntity<Workspace>,
|
||||
focus_handle: FocusHandle,
|
||||
}
|
||||
|
||||
impl Focusable for NotificationToast {
|
||||
fn focus_handle(&self, _cx: &App) -> FocusHandle {
|
||||
self.focus_handle.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl WorkspaceNotification for NotificationToast {}
|
||||
|
||||
impl NotificationToast {
|
||||
fn focus_notification_panel(&self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let workspace = self.workspace.clone();
|
||||
|
||||
@@ -27,7 +27,7 @@ impl<'de> Deserialize<'de> for ChatPanelButton {
|
||||
{
|
||||
struct Visitor;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for Visitor {
|
||||
impl serde::de::Visitor<'_> for Visitor {
|
||||
type Value = ChatPanelButton;
|
||||
|
||||
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
|
||||
@@ -15,7 +15,6 @@ path = "src/component.rs"
|
||||
collections.workspace = true
|
||||
gpui.workspace = true
|
||||
linkme.workspace = true
|
||||
once_cell.workspace = true
|
||||
parking_lot.workspace = true
|
||||
theme.workspace = true
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use collections::HashMap;
|
||||
use gpui::{div, prelude::*, px, AnyElement, App, IntoElement, RenderOnce, SharedString, Window};
|
||||
use linkme::distributed_slice;
|
||||
use once_cell::sync::Lazy;
|
||||
use parking_lot::RwLock;
|
||||
use theme::ActiveTheme;
|
||||
|
||||
@@ -18,7 +18,7 @@ pub trait Component {
|
||||
}
|
||||
|
||||
pub trait ComponentPreview: Component {
|
||||
fn preview(_window: &mut Window, _cx: &App) -> AnyElement;
|
||||
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement;
|
||||
}
|
||||
|
||||
#[distributed_slice]
|
||||
@@ -27,12 +27,12 @@ pub static __ALL_COMPONENTS: [fn()] = [..];
|
||||
#[distributed_slice]
|
||||
pub static __ALL_PREVIEWS: [fn()] = [..];
|
||||
|
||||
pub static COMPONENT_DATA: Lazy<RwLock<ComponentRegistry>> =
|
||||
Lazy::new(|| RwLock::new(ComponentRegistry::new()));
|
||||
pub static COMPONENT_DATA: LazyLock<RwLock<ComponentRegistry>> =
|
||||
LazyLock::new(|| RwLock::new(ComponentRegistry::new()));
|
||||
|
||||
pub struct ComponentRegistry {
|
||||
components: Vec<(Option<&'static str>, &'static str, Option<&'static str>)>,
|
||||
previews: HashMap<&'static str, fn(&mut Window, &App) -> AnyElement>,
|
||||
previews: HashMap<&'static str, fn(&mut Window, &mut App) -> AnyElement>,
|
||||
}
|
||||
|
||||
impl ComponentRegistry {
|
||||
@@ -62,7 +62,10 @@ pub fn register_component<T: Component>() {
|
||||
}
|
||||
|
||||
pub fn register_preview<T: ComponentPreview>() {
|
||||
let preview_data = (T::name(), T::preview as fn(&mut Window, &App) -> AnyElement);
|
||||
let preview_data = (
|
||||
T::name(),
|
||||
T::preview as fn(&mut Window, &mut App) -> AnyElement,
|
||||
);
|
||||
COMPONENT_DATA
|
||||
.write()
|
||||
.previews
|
||||
@@ -77,7 +80,7 @@ pub struct ComponentMetadata {
|
||||
name: SharedString,
|
||||
scope: Option<SharedString>,
|
||||
description: Option<SharedString>,
|
||||
preview: Option<fn(&mut Window, &App) -> AnyElement>,
|
||||
preview: Option<fn(&mut Window, &mut App) -> AnyElement>,
|
||||
}
|
||||
|
||||
impl ComponentMetadata {
|
||||
@@ -93,7 +96,7 @@ impl ComponentMetadata {
|
||||
self.description.clone()
|
||||
}
|
||||
|
||||
pub fn preview(&self) -> Option<fn(&mut Window, &App) -> AnyElement> {
|
||||
pub fn preview(&self) -> Option<fn(&mut Window, &mut App) -> AnyElement> {
|
||||
self.preview
|
||||
}
|
||||
}
|
||||
@@ -235,6 +238,7 @@ pub struct ComponentExampleGroup {
|
||||
pub title: Option<SharedString>,
|
||||
pub examples: Vec<ComponentExample>,
|
||||
pub grow: bool,
|
||||
pub vertical: bool,
|
||||
}
|
||||
|
||||
impl RenderOnce for ComponentExampleGroup {
|
||||
@@ -270,6 +274,7 @@ impl RenderOnce for ComponentExampleGroup {
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.when(self.vertical, |this| this.flex_col())
|
||||
.items_start()
|
||||
.w_full()
|
||||
.gap_6()
|
||||
@@ -287,6 +292,7 @@ impl ComponentExampleGroup {
|
||||
title: None,
|
||||
examples,
|
||||
grow: false,
|
||||
vertical: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,6 +302,7 @@ impl ComponentExampleGroup {
|
||||
title: Some(title.into()),
|
||||
examples,
|
||||
grow: false,
|
||||
vertical: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,6 +311,12 @@ impl ComponentExampleGroup {
|
||||
self.grow = true;
|
||||
self
|
||||
}
|
||||
|
||||
/// Lay the group out vertically.
|
||||
pub fn vertical(mut self) -> Self {
|
||||
self.vertical = true;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a single example
|
||||
|
||||
@@ -93,7 +93,7 @@ impl ComponentPreview {
|
||||
&self,
|
||||
ix: usize,
|
||||
window: &mut Window,
|
||||
cx: &Context<Self>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> impl IntoElement {
|
||||
let component = self.get_component(ix);
|
||||
|
||||
@@ -226,3 +226,7 @@ impl Item for ComponentPreview {
|
||||
f(*event)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: impl serializable item for component preview so it will restore with the workspace
|
||||
// ref: https://github.com/zed-industries/zed/blob/32201ac70a501e63dfa2ade9c00f85aea2d4dd94/crates/image_viewer/src/image_viewer.rs#L199
|
||||
// Use `ImageViewer` as a model for how to do it, except it'll be even simpler
|
||||
|
||||
@@ -14,6 +14,7 @@ path = "src/context_server.rs"
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
assistant_tool.workspace = true
|
||||
async-trait.workspace = true
|
||||
collections.workspace = true
|
||||
command_palette_hooks.workspace = true
|
||||
context_server_settings.workspace = true
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
use anyhow::{anyhow, Context as _, Result};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use collections::HashMap;
|
||||
use futures::{channel::oneshot, io::BufWriter, select, AsyncRead, AsyncWrite, FutureExt};
|
||||
use futures::{channel::oneshot, select, FutureExt, StreamExt};
|
||||
use gpui::{AppContext as _, AsyncApp, BackgroundExecutor, Task};
|
||||
use parking_lot::Mutex;
|
||||
use postage::barrier;
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
use serde_json::{value::RawValue, Value};
|
||||
use smol::{
|
||||
channel,
|
||||
io::{AsyncBufReadExt, AsyncWriteExt, BufReader},
|
||||
process::Child,
|
||||
};
|
||||
use smol::channel;
|
||||
use std::{
|
||||
fmt,
|
||||
path::PathBuf,
|
||||
@@ -22,6 +18,8 @@ use std::{
|
||||
};
|
||||
use util::TryFutureExt;
|
||||
|
||||
use crate::transport::{StdioTransport, Transport};
|
||||
|
||||
const JSON_RPC_VERSION: &str = "2.0";
|
||||
const REQUEST_TIMEOUT: Duration = Duration::from_secs(60);
|
||||
|
||||
@@ -55,7 +53,8 @@ pub struct Client {
|
||||
#[allow(dead_code)]
|
||||
output_done_rx: Mutex<Option<barrier::Receiver>>,
|
||||
executor: BackgroundExecutor,
|
||||
server: Arc<Mutex<Option<Child>>>,
|
||||
#[allow(dead_code)]
|
||||
transport: Arc<dyn Transport>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
@@ -152,25 +151,13 @@ impl Client {
|
||||
&binary.args
|
||||
);
|
||||
|
||||
let mut command = util::command::new_smol_command(&binary.executable);
|
||||
command
|
||||
.args(&binary.args)
|
||||
.envs(binary.env.unwrap_or_default())
|
||||
.stdin(std::process::Stdio::piped())
|
||||
.stdout(std::process::Stdio::piped())
|
||||
.stderr(std::process::Stdio::piped())
|
||||
.kill_on_drop(true);
|
||||
let server_name = binary
|
||||
.executable
|
||||
.file_name()
|
||||
.map(|name| name.to_string_lossy().to_string())
|
||||
.unwrap_or_else(String::new);
|
||||
|
||||
let mut server = command.spawn().with_context(|| {
|
||||
format!(
|
||||
"failed to spawn command. (path={:?}, args={:?})",
|
||||
binary.executable, &binary.args
|
||||
)
|
||||
})?;
|
||||
|
||||
let stdin = server.stdin.take().unwrap();
|
||||
let stdout = server.stdout.take().unwrap();
|
||||
let stderr = server.stderr.take().unwrap();
|
||||
let transport = Arc::new(StdioTransport::new(binary, &cx)?);
|
||||
|
||||
let (outbound_tx, outbound_rx) = channel::unbounded::<String>();
|
||||
let (output_done_tx, output_done_rx) = barrier::channel();
|
||||
@@ -183,18 +170,22 @@ impl Client {
|
||||
let stdout_input_task = cx.spawn({
|
||||
let notification_handlers = notification_handlers.clone();
|
||||
let response_handlers = response_handlers.clone();
|
||||
let transport = transport.clone();
|
||||
move |cx| {
|
||||
Self::handle_input(stdout, notification_handlers, response_handlers, cx).log_err()
|
||||
Self::handle_input(transport, notification_handlers, response_handlers, cx)
|
||||
.log_err()
|
||||
}
|
||||
});
|
||||
let stderr_input_task = cx.spawn(|_| Self::handle_stderr(stderr).log_err());
|
||||
let stderr_input_task = cx.spawn(|_| Self::handle_stderr(transport.clone()).log_err());
|
||||
let input_task = cx.spawn(|_| async move {
|
||||
let (stdout, stderr) = futures::join!(stdout_input_task, stderr_input_task);
|
||||
stdout.or(stderr)
|
||||
});
|
||||
|
||||
let output_task = cx.background_spawn({
|
||||
let transport = transport.clone();
|
||||
Self::handle_output(
|
||||
stdin,
|
||||
transport,
|
||||
outbound_rx,
|
||||
output_done_tx,
|
||||
response_handlers.clone(),
|
||||
@@ -202,24 +193,18 @@ impl Client {
|
||||
.log_err()
|
||||
});
|
||||
|
||||
let mut context_server = Self {
|
||||
Ok(Self {
|
||||
server_id,
|
||||
notification_handlers,
|
||||
response_handlers,
|
||||
name: "".into(),
|
||||
name: server_name.into(),
|
||||
next_id: Default::default(),
|
||||
outbound_tx,
|
||||
executor: cx.background_executor().clone(),
|
||||
io_tasks: Mutex::new(Some((input_task, output_task))),
|
||||
output_done_rx: Mutex::new(Some(output_done_rx)),
|
||||
server: Arc::new(Mutex::new(Some(server))),
|
||||
};
|
||||
|
||||
if let Some(name) = binary.executable.file_name() {
|
||||
context_server.name = name.to_string_lossy().into();
|
||||
}
|
||||
|
||||
Ok(context_server)
|
||||
transport,
|
||||
})
|
||||
}
|
||||
|
||||
/// Handles input from the server's stdout.
|
||||
@@ -228,79 +213,53 @@ impl Client {
|
||||
/// parses them as JSON-RPC responses or notifications, and dispatches them
|
||||
/// to the appropriate handlers. It processes both responses (which are matched
|
||||
/// to pending requests) and notifications (which trigger registered handlers).
|
||||
async fn handle_input<Stdout>(
|
||||
stdout: Stdout,
|
||||
async fn handle_input(
|
||||
transport: Arc<dyn Transport>,
|
||||
notification_handlers: Arc<Mutex<HashMap<&'static str, NotificationHandler>>>,
|
||||
response_handlers: Arc<Mutex<Option<HashMap<RequestId, ResponseHandler>>>>,
|
||||
cx: AsyncApp,
|
||||
) -> anyhow::Result<()>
|
||||
where
|
||||
Stdout: AsyncRead + Unpin + Send + 'static,
|
||||
{
|
||||
let mut stdout = BufReader::new(stdout);
|
||||
let mut buffer = String::new();
|
||||
) -> anyhow::Result<()> {
|
||||
let mut receiver = transport.receive();
|
||||
|
||||
loop {
|
||||
buffer.clear();
|
||||
if stdout.read_line(&mut buffer).await? == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let content = buffer.trim();
|
||||
|
||||
if !content.is_empty() {
|
||||
if let Ok(response) = serde_json::from_str::<AnyResponse>(content) {
|
||||
if let Some(handlers) = response_handlers.lock().as_mut() {
|
||||
if let Some(handler) = handlers.remove(&response.id) {
|
||||
handler(Ok(content.to_string()));
|
||||
}
|
||||
}
|
||||
} else if let Ok(notification) = serde_json::from_str::<AnyNotification>(content) {
|
||||
let mut notification_handlers = notification_handlers.lock();
|
||||
if let Some(handler) =
|
||||
notification_handlers.get_mut(notification.method.as_str())
|
||||
{
|
||||
handler(notification.params.unwrap_or(Value::Null), cx.clone());
|
||||
while let Some(message) = receiver.next().await {
|
||||
if let Ok(response) = serde_json::from_str::<AnyResponse>(&message) {
|
||||
if let Some(handlers) = response_handlers.lock().as_mut() {
|
||||
if let Some(handler) = handlers.remove(&response.id) {
|
||||
handler(Ok(message.to_string()));
|
||||
}
|
||||
}
|
||||
} else if let Ok(notification) = serde_json::from_str::<AnyNotification>(&message) {
|
||||
let mut notification_handlers = notification_handlers.lock();
|
||||
if let Some(handler) = notification_handlers.get_mut(notification.method.as_str()) {
|
||||
handler(notification.params.unwrap_or(Value::Null), cx.clone());
|
||||
}
|
||||
}
|
||||
|
||||
smol::future::yield_now().await;
|
||||
}
|
||||
|
||||
smol::future::yield_now().await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Handles the stderr output from the context server.
|
||||
/// Continuously reads and logs any error messages from the server.
|
||||
async fn handle_stderr<Stderr>(stderr: Stderr) -> anyhow::Result<()>
|
||||
where
|
||||
Stderr: AsyncRead + Unpin + Send + 'static,
|
||||
{
|
||||
let mut stderr = BufReader::new(stderr);
|
||||
let mut buffer = String::new();
|
||||
|
||||
loop {
|
||||
buffer.clear();
|
||||
if stderr.read_line(&mut buffer).await? == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
log::warn!("context server stderr: {}", buffer.trim());
|
||||
smol::future::yield_now().await;
|
||||
async fn handle_stderr(transport: Arc<dyn Transport>) -> anyhow::Result<()> {
|
||||
while let Some(err) = transport.receive_err().next().await {
|
||||
log::warn!("context server stderr: {}", err.trim());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Handles the output to the context server's stdin.
|
||||
/// This function continuously receives messages from the outbound channel,
|
||||
/// writes them to the server's stdin, and manages the lifecycle of response handlers.
|
||||
async fn handle_output<Stdin>(
|
||||
stdin: Stdin,
|
||||
async fn handle_output(
|
||||
transport: Arc<dyn Transport>,
|
||||
outbound_rx: channel::Receiver<String>,
|
||||
output_done_tx: barrier::Sender,
|
||||
response_handlers: Arc<Mutex<Option<HashMap<RequestId, ResponseHandler>>>>,
|
||||
) -> anyhow::Result<()>
|
||||
where
|
||||
Stdin: AsyncWrite + Unpin + Send + 'static,
|
||||
{
|
||||
let mut stdin = BufWriter::new(stdin);
|
||||
) -> anyhow::Result<()> {
|
||||
let _clear_response_handlers = util::defer({
|
||||
let response_handlers = response_handlers.clone();
|
||||
move || {
|
||||
@@ -309,10 +268,7 @@ impl Client {
|
||||
});
|
||||
while let Ok(message) = outbound_rx.recv().await {
|
||||
log::trace!("outgoing message: {}", message);
|
||||
|
||||
stdin.write_all(message.as_bytes()).await?;
|
||||
stdin.write_all(b"\n").await?;
|
||||
stdin.flush().await?;
|
||||
transport.send(message).await?;
|
||||
}
|
||||
drop(output_done_tx);
|
||||
Ok(())
|
||||
@@ -416,14 +372,6 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Client {
|
||||
fn drop(&mut self) {
|
||||
if let Some(mut server) = self.server.lock().take() {
|
||||
let _ = server.kill();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ContextServerId {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
|
||||
@@ -4,6 +4,7 @@ mod extension_context_server;
|
||||
pub mod manager;
|
||||
pub mod protocol;
|
||||
mod registry;
|
||||
mod transport;
|
||||
pub mod types;
|
||||
|
||||
use command_palette_hooks::CommandPaletteFilter;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user