Compare commits
266 Commits
stream-liv
...
single-cra
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12c9198fcf | ||
|
|
10784e3f03 | ||
|
|
4dc8bef6de | ||
|
|
69da8bdea7 | ||
|
|
eaf02ef7bd | ||
|
|
b0efc40cb3 | ||
|
|
f6e642a891 | ||
|
|
7b22d555e6 | ||
|
|
923b2e1464 | ||
|
|
a7e8f4face | ||
|
|
74ae682563 | ||
|
|
e5fcee943c | ||
|
|
72c6f82b1a | ||
|
|
3256458494 | ||
|
|
9508f33d71 | ||
|
|
20a5165f5b | ||
|
|
fd7a487c3d | ||
|
|
f393499076 | ||
|
|
94c77be93e | ||
|
|
5e96ecc5bf | ||
|
|
226f945a11 | ||
|
|
228a82ce41 | ||
|
|
ede4a23fc9 | ||
|
|
8bea01faf5 | ||
|
|
f275145a4c | ||
|
|
99fddd8280 | ||
|
|
28921fd632 | ||
|
|
3da964de05 | ||
|
|
a619bc6f95 | ||
|
|
7b4800407e | ||
|
|
35e2831c6d | ||
|
|
8abacd5a50 | ||
|
|
4db0e59fb7 | ||
|
|
d76240d941 | ||
|
|
35aefc6580 | ||
|
|
149e5fde36 | ||
|
|
97b542b22a | ||
|
|
6152230152 | ||
|
|
a47759fd03 | ||
|
|
b5da1198f5 | ||
|
|
ba743a1bd9 | ||
|
|
9e7afe870a | ||
|
|
94d8ead270 | ||
|
|
93ab6ad922 | ||
|
|
45bbfe077a | ||
|
|
be8cc1146a | ||
|
|
a97ab5eb3d | ||
|
|
f4024cc602 | ||
|
|
1460249a70 | ||
|
|
da7670cd6f | ||
|
|
ebdc255b73 | ||
|
|
4d49a851ef | ||
|
|
0dbda71423 | ||
|
|
f3320998a8 | ||
|
|
2b7ee1e872 | ||
|
|
767a82527a | ||
|
|
ba8f027c18 | ||
|
|
0a28800049 | ||
|
|
31a6ee0229 | ||
|
|
1f974d074e | ||
|
|
72125949d9 | ||
|
|
d605d192af | ||
|
|
f92e6e9a95 | ||
|
|
ff4f67993b | ||
|
|
07821083df | ||
|
|
09c599385a | ||
|
|
01503511ad | ||
|
|
8bc5bcf0a6 | ||
|
|
983bb5c5fc | ||
|
|
653b2dc676 | ||
|
|
7142d3777f | ||
|
|
01e12c0d3c | ||
|
|
706c385c24 | ||
|
|
edb89d8d11 | ||
|
|
09675d43b3 | ||
|
|
187356ab9b | ||
|
|
435708b615 | ||
|
|
2fe9cd8faa | ||
|
|
8cc3ce1f17 | ||
|
|
6ad8c4a0f4 | ||
|
|
30a94fa59b | ||
|
|
36fe364c05 | ||
|
|
f6d4a73c34 | ||
|
|
7e7f25df6c | ||
|
|
176314bfd2 | ||
|
|
6606e6e37f | ||
|
|
c350321318 | ||
|
|
9da040da3f | ||
|
|
f6385221c5 | ||
|
|
999853fee0 | ||
|
|
f924c3ef00 | ||
|
|
2c4984091c | ||
|
|
453c41205b | ||
|
|
e85ab077be | ||
|
|
daa35e98f1 | ||
|
|
de70852497 | ||
|
|
454c9dc06d | ||
|
|
71aeb6a636 | ||
|
|
cdd2128311 | ||
|
|
20b60e8dd2 | ||
|
|
37366ac907 | ||
|
|
083f06322d | ||
|
|
16cbff9118 | ||
|
|
e62d60c84c | ||
|
|
4f62ebe4be | ||
|
|
b33ae888c0 | ||
|
|
029d08350e | ||
|
|
6d0aa72226 | ||
|
|
12afd1264e | ||
|
|
b526d69387 | ||
|
|
4f06f5b8fe | ||
|
|
555a219f11 | ||
|
|
74540231e5 | ||
|
|
5c0ecc09fb | ||
|
|
5b59ef3456 | ||
|
|
fda3e4c69a | ||
|
|
028c2a8249 | ||
|
|
a86c4deb78 | ||
|
|
e645aa9d20 | ||
|
|
216ea4ddc4 | ||
|
|
29c5ea0a50 | ||
|
|
b129e18396 | ||
|
|
f6fbf662b4 | ||
|
|
a409123342 | ||
|
|
b0b29d91f9 | ||
|
|
290c9113b7 | ||
|
|
36427e0a87 | ||
|
|
e16d5c3a68 | ||
|
|
608addf641 | ||
|
|
f22e56ff42 | ||
|
|
449e20de3d | ||
|
|
1aac35cc1c | ||
|
|
815385cc5f | ||
|
|
eca3424cb5 | ||
|
|
71b3633c1b | ||
|
|
21f778c6db | ||
|
|
1eb6fb0b5d | ||
|
|
484e5df2ee | ||
|
|
fef7df667c | ||
|
|
1c84fd1fef | ||
|
|
b6adab84a0 | ||
|
|
d3a49f6d8f | ||
|
|
c2cf4c45c0 | ||
|
|
bd03dea296 | ||
|
|
3f777f0c68 | ||
|
|
846aec701f | ||
|
|
cfce6a8fbf | ||
|
|
803e5d4c9f | ||
|
|
c10c35ffda | ||
|
|
38b1940251 | ||
|
|
50069a2153 | ||
|
|
b23835b5a5 | ||
|
|
e47b305ca7 | ||
|
|
7931342455 | ||
|
|
282f6241b7 | ||
|
|
73bbdd4456 | ||
|
|
236498408f | ||
|
|
86ff6e2c8e | ||
|
|
4bf6fb217e | ||
|
|
c527f2e212 | ||
|
|
47defa2849 | ||
|
|
6dfff1b46d | ||
|
|
66e06616db | ||
|
|
765626a007 | ||
|
|
27cdc6cb93 | ||
|
|
87ba5fd7bc | ||
|
|
7c72929f0b | ||
|
|
9e49894ed6 | ||
|
|
2364804f17 | ||
|
|
db11a3b554 | ||
|
|
d0ca49f0e1 | ||
|
|
d6fcd9853a | ||
|
|
bc3550d991 | ||
|
|
b8501199c2 | ||
|
|
7fb9549098 | ||
|
|
4097118070 | ||
|
|
a26c0a8537 | ||
|
|
f8bd6c66f4 | ||
|
|
02b1e3a3c1 | ||
|
|
83ad28dfe7 | ||
|
|
17b9d1976f | ||
|
|
3856599853 | ||
|
|
81dd4ca1c9 | ||
|
|
2965119201 | ||
|
|
258cf6c746 | ||
|
|
369de400be | ||
|
|
dc02894db4 | ||
|
|
966b18e142 | ||
|
|
2c7e71028d | ||
|
|
24dba07a9b | ||
|
|
16e9b4ceeb | ||
|
|
bc4bd2e168 | ||
|
|
4d3a18cbdc | ||
|
|
cfcbfc1d82 | ||
|
|
c9ec235b12 | ||
|
|
8196db6022 | ||
|
|
dc5fad52a3 | ||
|
|
77de20c23a | ||
|
|
e1cb8a66f0 | ||
|
|
7025d3f29d | ||
|
|
4bbde40267 | ||
|
|
15e7b67559 | ||
|
|
f0aeab7d00 | ||
|
|
4bbddcad31 | ||
|
|
1e944a51ff | ||
|
|
d90770c673 | ||
|
|
6316151a83 | ||
|
|
49a0a11c4f | ||
|
|
376a45528d | ||
|
|
20eeb78251 | ||
|
|
67be6ec3b5 | ||
|
|
070e5914c9 | ||
|
|
c41a8e33a0 | ||
|
|
25443a91ca | ||
|
|
8e00caf23b | ||
|
|
9a869f0c5f | ||
|
|
de2483e132 | ||
|
|
95259bf9fe | ||
|
|
3b76ba6d5a | ||
|
|
773a3b335e | ||
|
|
b5c38e9a09 | ||
|
|
273173ec8a | ||
|
|
4084ba36f9 | ||
|
|
770886880f | ||
|
|
ea44c510a3 | ||
|
|
c8f1969916 | ||
|
|
a960344301 | ||
|
|
af9e7f1f96 | ||
|
|
c04c439d23 | ||
|
|
d3cd8f8f14 | ||
|
|
cd8d776fe1 | ||
|
|
6de2330253 | ||
|
|
0e264b5a68 | ||
|
|
1af5304074 | ||
|
|
dde692eb88 | ||
|
|
cec72b837e | ||
|
|
95842c7987 | ||
|
|
183e3664cc | ||
|
|
08b124c8d4 | ||
|
|
ea08026cd0 | ||
|
|
daa9939c03 | ||
|
|
f757e5a6c3 | ||
|
|
ecb874db62 | ||
|
|
75f1862268 | ||
|
|
f8ab86f930 | ||
|
|
155854d9a9 | ||
|
|
5b6578247f | ||
|
|
b87c4a1e13 | ||
|
|
a0988508f0 | ||
|
|
a347c4def7 | ||
|
|
9c77bcc827 | ||
|
|
8d1f377bf0 | ||
|
|
f766f6ceae | ||
|
|
9dad897d49 | ||
|
|
5b6401519b | ||
|
|
293e080f03 | ||
|
|
633b665379 | ||
|
|
7fd334fddb | ||
|
|
10226a3992 | ||
|
|
383e868af0 | ||
|
|
40802d91d4 | ||
|
|
6d5784daa6 | ||
|
|
f80eb264fb | ||
|
|
3d956ca68b | ||
|
|
7ce131aaf8 | ||
|
|
60be47d115 |
7
.github/ISSUE_TEMPLATE/0_feature_request.yml
vendored
7
.github/ISSUE_TEMPLATE/0_feature_request.yml
vendored
@@ -15,6 +15,13 @@ body:
|
|||||||
description: A clear and concise description of what you want to happen.
|
description: A clear and concise description of what you want to happen.
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: environment
|
||||||
|
attributes:
|
||||||
|
label: Environment
|
||||||
|
description: Run the `copy system specs into clipboard` command palette action and paste the output in the field below. If you are unable to run the command, please include your Zed version and release channel, operating system and version, RAM amount, and architecture.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: |
|
label: |
|
||||||
|
|||||||
13
.github/ISSUE_TEMPLATE/1_bug_report.yml
vendored
13
.github/ISSUE_TEMPLATE/1_bug_report.yml
vendored
@@ -2,7 +2,7 @@ name: Bug Report
|
|||||||
description: |
|
description: |
|
||||||
Use this template for **non-crash-related** bug reports.
|
Use this template for **non-crash-related** bug reports.
|
||||||
Tip: open this issue template from within Zed with the `file bug report` command palette action.
|
Tip: open this issue template from within Zed with the `file bug report` command palette action.
|
||||||
labels: ["admin read", "triage", "defect"]
|
labels: ["admin read", "triage", "bug"]
|
||||||
body:
|
body:
|
||||||
- type: checkboxes
|
- type: checkboxes
|
||||||
attributes:
|
attributes:
|
||||||
@@ -21,7 +21,7 @@ body:
|
|||||||
id: environment
|
id: environment
|
||||||
attributes:
|
attributes:
|
||||||
label: Environment
|
label: Environment
|
||||||
description: Run the `copy system specs into clipboard` command palette action and paste the output in the field below.
|
description: Run the `copy system specs into clipboard` command palette action and paste the output in the field below. If you are unable to run the command, please include your Zed version and release channel, operating system and version, RAM amount, and architecture.
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
@@ -38,9 +38,12 @@ body:
|
|||||||
Linux: `~/.local/share/zed/logs/Zed.log` or $XDG_DATA_HOME
|
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.
|
If you only need the most recent lines, you can run the `zed: open log` command palette action to see the last 1000.
|
||||||
value: |
|
value: |
|
||||||
<details><summary>Zed.log</summary><pre>
|
<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--></pre></details>
|
<!-- 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:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
|
|||||||
13
.github/ISSUE_TEMPLATE/2_crash_report.yml
vendored
13
.github/ISSUE_TEMPLATE/2_crash_report.yml
vendored
@@ -1,7 +1,7 @@
|
|||||||
name: Crash Report
|
name: Crash Report
|
||||||
description: |
|
description: |
|
||||||
Use this template for crash reports.
|
Use this template for crash reports.
|
||||||
labels: ["admin read", "triage", "defect", "panic / crash"]
|
labels: ["admin read", "triage", "bug", "panic / crash"]
|
||||||
body:
|
body:
|
||||||
- type: checkboxes
|
- type: checkboxes
|
||||||
attributes:
|
attributes:
|
||||||
@@ -20,7 +20,7 @@ body:
|
|||||||
id: environment
|
id: environment
|
||||||
attributes:
|
attributes:
|
||||||
label: Environment
|
label: Environment
|
||||||
description: Run the `copy system specs into clipboard` command palette action and paste the output in the field below.
|
description: Run the `copy system specs into clipboard` command palette action and paste the output in the field below. If you are unable to run the command, please include your Zed version and release channel, operating system and version, RAM amount, and architecture.
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
@@ -31,9 +31,12 @@ body:
|
|||||||
Linux: `~/.local/share/zed/logs/Zed.log` or $XDG_DATA_HOME
|
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.
|
If you only need the most recent lines, you can run the `zed: open log` command palette action to see the last 1000.
|
||||||
value: |
|
value: |
|
||||||
<details><summary>Zed.log</summary><pre>
|
<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--></pre></details>
|
<!-- 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:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
|
|||||||
2
.github/actions/run_tests/action.yml
vendored
2
.github/actions/run_tests/action.yml
vendored
@@ -10,7 +10,7 @@ runs:
|
|||||||
cargo install cargo-nextest
|
cargo install cargo-nextest
|
||||||
|
|
||||||
- name: Install Node
|
- name: Install Node
|
||||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4
|
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
|
||||||
with:
|
with:
|
||||||
node-version: "18"
|
node-version: "18"
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/bump_patch_version.yml
vendored
2
.github/workflows/bump_patch_version.yml
vendored
@@ -43,6 +43,8 @@ jobs:
|
|||||||
esac
|
esac
|
||||||
which cargo-set-version > /dev/null || cargo install cargo-edit
|
which cargo-set-version > /dev/null || cargo install cargo-edit
|
||||||
output=$(cargo set-version -p zed --bump patch 2>&1 | sed 's/.* //')
|
output=$(cargo set-version -p zed --bump patch 2>&1 | sed 's/.* //')
|
||||||
|
export GIT_COMMITTER_NAME="Zed Bot"
|
||||||
|
export GIT_COMMITTER_EMAIL="hi@zed.dev"
|
||||||
git commit -am "Bump to $output for @$GITHUB_ACTOR" --author "Zed Bot <hi@zed.dev>"
|
git commit -am "Bump to $output for @$GITHUB_ACTOR" --author "Zed Bot <hi@zed.dev>"
|
||||||
git tag v${output}${tag_suffix}
|
git tag v${output}${tag_suffix}
|
||||||
git push origin HEAD v${output}${tag_suffix}
|
git push origin HEAD v${output}${tag_suffix}
|
||||||
|
|||||||
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@@ -13,7 +13,7 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- "**"
|
- "**"
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- "docs/**"
|
- "docs/**/*"
|
||||||
- ".github/workflows/community_*"
|
- ".github/workflows/community_*"
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
@@ -232,7 +232,7 @@ jobs:
|
|||||||
DIGITALOCEAN_SPACES_SECRET_KEY: ${{ secrets.DIGITALOCEAN_SPACES_SECRET_KEY }}
|
DIGITALOCEAN_SPACES_SECRET_KEY: ${{ secrets.DIGITALOCEAN_SPACES_SECRET_KEY }}
|
||||||
steps:
|
steps:
|
||||||
- name: Install Node
|
- name: Install Node
|
||||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4
|
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
|
||||||
with:
|
with:
|
||||||
node-version: "18"
|
node-version: "18"
|
||||||
|
|
||||||
@@ -260,7 +260,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
mkdir -p target/
|
mkdir -p target/
|
||||||
# Ignore any errors that occur while drafting release notes to not fail the build.
|
# Ignore any errors that occur while drafting release notes to not fail the build.
|
||||||
script/draft-release-notes "$version" "$channel" > target/release-notes.md || true
|
script/draft-release-notes "$RELEASE_VERSION" "$RELEASE_CHANNEL" > target/release-notes.md || true
|
||||||
|
|
||||||
- name: Generate license file
|
- name: Generate license file
|
||||||
run: script/generate-licenses
|
run: script/generate-licenses
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
stale:
|
stale:
|
||||||
|
if: github.repository_owner == 'zed-industries'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # v9
|
- uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # v9
|
||||||
@@ -24,7 +25,7 @@ jobs:
|
|||||||
# issues, preventing 365 days from working until then.
|
# issues, preventing 365 days from working until then.
|
||||||
days-before-stale: 180
|
days-before-stale: 180
|
||||||
days-before-close: 7
|
days-before-close: 7
|
||||||
any-of-issue-labels: "defect,panic / crash"
|
any-of-issue-labels: "bug,panic / crash"
|
||||||
operations-per-run: 1000
|
operations-per-run: 1000
|
||||||
ascending: true
|
ascending: true
|
||||||
enable-statistics: true
|
enable-statistics: true
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||||
- name: Set up uv
|
- name: Set up uv
|
||||||
uses: astral-sh/setup-uv@f3bcaebff5eace81a1c062af9f9011aae482ca9d # v3
|
uses: astral-sh/setup-uv@2e657c127d5b1635d5a8e3fa40e0ac50a5bf6992 # v3
|
||||||
with:
|
with:
|
||||||
version: "latest"
|
version: "latest"
|
||||||
enable-cache: true
|
enable-cache: true
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||||
- name: Set up uv
|
- name: Set up uv
|
||||||
uses: astral-sh/setup-uv@f3bcaebff5eace81a1c062af9f9011aae482ca9d # v3
|
uses: astral-sh/setup-uv@2e657c127d5b1635d5a8e3fa40e0ac50a5bf6992 # v3
|
||||||
with:
|
with:
|
||||||
version: "latest"
|
version: "latest"
|
||||||
enable-cache: true
|
enable-cache: true
|
||||||
|
|||||||
2
.github/workflows/danger.yml
vendored
2
.github/workflows/danger.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
|||||||
version: 9
|
version: 9
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4
|
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
|
||||||
with:
|
with:
|
||||||
node-version: "20"
|
node-version: "20"
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
|
|||||||
8
.github/workflows/deploy_cloudflare.yml
vendored
8
.github/workflows/deploy_cloudflare.yml
vendored
@@ -37,28 +37,28 @@ jobs:
|
|||||||
mdbook build ./docs --dest-dir=../target/deploy/docs/
|
mdbook build ./docs --dest-dir=../target/deploy/docs/
|
||||||
|
|
||||||
- name: Deploy Docs
|
- name: Deploy Docs
|
||||||
uses: cloudflare/wrangler-action@9681c2997648301493e78cacbfb790a9f19c833f # v3
|
uses: cloudflare/wrangler-action@05f17c4a695b4d94b57b59997562c6a4624c64e4 # v3
|
||||||
with:
|
with:
|
||||||
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
command: pages deploy target/deploy --project-name=docs
|
command: pages deploy target/deploy --project-name=docs
|
||||||
|
|
||||||
- name: Deploy Install
|
- name: Deploy Install
|
||||||
uses: cloudflare/wrangler-action@9681c2997648301493e78cacbfb790a9f19c833f # v3
|
uses: cloudflare/wrangler-action@05f17c4a695b4d94b57b59997562c6a4624c64e4 # v3
|
||||||
with:
|
with:
|
||||||
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
command: r2 object put -f script/install.sh zed-open-source-website-assets/install.sh
|
command: r2 object put -f script/install.sh zed-open-source-website-assets/install.sh
|
||||||
|
|
||||||
- name: Deploy Docs Workers
|
- name: Deploy Docs Workers
|
||||||
uses: cloudflare/wrangler-action@9681c2997648301493e78cacbfb790a9f19c833f # v3
|
uses: cloudflare/wrangler-action@05f17c4a695b4d94b57b59997562c6a4624c64e4 # v3
|
||||||
with:
|
with:
|
||||||
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
command: deploy .cloudflare/docs-proxy/src/worker.js
|
command: deploy .cloudflare/docs-proxy/src/worker.js
|
||||||
|
|
||||||
- name: Deploy Install Workers
|
- name: Deploy Install Workers
|
||||||
uses: cloudflare/wrangler-action@9681c2997648301493e78cacbfb790a9f19c833f # v3
|
uses: cloudflare/wrangler-action@05f17c4a695b4d94b57b59997562c6a4624c64e4 # v3
|
||||||
with:
|
with:
|
||||||
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
|
|||||||
2
.github/workflows/randomized_tests.yml
vendored
2
.github/workflows/randomized_tests.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
|||||||
- buildjet-16vcpu-ubuntu-2204
|
- buildjet-16vcpu-ubuntu-2204
|
||||||
steps:
|
steps:
|
||||||
- name: Install Node
|
- name: Install Node
|
||||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4
|
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
|
||||||
with:
|
with:
|
||||||
node-version: "18"
|
node-version: "18"
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/release_nightly.yml
vendored
2
.github/workflows/release_nightly.yml
vendored
@@ -70,7 +70,7 @@ jobs:
|
|||||||
ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON: ${{ secrets.ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON }}
|
ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON: ${{ secrets.ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON }}
|
||||||
steps:
|
steps:
|
||||||
- name: Install Node
|
- name: Install Node
|
||||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4
|
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4
|
||||||
with:
|
with:
|
||||||
node-version: "18"
|
node-version: "18"
|
||||||
|
|
||||||
|
|||||||
2
.mailmap
2
.mailmap
@@ -60,6 +60,8 @@ Max Brunsfeld <maxbrunsfeld@gmail.com>
|
|||||||
Max Brunsfeld <maxbrunsfeld@gmail.com> <max@zed.dev>
|
Max Brunsfeld <maxbrunsfeld@gmail.com> <max@zed.dev>
|
||||||
Max Linke <maxlinke88@gmail.com>
|
Max Linke <maxlinke88@gmail.com>
|
||||||
Max Linke <maxlinke88@gmail.com> <kain88-de@users.noreply.github.com>
|
Max Linke <maxlinke88@gmail.com> <kain88-de@users.noreply.github.com>
|
||||||
|
Michael Sloan <michael@zed.dev>
|
||||||
|
Michael Sloan <michael@zed.dev> <mgsloan@google.com>
|
||||||
Mikayla Maki <mikayla@zed.dev>
|
Mikayla Maki <mikayla@zed.dev>
|
||||||
Mikayla Maki <mikayla@zed.dev> <mikayla.c.maki@gmail.com>
|
Mikayla Maki <mikayla@zed.dev> <mikayla.c.maki@gmail.com>
|
||||||
Mikayla Maki <mikayla@zed.dev> <mikayla.c.maki@icloud.com>
|
Mikayla Maki <mikayla@zed.dev> <mikayla.c.maki@icloud.com>
|
||||||
|
|||||||
1849
Cargo.lock
generated
1849
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
72
Cargo.toml
72
Cargo.toml
@@ -1,24 +1,17 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = [
|
members = [
|
||||||
"crates/activity_indicator",
|
|
||||||
"crates/anthropic",
|
"crates/anthropic",
|
||||||
"crates/assets",
|
"crates/assets",
|
||||||
"crates/assistant",
|
|
||||||
"crates/assistant_slash_command",
|
|
||||||
"crates/assistant_tool",
|
"crates/assistant_tool",
|
||||||
"crates/audio",
|
"crates/audio",
|
||||||
"crates/auto_update",
|
|
||||||
"crates/breadcrumbs",
|
|
||||||
"crates/call",
|
"crates/call",
|
||||||
"crates/channel",
|
"crates/channel",
|
||||||
"crates/cli",
|
"crates/cli",
|
||||||
"crates/client",
|
"crates/client",
|
||||||
"crates/clock",
|
"crates/clock",
|
||||||
"crates/collab",
|
"crates/collab",
|
||||||
"crates/collab_ui",
|
|
||||||
"crates/collections",
|
"crates/collections",
|
||||||
"crates/command_palette",
|
|
||||||
"crates/command_palette_hooks",
|
"crates/command_palette_hooks",
|
||||||
"crates/context_servers",
|
"crates/context_servers",
|
||||||
"crates/copilot",
|
"crates/copilot",
|
||||||
@@ -30,10 +23,9 @@ members = [
|
|||||||
"crates/extension",
|
"crates/extension",
|
||||||
"crates/extension_api",
|
"crates/extension_api",
|
||||||
"crates/extension_cli",
|
"crates/extension_cli",
|
||||||
"crates/extensions_ui",
|
"crates/extension_host",
|
||||||
"crates/feature_flags",
|
"crates/feature_flags",
|
||||||
"crates/feedback",
|
"crates/feedback",
|
||||||
"crates/file_finder",
|
|
||||||
"crates/file_icons",
|
"crates/file_icons",
|
||||||
"crates/fs",
|
"crates/fs",
|
||||||
"crates/fsevent",
|
"crates/fsevent",
|
||||||
@@ -48,13 +40,9 @@ members = [
|
|||||||
"crates/http_client",
|
"crates/http_client",
|
||||||
"crates/image_viewer",
|
"crates/image_viewer",
|
||||||
"crates/indexed_docs",
|
"crates/indexed_docs",
|
||||||
"crates/inline_completion_button",
|
|
||||||
"crates/install_cli",
|
"crates/install_cli",
|
||||||
"crates/journal",
|
"crates/journal",
|
||||||
"crates/language",
|
"crates/language",
|
||||||
"crates/language_model",
|
|
||||||
"crates/language_selector",
|
|
||||||
"crates/language_tools",
|
|
||||||
"crates/languages",
|
"crates/languages",
|
||||||
"crates/live_kit_client",
|
"crates/live_kit_client",
|
||||||
"crates/live_kit_server",
|
"crates/live_kit_server",
|
||||||
@@ -69,35 +57,26 @@ members = [
|
|||||||
"crates/ollama",
|
"crates/ollama",
|
||||||
"crates/open_ai",
|
"crates/open_ai",
|
||||||
"crates/outline",
|
"crates/outline",
|
||||||
"crates/outline_panel",
|
|
||||||
"crates/paths",
|
"crates/paths",
|
||||||
"crates/picker",
|
"crates/picker",
|
||||||
"crates/prettier",
|
"crates/prettier",
|
||||||
"crates/project",
|
"crates/project",
|
||||||
"crates/project_panel",
|
|
||||||
"crates/project_symbols",
|
|
||||||
"crates/proto",
|
"crates/proto",
|
||||||
"crates/quick_action_bar",
|
|
||||||
"crates/recent_projects",
|
|
||||||
"crates/refineable",
|
"crates/refineable",
|
||||||
"crates/refineable/derive_refineable",
|
"crates/refineable/derive_refineable",
|
||||||
"crates/release_channel",
|
"crates/release_channel",
|
||||||
"crates/remote",
|
"crates/remote",
|
||||||
"crates/remote_server",
|
"crates/remote_server",
|
||||||
"crates/repl",
|
|
||||||
"crates/reqwest_client",
|
"crates/reqwest_client",
|
||||||
"crates/rich_text",
|
"crates/rich_text",
|
||||||
"crates/rope",
|
"crates/rope",
|
||||||
"crates/rpc",
|
"crates/rpc",
|
||||||
"crates/search",
|
"crates/search",
|
||||||
"crates/semantic_index",
|
|
||||||
"crates/semantic_version",
|
"crates/semantic_version",
|
||||||
"crates/session",
|
"crates/session",
|
||||||
"crates/settings",
|
"crates/settings",
|
||||||
"crates/settings_ui",
|
|
||||||
"crates/snippet",
|
"crates/snippet",
|
||||||
"crates/snippet_provider",
|
"crates/snippet_provider",
|
||||||
"crates/snippets_ui",
|
|
||||||
"crates/sqlez",
|
"crates/sqlez",
|
||||||
"crates/sqlez_macros",
|
"crates/sqlez_macros",
|
||||||
"crates/story",
|
"crates/story",
|
||||||
@@ -105,31 +84,24 @@ members = [
|
|||||||
"crates/sum_tree",
|
"crates/sum_tree",
|
||||||
"crates/supermaven",
|
"crates/supermaven",
|
||||||
"crates/supermaven_api",
|
"crates/supermaven_api",
|
||||||
"crates/tab_switcher",
|
|
||||||
"crates/task",
|
"crates/task",
|
||||||
"crates/tasks_ui",
|
"crates/tasks_ui",
|
||||||
"crates/telemetry_events",
|
"crates/telemetry_events",
|
||||||
"crates/terminal",
|
"crates/terminal",
|
||||||
"crates/terminal_view",
|
|
||||||
"crates/text",
|
"crates/text",
|
||||||
"crates/theme",
|
"crates/theme",
|
||||||
"crates/theme_importer",
|
"crates/theme_importer",
|
||||||
"crates/theme_selector",
|
|
||||||
"crates/time_format",
|
"crates/time_format",
|
||||||
"crates/title_bar",
|
|
||||||
"crates/toolchain_selector",
|
|
||||||
"crates/ui",
|
"crates/ui",
|
||||||
"crates/ui_input",
|
"crates/ui_input",
|
||||||
"crates/ui_macros",
|
"crates/ui_macros",
|
||||||
"crates/reqwest_client",
|
"crates/reqwest_client",
|
||||||
"crates/util",
|
"crates/util",
|
||||||
"crates/vcs_menu",
|
|
||||||
"crates/vim",
|
|
||||||
"crates/welcome",
|
|
||||||
"crates/workspace",
|
"crates/workspace",
|
||||||
"crates/worktree",
|
"crates/worktree",
|
||||||
"crates/zed",
|
"crates/zed",
|
||||||
"crates/zed_actions",
|
"crates/zed_actions",
|
||||||
|
"crates/zed_common",
|
||||||
|
|
||||||
#
|
#
|
||||||
# Extensions
|
# Extensions
|
||||||
@@ -176,25 +148,18 @@ default-members = ["crates/zed"]
|
|||||||
# Workspace member crates
|
# Workspace member crates
|
||||||
#
|
#
|
||||||
|
|
||||||
activity_indicator = { path = "crates/activity_indicator" }
|
|
||||||
ai = { path = "crates/ai" }
|
ai = { path = "crates/ai" }
|
||||||
anthropic = { path = "crates/anthropic" }
|
anthropic = { path = "crates/anthropic" }
|
||||||
assets = { path = "crates/assets" }
|
assets = { path = "crates/assets" }
|
||||||
assistant = { path = "crates/assistant" }
|
|
||||||
assistant_slash_command = { path = "crates/assistant_slash_command" }
|
|
||||||
assistant_tool = { path = "crates/assistant_tool" }
|
assistant_tool = { path = "crates/assistant_tool" }
|
||||||
audio = { path = "crates/audio" }
|
audio = { path = "crates/audio" }
|
||||||
auto_update = { path = "crates/auto_update" }
|
|
||||||
breadcrumbs = { path = "crates/breadcrumbs" }
|
|
||||||
call = { path = "crates/call" }
|
call = { path = "crates/call" }
|
||||||
channel = { path = "crates/channel" }
|
channel = { path = "crates/channel" }
|
||||||
cli = { path = "crates/cli" }
|
cli = { path = "crates/cli" }
|
||||||
client = { path = "crates/client" }
|
client = { path = "crates/client" }
|
||||||
clock = { path = "crates/clock" }
|
clock = { path = "crates/clock" }
|
||||||
collab = { path = "crates/collab" }
|
collab = { path = "crates/collab" }
|
||||||
collab_ui = { path = "crates/collab_ui" }
|
|
||||||
collections = { path = "crates/collections" }
|
collections = { path = "crates/collections" }
|
||||||
command_palette = { path = "crates/command_palette" }
|
|
||||||
command_palette_hooks = { path = "crates/command_palette_hooks" }
|
command_palette_hooks = { path = "crates/command_palette_hooks" }
|
||||||
context_servers = { path = "crates/context_servers" }
|
context_servers = { path = "crates/context_servers" }
|
||||||
copilot = { path = "crates/copilot" }
|
copilot = { path = "crates/copilot" }
|
||||||
@@ -202,10 +167,9 @@ db = { path = "crates/db" }
|
|||||||
diagnostics = { path = "crates/diagnostics" }
|
diagnostics = { path = "crates/diagnostics" }
|
||||||
editor = { path = "crates/editor" }
|
editor = { path = "crates/editor" }
|
||||||
extension = { path = "crates/extension" }
|
extension = { path = "crates/extension" }
|
||||||
extensions_ui = { path = "crates/extensions_ui" }
|
extension_host = { path = "crates/extension_host" }
|
||||||
feature_flags = { path = "crates/feature_flags" }
|
feature_flags = { path = "crates/feature_flags" }
|
||||||
feedback = { path = "crates/feedback" }
|
feedback = { path = "crates/feedback" }
|
||||||
file_finder = { path = "crates/file_finder" }
|
|
||||||
file_icons = { path = "crates/file_icons" }
|
file_icons = { path = "crates/file_icons" }
|
||||||
fs = { path = "crates/fs" }
|
fs = { path = "crates/fs" }
|
||||||
fsevent = { path = "crates/fsevent" }
|
fsevent = { path = "crates/fsevent" }
|
||||||
@@ -220,13 +184,9 @@ html_to_markdown = { path = "crates/html_to_markdown" }
|
|||||||
http_client = { path = "crates/http_client" }
|
http_client = { path = "crates/http_client" }
|
||||||
image_viewer = { path = "crates/image_viewer" }
|
image_viewer = { path = "crates/image_viewer" }
|
||||||
indexed_docs = { path = "crates/indexed_docs" }
|
indexed_docs = { path = "crates/indexed_docs" }
|
||||||
inline_completion_button = { path = "crates/inline_completion_button" }
|
|
||||||
install_cli = { path = "crates/install_cli" }
|
install_cli = { path = "crates/install_cli" }
|
||||||
journal = { path = "crates/journal" }
|
journal = { path = "crates/journal" }
|
||||||
language = { path = "crates/language" }
|
language = { path = "crates/language" }
|
||||||
language_model = { path = "crates/language_model" }
|
|
||||||
language_selector = { path = "crates/language_selector" }
|
|
||||||
language_tools = { path = "crates/language_tools" }
|
|
||||||
languages = { path = "crates/languages" }
|
languages = { path = "crates/languages" }
|
||||||
live_kit_client = { path = "crates/live_kit_client" }
|
live_kit_client = { path = "crates/live_kit_client" }
|
||||||
live_kit_server = { path = "crates/live_kit_server" }
|
live_kit_server = { path = "crates/live_kit_server" }
|
||||||
@@ -241,36 +201,27 @@ notifications = { path = "crates/notifications" }
|
|||||||
ollama = { path = "crates/ollama" }
|
ollama = { path = "crates/ollama" }
|
||||||
open_ai = { path = "crates/open_ai" }
|
open_ai = { path = "crates/open_ai" }
|
||||||
outline = { path = "crates/outline" }
|
outline = { path = "crates/outline" }
|
||||||
outline_panel = { path = "crates/outline_panel" }
|
|
||||||
paths = { path = "crates/paths" }
|
paths = { path = "crates/paths" }
|
||||||
picker = { path = "crates/picker" }
|
picker = { path = "crates/picker" }
|
||||||
plugin = { path = "crates/plugin" }
|
plugin = { path = "crates/plugin" }
|
||||||
plugin_macros = { path = "crates/plugin_macros" }
|
plugin_macros = { path = "crates/plugin_macros" }
|
||||||
prettier = { path = "crates/prettier" }
|
prettier = { path = "crates/prettier" }
|
||||||
project = { path = "crates/project" }
|
project = { path = "crates/project" }
|
||||||
project_panel = { path = "crates/project_panel" }
|
|
||||||
project_symbols = { path = "crates/project_symbols" }
|
|
||||||
proto = { path = "crates/proto" }
|
proto = { path = "crates/proto" }
|
||||||
quick_action_bar = { path = "crates/quick_action_bar" }
|
|
||||||
recent_projects = { path = "crates/recent_projects" }
|
|
||||||
refineable = { path = "crates/refineable" }
|
refineable = { path = "crates/refineable" }
|
||||||
release_channel = { path = "crates/release_channel" }
|
release_channel = { path = "crates/release_channel" }
|
||||||
remote = { path = "crates/remote" }
|
remote = { path = "crates/remote" }
|
||||||
remote_server = { path = "crates/remote_server" }
|
remote_server = { path = "crates/remote_server" }
|
||||||
repl = { path = "crates/repl" }
|
|
||||||
reqwest_client = { path = "crates/reqwest_client" }
|
reqwest_client = { path = "crates/reqwest_client" }
|
||||||
rich_text = { path = "crates/rich_text" }
|
rich_text = { path = "crates/rich_text" }
|
||||||
rope = { path = "crates/rope" }
|
rope = { path = "crates/rope" }
|
||||||
rpc = { path = "crates/rpc" }
|
rpc = { path = "crates/rpc" }
|
||||||
search = { path = "crates/search" }
|
search = { path = "crates/search" }
|
||||||
semantic_index = { path = "crates/semantic_index" }
|
|
||||||
semantic_version = { path = "crates/semantic_version" }
|
semantic_version = { path = "crates/semantic_version" }
|
||||||
session = { path = "crates/session" }
|
session = { path = "crates/session" }
|
||||||
settings = { path = "crates/settings" }
|
settings = { path = "crates/settings" }
|
||||||
settings_ui = { path = "crates/settings_ui" }
|
|
||||||
snippet = { path = "crates/snippet" }
|
snippet = { path = "crates/snippet" }
|
||||||
snippet_provider = { path = "crates/snippet_provider" }
|
snippet_provider = { path = "crates/snippet_provider" }
|
||||||
snippets_ui = { path = "crates/snippets_ui" }
|
|
||||||
sqlez = { path = "crates/sqlez" }
|
sqlez = { path = "crates/sqlez" }
|
||||||
sqlez_macros = { path = "crates/sqlez_macros" }
|
sqlez_macros = { path = "crates/sqlez_macros" }
|
||||||
story = { path = "crates/story" }
|
story = { path = "crates/story" }
|
||||||
@@ -278,30 +229,23 @@ storybook = { path = "crates/storybook" }
|
|||||||
sum_tree = { path = "crates/sum_tree" }
|
sum_tree = { path = "crates/sum_tree" }
|
||||||
supermaven = { path = "crates/supermaven" }
|
supermaven = { path = "crates/supermaven" }
|
||||||
supermaven_api = { path = "crates/supermaven_api" }
|
supermaven_api = { path = "crates/supermaven_api" }
|
||||||
tab_switcher = { path = "crates/tab_switcher" }
|
|
||||||
task = { path = "crates/task" }
|
task = { path = "crates/task" }
|
||||||
tasks_ui = { path = "crates/tasks_ui" }
|
tasks_ui = { path = "crates/tasks_ui" }
|
||||||
telemetry_events = { path = "crates/telemetry_events" }
|
telemetry_events = { path = "crates/telemetry_events" }
|
||||||
terminal = { path = "crates/terminal" }
|
terminal = { path = "crates/terminal" }
|
||||||
terminal_view = { path = "crates/terminal_view" }
|
|
||||||
text = { path = "crates/text" }
|
text = { path = "crates/text" }
|
||||||
theme = { path = "crates/theme" }
|
theme = { path = "crates/theme" }
|
||||||
theme_importer = { path = "crates/theme_importer" }
|
theme_importer = { path = "crates/theme_importer" }
|
||||||
theme_selector = { path = "crates/theme_selector" }
|
|
||||||
time_format = { path = "crates/time_format" }
|
time_format = { path = "crates/time_format" }
|
||||||
title_bar = { path = "crates/title_bar" }
|
|
||||||
toolchain_selector = { path = "crates/toolchain_selector" }
|
|
||||||
ui = { path = "crates/ui" }
|
ui = { path = "crates/ui" }
|
||||||
ui_input = { path = "crates/ui_input" }
|
ui_input = { path = "crates/ui_input" }
|
||||||
ui_macros = { path = "crates/ui_macros" }
|
ui_macros = { path = "crates/ui_macros" }
|
||||||
util = { path = "crates/util" }
|
util = { path = "crates/util" }
|
||||||
vcs_menu = { path = "crates/vcs_menu" }
|
|
||||||
vim = { path = "crates/vim" }
|
|
||||||
welcome = { path = "crates/welcome" }
|
|
||||||
workspace = { path = "crates/workspace" }
|
workspace = { path = "crates/workspace" }
|
||||||
worktree = { path = "crates/worktree" }
|
worktree = { path = "crates/worktree" }
|
||||||
zed = { path = "crates/zed" }
|
zed = { path = "crates/zed" }
|
||||||
zed_actions = { path = "crates/zed_actions" }
|
zed_actions = { path = "crates/zed_actions" }
|
||||||
|
zed_common = { path = "crates/zed_common" }
|
||||||
|
|
||||||
#
|
#
|
||||||
# External crates
|
# External crates
|
||||||
@@ -337,6 +281,7 @@ chrono = { version = "0.4", features = ["serde"] }
|
|||||||
clap = { version = "4.4", features = ["derive"] }
|
clap = { version = "4.4", features = ["derive"] }
|
||||||
clickhouse = "0.11.6"
|
clickhouse = "0.11.6"
|
||||||
cocoa = "0.26"
|
cocoa = "0.26"
|
||||||
|
cocoa-foundation = "0.2.0"
|
||||||
convert_case = "0.6.0"
|
convert_case = "0.6.0"
|
||||||
core-foundation = "0.9.3"
|
core-foundation = "0.9.3"
|
||||||
core-foundation-sys = "0.8.6"
|
core-foundation-sys = "0.8.6"
|
||||||
@@ -348,6 +293,7 @@ ec4rs = "1.1"
|
|||||||
emojis = "0.6.1"
|
emojis = "0.6.1"
|
||||||
env_logger = "0.11"
|
env_logger = "0.11"
|
||||||
exec = "0.3.1"
|
exec = "0.3.1"
|
||||||
|
fancy-regex = "0.14.0"
|
||||||
fork = "0.2.0"
|
fork = "0.2.0"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
futures-batch = "0.6.1"
|
futures-batch = "0.6.1"
|
||||||
@@ -370,7 +316,7 @@ linkify = "0.10.0"
|
|||||||
log = { version = "0.4.16", features = ["kv_unstable_serde", "serde"] }
|
log = { version = "0.4.16", features = ["kv_unstable_serde", "serde"] }
|
||||||
markup5ever_rcdom = "0.3.0"
|
markup5ever_rcdom = "0.3.0"
|
||||||
nanoid = "0.4"
|
nanoid = "0.4"
|
||||||
nbformat = "0.3.1"
|
nbformat = "0.3.2"
|
||||||
nix = "0.29"
|
nix = "0.29"
|
||||||
num-format = "0.4.4"
|
num-format = "0.4.4"
|
||||||
once_cell = "1.19.0"
|
once_cell = "1.19.0"
|
||||||
@@ -379,6 +325,7 @@ palette = { version = "0.7.5", default-features = false, features = ["std"] }
|
|||||||
parking_lot = "0.12.1"
|
parking_lot = "0.12.1"
|
||||||
pathdiff = "0.2"
|
pathdiff = "0.2"
|
||||||
pet = { git = "https://github.com/microsoft/python-environment-tools.git", rev = "ffcbf3f28c46633abd5448a52b1f396c322e0d6c" }
|
pet = { git = "https://github.com/microsoft/python-environment-tools.git", rev = "ffcbf3f28c46633abd5448a52b1f396c322e0d6c" }
|
||||||
|
pet-fs = { git = "https://github.com/microsoft/python-environment-tools.git", rev = "ffcbf3f28c46633abd5448a52b1f396c322e0d6c" }
|
||||||
pet-conda = { git = "https://github.com/microsoft/python-environment-tools.git", rev = "ffcbf3f28c46633abd5448a52b1f396c322e0d6c" }
|
pet-conda = { git = "https://github.com/microsoft/python-environment-tools.git", rev = "ffcbf3f28c46633abd5448a52b1f396c322e0d6c" }
|
||||||
pet-core = { git = "https://github.com/microsoft/python-environment-tools.git", rev = "ffcbf3f28c46633abd5448a52b1f396c322e0d6c" }
|
pet-core = { git = "https://github.com/microsoft/python-environment-tools.git", rev = "ffcbf3f28c46633abd5448a52b1f396c322e0d6c" }
|
||||||
pet-poetry = { git = "https://github.com/microsoft/python-environment-tools.git", rev = "ffcbf3f28c46633abd5448a52b1f396c322e0d6c" }
|
pet-poetry = { git = "https://github.com/microsoft/python-environment-tools.git", rev = "ffcbf3f28c46633abd5448a52b1f396c322e0d6c" }
|
||||||
@@ -403,7 +350,7 @@ reqwest = { git = "https://github.com/zed-industries/reqwest.git", rev = "fd110f
|
|||||||
"stream",
|
"stream",
|
||||||
] }
|
] }
|
||||||
rsa = "0.9.6"
|
rsa = "0.9.6"
|
||||||
runtimelib = { version = "0.16.0", default-features = false, features = [
|
runtimelib = { version = "0.16.1", default-features = false, features = [
|
||||||
"async-dispatcher-runtime",
|
"async-dispatcher-runtime",
|
||||||
] }
|
] }
|
||||||
rustc-demangle = "0.1.23"
|
rustc-demangle = "0.1.23"
|
||||||
@@ -473,6 +420,7 @@ tree-sitter-yaml = { git = "https://github.com/zed-industries/tree-sitter-yaml",
|
|||||||
unicase = "2.6"
|
unicase = "2.6"
|
||||||
unindent = "0.1.7"
|
unindent = "0.1.7"
|
||||||
unicode-segmentation = "1.10"
|
unicode-segmentation = "1.10"
|
||||||
|
unicode-script = "0.5.7"
|
||||||
url = "2.2"
|
url = "2.2"
|
||||||
uuid = { version = "1.1.2", features = ["v4", "v5", "serde"] }
|
uuid = { version = "1.1.2", features = ["v4", "v5", "serde"] }
|
||||||
wasmparser = "0.215"
|
wasmparser = "0.215"
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path fill-rule="evenodd" fill="black" d="M 3.828125 14.601562 C 3.894531 15.726562 5.183594 16.375 6.132812 15.785156 L 6.136719 15.785156 L 8.988281 13.824219 C 8.996094 13.816406 9.007812 13.8125 9.015625 13.804688 C 9.203125 13.675781 9.4375 13.636719 9.65625 13.691406 L 12.988281 14.550781 C 14.105469 14.839844 15.140625 13.769531 14.8125 12.667969 L 13.832031 9.386719 C 13.769531 9.167969 13.800781 8.9375 13.921875 8.75 C 13.921875 8.746094 13.925781 8.746094 13.925781 8.746094 L 15.777344 5.863281 L 15.777344 5.859375 C 15.78125 5.851562 15.785156 5.84375 15.789062 5.835938 L 15.792969 5.835938 C 16.382812 4.871094 15.6875 3.582031 14.542969 3.554688 L 11.109375 3.472656 C 10.878906 3.464844 10.664062 3.359375 10.519531 3.183594 L 8.339844 0.542969 C 8.019531 0.152344 7.550781 -0.015625 7.105469 0.0078125 L 7.101562 0.0078125 C 7.039062 0.0117188 6.976562 0.0195312 6.914062 0.0273438 C 6.414062 0.117188 5.945312 0.453125 5.75 1 L 4.609375 4.222656 C 4.535156 4.4375 4.367188 4.613281 4.152344 4.695312 L 0.957031 5.945312 C -0.121094 6.363281 -0.328125 7.835938 0.589844 8.535156 L 3.316406 10.609375 C 3.5 10.75 3.609375 10.960938 3.625 11.191406 Z M 7.515625 1.847656 C 7.421875 1.730469 7.296875 1.695312 7.183594 1.714844 C 7.066406 1.734375 6.960938 1.8125 6.914062 1.953125 L 5.867188 4.902344 C 5.699219 5.382812 5.328125 5.765625 4.851562 5.949219 L 1.925781 7.09375 C 1.785156 7.148438 1.710938 7.253906 1.695312 7.371094 C 1.679688 7.484375 1.71875 7.605469 1.839844 7.695312 L 4.335938 9.597656 C 4.742188 9.90625 4.992188 10.375 5.023438 10.882812 L 5.207031 14.003906 C 5.214844 14.152344 5.296875 14.253906 5.398438 14.304688 C 5.503906 14.355469 5.632812 14.355469 5.757812 14.269531 L 8.347656 12.492188 C 8.765625 12.207031 9.292969 12.113281 9.785156 12.242188 L 12.824219 13.027344 C 12.972656 13.066406 13.09375 13.023438 13.175781 12.9375 C 13.257812 12.855469 13.296875 12.734375 13.253906 12.589844 L 12.355469 9.589844 C 12.210938 9.105469 12.285156 8.578125 12.558594 8.148438 L 14.253906 5.511719 C 14.335938 5.386719 14.332031 5.257812 14.277344 5.15625 C 14.222656 5.054688 14.117188 4.980469 13.964844 4.976562 L 10.824219 4.902344 C 10.316406 4.886719 9.835938 4.65625 9.511719 4.261719 Z M 7.515625 1.847656 "/>
|
<path d="M7.3848 9.30444C7.3848 9.30444 7.53254 10.2646 8.53248 10.0882C9.53242 9.91193 9.36378 8.95549 9.36378 8.95549" stroke="black" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
<path fill="black" d="M 5.71875 7.257812 C 5.671875 7.25 5.628906 7.246094 5.582031 7.246094 C 5.09375 7.246094 4.695312 7.644531 4.695312 8.128906 C 4.695312 8.613281 5.09375 9.011719 5.582031 9.011719 C 6.070312 9.011719 6.46875 8.613281 6.46875 8.128906 C 6.46875 7.6875 6.140625 7.320312 5.71875 7.257812 Z M 5.71875 7.257812 "/>
|
<path d="M5.54155 5.54157C6.12355 4.90104 6.01688 2.62541 7.22875 2.3985C8.44063 2.17158 9.19097 4.33148 9.91982 4.6814C10.6487 5.03133 12.8517 4.3028 13.4381 5.38734C14.0244 6.47188 12.1395 7.95973 12.026 8.64088C11.9126 9.32203 13.3614 11.2416 12.4675 12.1701C11.5736 13.0986 9.73005 11.7545 8.90486 11.8834C8.07966 12.0123 6.79244 13.9095 5.67367 13.3502C4.55491 12.7909 5.16702 10.5455 4.82437 9.87612C4.48171 9.20673 2.34028 8.54978 2.4525 7.35049C2.56471 6.15121 4.95956 6.1821 5.54155 5.54157Z" stroke="#FF7676" stroke-opacity="0.52" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
<path fill="black" d="M 11.019531 7.953125 C 10.976562 7.957031 10.929688 7.960938 10.886719 7.960938 C 10.398438 7.960938 10 7.5625 10 7.078125 C 10 6.59375 10.398438 6.195312 10.886719 6.195312 C 11.371094 6.195312 11.773438 6.59375 11.773438 7.078125 C 11.773438 7.519531 11.445312 7.886719 11.019531 7.953125 Z M 11.019531 7.953125 "/>
|
<path d="M5.54155 5.54157C6.12355 4.90104 6.01688 2.62541 7.22875 2.3985C8.44063 2.17158 9.19097 4.33148 9.91982 4.6814C10.6487 5.03133 12.8517 4.3028 13.4381 5.38734C14.0244 6.47188 12.1395 7.95973 12.026 8.64088C11.9126 9.32203 13.3614 11.2416 12.4675 12.1701C11.5736 13.0986 9.73005 11.7545 8.90486 11.8834C8.07966 12.0123 6.79244 13.9095 5.67367 13.3502C4.55491 12.7909 5.16702 10.5455 4.82437 9.87612C4.48171 9.20673 2.34028 8.54978 2.4525 7.35049C2.56471 6.15121 4.95956 6.1821 5.54155 5.54157Z" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
<path fill="black" d="M 7.269531 9.089844 C 7.53125 8.988281 7.828125 9.113281 7.933594 9.375 C 8.125 9.859375 8.503906 9.996094 8.796875 9.949219 C 9.082031 9.898438 9.378906 9.664062 9.378906 9.136719 C 9.378906 8.855469 9.605469 8.628906 9.886719 8.628906 C 10.167969 8.628906 10.398438 8.855469 10.398438 9.136719 C 10.398438 10.140625 9.757812 10.816406 8.96875 10.949219 C 8.1875 11.078125 7.351562 10.664062 6.988281 9.75 C 6.882812 9.488281 7.011719 9.195312 7.269531 9.089844 Z M 7.269531 9.089844 "/>
|
<circle cx="6.25098" cy="7.75" r="0.75" fill="black"/>
|
||||||
|
<circle cx="10.1035" cy="7.25" r="0.75" fill="black"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 1.6 KiB |
1
assets/icons/file_search.svg
Normal file
1
assets/icons/file_search.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-file-search"><path d="M14 2v4a2 2 0 0 0 2 2h4"/><path d="M4.268 21a2 2 0 0 0 1.727 1H18a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v3"/><path d="m9 18-1.5-1.5"/><circle cx="5" cy="14" r="3"/></svg>
|
||||||
|
After Width: | Height: | Size: 393 B |
5
assets/icons/refresh_title.svg
Normal file
5
assets/icons/refresh_title.svg
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M7 21V12M7 12H3M7 12H11" stroke="black" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
<path d="M21 19L16 19L16 14" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M7.99987 5.07027L7.49915 4.20467L7.99987 5.07027ZM6.04652 5.25026C5.63245 5.61573 5.59305 6.24766 5.95851 6.66173C6.32398 7.0758 6.95592 7.1152 7.36999 6.74974L6.04652 5.25026ZM11.9999 5C15.8659 5 18.9999 8.13401 18.9999 12H20.9999C20.9999 7.02944 16.9705 3 11.9999 3V5ZM18.9999 12C18.9999 14.2101 17.9768 16.1806 16.3744 17.4651L17.6254 19.0256C19.6809 17.3779 20.9999 14.8426 20.9999 12H18.9999ZM8.5006 5.93588C9.5292 5.34086 10.7232 5 11.9999 5V3C10.3623 3 8.82395 3.4383 7.49915 4.20467L8.5006 5.93588ZM7.36999 6.74974C7.71803 6.44255 8.09667 6.16954 8.5006 5.93588L7.49915 4.20467C6.9797 4.50515 6.49329 4.85593 6.04652 5.25026L7.36999 6.74974Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 979 B |
1
assets/icons/wand.svg
Normal file
1
assets/icons/wand.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-wand"><path d="M15 4V2"/><path d="M15 16v-2"/><path d="M8 9h2"/><path d="M20 9h2"/><path d="M17.8 11.8 19 13"/><path d="M15 9h.01"/><path d="M17.8 6.2 19 5"/><path d="m3 21 9-9"/><path d="M12.2 6.2 11 5"/></svg>
|
||||||
|
After Width: | Height: | Size: 414 B |
@@ -56,7 +56,8 @@
|
|||||||
"shift-tab": "editor::TabPrev",
|
"shift-tab": "editor::TabPrev",
|
||||||
"ctrl-k": "editor::CutToEndOfLine",
|
"ctrl-k": "editor::CutToEndOfLine",
|
||||||
// "ctrl-t": "editor::Transpose",
|
// "ctrl-t": "editor::Transpose",
|
||||||
"alt-q": "editor::Rewrap",
|
"ctrl-k ctrl-q": "editor::Rewrap",
|
||||||
|
"ctrl-k q": "editor::Rewrap",
|
||||||
"ctrl-backspace": "editor::DeleteToPreviousWordStart",
|
"ctrl-backspace": "editor::DeleteToPreviousWordStart",
|
||||||
"ctrl-delete": "editor::DeleteToNextWordEnd",
|
"ctrl-delete": "editor::DeleteToNextWordEnd",
|
||||||
"shift-delete": "editor::Cut",
|
"shift-delete": "editor::Cut",
|
||||||
@@ -126,7 +127,8 @@
|
|||||||
"shift-enter": "editor::Newline",
|
"shift-enter": "editor::Newline",
|
||||||
"ctrl-enter": "editor::NewlineAbove",
|
"ctrl-enter": "editor::NewlineAbove",
|
||||||
"ctrl-shift-enter": "editor::NewlineBelow",
|
"ctrl-shift-enter": "editor::NewlineBelow",
|
||||||
"alt-z": "editor::ToggleSoftWrap",
|
"ctrl-k ctrl-z": "editor::ToggleSoftWrap",
|
||||||
|
"ctrl-k z": "editor::ToggleSoftWrap",
|
||||||
"ctrl-f": "buffer_search::Deploy",
|
"ctrl-f": "buffer_search::Deploy",
|
||||||
"ctrl-h": ["buffer_search::Deploy", { "replace_enabled": true }],
|
"ctrl-h": ["buffer_search::Deploy", { "replace_enabled": true }],
|
||||||
// "cmd-e": ["buffer_search::Deploy", { "focus": false }],
|
// "cmd-e": ["buffer_search::Deploy", { "focus": false }],
|
||||||
@@ -140,7 +142,7 @@
|
|||||||
"bindings": {
|
"bindings": {
|
||||||
"alt-]": "editor::NextInlineCompletion",
|
"alt-]": "editor::NextInlineCompletion",
|
||||||
"alt-[": "editor::PreviousInlineCompletion",
|
"alt-[": "editor::PreviousInlineCompletion",
|
||||||
"ctrl-right": "editor::AcceptPartialInlineCompletion"
|
"alt-right": "editor::AcceptPartialInlineCompletion"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -169,7 +171,7 @@
|
|||||||
"ctrl-k c": "assistant::CopyCode",
|
"ctrl-k c": "assistant::CopyCode",
|
||||||
"ctrl-g": "search::SelectNextMatch",
|
"ctrl-g": "search::SelectNextMatch",
|
||||||
"ctrl-shift-g": "search::SelectPrevMatch",
|
"ctrl-shift-g": "search::SelectPrevMatch",
|
||||||
"alt-m": "assistant::ToggleModelSelector",
|
"ctrl-shift-m": "assistant::ToggleModelSelector",
|
||||||
"ctrl-k h": "assistant::DeployHistory",
|
"ctrl-k h": "assistant::DeployHistory",
|
||||||
"ctrl-k l": "assistant::DeployPromptLibrary",
|
"ctrl-k l": "assistant::DeployPromptLibrary",
|
||||||
"ctrl-n": "assistant::NewContext"
|
"ctrl-n": "assistant::NewContext"
|
||||||
@@ -251,10 +253,10 @@
|
|||||||
"ctrl-shift-pagedown": "pane::SwapItemRight",
|
"ctrl-shift-pagedown": "pane::SwapItemRight",
|
||||||
"ctrl-w": "pane::CloseActiveItem",
|
"ctrl-w": "pane::CloseActiveItem",
|
||||||
"ctrl-f4": "pane::CloseActiveItem",
|
"ctrl-f4": "pane::CloseActiveItem",
|
||||||
"alt-ctrl-t": "pane::CloseInactiveItems",
|
"alt-ctrl-t": ["pane::CloseInactiveItems", { "close_pinned": false }],
|
||||||
"alt-ctrl-shift-w": "workspace::CloseInactiveTabsAndPanes",
|
"alt-ctrl-shift-w": "workspace::CloseInactiveTabsAndPanes",
|
||||||
"ctrl-k u": "pane::CloseCleanItems",
|
"ctrl-k u": ["pane::CloseCleanItems", { "close_pinned": false }],
|
||||||
"ctrl-k w": "pane::CloseAllItems",
|
"ctrl-k w": ["pane::CloseAllItems", { "close_pinned": false }],
|
||||||
"ctrl-shift-f": "project_search::ToggleFocus",
|
"ctrl-shift-f": "project_search::ToggleFocus",
|
||||||
"ctrl-alt-g": "search::SelectNextMatch",
|
"ctrl-alt-g": "search::SelectNextMatch",
|
||||||
"ctrl-alt-shift-g": "search::SelectPrevMatch",
|
"ctrl-alt-shift-g": "search::SelectPrevMatch",
|
||||||
@@ -326,7 +328,6 @@
|
|||||||
"ctrl-k ctrl-j": "editor::UnfoldAll",
|
"ctrl-k ctrl-j": "editor::UnfoldAll",
|
||||||
"ctrl-space": "editor::ShowCompletions",
|
"ctrl-space": "editor::ShowCompletions",
|
||||||
"ctrl-.": "editor::ToggleCodeActions",
|
"ctrl-.": "editor::ToggleCodeActions",
|
||||||
"alt-ctrl-r": "editor::RevealInFileManager",
|
|
||||||
"ctrl-k r": "editor::RevealInFileManager",
|
"ctrl-k r": "editor::RevealInFileManager",
|
||||||
"ctrl-k p": "editor::CopyPath",
|
"ctrl-k p": "editor::CopyPath",
|
||||||
"ctrl-\\": "pane::SplitRight",
|
"ctrl-\\": "pane::SplitRight",
|
||||||
@@ -417,6 +418,8 @@
|
|||||||
"ctrl-k shift-up": ["workspace::SwapPaneInDirection", "Up"],
|
"ctrl-k shift-up": ["workspace::SwapPaneInDirection", "Up"],
|
||||||
"ctrl-k shift-down": ["workspace::SwapPaneInDirection", "Down"],
|
"ctrl-k shift-down": ["workspace::SwapPaneInDirection", "Down"],
|
||||||
"ctrl-shift-x": "zed::Extensions",
|
"ctrl-shift-x": "zed::Extensions",
|
||||||
|
"ctrl-shift-r": "task::Rerun",
|
||||||
|
"ctrl-alt-r": "task::Rerun",
|
||||||
"alt-t": "task::Rerun",
|
"alt-t": "task::Rerun",
|
||||||
"alt-shift-t": "task::Spawn"
|
"alt-shift-t": "task::Spawn"
|
||||||
}
|
}
|
||||||
@@ -564,9 +567,11 @@
|
|||||||
"ctrl-alt-c": "outline_panel::CopyPath",
|
"ctrl-alt-c": "outline_panel::CopyPath",
|
||||||
"alt-ctrl-shift-c": "outline_panel::CopyRelativePath",
|
"alt-ctrl-shift-c": "outline_panel::CopyRelativePath",
|
||||||
"alt-ctrl-r": "outline_panel::RevealInFileManager",
|
"alt-ctrl-r": "outline_panel::RevealInFileManager",
|
||||||
"space": ["outline_panel::Open", { "change_selection": false }],
|
"space": "outline_panel::Open",
|
||||||
"shift-down": "menu::SelectNext",
|
"shift-down": "menu::SelectNext",
|
||||||
"shift-up": "menu::SelectPrev"
|
"shift-up": "menu::SelectPrev",
|
||||||
|
"alt-enter": "editor::OpenExcerpts",
|
||||||
|
"ctrl-k enter": "editor::OpenExcerptsSplit"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -587,7 +592,7 @@
|
|||||||
"ctrl-delete": ["project_panel::Delete", { "skip_prompt": false }],
|
"ctrl-delete": ["project_panel::Delete", { "skip_prompt": false }],
|
||||||
"alt-ctrl-r": "project_panel::RevealInFileManager",
|
"alt-ctrl-r": "project_panel::RevealInFileManager",
|
||||||
"ctrl-shift-enter": "project_panel::OpenWithSystem",
|
"ctrl-shift-enter": "project_panel::OpenWithSystem",
|
||||||
"alt-shift-f": "project_panel::NewSearchInDirectory",
|
"ctrl-shift-f": "project_panel::NewSearchInDirectory",
|
||||||
"shift-down": "menu::SelectNext",
|
"shift-down": "menu::SelectNext",
|
||||||
"shift-up": "menu::SelectPrev",
|
"shift-up": "menu::SelectPrev",
|
||||||
"escape": "menu::Cancel"
|
"escape": "menu::Cancel"
|
||||||
|
|||||||
@@ -51,14 +51,13 @@
|
|||||||
"shift-tab": "editor::TabPrev",
|
"shift-tab": "editor::TabPrev",
|
||||||
"ctrl-k": "editor::CutToEndOfLine",
|
"ctrl-k": "editor::CutToEndOfLine",
|
||||||
"ctrl-t": "editor::Transpose",
|
"ctrl-t": "editor::Transpose",
|
||||||
"alt-q": "editor::Rewrap",
|
"cmd-k q": "editor::Rewrap",
|
||||||
|
"cmd-k cmd-q": "editor::Rewrap",
|
||||||
"cmd-backspace": "editor::DeleteToBeginningOfLine",
|
"cmd-backspace": "editor::DeleteToBeginningOfLine",
|
||||||
"cmd-delete": "editor::DeleteToEndOfLine",
|
"cmd-delete": "editor::DeleteToEndOfLine",
|
||||||
"alt-backspace": "editor::DeleteToPreviousWordStart",
|
"alt-backspace": "editor::DeleteToPreviousWordStart",
|
||||||
"ctrl-w": "editor::DeleteToPreviousWordStart",
|
"ctrl-w": "editor::DeleteToPreviousWordStart",
|
||||||
"alt-delete": "editor::DeleteToNextWordEnd",
|
"alt-delete": "editor::DeleteToNextWordEnd",
|
||||||
"alt-h": "editor::DeleteToPreviousWordStart",
|
|
||||||
"alt-d": "editor::DeleteToNextWordEnd",
|
|
||||||
"cmd-x": "editor::Cut",
|
"cmd-x": "editor::Cut",
|
||||||
"cmd-c": "editor::Copy",
|
"cmd-c": "editor::Copy",
|
||||||
"cmd-v": "editor::Paste",
|
"cmd-v": "editor::Paste",
|
||||||
@@ -86,9 +85,7 @@
|
|||||||
"ctrl-f": "editor::MoveRight",
|
"ctrl-f": "editor::MoveRight",
|
||||||
"ctrl-l": "editor::ScrollCursorCenter",
|
"ctrl-l": "editor::ScrollCursorCenter",
|
||||||
"alt-left": "editor::MoveToPreviousWordStart",
|
"alt-left": "editor::MoveToPreviousWordStart",
|
||||||
"alt-b": "editor::MoveToPreviousWordStart",
|
|
||||||
"alt-right": "editor::MoveToNextWordEnd",
|
"alt-right": "editor::MoveToNextWordEnd",
|
||||||
"alt-f": "editor::MoveToNextWordEnd",
|
|
||||||
"cmd-left": "editor::MoveToBeginningOfLine",
|
"cmd-left": "editor::MoveToBeginningOfLine",
|
||||||
"ctrl-a": "editor::MoveToBeginningOfLine",
|
"ctrl-a": "editor::MoveToBeginningOfLine",
|
||||||
"cmd-right": "editor::MoveToEndOfLine",
|
"cmd-right": "editor::MoveToEndOfLine",
|
||||||
@@ -104,9 +101,7 @@
|
|||||||
"shift-right": "editor::SelectRight",
|
"shift-right": "editor::SelectRight",
|
||||||
"ctrl-shift-f": "editor::SelectRight",
|
"ctrl-shift-f": "editor::SelectRight",
|
||||||
"alt-shift-left": "editor::SelectToPreviousWordStart", // cursorWordLeftSelect
|
"alt-shift-left": "editor::SelectToPreviousWordStart", // cursorWordLeftSelect
|
||||||
"alt-shift-b": "editor::SelectToPreviousWordStart",
|
|
||||||
"alt-shift-right": "editor::SelectToNextWordEnd", // cursorWordRightSelect
|
"alt-shift-right": "editor::SelectToNextWordEnd", // cursorWordRightSelect
|
||||||
"alt-shift-f": "editor::SelectToNextWordEnd",
|
|
||||||
"ctrl-shift-up": "editor::SelectToStartOfParagraph",
|
"ctrl-shift-up": "editor::SelectToStartOfParagraph",
|
||||||
"ctrl-shift-down": "editor::SelectToEndOfParagraph",
|
"ctrl-shift-down": "editor::SelectToEndOfParagraph",
|
||||||
"cmd-shift-up": "editor::SelectToBeginning",
|
"cmd-shift-up": "editor::SelectToBeginning",
|
||||||
@@ -121,7 +116,7 @@
|
|||||||
"shift-end": ["editor::SelectToEndOfLine", { "stop_at_soft_wraps": true }],
|
"shift-end": ["editor::SelectToEndOfLine", { "stop_at_soft_wraps": true }],
|
||||||
"ctrl-shift-e": ["editor::SelectToEndOfLine", { "stop_at_soft_wraps": true }],
|
"ctrl-shift-e": ["editor::SelectToEndOfLine", { "stop_at_soft_wraps": true }],
|
||||||
"ctrl-v": ["editor::MovePageDown", { "center_cursor": true }],
|
"ctrl-v": ["editor::MovePageDown", { "center_cursor": true }],
|
||||||
"alt-v": ["editor::MovePageUp", { "center_cursor": true }],
|
"ctrl-shift-v": ["editor::MovePageUp", { "center_cursor": true }],
|
||||||
"ctrl-cmd-space": "editor::ShowCharacterPalette",
|
"ctrl-cmd-space": "editor::ShowCharacterPalette",
|
||||||
"cmd-;": "editor::ToggleLineNumbers",
|
"cmd-;": "editor::ToggleLineNumbers",
|
||||||
"cmd-alt-z": "editor::RevertSelectedHunks",
|
"cmd-alt-z": "editor::RevertSelectedHunks",
|
||||||
@@ -140,7 +135,7 @@
|
|||||||
"shift-enter": "editor::Newline",
|
"shift-enter": "editor::Newline",
|
||||||
"cmd-enter": "editor::NewlineBelow",
|
"cmd-enter": "editor::NewlineBelow",
|
||||||
"cmd-shift-enter": "editor::NewlineAbove",
|
"cmd-shift-enter": "editor::NewlineAbove",
|
||||||
"alt-z": "editor::ToggleSoftWrap",
|
"cmd-k z": "editor::ToggleSoftWrap",
|
||||||
"cmd-f": "buffer_search::Deploy",
|
"cmd-f": "buffer_search::Deploy",
|
||||||
"cmd-alt-f": ["buffer_search::Deploy", { "replace_enabled": true }],
|
"cmd-alt-f": ["buffer_search::Deploy", { "replace_enabled": true }],
|
||||||
"cmd-alt-l": ["buffer_search::Deploy", { "selection_search_enabled": true }],
|
"cmd-alt-l": ["buffer_search::Deploy", { "selection_search_enabled": true }],
|
||||||
@@ -155,7 +150,7 @@
|
|||||||
"bindings": {
|
"bindings": {
|
||||||
"alt-]": "editor::NextInlineCompletion",
|
"alt-]": "editor::NextInlineCompletion",
|
||||||
"alt-[": "editor::PreviousInlineCompletion",
|
"alt-[": "editor::PreviousInlineCompletion",
|
||||||
"cmd-right": "editor::AcceptPartialInlineCompletion"
|
"ctrl-right": "editor::AcceptPartialInlineCompletion"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -191,7 +186,7 @@
|
|||||||
"cmd-k c": "assistant::CopyCode",
|
"cmd-k c": "assistant::CopyCode",
|
||||||
"cmd-g": "search::SelectNextMatch",
|
"cmd-g": "search::SelectNextMatch",
|
||||||
"cmd-shift-g": "search::SelectPrevMatch",
|
"cmd-shift-g": "search::SelectPrevMatch",
|
||||||
"alt-m": "assistant::ToggleModelSelector",
|
"cmd-shift-m": "assistant::ToggleModelSelector",
|
||||||
"cmd-k h": "assistant::DeployHistory",
|
"cmd-k h": "assistant::DeployHistory",
|
||||||
"cmd-k l": "assistant::DeployPromptLibrary",
|
"cmd-k l": "assistant::DeployPromptLibrary",
|
||||||
"cmd-n": "assistant::NewContext"
|
"cmd-n": "assistant::NewContext"
|
||||||
@@ -291,10 +286,10 @@
|
|||||||
"ctrl-shift-pageup": "pane::SwapItemLeft",
|
"ctrl-shift-pageup": "pane::SwapItemLeft",
|
||||||
"ctrl-shift-pagedown": "pane::SwapItemRight",
|
"ctrl-shift-pagedown": "pane::SwapItemRight",
|
||||||
"cmd-w": "pane::CloseActiveItem",
|
"cmd-w": "pane::CloseActiveItem",
|
||||||
"alt-cmd-t": "pane::CloseInactiveItems",
|
"alt-cmd-t": ["pane::CloseInactiveItems", { "close_pinned": false }],
|
||||||
"ctrl-alt-cmd-w": "workspace::CloseInactiveTabsAndPanes",
|
"ctrl-alt-cmd-w": "workspace::CloseInactiveTabsAndPanes",
|
||||||
"cmd-k u": "pane::CloseCleanItems",
|
"cmd-k u": ["pane::CloseCleanItems", { "close_pinned": false }],
|
||||||
"cmd-k cmd-w": "pane::CloseAllItems",
|
"cmd-k cmd-w": ["pane::CloseAllItems", { "close_pinned": false }],
|
||||||
"cmd-f": "project_search::ToggleFocus",
|
"cmd-f": "project_search::ToggleFocus",
|
||||||
"cmd-g": "search::SelectNextMatch",
|
"cmd-g": "search::SelectNextMatch",
|
||||||
"cmd-shift-g": "search::SelectPrevMatch",
|
"cmd-shift-g": "search::SelectPrevMatch",
|
||||||
@@ -364,7 +359,6 @@
|
|||||||
"cmd-k cmd-j": "editor::UnfoldAll",
|
"cmd-k cmd-j": "editor::UnfoldAll",
|
||||||
"ctrl-space": "editor::ShowCompletions",
|
"ctrl-space": "editor::ShowCompletions",
|
||||||
"cmd-.": "editor::ToggleCodeActions",
|
"cmd-.": "editor::ToggleCodeActions",
|
||||||
"alt-cmd-r": "editor::RevealInFileManager",
|
|
||||||
"cmd-k r": "editor::RevealInFileManager",
|
"cmd-k r": "editor::RevealInFileManager",
|
||||||
"cmd-k p": "editor::CopyPath",
|
"cmd-k p": "editor::CopyPath",
|
||||||
"cmd-\\": "pane::SplitRight",
|
"cmd-\\": "pane::SplitRight",
|
||||||
@@ -457,7 +451,9 @@
|
|||||||
{
|
{
|
||||||
"context": "Workspace && !Terminal",
|
"context": "Workspace && !Terminal",
|
||||||
"bindings": {
|
"bindings": {
|
||||||
"alt-t": "task::Rerun",
|
"cmd-shift-r": "task::Spawn",
|
||||||
|
"cmd-alt-r": "task::Rerun",
|
||||||
|
"alt-t": "task::Spawn",
|
||||||
"alt-shift-t": "task::Spawn"
|
"alt-shift-t": "task::Spawn"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -577,9 +573,11 @@
|
|||||||
"cmd-alt-c": "outline_panel::CopyPath",
|
"cmd-alt-c": "outline_panel::CopyPath",
|
||||||
"alt-cmd-shift-c": "outline_panel::CopyRelativePath",
|
"alt-cmd-shift-c": "outline_panel::CopyRelativePath",
|
||||||
"alt-cmd-r": "outline_panel::RevealInFileManager",
|
"alt-cmd-r": "outline_panel::RevealInFileManager",
|
||||||
"space": ["outline_panel::Open", { "change_selection": false }],
|
"space": "outline_panel::Open",
|
||||||
"shift-down": "menu::SelectNext",
|
"shift-down": "menu::SelectNext",
|
||||||
"shift-up": "menu::SelectPrev"
|
"shift-up": "menu::SelectPrev",
|
||||||
|
"alt-enter": "editor::OpenExcerpts",
|
||||||
|
"cmd-k enter": "editor::OpenExcerptsSplit"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -604,7 +602,7 @@
|
|||||||
"alt-cmd-r": "project_panel::RevealInFileManager",
|
"alt-cmd-r": "project_panel::RevealInFileManager",
|
||||||
"ctrl-shift-enter": "project_panel::OpenWithSystem",
|
"ctrl-shift-enter": "project_panel::OpenWithSystem",
|
||||||
"cmd-alt-backspace": ["project_panel::Delete", { "skip_prompt": false }],
|
"cmd-alt-backspace": ["project_panel::Delete", { "skip_prompt": false }],
|
||||||
"alt-shift-f": "project_panel::NewSearchInDirectory",
|
"cmd-shift-f": "project_panel::NewSearchInDirectory",
|
||||||
"shift-down": "menu::SelectNext",
|
"shift-down": "menu::SelectNext",
|
||||||
"shift-up": "menu::SelectPrev",
|
"shift-up": "menu::SelectPrev",
|
||||||
"escape": "menu::Cancel"
|
"escape": "menu::Cancel"
|
||||||
|
|||||||
63
assets/keymaps/linux/emacs.json
Executable file
63
assets/keymaps/linux/emacs.json
Executable file
@@ -0,0 +1,63 @@
|
|||||||
|
// documentation: https://zed.dev/docs/key-bindings
|
||||||
|
//
|
||||||
|
// To see the default key bindings run `zed: open default keymap`
|
||||||
|
// from the command palette.
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"context": "Editor",
|
||||||
|
"bindings": {
|
||||||
|
"ctrl-g": "editor::Cancel",
|
||||||
|
"ctrl-shift-g": "go_to_line::Toggle",
|
||||||
|
//"ctrl-space": "editor::SetMark",
|
||||||
|
"ctrl-x u": "editor::Undo",
|
||||||
|
"ctrl-x ctrl-u": "editor::Redo",
|
||||||
|
"ctrl-f": "editor::MoveRight",
|
||||||
|
"ctrl-b": "editor::MoveLeft",
|
||||||
|
"ctrl-n": "editor::MoveDown",
|
||||||
|
"ctrl-p": "editor::MoveUp",
|
||||||
|
"ctrl-a": "editor::MoveToBeginningOfLine",
|
||||||
|
"ctrl-e": "editor::MoveToEndOfLine",
|
||||||
|
"alt-f": "editor::MoveToNextSubwordEnd",
|
||||||
|
"alt-b": "editor::MoveToPreviousSubwordStart",
|
||||||
|
"ctrl-d": "editor::Delete",
|
||||||
|
"alt-d": "editor::DeleteToNextWordEnd",
|
||||||
|
"ctrl-k": "editor::CutToEndOfLine",
|
||||||
|
"ctrl-w": "editor::Cut",
|
||||||
|
"alt-w": "editor::Copy",
|
||||||
|
"ctrl-y": "editor::Paste",
|
||||||
|
"ctrl-_": "editor::Undo",
|
||||||
|
"ctrl-v": "editor::MovePageDown",
|
||||||
|
"alt-v": "editor::MovePageUp",
|
||||||
|
"ctrl-x ]": "editor::MoveToEnd",
|
||||||
|
"ctrl-x [": "editor::MoveToBeginning",
|
||||||
|
"ctrl-l": "editor::ScrollCursorCenterTopBottom",
|
||||||
|
"ctrl-s": "buffer_search::Deploy",
|
||||||
|
"ctrl-x ctrl-f": "file_finder::Toggle",
|
||||||
|
"ctrl-shift-r": "editor::Rename"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "Workspace",
|
||||||
|
"bindings": {
|
||||||
|
"ctrl-x k": "pane::CloseActiveItem",
|
||||||
|
"ctrl-x ctrl-c": "workspace::CloseWindow",
|
||||||
|
"ctrl-x o": "workspace::ActivateNextPane",
|
||||||
|
"ctrl-x b": "tab_switcher::Toggle",
|
||||||
|
"ctrl-x 0": "pane::CloseActiveItem",
|
||||||
|
"ctrl-x 1": "pane::CloseInactiveItems",
|
||||||
|
"ctrl-x 2": "pane::SplitVertical",
|
||||||
|
"ctrl-x ctrl-f": "file_finder::Toggle",
|
||||||
|
"ctrl-x ctrl-s": "workspace::Save",
|
||||||
|
"ctrl-x ctrl-w": "workspace::SaveAs",
|
||||||
|
"ctrl-x s": "workspace::SaveAll",
|
||||||
|
"shift shift": "file_finder::Toggle"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "Pane",
|
||||||
|
"bindings": {
|
||||||
|
"ctrl-alt-left": "pane::GoBack",
|
||||||
|
"ctrl-alt-right": "pane::GoForward"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"bindings": {
|
"bindings": {
|
||||||
|
"ctrl-alt-s": "zed::OpenSettings",
|
||||||
"ctrl-shift-[": "pane::ActivatePrevItem",
|
"ctrl-shift-[": "pane::ActivatePrevItem",
|
||||||
"ctrl-shift-]": "pane::ActivateNextItem"
|
"ctrl-shift-]": "pane::ActivateNextItem"
|
||||||
}
|
}
|
||||||
@@ -25,8 +26,8 @@
|
|||||||
"alt-j": ["editor::SelectNext", { "replace_newest": false }],
|
"alt-j": ["editor::SelectNext", { "replace_newest": false }],
|
||||||
"alt-shift-j": ["editor::SelectPrevious", { "replace_newest": false }],
|
"alt-shift-j": ["editor::SelectPrevious", { "replace_newest": false }],
|
||||||
"ctrl-/": ["editor::ToggleComments", { "advance_downwards": true }],
|
"ctrl-/": ["editor::ToggleComments", { "advance_downwards": true }],
|
||||||
"alt-up": "editor::SelectLargerSyntaxNode",
|
"ctrl-w": "editor::SelectLargerSyntaxNode",
|
||||||
"alt-down": "editor::SelectSmallerSyntaxNode",
|
"ctrl-shift-w": "editor::SelectSmallerSyntaxNode",
|
||||||
"shift-alt-up": "editor::MoveLineUp",
|
"shift-alt-up": "editor::MoveLineUp",
|
||||||
"shift-alt-down": "editor::MoveLineDown",
|
"shift-alt-down": "editor::MoveLineDown",
|
||||||
"ctrl-alt-l": "editor::Format",
|
"ctrl-alt-l": "editor::Format",
|
||||||
@@ -43,6 +44,7 @@
|
|||||||
"shift-f2": "editor::GoToPrevDiagnostic",
|
"shift-f2": "editor::GoToPrevDiagnostic",
|
||||||
"ctrl-alt-shift-down": "editor::GoToHunk",
|
"ctrl-alt-shift-down": "editor::GoToHunk",
|
||||||
"ctrl-alt-shift-up": "editor::GoToPrevHunk",
|
"ctrl-alt-shift-up": "editor::GoToPrevHunk",
|
||||||
|
"ctrl-alt-z": "editor::RevertSelectedHunks",
|
||||||
"ctrl-home": "editor::MoveToBeginning",
|
"ctrl-home": "editor::MoveToBeginning",
|
||||||
"ctrl-end": "editor::MoveToEnd",
|
"ctrl-end": "editor::MoveToEnd",
|
||||||
"ctrl-shift-home": "editor::SelectToBeginning",
|
"ctrl-shift-home": "editor::SelectToBeginning",
|
||||||
|
|||||||
63
assets/keymaps/macos/emacs.json
Executable file
63
assets/keymaps/macos/emacs.json
Executable file
@@ -0,0 +1,63 @@
|
|||||||
|
// documentation: https://zed.dev/docs/key-bindings
|
||||||
|
//
|
||||||
|
// To see the default key bindings run `zed: open default keymap`
|
||||||
|
// from the command palette.
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"context": "Editor",
|
||||||
|
"bindings": {
|
||||||
|
"ctrl-g": "editor::Cancel",
|
||||||
|
"ctrl-shift-g": "go_to_line::Toggle",
|
||||||
|
//"ctrl-space": "editor::SetMark",
|
||||||
|
"ctrl-x u": "editor::Undo",
|
||||||
|
"ctrl-x ctrl-u": "editor::Redo",
|
||||||
|
"ctrl-f": "editor::MoveRight",
|
||||||
|
"ctrl-b": "editor::MoveLeft",
|
||||||
|
"ctrl-n": "editor::MoveDown",
|
||||||
|
"ctrl-p": "editor::MoveUp",
|
||||||
|
"ctrl-a": "editor::MoveToBeginningOfLine",
|
||||||
|
"ctrl-e": "editor::MoveToEndOfLine",
|
||||||
|
"alt-f": "editor::MoveToNextSubwordEnd",
|
||||||
|
"alt-b": "editor::MoveToPreviousSubwordStart",
|
||||||
|
"ctrl-d": "editor::Delete",
|
||||||
|
"alt-d": "editor::DeleteToNextWordEnd",
|
||||||
|
"ctrl-k": "editor::CutToEndOfLine",
|
||||||
|
"ctrl-w": "editor::Cut",
|
||||||
|
"alt-w": "editor::Copy",
|
||||||
|
"ctrl-y": "editor::Paste",
|
||||||
|
"ctrl-_": "editor::Undo",
|
||||||
|
"ctrl-v": "editor::MovePageDown",
|
||||||
|
"alt-v": "editor::MovePageUp",
|
||||||
|
"ctrl-x ]": "editor::MoveToEnd",
|
||||||
|
"ctrl-x [": "editor::MoveToBeginning",
|
||||||
|
"ctrl-l": "editor::ScrollCursorCenterTopBottom",
|
||||||
|
"ctrl-s": "buffer_search::Deploy",
|
||||||
|
"ctrl-x ctrl-f": "file_finder::Toggle",
|
||||||
|
"ctrl-shift-r": "editor::Rename"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "Workspace",
|
||||||
|
"bindings": {
|
||||||
|
"ctrl-x k": "pane::CloseActiveItem",
|
||||||
|
"ctrl-x ctrl-c": "workspace::CloseWindow",
|
||||||
|
"ctrl-x o": "workspace::ActivateNextPane",
|
||||||
|
"ctrl-x b": "tab_switcher::Toggle",
|
||||||
|
"ctrl-x 0": "pane::CloseActiveItem",
|
||||||
|
"ctrl-x 1": "pane::CloseInactiveItems",
|
||||||
|
"ctrl-x 2": "pane::SplitVertical",
|
||||||
|
"ctrl-x ctrl-f": "file_finder::Toggle",
|
||||||
|
"ctrl-x ctrl-s": "workspace::Save",
|
||||||
|
"ctrl-x ctrl-w": "workspace::SaveAs",
|
||||||
|
"ctrl-x s": "workspace::SaveAll",
|
||||||
|
"shift shift": "file_finder::Toggle"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "Pane",
|
||||||
|
"bindings": {
|
||||||
|
"ctrl-alt-left": "pane::GoBack",
|
||||||
|
"ctrl-alt-right": "pane::GoForward"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -24,8 +24,8 @@
|
|||||||
"ctrl-g": ["editor::SelectNext", { "replace_newest": false }],
|
"ctrl-g": ["editor::SelectNext", { "replace_newest": false }],
|
||||||
"ctrl-cmd-g": ["editor::SelectPrevious", { "replace_newest": false }],
|
"ctrl-cmd-g": ["editor::SelectPrevious", { "replace_newest": false }],
|
||||||
"cmd-/": ["editor::ToggleComments", { "advance_downwards": true }],
|
"cmd-/": ["editor::ToggleComments", { "advance_downwards": true }],
|
||||||
"alt-up": "editor::SelectLargerSyntaxNode",
|
"cmd-up": "editor::SelectLargerSyntaxNode",
|
||||||
"alt-down": "editor::SelectSmallerSyntaxNode",
|
"cmd-down": "editor::SelectSmallerSyntaxNode",
|
||||||
"shift-alt-up": "editor::MoveLineUp",
|
"shift-alt-up": "editor::MoveLineUp",
|
||||||
"shift-alt-down": "editor::MoveLineDown",
|
"shift-alt-down": "editor::MoveLineDown",
|
||||||
"cmd-alt-l": "editor::Format",
|
"cmd-alt-l": "editor::Format",
|
||||||
@@ -58,6 +58,12 @@
|
|||||||
"alt-enter": "editor::ToggleCodeActions"
|
"alt-enter": "editor::ToggleCodeActions"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"context": "BufferSearchBar > Editor",
|
||||||
|
"bindings": {
|
||||||
|
"shift-enter": "search::SelectPrevMatch"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"context": "Workspace",
|
"context": "Workspace",
|
||||||
"bindings": {
|
"bindings": {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"context": "VimControl && !menu",
|
"context": "VimControl && !menu",
|
||||||
|
"use_layout_keys": true,
|
||||||
"bindings": {
|
"bindings": {
|
||||||
"i": ["vim::PushOperator", { "Object": { "around": false } }],
|
"i": ["vim::PushOperator", { "Object": { "around": false } }],
|
||||||
"a": ["vim::PushOperator", { "Object": { "around": true } }],
|
"a": ["vim::PushOperator", { "Object": { "around": true } }],
|
||||||
@@ -127,6 +128,9 @@
|
|||||||
"shift-h": "vim::WindowTop",
|
"shift-h": "vim::WindowTop",
|
||||||
"shift-m": "vim::WindowMiddle",
|
"shift-m": "vim::WindowMiddle",
|
||||||
"shift-l": "vim::WindowBottom",
|
"shift-l": "vim::WindowBottom",
|
||||||
|
"q": "vim::ToggleRecord",
|
||||||
|
"shift-q": "vim::ReplayLastRecording",
|
||||||
|
"@": ["vim::PushOperator", "ReplayRegister"],
|
||||||
// z commands
|
// z commands
|
||||||
"z enter": ["workspace::SendKeystrokes", "z t ^"],
|
"z enter": ["workspace::SendKeystrokes", "z t ^"],
|
||||||
"z -": ["workspace::SendKeystrokes", "z b ^"],
|
"z -": ["workspace::SendKeystrokes", "z b ^"],
|
||||||
@@ -137,14 +141,14 @@
|
|||||||
"z .": ["workspace::SendKeystrokes", "z z ^"],
|
"z .": ["workspace::SendKeystrokes", "z z ^"],
|
||||||
"z b": "editor::ScrollCursorBottom",
|
"z b": "editor::ScrollCursorBottom",
|
||||||
"z a": "editor::ToggleFold",
|
"z a": "editor::ToggleFold",
|
||||||
"z A": "editor::ToggleFoldRecursive",
|
"z shift-a": "editor::ToggleFoldRecursive",
|
||||||
"z c": "editor::Fold",
|
"z c": "editor::Fold",
|
||||||
"z C": "editor::FoldRecursive",
|
"z shift-c": "editor::FoldRecursive",
|
||||||
"z o": "editor::UnfoldLines",
|
"z o": "editor::UnfoldLines",
|
||||||
"z O": "editor::UnfoldRecursive",
|
"z shift-o": "editor::UnfoldRecursive",
|
||||||
"z f": "editor::FoldSelectedRanges",
|
"z f": "editor::FoldSelectedRanges",
|
||||||
"z M": "editor::FoldAll",
|
"z shift-m": "editor::FoldAll",
|
||||||
"z R": "editor::UnfoldAll",
|
"z shift-r": "editor::UnfoldAll",
|
||||||
"shift-z shift-q": ["pane::CloseActiveItem", { "saveIntent": "skip" }],
|
"shift-z shift-q": ["pane::CloseActiveItem", { "saveIntent": "skip" }],
|
||||||
"shift-z shift-z": ["pane::CloseActiveItem", { "saveIntent": "saveAll" }],
|
"shift-z shift-z": ["pane::CloseActiveItem", { "saveIntent": "saveAll" }],
|
||||||
// Count support
|
// Count support
|
||||||
@@ -157,6 +161,374 @@
|
|||||||
"7": ["vim::Number", 7],
|
"7": ["vim::Number", 7],
|
||||||
"8": ["vim::Number", 8],
|
"8": ["vim::Number", 8],
|
||||||
"9": ["vim::Number", 9],
|
"9": ["vim::Number", 9],
|
||||||
|
"ctrl-w d": "editor::GoToDefinitionSplit",
|
||||||
|
"ctrl-w g d": "editor::GoToDefinitionSplit",
|
||||||
|
"ctrl-w shift-d": "editor::GoToTypeDefinitionSplit",
|
||||||
|
"ctrl-w g shift-d": "editor::GoToTypeDefinitionSplit",
|
||||||
|
"ctrl-w space": "editor::OpenExcerptsSplit",
|
||||||
|
"ctrl-w g space": "editor::OpenExcerptsSplit",
|
||||||
|
"ctrl-6": "pane::AlternateFile"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "vim_mode == normal",
|
||||||
|
"use_layout_keys": true,
|
||||||
|
"bindings": {
|
||||||
|
"escape": "editor::Cancel",
|
||||||
|
"ctrl-[": "editor::Cancel",
|
||||||
|
":": "command_palette::Toggle",
|
||||||
|
".": "vim::Repeat",
|
||||||
|
"c": ["vim::PushOperator", "Change"],
|
||||||
|
"shift-c": "vim::ChangeToEndOfLine",
|
||||||
|
"d": ["vim::PushOperator", "Delete"],
|
||||||
|
"shift-d": "vim::DeleteToEndOfLine",
|
||||||
|
"shift-j": "vim::JoinLines",
|
||||||
|
"y": ["vim::PushOperator", "Yank"],
|
||||||
|
"shift-y": "vim::YankLine",
|
||||||
|
"i": "vim::InsertBefore",
|
||||||
|
"shift-i": "vim::InsertFirstNonWhitespace",
|
||||||
|
"a": "vim::InsertAfter",
|
||||||
|
"shift-a": "vim::InsertEndOfLine",
|
||||||
|
"x": "vim::DeleteRight",
|
||||||
|
"shift-x": "vim::DeleteLeft",
|
||||||
|
"o": "vim::InsertLineBelow",
|
||||||
|
"shift-o": "vim::InsertLineAbove",
|
||||||
|
"~": "vim::ChangeCase",
|
||||||
|
"ctrl-a": "vim::Increment",
|
||||||
|
"ctrl-x": "vim::Decrement",
|
||||||
|
"p": "vim::Paste",
|
||||||
|
"shift-p": ["vim::Paste", { "before": true }],
|
||||||
|
"u": "vim::Undo",
|
||||||
|
"ctrl-r": "vim::Redo",
|
||||||
|
"r": ["vim::PushOperator", "Replace"],
|
||||||
|
"s": "vim::Substitute",
|
||||||
|
"shift-s": "vim::SubstituteLine",
|
||||||
|
">": ["vim::PushOperator", "Indent"],
|
||||||
|
"<": ["vim::PushOperator", "Outdent"],
|
||||||
|
"g u": ["vim::PushOperator", "Lowercase"],
|
||||||
|
"g shift-u": ["vim::PushOperator", "Uppercase"],
|
||||||
|
"g ~": ["vim::PushOperator", "OppositeCase"],
|
||||||
|
"\"": ["vim::PushOperator", "Register"],
|
||||||
|
"g q": ["vim::PushOperator", "Rewrap"],
|
||||||
|
"g w": ["vim::PushOperator", "Rewrap"],
|
||||||
|
"ctrl-pagedown": "pane::ActivateNextItem",
|
||||||
|
"ctrl-pageup": "pane::ActivatePrevItem",
|
||||||
|
"insert": "vim::InsertBefore",
|
||||||
|
// tree-sitter related commands
|
||||||
|
"[ x": "editor::SelectLargerSyntaxNode",
|
||||||
|
"] x": "editor::SelectSmallerSyntaxNode",
|
||||||
|
"] d": "editor::GoToDiagnostic",
|
||||||
|
"[ d": "editor::GoToPrevDiagnostic",
|
||||||
|
"] c": "editor::GoToHunk",
|
||||||
|
"[ c": "editor::GoToPrevHunk",
|
||||||
|
"g c": ["vim::PushOperator", "ToggleComments"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "VimControl && VimCount",
|
||||||
|
"use_layout_keys": true,
|
||||||
|
"bindings": {
|
||||||
|
"0": ["vim::Number", 0],
|
||||||
|
":": "vim::CountCommand"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "vim_mode == visual",
|
||||||
|
"use_layout_keys": true,
|
||||||
|
"bindings": {
|
||||||
|
":": "vim::VisualCommand",
|
||||||
|
"u": "vim::ConvertToLowerCase",
|
||||||
|
"shift-u": "vim::ConvertToUpperCase",
|
||||||
|
"o": "vim::OtherEnd",
|
||||||
|
"shift-o": "vim::OtherEnd",
|
||||||
|
"d": "vim::VisualDelete",
|
||||||
|
"x": "vim::VisualDelete",
|
||||||
|
"shift-d": "vim::VisualDeleteLine",
|
||||||
|
"shift-x": "vim::VisualDeleteLine",
|
||||||
|
"y": "vim::VisualYank",
|
||||||
|
"shift-y": "vim::VisualYank",
|
||||||
|
"p": "vim::Paste",
|
||||||
|
"shift-p": ["vim::Paste", { "preserveClipboard": true }],
|
||||||
|
"s": "vim::Substitute",
|
||||||
|
"shift-s": "vim::SubstituteLine",
|
||||||
|
"shift-r": "vim::SubstituteLine",
|
||||||
|
"c": "vim::Substitute",
|
||||||
|
"~": "vim::ChangeCase",
|
||||||
|
"*": ["vim::MoveToNext", { "partialWord": true }],
|
||||||
|
"#": ["vim::MoveToPrev", { "partialWord": true }],
|
||||||
|
"ctrl-a": "vim::Increment",
|
||||||
|
"ctrl-x": "vim::Decrement",
|
||||||
|
"g ctrl-a": ["vim::Increment", { "step": true }],
|
||||||
|
"g ctrl-x": ["vim::Decrement", { "step": true }],
|
||||||
|
"shift-i": "vim::InsertBefore",
|
||||||
|
"shift-a": "vim::InsertAfter",
|
||||||
|
"g shift-i": "vim::VisualInsertFirstNonWhiteSpace",
|
||||||
|
"g shift-a": "vim::VisualInsertEndOfLine",
|
||||||
|
"shift-j": "vim::JoinLines",
|
||||||
|
"r": ["vim::PushOperator", "Replace"],
|
||||||
|
"ctrl-c": ["vim::SwitchMode", "Normal"],
|
||||||
|
"escape": ["vim::SwitchMode", "Normal"],
|
||||||
|
"ctrl-[": ["vim::SwitchMode", "Normal"],
|
||||||
|
">": "vim::Indent",
|
||||||
|
"<": "vim::Outdent",
|
||||||
|
"i": ["vim::PushOperator", { "Object": { "around": false } }],
|
||||||
|
"a": ["vim::PushOperator", { "Object": { "around": true } }],
|
||||||
|
"g c": "vim::ToggleComments",
|
||||||
|
"g q": "vim::Rewrap",
|
||||||
|
"\"": ["vim::PushOperator", "Register"],
|
||||||
|
// tree-sitter related commands
|
||||||
|
"[ x": "editor::SelectLargerSyntaxNode",
|
||||||
|
"] x": "editor::SelectSmallerSyntaxNode"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "vim_mode == insert",
|
||||||
|
"use_layout_keys": true,
|
||||||
|
"bindings": {
|
||||||
|
"escape": "vim::NormalBefore",
|
||||||
|
"ctrl-c": "vim::NormalBefore",
|
||||||
|
"ctrl-[": "vim::NormalBefore",
|
||||||
|
"ctrl-x": null,
|
||||||
|
"ctrl-x ctrl-o": "editor::ShowCompletions",
|
||||||
|
"ctrl-x ctrl-a": "assistant::InlineAssist", // zed specific
|
||||||
|
"ctrl-x ctrl-c": "editor::ShowInlineCompletion", // zed specific
|
||||||
|
"ctrl-x ctrl-l": "editor::ToggleCodeActions", // zed specific
|
||||||
|
"ctrl-x ctrl-z": "editor::Cancel",
|
||||||
|
"ctrl-w": "editor::DeleteToPreviousWordStart",
|
||||||
|
"ctrl-u": "editor::DeleteToBeginningOfLine",
|
||||||
|
"ctrl-t": "vim::Indent",
|
||||||
|
"ctrl-d": "vim::Outdent",
|
||||||
|
"ctrl-k": ["vim::PushOperator", { "Digraph": {} }],
|
||||||
|
"ctrl-v": ["vim::PushOperator", { "Literal": {} }],
|
||||||
|
"ctrl-shift-v": "editor::Paste", // note: this is *very* similar to ctrl-v in vim, but ctrl-shift-v on linux is the typical shortcut for paste when ctrl-v is already in use.
|
||||||
|
"ctrl-q": ["vim::PushOperator", { "Literal": {} }],
|
||||||
|
"ctrl-shift-q": ["vim::PushOperator", { "Literal": {} }],
|
||||||
|
"ctrl-r": ["vim::PushOperator", "Register"],
|
||||||
|
"insert": "vim::ToggleReplace"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "vim_mode == insert && !(showing_code_actions || showing_completions)",
|
||||||
|
"use_layout_keys": true,
|
||||||
|
"bindings": {
|
||||||
|
"ctrl-p": "editor::ShowCompletions",
|
||||||
|
"ctrl-n": "editor::ShowCompletions"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "vim_mode == replace",
|
||||||
|
"use_layout_keys": true,
|
||||||
|
"bindings": {
|
||||||
|
"escape": "vim::NormalBefore",
|
||||||
|
"ctrl-c": "vim::NormalBefore",
|
||||||
|
"ctrl-[": "vim::NormalBefore",
|
||||||
|
"ctrl-k": ["vim::PushOperator", { "Digraph": {} }],
|
||||||
|
"ctrl-v": ["vim::PushOperator", { "Literal": {} }],
|
||||||
|
"ctrl-shift-v": "editor::Paste", // note: this is *very* similar to ctrl-v in vim, but ctrl-shift-v on linux is the typical shortcut for paste when ctrl-v is already in use.
|
||||||
|
"ctrl-q": ["vim::PushOperator", { "Literal": {} }],
|
||||||
|
"ctrl-shift-q": ["vim::PushOperator", { "Literal": {} }],
|
||||||
|
"backspace": "vim::UndoReplace",
|
||||||
|
"tab": "vim::Tab",
|
||||||
|
"enter": "vim::Enter",
|
||||||
|
"insert": "vim::InsertBefore"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "vim_mode == waiting",
|
||||||
|
"use_layout_keys": true,
|
||||||
|
"bindings": {
|
||||||
|
"tab": "vim::Tab",
|
||||||
|
"enter": "vim::Enter",
|
||||||
|
"escape": "vim::ClearOperators",
|
||||||
|
"ctrl-c": "vim::ClearOperators",
|
||||||
|
"ctrl-[": "vim::ClearOperators",
|
||||||
|
"ctrl-k": ["vim::PushOperator", { "Digraph": {} }],
|
||||||
|
"ctrl-v": ["vim::PushOperator", { "Literal": {} }],
|
||||||
|
"ctrl-q": ["vim::PushOperator", { "Literal": {} }]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "vim_mode == operator",
|
||||||
|
"use_layout_keys": true,
|
||||||
|
"bindings": {
|
||||||
|
"escape": "vim::ClearOperators",
|
||||||
|
"ctrl-c": "vim::ClearOperators",
|
||||||
|
"ctrl-[": "vim::ClearOperators"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "vim_operator == a || vim_operator == i || vim_operator == cs",
|
||||||
|
"use_layout_keys": true,
|
||||||
|
"bindings": {
|
||||||
|
"w": "vim::Word",
|
||||||
|
"shift-w": ["vim::Word", { "ignorePunctuation": true }],
|
||||||
|
"t": "vim::Tag",
|
||||||
|
"s": "vim::Sentence",
|
||||||
|
"p": "vim::Paragraph",
|
||||||
|
"'": "vim::Quotes",
|
||||||
|
"`": "vim::BackQuotes",
|
||||||
|
"\"": "vim::DoubleQuotes",
|
||||||
|
"|": "vim::VerticalBars",
|
||||||
|
"(": "vim::Parentheses",
|
||||||
|
")": "vim::Parentheses",
|
||||||
|
"b": "vim::Parentheses",
|
||||||
|
"[": "vim::SquareBrackets",
|
||||||
|
"]": "vim::SquareBrackets",
|
||||||
|
"r": "vim::SquareBrackets",
|
||||||
|
"{": "vim::CurlyBrackets",
|
||||||
|
"}": "vim::CurlyBrackets",
|
||||||
|
"shift-b": "vim::CurlyBrackets",
|
||||||
|
"<": "vim::AngleBrackets",
|
||||||
|
">": "vim::AngleBrackets",
|
||||||
|
"a": "vim::AngleBrackets",
|
||||||
|
"g": "vim::Argument"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "vim_operator == c",
|
||||||
|
"use_layout_keys": true,
|
||||||
|
"bindings": {
|
||||||
|
"c": "vim::CurrentLine",
|
||||||
|
"d": "editor::Rename", // zed specific
|
||||||
|
"s": ["vim::PushOperator", { "ChangeSurrounds": {} }]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "vim_operator == d",
|
||||||
|
"use_layout_keys": true,
|
||||||
|
"bindings": {
|
||||||
|
"d": "vim::CurrentLine",
|
||||||
|
"s": ["vim::PushOperator", "DeleteSurrounds"],
|
||||||
|
"o": "editor::ToggleHunkDiff", // "d o"
|
||||||
|
"p": "editor::RevertSelectedHunks" // "d p"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "vim_operator == gu",
|
||||||
|
"use_layout_keys": true,
|
||||||
|
"bindings": {
|
||||||
|
"g u": "vim::CurrentLine",
|
||||||
|
"u": "vim::CurrentLine"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "vim_operator == gU",
|
||||||
|
"use_layout_keys": true,
|
||||||
|
"bindings": {
|
||||||
|
"g shift-u": "vim::CurrentLine",
|
||||||
|
"shift-u": "vim::CurrentLine"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "vim_operator == g~",
|
||||||
|
"use_layout_keys": true,
|
||||||
|
"bindings": {
|
||||||
|
"g ~": "vim::CurrentLine",
|
||||||
|
"~": "vim::CurrentLine"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "vim_operator == gq",
|
||||||
|
"use_layout_keys": true,
|
||||||
|
"bindings": {
|
||||||
|
"g q": "vim::CurrentLine",
|
||||||
|
"q": "vim::CurrentLine",
|
||||||
|
"g w": "vim::CurrentLine",
|
||||||
|
"w": "vim::CurrentLine"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "vim_operator == y",
|
||||||
|
"use_layout_keys": true,
|
||||||
|
"bindings": {
|
||||||
|
"y": "vim::CurrentLine",
|
||||||
|
"s": ["vim::PushOperator", { "AddSurrounds": {} }]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "vim_operator == ys",
|
||||||
|
"use_layout_keys": true,
|
||||||
|
"bindings": {
|
||||||
|
"s": "vim::CurrentLine"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "vim_operator == >",
|
||||||
|
"use_layout_keys": true,
|
||||||
|
"bindings": {
|
||||||
|
">": "vim::CurrentLine"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "vim_operator == <",
|
||||||
|
"use_layout_keys": true,
|
||||||
|
"bindings": {
|
||||||
|
"<": "vim::CurrentLine"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "vim_operator == gc",
|
||||||
|
"use_layout_keys": true,
|
||||||
|
"bindings": {
|
||||||
|
"c": "vim::CurrentLine"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "vim_mode == literal",
|
||||||
|
"use_layout_keys": true,
|
||||||
|
"bindings": {
|
||||||
|
"ctrl-@": ["vim::Literal", ["ctrl-@", "\u0000"]],
|
||||||
|
"ctrl-a": ["vim::Literal", ["ctrl-a", "\u0001"]],
|
||||||
|
"ctrl-b": ["vim::Literal", ["ctrl-b", "\u0002"]],
|
||||||
|
"ctrl-c": ["vim::Literal", ["ctrl-c", "\u0003"]],
|
||||||
|
"ctrl-d": ["vim::Literal", ["ctrl-d", "\u0004"]],
|
||||||
|
"ctrl-e": ["vim::Literal", ["ctrl-e", "\u0005"]],
|
||||||
|
"ctrl-f": ["vim::Literal", ["ctrl-f", "\u0006"]],
|
||||||
|
"ctrl-g": ["vim::Literal", ["ctrl-g", "\u0007"]],
|
||||||
|
"ctrl-h": ["vim::Literal", ["ctrl-h", "\u0008"]],
|
||||||
|
"ctrl-i": ["vim::Literal", ["ctrl-i", "\u0009"]],
|
||||||
|
"ctrl-j": ["vim::Literal", ["ctrl-j", "\u000A"]],
|
||||||
|
"ctrl-k": ["vim::Literal", ["ctrl-k", "\u000B"]],
|
||||||
|
"ctrl-l": ["vim::Literal", ["ctrl-l", "\u000C"]],
|
||||||
|
"ctrl-m": ["vim::Literal", ["ctrl-m", "\u000D"]],
|
||||||
|
"ctrl-n": ["vim::Literal", ["ctrl-n", "\u000E"]],
|
||||||
|
"ctrl-o": ["vim::Literal", ["ctrl-o", "\u000F"]],
|
||||||
|
"ctrl-p": ["vim::Literal", ["ctrl-p", "\u0010"]],
|
||||||
|
"ctrl-q": ["vim::Literal", ["ctrl-q", "\u0011"]],
|
||||||
|
"ctrl-r": ["vim::Literal", ["ctrl-r", "\u0012"]],
|
||||||
|
"ctrl-s": ["vim::Literal", ["ctrl-s", "\u0013"]],
|
||||||
|
"ctrl-t": ["vim::Literal", ["ctrl-t", "\u0014"]],
|
||||||
|
"ctrl-u": ["vim::Literal", ["ctrl-u", "\u0015"]],
|
||||||
|
"ctrl-v": ["vim::Literal", ["ctrl-v", "\u0016"]],
|
||||||
|
"ctrl-w": ["vim::Literal", ["ctrl-w", "\u0017"]],
|
||||||
|
"ctrl-x": ["vim::Literal", ["ctrl-x", "\u0018"]],
|
||||||
|
"ctrl-y": ["vim::Literal", ["ctrl-y", "\u0019"]],
|
||||||
|
"ctrl-z": ["vim::Literal", ["ctrl-z", "\u001A"]],
|
||||||
|
"ctrl-[": ["vim::Literal", ["ctrl-[", "\u001B"]],
|
||||||
|
"ctrl-\\": ["vim::Literal", ["ctrl-\\", "\u001C"]],
|
||||||
|
"ctrl-]": ["vim::Literal", ["ctrl-]", "\u001D"]],
|
||||||
|
"ctrl-^": ["vim::Literal", ["ctrl-^", "\u001E"]],
|
||||||
|
"ctrl-_": ["vim::Literal", ["ctrl-_", "\u001F"]],
|
||||||
|
"escape": ["vim::Literal", ["escape", "\u001B"]],
|
||||||
|
"enter": ["vim::Literal", ["enter", "\u000D"]],
|
||||||
|
"tab": ["vim::Literal", ["tab", "\u0009"]],
|
||||||
|
// zed extensions:
|
||||||
|
"backspace": ["vim::Literal", ["backspace", "\u0008"]],
|
||||||
|
"delete": ["vim::Literal", ["delete", "\u007F"]]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "BufferSearchBar && !in_replace",
|
||||||
|
"use_layout_keys": true,
|
||||||
|
"bindings": {
|
||||||
|
"enter": "vim::SearchSubmit",
|
||||||
|
"escape": "buffer_search::Dismiss"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"context": "ProjectPanel || CollabPanel || OutlinePanel || ChatPanel || VimControl || EmptyPane || SharedScreen || MarkdownPreview || KeyContextView",
|
||||||
|
"use_layout_keys": true,
|
||||||
|
"bindings": {
|
||||||
// window related commands (ctrl-w X)
|
// window related commands (ctrl-w X)
|
||||||
"ctrl-w": null,
|
"ctrl-w": null,
|
||||||
"ctrl-w left": ["workspace::ActivatePaneInDirection", "Left"],
|
"ctrl-w left": ["workspace::ActivatePaneInDirection", "Left"],
|
||||||
@@ -201,299 +573,12 @@
|
|||||||
"ctrl-w o": "workspace::CloseInactiveTabsAndPanes",
|
"ctrl-w o": "workspace::CloseInactiveTabsAndPanes",
|
||||||
"ctrl-w ctrl-o": "workspace::CloseInactiveTabsAndPanes",
|
"ctrl-w ctrl-o": "workspace::CloseInactiveTabsAndPanes",
|
||||||
"ctrl-w n": "workspace::NewFileSplitHorizontal",
|
"ctrl-w n": "workspace::NewFileSplitHorizontal",
|
||||||
"ctrl-w ctrl-n": "workspace::NewFileSplitHorizontal",
|
"ctrl-w ctrl-n": "workspace::NewFileSplitHorizontal"
|
||||||
"ctrl-w d": "editor::GoToDefinitionSplit",
|
|
||||||
"ctrl-w g d": "editor::GoToDefinitionSplit",
|
|
||||||
"ctrl-w shift-d": "editor::GoToTypeDefinitionSplit",
|
|
||||||
"ctrl-w g shift-d": "editor::GoToTypeDefinitionSplit",
|
|
||||||
"ctrl-w space": "editor::OpenExcerptsSplit",
|
|
||||||
"ctrl-w g space": "editor::OpenExcerptsSplit",
|
|
||||||
"ctrl-6": "pane::AlternateFile"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"context": "vim_mode == normal",
|
"context": "EmptyPane || SharedScreen || MarkdownPreview || KeyContextView",
|
||||||
"bindings": {
|
"use_layout_keys": true,
|
||||||
"escape": "editor::Cancel",
|
|
||||||
"ctrl-[": "editor::Cancel",
|
|
||||||
":": "command_palette::Toggle",
|
|
||||||
".": "vim::Repeat",
|
|
||||||
"c": ["vim::PushOperator", "Change"],
|
|
||||||
"shift-c": "vim::ChangeToEndOfLine",
|
|
||||||
"d": ["vim::PushOperator", "Delete"],
|
|
||||||
"shift-d": "vim::DeleteToEndOfLine",
|
|
||||||
"shift-j": "vim::JoinLines",
|
|
||||||
"y": ["vim::PushOperator", "Yank"],
|
|
||||||
"shift-y": "vim::YankLine",
|
|
||||||
"i": "vim::InsertBefore",
|
|
||||||
"shift-i": "vim::InsertFirstNonWhitespace",
|
|
||||||
"a": "vim::InsertAfter",
|
|
||||||
"shift-a": "vim::InsertEndOfLine",
|
|
||||||
"x": "vim::DeleteRight",
|
|
||||||
"shift-x": "vim::DeleteLeft",
|
|
||||||
"o": "vim::InsertLineBelow",
|
|
||||||
"shift-o": "vim::InsertLineAbove",
|
|
||||||
"~": "vim::ChangeCase",
|
|
||||||
"ctrl-a": "vim::Increment",
|
|
||||||
"ctrl-x": "vim::Decrement",
|
|
||||||
"p": "vim::Paste",
|
|
||||||
"shift-p": ["vim::Paste", { "before": true }],
|
|
||||||
"u": "vim::Undo",
|
|
||||||
"ctrl-r": "vim::Redo",
|
|
||||||
"r": ["vim::PushOperator", "Replace"],
|
|
||||||
"s": "vim::Substitute",
|
|
||||||
"shift-s": "vim::SubstituteLine",
|
|
||||||
">": ["vim::PushOperator", "Indent"],
|
|
||||||
"<": ["vim::PushOperator", "Outdent"],
|
|
||||||
"g u": ["vim::PushOperator", "Lowercase"],
|
|
||||||
"g shift-u": ["vim::PushOperator", "Uppercase"],
|
|
||||||
"g ~": ["vim::PushOperator", "OppositeCase"],
|
|
||||||
"\"": ["vim::PushOperator", "Register"],
|
|
||||||
"g q": ["vim::PushOperator", "Rewrap"],
|
|
||||||
"g w": ["vim::PushOperator", "Rewrap"],
|
|
||||||
"q": "vim::ToggleRecord",
|
|
||||||
"shift-q": "vim::ReplayLastRecording",
|
|
||||||
"@": ["vim::PushOperator", "ReplayRegister"],
|
|
||||||
"ctrl-pagedown": "pane::ActivateNextItem",
|
|
||||||
"ctrl-pageup": "pane::ActivatePrevItem",
|
|
||||||
"insert": "vim::InsertBefore",
|
|
||||||
// tree-sitter related commands
|
|
||||||
"[ x": "editor::SelectLargerSyntaxNode",
|
|
||||||
"] x": "editor::SelectSmallerSyntaxNode",
|
|
||||||
"] d": "editor::GoToDiagnostic",
|
|
||||||
"[ d": "editor::GoToPrevDiagnostic",
|
|
||||||
"] c": "editor::GoToHunk",
|
|
||||||
"[ c": "editor::GoToPrevHunk",
|
|
||||||
"g c": ["vim::PushOperator", "ToggleComments"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"context": "VimControl && VimCount",
|
|
||||||
"bindings": {
|
|
||||||
"0": ["vim::Number", 0],
|
|
||||||
":": "vim::CountCommand"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"context": "vim_mode == visual",
|
|
||||||
"bindings": {
|
|
||||||
":": "vim::VisualCommand",
|
|
||||||
"u": "vim::ConvertToLowerCase",
|
|
||||||
"U": "vim::ConvertToUpperCase",
|
|
||||||
"o": "vim::OtherEnd",
|
|
||||||
"shift-o": "vim::OtherEnd",
|
|
||||||
"d": "vim::VisualDelete",
|
|
||||||
"x": "vim::VisualDelete",
|
|
||||||
"shift-d": "vim::VisualDeleteLine",
|
|
||||||
"shift-x": "vim::VisualDeleteLine",
|
|
||||||
"y": "vim::VisualYank",
|
|
||||||
"shift-y": "vim::VisualYank",
|
|
||||||
"p": "vim::Paste",
|
|
||||||
"shift-p": ["vim::Paste", { "preserveClipboard": true }],
|
|
||||||
"s": "vim::Substitute",
|
|
||||||
"shift-s": "vim::SubstituteLine",
|
|
||||||
"shift-r": "vim::SubstituteLine",
|
|
||||||
"c": "vim::Substitute",
|
|
||||||
"~": "vim::ChangeCase",
|
|
||||||
"*": ["vim::MoveToNext", { "partialWord": true }],
|
|
||||||
"#": ["vim::MoveToPrev", { "partialWord": true }],
|
|
||||||
"ctrl-a": "vim::Increment",
|
|
||||||
"ctrl-x": "vim::Decrement",
|
|
||||||
"g ctrl-a": ["vim::Increment", { "step": true }],
|
|
||||||
"g ctrl-x": ["vim::Decrement", { "step": true }],
|
|
||||||
"shift-i": "vim::InsertBefore",
|
|
||||||
"shift-a": "vim::InsertAfter",
|
|
||||||
"g I": "vim::VisualInsertFirstNonWhiteSpace",
|
|
||||||
"g A": "vim::VisualInsertEndOfLine",
|
|
||||||
"shift-j": "vim::JoinLines",
|
|
||||||
"r": ["vim::PushOperator", "Replace"],
|
|
||||||
"ctrl-c": ["vim::SwitchMode", "Normal"],
|
|
||||||
"escape": ["vim::SwitchMode", "Normal"],
|
|
||||||
"ctrl-[": ["vim::SwitchMode", "Normal"],
|
|
||||||
">": "vim::Indent",
|
|
||||||
"<": "vim::Outdent",
|
|
||||||
"i": ["vim::PushOperator", { "Object": { "around": false } }],
|
|
||||||
"a": ["vim::PushOperator", { "Object": { "around": true } }],
|
|
||||||
"g c": "vim::ToggleComments",
|
|
||||||
"g q": "vim::Rewrap",
|
|
||||||
"\"": ["vim::PushOperator", "Register"],
|
|
||||||
// tree-sitter related commands
|
|
||||||
"[ x": "editor::SelectLargerSyntaxNode",
|
|
||||||
"] x": "editor::SelectSmallerSyntaxNode"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"context": "vim_mode == insert",
|
|
||||||
"bindings": {
|
|
||||||
"escape": "vim::NormalBefore",
|
|
||||||
"ctrl-c": "vim::NormalBefore",
|
|
||||||
"ctrl-[": "vim::NormalBefore",
|
|
||||||
"ctrl-x": null,
|
|
||||||
"ctrl-x ctrl-o": "editor::ShowCompletions",
|
|
||||||
"ctrl-x ctrl-a": "assistant::InlineAssist", // zed specific
|
|
||||||
"ctrl-x ctrl-c": "editor::ShowInlineCompletion", // zed specific
|
|
||||||
"ctrl-x ctrl-l": "editor::ToggleCodeActions", // zed specific
|
|
||||||
"ctrl-x ctrl-z": "editor::Cancel",
|
|
||||||
"ctrl-w": "editor::DeleteToPreviousWordStart",
|
|
||||||
"ctrl-u": "editor::DeleteToBeginningOfLine",
|
|
||||||
"ctrl-t": "vim::Indent",
|
|
||||||
"ctrl-d": "vim::Outdent",
|
|
||||||
"ctrl-k": ["vim::PushOperator", { "Digraph": {} }],
|
|
||||||
"ctrl-r": ["vim::PushOperator", "Register"],
|
|
||||||
"insert": "vim::ToggleReplace"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"context": "vim_mode == insert && !(showing_code_actions || showing_completions)",
|
|
||||||
"bindings": {
|
|
||||||
"ctrl-p": "editor::ShowCompletions",
|
|
||||||
"ctrl-n": "editor::ShowCompletions"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"context": "vim_mode == replace",
|
|
||||||
"bindings": {
|
|
||||||
"escape": "vim::NormalBefore",
|
|
||||||
"ctrl-c": "vim::NormalBefore",
|
|
||||||
"ctrl-[": "vim::NormalBefore",
|
|
||||||
"ctrl-k": ["vim::PushOperator", { "Digraph": {} }],
|
|
||||||
"backspace": "vim::UndoReplace",
|
|
||||||
"tab": "vim::Tab",
|
|
||||||
"enter": "vim::Enter",
|
|
||||||
"insert": "vim::InsertBefore"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"context": "vim_mode == waiting",
|
|
||||||
"bindings": {
|
|
||||||
"tab": "vim::Tab",
|
|
||||||
"enter": "vim::Enter",
|
|
||||||
"escape": "vim::ClearOperators",
|
|
||||||
"ctrl-c": "vim::ClearOperators",
|
|
||||||
"ctrl-[": "vim::ClearOperators",
|
|
||||||
"ctrl-k": ["vim::PushOperator", { "Digraph": {} }]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"context": "vim_mode == operator",
|
|
||||||
"bindings": {
|
|
||||||
"escape": "vim::ClearOperators",
|
|
||||||
"ctrl-c": "vim::ClearOperators",
|
|
||||||
"ctrl-[": "vim::ClearOperators"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"context": "vim_operator == a || vim_operator == i || vim_operator == cs",
|
|
||||||
"bindings": {
|
|
||||||
"w": "vim::Word",
|
|
||||||
"shift-w": ["vim::Word", { "ignorePunctuation": true }],
|
|
||||||
"t": "vim::Tag",
|
|
||||||
"s": "vim::Sentence",
|
|
||||||
"p": "vim::Paragraph",
|
|
||||||
"'": "vim::Quotes",
|
|
||||||
"`": "vim::BackQuotes",
|
|
||||||
"\"": "vim::DoubleQuotes",
|
|
||||||
"|": "vim::VerticalBars",
|
|
||||||
"(": "vim::Parentheses",
|
|
||||||
")": "vim::Parentheses",
|
|
||||||
"b": "vim::Parentheses",
|
|
||||||
"[": "vim::SquareBrackets",
|
|
||||||
"]": "vim::SquareBrackets",
|
|
||||||
"{": "vim::CurlyBrackets",
|
|
||||||
"}": "vim::CurlyBrackets",
|
|
||||||
"shift-b": "vim::CurlyBrackets",
|
|
||||||
"<": "vim::AngleBrackets",
|
|
||||||
">": "vim::AngleBrackets",
|
|
||||||
"a": "vim::Argument"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"context": "vim_operator == c",
|
|
||||||
"bindings": {
|
|
||||||
"c": "vim::CurrentLine",
|
|
||||||
"d": "editor::Rename", // zed specific
|
|
||||||
"s": ["vim::PushOperator", { "ChangeSurrounds": {} }]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"context": "vim_operator == d",
|
|
||||||
"bindings": {
|
|
||||||
"d": "vim::CurrentLine",
|
|
||||||
"s": ["vim::PushOperator", "DeleteSurrounds"],
|
|
||||||
"o": "editor::ToggleHunkDiff", // "d o"
|
|
||||||
"p": "editor::RevertSelectedHunks" // "d p"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"context": "vim_operator == gu",
|
|
||||||
"bindings": {
|
|
||||||
"g u": "vim::CurrentLine",
|
|
||||||
"u": "vim::CurrentLine"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"context": "vim_operator == gU",
|
|
||||||
"bindings": {
|
|
||||||
"g shift-u": "vim::CurrentLine",
|
|
||||||
"shift-u": "vim::CurrentLine"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"context": "vim_operator == g~",
|
|
||||||
"bindings": {
|
|
||||||
"g ~": "vim::CurrentLine",
|
|
||||||
"~": "vim::CurrentLine"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"context": "vim_operator == gq",
|
|
||||||
"bindings": {
|
|
||||||
"g q": "vim::CurrentLine",
|
|
||||||
"q": "vim::CurrentLine",
|
|
||||||
"g w": "vim::CurrentLine",
|
|
||||||
"w": "vim::CurrentLine"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"context": "vim_operator == y",
|
|
||||||
"bindings": {
|
|
||||||
"y": "vim::CurrentLine",
|
|
||||||
"s": ["vim::PushOperator", { "AddSurrounds": {} }]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"context": "vim_operator == ys",
|
|
||||||
"bindings": {
|
|
||||||
"s": "vim::CurrentLine"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"context": "vim_operator == >",
|
|
||||||
"bindings": {
|
|
||||||
">": "vim::CurrentLine"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"context": "vim_operator == <",
|
|
||||||
"bindings": {
|
|
||||||
"<": "vim::CurrentLine"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"context": "vim_operator == gc",
|
|
||||||
"bindings": {
|
|
||||||
"c": "vim::CurrentLine"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"context": "BufferSearchBar && !in_replace",
|
|
||||||
"bindings": {
|
|
||||||
"enter": "vim::SearchSubmit",
|
|
||||||
"escape": "buffer_search::Dismiss"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"context": "EmptyPane || SharedScreen",
|
|
||||||
"bindings": {
|
"bindings": {
|
||||||
":": "command_palette::Toggle",
|
":": "command_palette::Toggle",
|
||||||
"g /": "pane::DeploySearch"
|
"g /": "pane::DeploySearch"
|
||||||
@@ -502,6 +587,7 @@
|
|||||||
{
|
{
|
||||||
// netrw compatibility
|
// netrw compatibility
|
||||||
"context": "ProjectPanel && not_editing",
|
"context": "ProjectPanel && not_editing",
|
||||||
|
"use_layout_keys": true,
|
||||||
"bindings": {
|
"bindings": {
|
||||||
":": "command_palette::Toggle",
|
":": "command_palette::Toggle",
|
||||||
"%": "project_panel::NewFile",
|
"%": "project_panel::NewFile",
|
||||||
@@ -529,6 +615,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"context": "OutlinePanel && not_editing",
|
"context": "OutlinePanel && not_editing",
|
||||||
|
"use_layout_keys": true,
|
||||||
"bindings": {
|
"bindings": {
|
||||||
"j": "menu::SelectNext",
|
"j": "menu::SelectNext",
|
||||||
"k": "menu::SelectPrev",
|
"k": "menu::SelectPrev",
|
||||||
|
|||||||
@@ -68,9 +68,17 @@
|
|||||||
"ui_font_size": 16,
|
"ui_font_size": 16,
|
||||||
// How much to fade out unused code.
|
// How much to fade out unused code.
|
||||||
"unnecessary_code_fade": 0.3,
|
"unnecessary_code_fade": 0.3,
|
||||||
// The factor to grow the active pane by. Defaults to 1.0
|
// Active pane styling settings.
|
||||||
// which gives the same size as all other panes.
|
"active_pane_modifiers": {
|
||||||
"active_pane_magnification": 1.0,
|
// The factor to grow the active pane by. Defaults to 1.0
|
||||||
|
// which gives the same size as all other panes.
|
||||||
|
"magnification": 1.0,
|
||||||
|
// Inset border size of the active pane, in pixels.
|
||||||
|
"border_size": 0.0,
|
||||||
|
// Opacity of the inactive panes. 0 means transparent, 1 means opaque.
|
||||||
|
// Values are clamped to the [0.0, 1.0] range.
|
||||||
|
"inactive_opacity": 1.0
|
||||||
|
},
|
||||||
// The direction that you want to split panes horizontally. Defaults to "up"
|
// The direction that you want to split panes horizontally. Defaults to "up"
|
||||||
"pane_split_direction_horizontal": "up",
|
"pane_split_direction_horizontal": "up",
|
||||||
// The direction that you want to split panes horizontally. Defaults to "left"
|
// The direction that you want to split panes horizontally. Defaults to "left"
|
||||||
@@ -152,7 +160,7 @@
|
|||||||
"show_signature_help_after_edits": true,
|
"show_signature_help_after_edits": true,
|
||||||
// Whether to show wrap guides (vertical rulers) in the editor.
|
// Whether to show wrap guides (vertical rulers) in the editor.
|
||||||
// Setting this to true will show a guide at the 'preferred_line_length' value
|
// Setting this to true will show a guide at the 'preferred_line_length' value
|
||||||
// if softwrap is set to 'preferred_line_length', and will show any
|
// if 'soft_wrap' is set to 'preferred_line_length', and will show any
|
||||||
// additional guides as specified by the 'wrap_guides' setting.
|
// additional guides as specified by the 'wrap_guides' setting.
|
||||||
"show_wrap_guides": true,
|
"show_wrap_guides": true,
|
||||||
// Character counts at which to show wrap guides in the editor.
|
// Character counts at which to show wrap guides in the editor.
|
||||||
@@ -174,6 +182,8 @@
|
|||||||
// bracket, brace, single or double quote characters.
|
// bracket, brace, single or double quote characters.
|
||||||
// For example, when you select text and type (, Zed will surround the text with ().
|
// For example, when you select text and type (, Zed will surround the text with ().
|
||||||
"use_auto_surround": true,
|
"use_auto_surround": true,
|
||||||
|
// Whether indentation of pasted content should be adjusted based on the context.
|
||||||
|
"auto_indent_on_paste": true,
|
||||||
// Controls how the editor handles the autoclosed characters.
|
// Controls how the editor handles the autoclosed characters.
|
||||||
// When set to `false`(default), skipping over and auto-removing of the closing characters
|
// When set to `false`(default), skipping over and auto-removing of the closing characters
|
||||||
// happen only for auto-inserted characters.
|
// happen only for auto-inserted characters.
|
||||||
@@ -183,6 +193,9 @@
|
|||||||
// Controls whether inline completions are shown immediately (true)
|
// Controls whether inline completions are shown immediately (true)
|
||||||
// or manually by triggering `editor::ShowInlineCompletion` (false).
|
// or manually by triggering `editor::ShowInlineCompletion` (false).
|
||||||
"show_inline_completions": true,
|
"show_inline_completions": true,
|
||||||
|
// Controls whether inline completions are shown in a given language scope.
|
||||||
|
// Example: ["string", "comment"]
|
||||||
|
"inline_completions_disabled_in": [],
|
||||||
// Whether to show tabs and spaces in the editor.
|
// Whether to show tabs and spaces in the editor.
|
||||||
// This setting can take three values:
|
// This setting can take three values:
|
||||||
//
|
//
|
||||||
@@ -475,7 +488,7 @@
|
|||||||
"default_width": 640,
|
"default_width": 640,
|
||||||
// Default height when the assistant is docked to the bottom.
|
// Default height when the assistant is docked to the bottom.
|
||||||
"default_height": 320,
|
"default_height": 320,
|
||||||
// The default model to use when creating new contexts.
|
// The default model to use when creating new chats.
|
||||||
"default_model": {
|
"default_model": {
|
||||||
// The provider to use.
|
// The provider to use.
|
||||||
"provider": "zed.dev",
|
"provider": "zed.dev",
|
||||||
@@ -652,6 +665,12 @@
|
|||||||
// Sets a delay after which the inline blame information is shown.
|
// Sets a delay after which the inline blame information is shown.
|
||||||
// Delay is restarted with every cursor movement.
|
// Delay is restarted with every cursor movement.
|
||||||
// "delay_ms": 600
|
// "delay_ms": 600
|
||||||
|
//
|
||||||
|
// Whether or not do display the git commit summary on the same line.
|
||||||
|
// "show_commit_summary": false
|
||||||
|
//
|
||||||
|
// The minimum column number to show the inline blame information at
|
||||||
|
// "min_column": 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// Configuration for how direnv configuration should be loaded. May take 2 values:
|
// Configuration for how direnv configuration should be loaded. May take 2 values:
|
||||||
@@ -814,7 +833,6 @@
|
|||||||
"tasks": {
|
"tasks": {
|
||||||
"variables": {}
|
"variables": {}
|
||||||
},
|
},
|
||||||
"toolchain": { "name": "default", "path": "default" },
|
|
||||||
// An object whose keys are language names, and whose values
|
// An object whose keys are language names, and whose values
|
||||||
// are arrays of filenames or extensions of files that should
|
// are arrays of filenames or extensions of files that should
|
||||||
// use those languages.
|
// use those languages.
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
"allow_concurrent_runs": false,
|
"allow_concurrent_runs": false,
|
||||||
// What to do with the terminal pane and tab, after the command was started:
|
// What to do with the terminal pane and tab, after the command was started:
|
||||||
// * `always` — always show the terminal pane, add and focus the corresponding task's tab in it (default)
|
// * `always` — always show the terminal pane, add and focus the corresponding task's tab in it (default)
|
||||||
|
// * `no_focus` — always show the terminal pane, add/reuse the task's tab there, but don't focus it
|
||||||
// * `never` — avoid changing current terminal pane focus, but still add/reuse the task's tab there
|
// * `never` — avoid changing current terminal pane focus, but still add/reuse the task's tab there
|
||||||
"reveal": "always",
|
"reveal": "always",
|
||||||
// What to do with the terminal pane and tab, after the command had finished:
|
// What to do with the terminal pane and tab, after the command had finished:
|
||||||
|
|||||||
@@ -27,15 +27,15 @@
|
|||||||
"ghost_element.active": "#454a56ff",
|
"ghost_element.active": "#454a56ff",
|
||||||
"ghost_element.selected": "#454a56ff",
|
"ghost_element.selected": "#454a56ff",
|
||||||
"ghost_element.disabled": "#2e343eff",
|
"ghost_element.disabled": "#2e343eff",
|
||||||
"text": "#c8ccd4ff",
|
"text": "#dce0e5ff",
|
||||||
"text.muted": "#838994ff",
|
"text.muted": "#a9afbcff",
|
||||||
"text.placeholder": "#696B77ff",
|
"text.placeholder": "#878a98ff",
|
||||||
"text.disabled": "#696B77ff",
|
"text.disabled": "#878a98ff",
|
||||||
"text.accent": "#74ade8ff",
|
"text.accent": "#74ade8ff",
|
||||||
"icon": "#c8ccd4ff",
|
"icon": "#dce0e5ff",
|
||||||
"icon.muted": "#838994ff",
|
"icon.muted": "#a9afbcff",
|
||||||
"icon.disabled": "#696B77ff",
|
"icon.disabled": "#878a98ff",
|
||||||
"icon.placeholder": "#838994ff",
|
"icon.placeholder": "#a9afbcff",
|
||||||
"icon.accent": "#74ade8ff",
|
"icon.accent": "#74ade8ff",
|
||||||
"status_bar.background": "#3b414dff",
|
"status_bar.background": "#3b414dff",
|
||||||
"title_bar.background": "#3b414dff",
|
"title_bar.background": "#3b414dff",
|
||||||
@@ -60,19 +60,19 @@
|
|||||||
"editor.active_line.background": "#2f343ebf",
|
"editor.active_line.background": "#2f343ebf",
|
||||||
"editor.highlighted_line.background": "#2f343eff",
|
"editor.highlighted_line.background": "#2f343eff",
|
||||||
"editor.line_number": "#c8ccd459",
|
"editor.line_number": "#c8ccd459",
|
||||||
"editor.active_line_number": "#c8ccd4ff",
|
"editor.active_line_number": "#dce0e5ff",
|
||||||
"editor.invisible": "#696B77ff",
|
"editor.invisible": "#878a98ff",
|
||||||
"editor.wrap_guide": "#c8ccd40d",
|
"editor.wrap_guide": "#c8ccd40d",
|
||||||
"editor.active_wrap_guide": "#c8ccd41a",
|
"editor.active_wrap_guide": "#c8ccd41a",
|
||||||
"editor.document_highlight.read_background": "#74ade81a",
|
"editor.document_highlight.read_background": "#74ade81a",
|
||||||
"editor.document_highlight.write_background": "#555a6366",
|
"editor.document_highlight.write_background": "#555a6366",
|
||||||
"terminal.background": "#282c33ff",
|
"terminal.background": "#282c33ff",
|
||||||
"terminal.foreground": "#c8ccd4ff",
|
"terminal.foreground": "#dce0e5ff",
|
||||||
"terminal.bright_foreground": "#c8ccd4ff",
|
"terminal.bright_foreground": "#dce0e5ff",
|
||||||
"terminal.dim_foreground": "#282c33ff",
|
"terminal.dim_foreground": "#282c33ff",
|
||||||
"terminal.ansi.black": "#282c33ff",
|
"terminal.ansi.black": "#282c33ff",
|
||||||
"terminal.ansi.bright_black": "#525561ff",
|
"terminal.ansi.bright_black": "#525561ff",
|
||||||
"terminal.ansi.dim_black": "#c8ccd4ff",
|
"terminal.ansi.dim_black": "#dce0e5ff",
|
||||||
"terminal.ansi.red": "#d07277ff",
|
"terminal.ansi.red": "#d07277ff",
|
||||||
"terminal.ansi.bright_red": "#673a3cff",
|
"terminal.ansi.bright_red": "#673a3cff",
|
||||||
"terminal.ansi.dim_red": "#eab7b9ff",
|
"terminal.ansi.dim_red": "#eab7b9ff",
|
||||||
@@ -91,8 +91,8 @@
|
|||||||
"terminal.ansi.cyan": "#6eb4bfff",
|
"terminal.ansi.cyan": "#6eb4bfff",
|
||||||
"terminal.ansi.bright_cyan": "#3a565bff",
|
"terminal.ansi.bright_cyan": "#3a565bff",
|
||||||
"terminal.ansi.dim_cyan": "#b9d9dfff",
|
"terminal.ansi.dim_cyan": "#b9d9dfff",
|
||||||
"terminal.ansi.white": "#c8ccd4ff",
|
"terminal.ansi.white": "#dce0e5ff",
|
||||||
"terminal.ansi.bright_white": "#c8ccd4ff",
|
"terminal.ansi.bright_white": "#dce0e5ff",
|
||||||
"terminal.ansi.dim_white": "#575d65ff",
|
"terminal.ansi.dim_white": "#575d65ff",
|
||||||
"link_text.hover": "#74ade8ff",
|
"link_text.hover": "#74ade8ff",
|
||||||
"conflict": "#dec184ff",
|
"conflict": "#dec184ff",
|
||||||
@@ -107,14 +107,14 @@
|
|||||||
"error": "#d07277ff",
|
"error": "#d07277ff",
|
||||||
"error.background": "#d072771a",
|
"error.background": "#d072771a",
|
||||||
"error.border": "#4c2b2cff",
|
"error.border": "#4c2b2cff",
|
||||||
"hidden": "#696B77ff",
|
"hidden": "#878a98ff",
|
||||||
"hidden.background": "#696B771a",
|
"hidden.background": "#696b771a",
|
||||||
"hidden.border": "#414754ff",
|
"hidden.border": "#414754ff",
|
||||||
"hint": "#5a6f89ff",
|
"hint": "#788ca6ff",
|
||||||
"hint.background": "#5a6f891a",
|
"hint.background": "#5a6f891a",
|
||||||
"hint.border": "#293b5bff",
|
"hint.border": "#293b5bff",
|
||||||
"ignored": "#696B77ff",
|
"ignored": "#878a98ff",
|
||||||
"ignored.background": "#696B771a",
|
"ignored.background": "#696b771a",
|
||||||
"ignored.border": "#464b57ff",
|
"ignored.border": "#464b57ff",
|
||||||
"info": "#74ade8ff",
|
"info": "#74ade8ff",
|
||||||
"info.background": "#74ade81a",
|
"info.background": "#74ade81a",
|
||||||
@@ -131,7 +131,7 @@
|
|||||||
"success": "#a1c181ff",
|
"success": "#a1c181ff",
|
||||||
"success.background": "#a1c1811a",
|
"success.background": "#a1c1811a",
|
||||||
"success.border": "#38482fff",
|
"success.border": "#38482fff",
|
||||||
"unreachable": "#838994ff",
|
"unreachable": "#a9afbcff",
|
||||||
"unreachable.background": "#8389941a",
|
"unreachable.background": "#8389941a",
|
||||||
"unreachable.border": "#464b57ff",
|
"unreachable.border": "#464b57ff",
|
||||||
"warning": "#dec184ff",
|
"warning": "#dec184ff",
|
||||||
@@ -211,7 +211,7 @@
|
|||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
"embedded": {
|
"embedded": {
|
||||||
"color": "#c8ccd4ff",
|
"color": "#dce0e5ff",
|
||||||
"font_style": null,
|
"font_style": null,
|
||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
@@ -236,7 +236,7 @@
|
|||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
"hint": {
|
"hint": {
|
||||||
"color": "#5a6f89ff",
|
"color": "#788ca6ff",
|
||||||
"font_style": null,
|
"font_style": null,
|
||||||
"font_weight": 700
|
"font_weight": 700
|
||||||
},
|
},
|
||||||
@@ -276,7 +276,7 @@
|
|||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
"preproc": {
|
"preproc": {
|
||||||
"color": "#c8ccd4ff",
|
"color": "#dce0e5ff",
|
||||||
"font_style": null,
|
"font_style": null,
|
||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
@@ -361,7 +361,7 @@
|
|||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
"variable": {
|
"variable": {
|
||||||
"color": "#c8ccd4ff",
|
"color": "#dce0e5ff",
|
||||||
"font_style": null,
|
"font_style": null,
|
||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
@@ -402,15 +402,15 @@
|
|||||||
"ghost_element.active": "#cacacaff",
|
"ghost_element.active": "#cacacaff",
|
||||||
"ghost_element.selected": "#cacacaff",
|
"ghost_element.selected": "#cacacaff",
|
||||||
"ghost_element.disabled": "#ebebecff",
|
"ghost_element.disabled": "#ebebecff",
|
||||||
"text": "#383a41ff",
|
"text": "#242529ff",
|
||||||
"text.muted": "#7e8087ff",
|
"text.muted": "#58585aff",
|
||||||
"text.placeholder": "#a1a1a3ff",
|
"text.placeholder": "#7e8086ff",
|
||||||
"text.disabled": "#a1a1a3ff",
|
"text.disabled": "#7e8086ff",
|
||||||
"text.accent": "#5c78e2ff",
|
"text.accent": "#5c78e2ff",
|
||||||
"icon": "#383a41ff",
|
"icon": "#242529ff",
|
||||||
"icon.muted": "#7e8087ff",
|
"icon.muted": "#58585aff",
|
||||||
"icon.disabled": "#a1a1a3ff",
|
"icon.disabled": "#7e8086ff",
|
||||||
"icon.placeholder": "#7e8087ff",
|
"icon.placeholder": "#58585aff",
|
||||||
"icon.accent": "#5c78e2ff",
|
"icon.accent": "#5c78e2ff",
|
||||||
"status_bar.background": "#dcdcddff",
|
"status_bar.background": "#dcdcddff",
|
||||||
"title_bar.background": "#dcdcddff",
|
"title_bar.background": "#dcdcddff",
|
||||||
@@ -428,26 +428,26 @@
|
|||||||
"scrollbar.thumb.border": "#dfdfe0ff",
|
"scrollbar.thumb.border": "#dfdfe0ff",
|
||||||
"scrollbar.track.background": "#00000000",
|
"scrollbar.track.background": "#00000000",
|
||||||
"scrollbar.track.border": "#eeeeeeff",
|
"scrollbar.track.border": "#eeeeeeff",
|
||||||
"editor.foreground": "#383a41ff",
|
"editor.foreground": "#242529ff",
|
||||||
"editor.background": "#fafafaff",
|
"editor.background": "#fafafaff",
|
||||||
"editor.gutter.background": "#fafafaff",
|
"editor.gutter.background": "#fafafaff",
|
||||||
"editor.subheader.background": "#ebebecff",
|
"editor.subheader.background": "#ebebecff",
|
||||||
"editor.active_line.background": "#ebebecbf",
|
"editor.active_line.background": "#ebebecbf",
|
||||||
"editor.highlighted_line.background": "#ebebecff",
|
"editor.highlighted_line.background": "#ebebecff",
|
||||||
"editor.line_number": "#383a4159",
|
"editor.line_number": "#383a4159",
|
||||||
"editor.active_line_number": "#383a41ff",
|
"editor.active_line_number": "#242529ff",
|
||||||
"editor.invisible": "#a3a3a4ff",
|
"editor.invisible": "#a3a3a4ff",
|
||||||
"editor.wrap_guide": "#383a410d",
|
"editor.wrap_guide": "#383a410d",
|
||||||
"editor.active_wrap_guide": "#383a411a",
|
"editor.active_wrap_guide": "#383a411a",
|
||||||
"editor.document_highlight.read_background": "#5c78e21a",
|
"editor.document_highlight.read_background": "#5c78e21a",
|
||||||
"editor.document_highlight.write_background": "#a3a3a466",
|
"editor.document_highlight.write_background": "#a3a3a466",
|
||||||
"terminal.background": "#fafafaff",
|
"terminal.background": "#fafafaff",
|
||||||
"terminal.foreground": "#383a41ff",
|
"terminal.foreground": "#242529ff",
|
||||||
"terminal.bright_foreground": "#383a41ff",
|
"terminal.bright_foreground": "#242529ff",
|
||||||
"terminal.dim_foreground": "#fafafaff",
|
"terminal.dim_foreground": "#fafafaff",
|
||||||
"terminal.ansi.black": "#fafafaff",
|
"terminal.ansi.black": "#fafafaff",
|
||||||
"terminal.ansi.bright_black": "#aaaaaaff",
|
"terminal.ansi.bright_black": "#aaaaaaff",
|
||||||
"terminal.ansi.dim_black": "#383a41ff",
|
"terminal.ansi.dim_black": "#242529ff",
|
||||||
"terminal.ansi.red": "#d36151ff",
|
"terminal.ansi.red": "#d36151ff",
|
||||||
"terminal.ansi.bright_red": "#f0b0a4ff",
|
"terminal.ansi.bright_red": "#f0b0a4ff",
|
||||||
"terminal.ansi.dim_red": "#6f312aff",
|
"terminal.ansi.dim_red": "#6f312aff",
|
||||||
@@ -466,11 +466,11 @@
|
|||||||
"terminal.ansi.cyan": "#3a82b7ff",
|
"terminal.ansi.cyan": "#3a82b7ff",
|
||||||
"terminal.ansi.bright_cyan": "#a3bedaff",
|
"terminal.ansi.bright_cyan": "#a3bedaff",
|
||||||
"terminal.ansi.dim_cyan": "#254058ff",
|
"terminal.ansi.dim_cyan": "#254058ff",
|
||||||
"terminal.ansi.white": "#383a41ff",
|
"terminal.ansi.white": "#242529ff",
|
||||||
"terminal.ansi.bright_white": "#383a41ff",
|
"terminal.ansi.bright_white": "#242529ff",
|
||||||
"terminal.ansi.dim_white": "#97979aff",
|
"terminal.ansi.dim_white": "#97979aff",
|
||||||
"link_text.hover": "#5c78e2ff",
|
"link_text.hover": "#5c78e2ff",
|
||||||
"conflict": "#dec184ff",
|
"conflict": "#a48819ff",
|
||||||
"conflict.background": "#faf2e6ff",
|
"conflict.background": "#faf2e6ff",
|
||||||
"conflict.border": "#f4e7d1ff",
|
"conflict.border": "#f4e7d1ff",
|
||||||
"created": "#669f59ff",
|
"created": "#669f59ff",
|
||||||
@@ -482,19 +482,19 @@
|
|||||||
"error": "#d36151ff",
|
"error": "#d36151ff",
|
||||||
"error.background": "#fbdfd9ff",
|
"error.background": "#fbdfd9ff",
|
||||||
"error.border": "#f6c6bdff",
|
"error.border": "#f6c6bdff",
|
||||||
"hidden": "#a1a1a3ff",
|
"hidden": "#7e8086ff",
|
||||||
"hidden.background": "#dcdcddff",
|
"hidden.background": "#dcdcddff",
|
||||||
"hidden.border": "#d3d3d4ff",
|
"hidden.border": "#d3d3d4ff",
|
||||||
"hint": "#9294beff",
|
"hint": "#7274a7ff",
|
||||||
"hint.background": "#e2e2faff",
|
"hint.background": "#e2e2faff",
|
||||||
"hint.border": "#cbcdf6ff",
|
"hint.border": "#cbcdf6ff",
|
||||||
"ignored": "#a1a1a3ff",
|
"ignored": "#7e8086ff",
|
||||||
"ignored.background": "#dcdcddff",
|
"ignored.background": "#dcdcddff",
|
||||||
"ignored.border": "#c9c9caff",
|
"ignored.border": "#c9c9caff",
|
||||||
"info": "#5c78e2ff",
|
"info": "#5c78e2ff",
|
||||||
"info.background": "#e2e2faff",
|
"info.background": "#e2e2faff",
|
||||||
"info.border": "#cbcdf6ff",
|
"info.border": "#cbcdf6ff",
|
||||||
"modified": "#a47a23ff",
|
"modified": "#a48819ff",
|
||||||
"modified.background": "#faf2e6ff",
|
"modified.background": "#faf2e6ff",
|
||||||
"modified.border": "#f4e7d1ff",
|
"modified.border": "#f4e7d1ff",
|
||||||
"predictive": "#9b9ec6ff",
|
"predictive": "#9b9ec6ff",
|
||||||
@@ -506,10 +506,10 @@
|
|||||||
"success": "#669f59ff",
|
"success": "#669f59ff",
|
||||||
"success.background": "#dfeadbff",
|
"success.background": "#dfeadbff",
|
||||||
"success.border": "#c8dcc1ff",
|
"success.border": "#c8dcc1ff",
|
||||||
"unreachable": "#7e8087ff",
|
"unreachable": "#58585aff",
|
||||||
"unreachable.background": "#dcdcddff",
|
"unreachable.background": "#dcdcddff",
|
||||||
"unreachable.border": "#c9c9caff",
|
"unreachable.border": "#c9c9caff",
|
||||||
"warning": "#dec184ff",
|
"warning": "#a48819ff",
|
||||||
"warning.background": "#faf2e6ff",
|
"warning.background": "#faf2e6ff",
|
||||||
"warning.border": "#f4e7d1ff",
|
"warning.border": "#f4e7d1ff",
|
||||||
"players": [
|
"players": [
|
||||||
@@ -544,7 +544,7 @@
|
|||||||
"selection": "#d361513d"
|
"selection": "#d361513d"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cursor": "#dec184ff",
|
"cursor": "#a48819ff",
|
||||||
"background": "#dec184ff",
|
"background": "#dec184ff",
|
||||||
"selection": "#dec1843d"
|
"selection": "#dec1843d"
|
||||||
},
|
},
|
||||||
@@ -586,7 +586,7 @@
|
|||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
"embedded": {
|
"embedded": {
|
||||||
"color": "#383a41ff",
|
"color": "#242529ff",
|
||||||
"font_style": null,
|
"font_style": null,
|
||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
@@ -611,7 +611,7 @@
|
|||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
"hint": {
|
"hint": {
|
||||||
"color": "#9294beff",
|
"color": "#7274a7ff",
|
||||||
"font_style": null,
|
"font_style": null,
|
||||||
"font_weight": 700
|
"font_weight": 700
|
||||||
},
|
},
|
||||||
@@ -651,12 +651,12 @@
|
|||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
"preproc": {
|
"preproc": {
|
||||||
"color": "#383a41ff",
|
"color": "#242529ff",
|
||||||
"font_style": null,
|
"font_style": null,
|
||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
"primary": {
|
"primary": {
|
||||||
"color": "#383a41ff",
|
"color": "#242529ff",
|
||||||
"font_style": null,
|
"font_style": null,
|
||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
@@ -666,7 +666,7 @@
|
|||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
"punctuation": {
|
"punctuation": {
|
||||||
"color": "#383a41ff",
|
"color": "#242529ff",
|
||||||
"font_style": null,
|
"font_style": null,
|
||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
@@ -736,7 +736,7 @@
|
|||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
"variable": {
|
"variable": {
|
||||||
"color": "#383a41ff",
|
"color": "#242529ff",
|
||||||
"font_style": null,
|
"font_style": null,
|
||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -519,8 +519,8 @@
|
|||||||
"selection": "#d337813d"
|
"selection": "#d337813d"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cursor": "#cb4b17ff",
|
"cursor": "#cb4b16ff",
|
||||||
"background": "#cb4b17ff",
|
"background": "#cb4b16ff",
|
||||||
"selection": "#cb4b173d"
|
"selection": "#cb4b173d"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -596,7 +596,7 @@
|
|||||||
"font_weight": 700
|
"font_weight": 700
|
||||||
},
|
},
|
||||||
"enum": {
|
"enum": {
|
||||||
"color": "#cb4b17ff",
|
"color": "#cb4b16ff",
|
||||||
"font_style": null,
|
"font_style": null,
|
||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
@@ -621,7 +621,7 @@
|
|||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
"link_text": {
|
"link_text": {
|
||||||
"color": "#cb4b17ff",
|
"color": "#cb4b16ff",
|
||||||
"font_style": "italic",
|
"font_style": "italic",
|
||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
@@ -636,7 +636,7 @@
|
|||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
"operator": {
|
"operator": {
|
||||||
"color": "#cb4b17ff",
|
"color": "#cb4b16ff",
|
||||||
"font_style": null,
|
"font_style": null,
|
||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
@@ -686,7 +686,7 @@
|
|||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
"string": {
|
"string": {
|
||||||
"color": "#cb4b17ff",
|
"color": "#cb4b16ff",
|
||||||
"font_style": null,
|
"font_style": null,
|
||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
@@ -696,17 +696,17 @@
|
|||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
"string.regex": {
|
"string.regex": {
|
||||||
"color": "#cb4b17ff",
|
"color": "#cb4b16ff",
|
||||||
"font_style": null,
|
"font_style": null,
|
||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
"string.special": {
|
"string.special": {
|
||||||
"color": "#cb4b17ff",
|
"color": "#cb4b16ff",
|
||||||
"font_style": null,
|
"font_style": null,
|
||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
"string.special.symbol": {
|
"string.special.symbol": {
|
||||||
"color": "#cb4b17ff",
|
"color": "#cb4b16ff",
|
||||||
"font_style": null,
|
"font_style": null,
|
||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
@@ -716,7 +716,7 @@
|
|||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
"text.literal": {
|
"text.literal": {
|
||||||
"color": "#cb4b17ff",
|
"color": "#cb4b16ff",
|
||||||
"font_style": null,
|
"font_style": null,
|
||||||
"font_weight": null
|
"font_weight": null
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "activity_indicator"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
publish = false
|
|
||||||
license = "GPL-3.0-or-later"
|
|
||||||
|
|
||||||
[lints]
|
|
||||||
workspace = true
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
path = "src/activity_indicator.rs"
|
|
||||||
doctest = false
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
anyhow.workspace = true
|
|
||||||
auto_update.workspace = true
|
|
||||||
editor.workspace = true
|
|
||||||
extension.workspace = true
|
|
||||||
futures.workspace = true
|
|
||||||
gpui.workspace = true
|
|
||||||
language.workspace = true
|
|
||||||
project.workspace = true
|
|
||||||
smallvec.workspace = true
|
|
||||||
ui.workspace = true
|
|
||||||
util.workspace = true
|
|
||||||
workspace.workspace = true
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
editor = { workspace = true, features = ["test-support"] }
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "assistant"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
publish = false
|
|
||||||
license = "GPL-3.0-or-later"
|
|
||||||
|
|
||||||
[lints]
|
|
||||||
workspace = true
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
path = "src/assistant.rs"
|
|
||||||
doctest = false
|
|
||||||
|
|
||||||
[features]
|
|
||||||
test-support = [
|
|
||||||
"editor/test-support",
|
|
||||||
"language/test-support",
|
|
||||||
"project/test-support",
|
|
||||||
"text/test-support",
|
|
||||||
]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
anthropic = { workspace = true, features = ["schemars"] }
|
|
||||||
anyhow.workspace = true
|
|
||||||
assets.workspace = true
|
|
||||||
assistant_slash_command.workspace = true
|
|
||||||
assistant_tool.workspace = true
|
|
||||||
async-watch.workspace = true
|
|
||||||
cargo_toml.workspace = true
|
|
||||||
chrono.workspace = true
|
|
||||||
client.workspace = true
|
|
||||||
clock.workspace = true
|
|
||||||
collections.workspace = true
|
|
||||||
command_palette_hooks.workspace = true
|
|
||||||
context_servers.workspace = true
|
|
||||||
db.workspace = true
|
|
||||||
editor.workspace = true
|
|
||||||
feature_flags.workspace = true
|
|
||||||
fs.workspace = true
|
|
||||||
futures.workspace = true
|
|
||||||
fuzzy.workspace = true
|
|
||||||
globset.workspace = true
|
|
||||||
gpui.workspace = true
|
|
||||||
handlebars.workspace = true
|
|
||||||
heed.workspace = true
|
|
||||||
html_to_markdown.workspace = true
|
|
||||||
http_client.workspace = true
|
|
||||||
indexed_docs.workspace = true
|
|
||||||
indoc.workspace = true
|
|
||||||
language.workspace = true
|
|
||||||
language_model.workspace = true
|
|
||||||
log.workspace = true
|
|
||||||
lsp.workspace = true
|
|
||||||
markdown.workspace = true
|
|
||||||
menu.workspace = true
|
|
||||||
multi_buffer.workspace = true
|
|
||||||
ollama = { workspace = true, features = ["schemars"] }
|
|
||||||
open_ai = { workspace = true, features = ["schemars"] }
|
|
||||||
ordered-float.workspace = true
|
|
||||||
parking_lot.workspace = true
|
|
||||||
paths.workspace = true
|
|
||||||
picker.workspace = true
|
|
||||||
project.workspace = true
|
|
||||||
proto.workspace = true
|
|
||||||
regex.workspace = true
|
|
||||||
release_channel.workspace = true
|
|
||||||
rope.workspace = true
|
|
||||||
rpc.workspace = true
|
|
||||||
schemars.workspace = true
|
|
||||||
search.workspace = true
|
|
||||||
semantic_index.workspace = true
|
|
||||||
serde.workspace = true
|
|
||||||
serde_json.workspace = true
|
|
||||||
settings.workspace = true
|
|
||||||
similar.workspace = true
|
|
||||||
smallvec.workspace = true
|
|
||||||
smol.workspace = true
|
|
||||||
strum.workspace = true
|
|
||||||
telemetry_events.workspace = true
|
|
||||||
terminal.workspace = true
|
|
||||||
terminal_view.workspace = true
|
|
||||||
text.workspace = true
|
|
||||||
theme.workspace = true
|
|
||||||
toml.workspace = true
|
|
||||||
ui.workspace = true
|
|
||||||
util.workspace = true
|
|
||||||
uuid.workspace = true
|
|
||||||
workspace.workspace = true
|
|
||||||
zed_actions.workspace = true
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
ctor.workspace = true
|
|
||||||
editor = { workspace = true, features = ["test-support"] }
|
|
||||||
env_logger.workspace = true
|
|
||||||
language = { workspace = true, features = ["test-support"] }
|
|
||||||
language_model = { workspace = true, features = ["test-support"] }
|
|
||||||
languages = { workspace = true, features = ["test-support"] }
|
|
||||||
log.workspace = true
|
|
||||||
pretty_assertions.workspace = true
|
|
||||||
project = { workspace = true, features = ["test-support"] }
|
|
||||||
rand.workspace = true
|
|
||||||
serde_json_lenient.workspace = true
|
|
||||||
text = { workspace = true, features = ["test-support"] }
|
|
||||||
tree-sitter-md.workspace = true
|
|
||||||
unindent.workspace = true
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../LICENSE-GPL
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "assistant_slash_command"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
publish = false
|
|
||||||
license = "GPL-3.0-or-later"
|
|
||||||
|
|
||||||
[lints]
|
|
||||||
workspace = true
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
path = "src/assistant_slash_command.rs"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
anyhow.workspace = true
|
|
||||||
collections.workspace = true
|
|
||||||
derive_more.workspace = true
|
|
||||||
futures.workspace = true
|
|
||||||
gpui.workspace = true
|
|
||||||
language.workspace = true
|
|
||||||
parking_lot.workspace = true
|
|
||||||
serde.workspace = true
|
|
||||||
serde_json.workspace = true
|
|
||||||
workspace.workspace = true
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
gpui = { workspace = true, features = ["test-support"] }
|
|
||||||
pretty_assertions.workspace = true
|
|
||||||
workspace = { workspace = true, features = ["test-support"] }
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../LICENSE-GPL
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "auto_update"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
publish = false
|
|
||||||
license = "GPL-3.0-or-later"
|
|
||||||
|
|
||||||
[lints]
|
|
||||||
workspace = true
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
path = "src/auto_update.rs"
|
|
||||||
doctest = false
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
anyhow.workspace = true
|
|
||||||
client.workspace = true
|
|
||||||
db.workspace = true
|
|
||||||
editor.workspace = true
|
|
||||||
gpui.workspace = true
|
|
||||||
http_client.workspace = true
|
|
||||||
log.workspace = true
|
|
||||||
markdown_preview.workspace = true
|
|
||||||
menu.workspace = true
|
|
||||||
paths.workspace = true
|
|
||||||
release_channel.workspace = true
|
|
||||||
schemars.workspace = true
|
|
||||||
serde.workspace = true
|
|
||||||
serde_derive.workspace = true
|
|
||||||
serde_json.workspace = true
|
|
||||||
settings.workspace = true
|
|
||||||
smol.workspace = true
|
|
||||||
tempfile.workspace = true
|
|
||||||
util.workspace = true
|
|
||||||
which.workspace = true
|
|
||||||
workspace.workspace = true
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../LICENSE-GPL
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "breadcrumbs"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
publish = false
|
|
||||||
license = "GPL-3.0-or-later"
|
|
||||||
|
|
||||||
[lints]
|
|
||||||
workspace = true
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
path = "src/breadcrumbs.rs"
|
|
||||||
doctest = false
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
editor.workspace = true
|
|
||||||
gpui.workspace = true
|
|
||||||
itertools.workspace = true
|
|
||||||
outline.workspace = true
|
|
||||||
theme.workspace = true
|
|
||||||
ui.workspace = true
|
|
||||||
workspace.workspace = true
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
editor = { workspace = true, features = ["test-support"] }
|
|
||||||
gpui = { workspace = true, features = ["test-support"] }
|
|
||||||
workspace = { workspace = true, features = ["test-support"] }
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../LICENSE-GPL
|
|
||||||
@@ -13,7 +13,6 @@ path = "src/call.rs"
|
|||||||
doctest = false
|
doctest = false
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
no-webrtc = ["live_kit_client/no-webrtc"]
|
|
||||||
test-support = [
|
test-support = [
|
||||||
"client/test-support",
|
"client/test-support",
|
||||||
"collections/test-support",
|
"collections/test-support",
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ serde.workspace = true
|
|||||||
util.workspace = true
|
util.workspace = true
|
||||||
tempfile.workspace = true
|
tempfile.workspace = true
|
||||||
|
|
||||||
[target.'cfg(target_os = "linux")'.dependencies]
|
[target.'cfg(any(target_os = "linux", target_os = "freebsd"))'.dependencies]
|
||||||
exec.workspace = true
|
exec.workspace = true
|
||||||
fork.workspace = true
|
fork.workspace = true
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
#![cfg_attr(any(target_os = "linux", target_os = "windows"), allow(dead_code))]
|
#![cfg_attr(
|
||||||
|
any(target_os = "linux", target_os = "freebsd", target_os = "windows"),
|
||||||
|
allow(dead_code)
|
||||||
|
)]
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
@@ -88,7 +91,7 @@ fn parse_path_with_position(argument_str: &str) -> anyhow::Result<String> {
|
|||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
// Exit flatpak sandbox if needed
|
// Exit flatpak sandbox if needed
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
||||||
{
|
{
|
||||||
flatpak::try_restart_to_host();
|
flatpak::try_restart_to_host();
|
||||||
flatpak::ld_extra_libs();
|
flatpak::ld_extra_libs();
|
||||||
@@ -106,7 +109,7 @@ fn main() -> Result<()> {
|
|||||||
}
|
}
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
||||||
let args = flatpak::set_bin_if_no_escape(args);
|
let args = flatpak::set_bin_if_no_escape(args);
|
||||||
|
|
||||||
let app = Detect::detect(args.zed.as_deref()).context("Bundle detection")?;
|
let app = Detect::detect(args.zed.as_deref()).context("Bundle detection")?;
|
||||||
@@ -220,7 +223,7 @@ fn main() -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
||||||
mod linux {
|
mod linux {
|
||||||
use std::{
|
use std::{
|
||||||
env,
|
env,
|
||||||
@@ -344,7 +347,7 @@ mod linux {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
||||||
mod flatpak {
|
mod flatpak {
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ sha2.workspace = true
|
|||||||
smol.workspace = true
|
smol.workspace = true
|
||||||
sysinfo.workspace = true
|
sysinfo.workspace = true
|
||||||
telemetry_events.workspace = true
|
telemetry_events.workspace = true
|
||||||
tempfile.workspace = true
|
|
||||||
text.workspace = true
|
text.workspace = true
|
||||||
thiserror.workspace = true
|
thiserror.workspace = true
|
||||||
time.workspace = true
|
time.workspace = true
|
||||||
|
|||||||
@@ -889,7 +889,7 @@ impl Client {
|
|||||||
cx: &AsyncAppContext,
|
cx: &AsyncAppContext,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let executor = cx.background_executor();
|
let executor = cx.background_executor();
|
||||||
log::info!("add connection to peer");
|
log::debug!("add connection to peer");
|
||||||
let (connection_id, handle_io, mut incoming) = self.peer.add_connection(conn, {
|
let (connection_id, handle_io, mut incoming) = self.peer.add_connection(conn, {
|
||||||
let executor = executor.clone();
|
let executor = executor.clone();
|
||||||
move |duration| executor.timer(duration)
|
move |duration| executor.timer(duration)
|
||||||
@@ -897,12 +897,12 @@ impl Client {
|
|||||||
let handle_io = executor.spawn(handle_io);
|
let handle_io = executor.spawn(handle_io);
|
||||||
|
|
||||||
let peer_id = async {
|
let peer_id = async {
|
||||||
log::info!("waiting for server hello");
|
log::debug!("waiting for server hello");
|
||||||
let message = incoming
|
let message = incoming
|
||||||
.next()
|
.next()
|
||||||
.await
|
.await
|
||||||
.ok_or_else(|| anyhow!("no hello message received"))?;
|
.ok_or_else(|| anyhow!("no hello message received"))?;
|
||||||
log::info!("got server hello");
|
log::debug!("got server hello");
|
||||||
let hello_message_type_name = message.payload_type_name().to_string();
|
let hello_message_type_name = message.payload_type_name().to_string();
|
||||||
let hello = message
|
let hello = message
|
||||||
.into_any()
|
.into_any()
|
||||||
@@ -928,7 +928,7 @@ impl Client {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
log::info!(
|
log::debug!(
|
||||||
"set status to connected (connection id: {:?}, peer id: {:?})",
|
"set status to connected (connection id: {:?}, peer id: {:?})",
|
||||||
connection_id,
|
connection_id,
|
||||||
peer_id
|
peer_id
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ use parking_lot::Mutex;
|
|||||||
use release_channel::ReleaseChannel;
|
use release_channel::ReleaseChannel;
|
||||||
use settings::{Settings, SettingsStore};
|
use settings::{Settings, SettingsStore};
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
|
use std::fs::File;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::{env, mem, path::PathBuf, sync::Arc, time::Duration};
|
use std::{env, mem, path::PathBuf, sync::Arc, time::Duration};
|
||||||
use sysinfo::{CpuRefreshKind, Pid, ProcessRefreshKind, RefreshKind, System};
|
use sysinfo::{CpuRefreshKind, Pid, ProcessRefreshKind, RefreshKind, System};
|
||||||
@@ -21,10 +22,7 @@ use telemetry_events::{
|
|||||||
EventRequestBody, EventWrapper, ExtensionEvent, InlineCompletionEvent, MemoryEvent, ReplEvent,
|
EventRequestBody, EventWrapper, ExtensionEvent, InlineCompletionEvent, MemoryEvent, ReplEvent,
|
||||||
SettingEvent,
|
SettingEvent,
|
||||||
};
|
};
|
||||||
use tempfile::NamedTempFile;
|
use util::{ResultExt, TryFutureExt};
|
||||||
#[cfg(not(debug_assertions))]
|
|
||||||
use util::ResultExt;
|
|
||||||
use util::TryFutureExt;
|
|
||||||
use worktree::{UpdatedEntriesSet, WorktreeId};
|
use worktree::{UpdatedEntriesSet, WorktreeId};
|
||||||
|
|
||||||
use self::event_coalescer::EventCoalescer;
|
use self::event_coalescer::EventCoalescer;
|
||||||
@@ -46,7 +44,7 @@ struct TelemetryState {
|
|||||||
architecture: &'static str,
|
architecture: &'static str,
|
||||||
events_queue: Vec<EventWrapper>,
|
events_queue: Vec<EventWrapper>,
|
||||||
flush_events_task: Option<Task<()>>,
|
flush_events_task: Option<Task<()>>,
|
||||||
log_file: Option<NamedTempFile>,
|
log_file: Option<File>,
|
||||||
is_staff: Option<bool>,
|
is_staff: Option<bool>,
|
||||||
first_event_date_time: Option<DateTime<Utc>>,
|
first_event_date_time: Option<DateTime<Utc>>,
|
||||||
event_coalescer: EventCoalescer,
|
event_coalescer: EventCoalescer,
|
||||||
@@ -102,7 +100,7 @@ pub fn os_name() -> String {
|
|||||||
{
|
{
|
||||||
"macOS".to_string()
|
"macOS".to_string()
|
||||||
}
|
}
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
||||||
{
|
{
|
||||||
format!("Linux {}", gpui::guess_compositor())
|
format!("Linux {}", gpui::guess_compositor())
|
||||||
}
|
}
|
||||||
@@ -131,7 +129,7 @@ pub fn os_version() -> String {
|
|||||||
.to_string()
|
.to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
||||||
{
|
{
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
@@ -223,15 +221,13 @@ impl Telemetry {
|
|||||||
os_name: os_name(),
|
os_name: os_name(),
|
||||||
app_version: release_channel::AppVersion::global(cx).to_string(),
|
app_version: release_channel::AppVersion::global(cx).to_string(),
|
||||||
}));
|
}));
|
||||||
|
Self::log_file_path();
|
||||||
|
|
||||||
#[cfg(not(debug_assertions))]
|
|
||||||
cx.background_executor()
|
cx.background_executor()
|
||||||
.spawn({
|
.spawn({
|
||||||
let state = state.clone();
|
let state = state.clone();
|
||||||
async move {
|
async move {
|
||||||
if let Some(tempfile) =
|
if let Some(tempfile) = File::create(Self::log_file_path()).log_err() {
|
||||||
NamedTempFile::new_in(paths::logs_dir().as_path()).log_err()
|
|
||||||
{
|
|
||||||
state.lock().log_file = Some(tempfile);
|
state.lock().log_file = Some(tempfile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -280,8 +276,8 @@ impl Telemetry {
|
|||||||
Task::ready(())
|
Task::ready(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn log_file_path(&self) -> Option<PathBuf> {
|
pub fn log_file_path() -> PathBuf {
|
||||||
Some(self.state.lock().log_file.as_ref()?.path().to_path_buf())
|
paths::logs_dir().join("telemetry.log")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(
|
pub fn start(
|
||||||
@@ -341,6 +337,13 @@ impl Telemetry {
|
|||||||
.detach();
|
.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn metrics_enabled(self: &Arc<Self>) -> bool {
|
||||||
|
let state = self.state.lock();
|
||||||
|
let enabled = state.settings.metrics;
|
||||||
|
drop(state);
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_authenticated_user_info(
|
pub fn set_authenticated_user_info(
|
||||||
self: &Arc<Self>,
|
self: &Arc<Self>,
|
||||||
metrics_id: Option<String>,
|
metrics_id: Option<String>,
|
||||||
@@ -638,7 +641,6 @@ impl Telemetry {
|
|||||||
let mut json_bytes = Vec::new();
|
let mut json_bytes = Vec::new();
|
||||||
|
|
||||||
if let Some(file) = &mut this.state.lock().log_file {
|
if let Some(file) = &mut this.state.lock().log_file {
|
||||||
let file = file.as_file_mut();
|
|
||||||
for event in &mut events {
|
for event in &mut events {
|
||||||
json_bytes.clear();
|
json_bytes.clear();
|
||||||
serde_json::to_writer(&mut json_bytes, event)?;
|
serde_json::to_writer(&mut json_bytes, event)?;
|
||||||
|
|||||||
@@ -77,18 +77,15 @@ util.workspace = true
|
|||||||
uuid.workspace = true
|
uuid.workspace = true
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assistant = { workspace = true, features = ["test-support"] }
|
|
||||||
async-trait.workspace = true
|
async-trait.workspace = true
|
||||||
audio.workspace = true
|
audio.workspace = true
|
||||||
call = { workspace = true, features = ["test-support"] }
|
call = { workspace = true, features = ["test-support"] }
|
||||||
channel.workspace = true
|
channel.workspace = true
|
||||||
client = { workspace = true, features = ["test-support"] }
|
client = { workspace = true, features = ["test-support"] }
|
||||||
collab_ui = { workspace = true, features = ["test-support"] }
|
|
||||||
collections = { workspace = true, features = ["test-support"] }
|
collections = { workspace = true, features = ["test-support"] }
|
||||||
ctor.workspace = true
|
ctor.workspace = true
|
||||||
editor = { workspace = true, features = ["test-support"] }
|
editor = { workspace = true, features = ["test-support"] }
|
||||||
env_logger.workspace = true
|
env_logger.workspace = true
|
||||||
file_finder.workspace = true
|
|
||||||
fs = { workspace = true, features = ["test-support"] }
|
fs = { workspace = true, features = ["test-support"] }
|
||||||
git = { workspace = true, features = ["test-support"] }
|
git = { workspace = true, features = ["test-support"] }
|
||||||
git_hosting_providers.workspace = true
|
git_hosting_providers.workspace = true
|
||||||
@@ -96,7 +93,6 @@ gpui = { workspace = true, features = ["test-support"] }
|
|||||||
hyper.workspace = true
|
hyper.workspace = true
|
||||||
indoc.workspace = true
|
indoc.workspace = true
|
||||||
language = { workspace = true, features = ["test-support"] }
|
language = { workspace = true, features = ["test-support"] }
|
||||||
language_model = { workspace = true, features = ["test-support"] }
|
|
||||||
live_kit_client = { workspace = true, features = ["test-support"] }
|
live_kit_client = { workspace = true, features = ["test-support"] }
|
||||||
lsp = { workspace = true, features = ["test-support"] }
|
lsp = { workspace = true, features = ["test-support"] }
|
||||||
menu.workspace = true
|
menu.workspace = true
|
||||||
@@ -105,7 +101,6 @@ node_runtime.workspace = true
|
|||||||
notifications = { workspace = true, features = ["test-support"] }
|
notifications = { workspace = true, features = ["test-support"] }
|
||||||
pretty_assertions.workspace = true
|
pretty_assertions.workspace = true
|
||||||
project = { workspace = true, features = ["test-support"] }
|
project = { workspace = true, features = ["test-support"] }
|
||||||
recent_projects = { workspace = true }
|
|
||||||
release_channel.workspace = true
|
release_channel.workspace = true
|
||||||
remote = { workspace = true, features = ["test-support"] }
|
remote = { workspace = true, features = ["test-support"] }
|
||||||
remote_server.workspace = true
|
remote_server.workspace = true
|
||||||
@@ -120,6 +115,7 @@ unindent.workspace = true
|
|||||||
util.workspace = true
|
util.workspace = true
|
||||||
workspace = { workspace = true, features = ["test-support"] }
|
workspace = { workspace = true, features = ["test-support"] }
|
||||||
worktree = { workspace = true, features = ["test-support"] }
|
worktree = { workspace = true, features = ["test-support"] }
|
||||||
|
zed_common = { workspace = true, features = ["test-support"] }
|
||||||
|
|
||||||
[package.metadata.cargo-machete]
|
[package.metadata.cargo-machete]
|
||||||
ignored = ["async-stripe"]
|
ignored = ["async-stripe"]
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ use crate::{
|
|||||||
use call::ActiveCall;
|
use call::ActiveCall;
|
||||||
use channel::ACKNOWLEDGE_DEBOUNCE_INTERVAL;
|
use channel::ACKNOWLEDGE_DEBOUNCE_INTERVAL;
|
||||||
use client::{Collaborator, ParticipantIndex, UserId};
|
use client::{Collaborator, ParticipantIndex, UserId};
|
||||||
use collab_ui::channel_view::ChannelView;
|
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use editor::{Anchor, Editor, ToOffset};
|
use editor::{Anchor, Editor, ToOffset};
|
||||||
use futures::future;
|
use futures::future;
|
||||||
@@ -13,6 +12,7 @@ use gpui::{BackgroundExecutor, Model, TestAppContext, ViewContext};
|
|||||||
use rpc::{proto::PeerId, RECEIVE_TIMEOUT};
|
use rpc::{proto::PeerId, RECEIVE_TIMEOUT};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
use zed_common::collab_ui::channel_view::ChannelView;
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_core_channel_buffers(
|
async fn test_core_channel_buffers(
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use crate::{rpc::RECONNECT_TIMEOUT, tests::TestServer};
|
use crate::{rpc::RECONNECT_TIMEOUT, tests::TestServer};
|
||||||
use channel::{ChannelChat, ChannelMessageId, MessageParams};
|
use channel::{ChannelChat, ChannelMessageId, MessageParams};
|
||||||
use collab_ui::chat_panel::ChatPanel;
|
|
||||||
use gpui::{BackgroundExecutor, Model, TestAppContext};
|
use gpui::{BackgroundExecutor, Model, TestAppContext};
|
||||||
use rpc::Notification;
|
use rpc::Notification;
|
||||||
use workspace::dock::Panel;
|
use workspace::dock::Panel;
|
||||||
|
use zed_common::collab_ui::chat_panel::ChatPanel;
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_basic_channel_messages(
|
async fn test_basic_channel_messages(
|
||||||
@@ -351,7 +351,7 @@ async fn test_channel_message_changes(
|
|||||||
|
|
||||||
// Opening the chat should clear the changed flag.
|
// Opening the chat should clear the changed flag.
|
||||||
cx_b.update(|cx| {
|
cx_b.update(|cx| {
|
||||||
collab_ui::init(&client_b.app_state, cx);
|
zed_common::collab_ui::init(&client_b.app_state, cx);
|
||||||
});
|
});
|
||||||
let project_b = client_b.build_empty_local_project(cx_b);
|
let project_b = client_b.build_empty_local_project(cx_b);
|
||||||
let (workspace_b, cx_b) = client_b.build_workspace(&project_b, cx_b);
|
let (workspace_b, cx_b) = client_b.build_workspace(&project_b, cx_b);
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ use project::{
|
|||||||
project_settings::{InlineBlameSettings, ProjectSettings},
|
project_settings::{InlineBlameSettings, ProjectSettings},
|
||||||
SERVER_PROGRESS_THROTTLE_TIMEOUT,
|
SERVER_PROGRESS_THROTTLE_TIMEOUT,
|
||||||
};
|
};
|
||||||
use recent_projects::disconnected_overlay::DisconnectedOverlay;
|
|
||||||
use rpc::RECEIVE_TIMEOUT;
|
use rpc::RECEIVE_TIMEOUT;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use settings::SettingsStore;
|
use settings::SettingsStore;
|
||||||
@@ -39,6 +38,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
use text::Point;
|
use text::Point;
|
||||||
use workspace::{CloseIntent, Workspace};
|
use workspace::{CloseIntent, Workspace};
|
||||||
|
use zed_common::recent_projects::disconnected_overlay::DisconnectedOverlay;
|
||||||
|
|
||||||
#[gpui::test(iterations = 10)]
|
#[gpui::test(iterations = 10)]
|
||||||
async fn test_host_disconnect(
|
async fn test_host_disconnect(
|
||||||
@@ -55,7 +55,7 @@ async fn test_host_disconnect(
|
|||||||
.await;
|
.await;
|
||||||
|
|
||||||
cx_b.update(editor::init);
|
cx_b.update(editor::init);
|
||||||
cx_b.update(recent_projects::init);
|
cx_b.update(zed_common::recent_projects::init);
|
||||||
|
|
||||||
client_a
|
client_a
|
||||||
.fs()
|
.fs()
|
||||||
|
|||||||
@@ -2,10 +2,6 @@
|
|||||||
use crate::{rpc::RECONNECT_TIMEOUT, tests::TestServer};
|
use crate::{rpc::RECONNECT_TIMEOUT, tests::TestServer};
|
||||||
use call::{ActiveCall, ParticipantLocation};
|
use call::{ActiveCall, ParticipantLocation};
|
||||||
use client::ChannelId;
|
use client::ChannelId;
|
||||||
use collab_ui::{
|
|
||||||
channel_view::ChannelView,
|
|
||||||
notifications::project_shared_notification::ProjectSharedNotification,
|
|
||||||
};
|
|
||||||
use editor::{Editor, ExcerptRange, MultiBuffer};
|
use editor::{Editor, ExcerptRange, MultiBuffer};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
point, BackgroundExecutor, BorrowAppContext, Context, Entity, SharedString, TestAppContext,
|
point, BackgroundExecutor, BorrowAppContext, Context, Entity, SharedString, TestAppContext,
|
||||||
@@ -23,6 +19,10 @@ use workspace::{
|
|||||||
shared_screen::SharedScreen,
|
shared_screen::SharedScreen,
|
||||||
SplitDirection, Workspace,
|
SplitDirection, Workspace,
|
||||||
};
|
};
|
||||||
|
use zed_common::collab_ui::{
|
||||||
|
channel_view::ChannelView,
|
||||||
|
notifications::project_shared_notification::ProjectSharedNotification,
|
||||||
|
};
|
||||||
|
|
||||||
use super::TestClient;
|
use super::TestClient;
|
||||||
|
|
||||||
@@ -1861,9 +1861,9 @@ async fn test_following_to_channel_notes_without_a_shared_project(
|
|||||||
cx_a.update(editor::init);
|
cx_a.update(editor::init);
|
||||||
cx_b.update(editor::init);
|
cx_b.update(editor::init);
|
||||||
cx_c.update(editor::init);
|
cx_c.update(editor::init);
|
||||||
cx_a.update(collab_ui::channel_view::init);
|
cx_a.update(zed_common::collab_ui::channel_view::init);
|
||||||
cx_b.update(collab_ui::channel_view::init);
|
cx_b.update(zed_common::collab_ui::channel_view::init);
|
||||||
cx_c.update(collab_ui::channel_view::init);
|
cx_c.update(zed_common::collab_ui::channel_view::init);
|
||||||
|
|
||||||
let channel_1_id = server
|
let channel_1_id = server
|
||||||
.make_channel(
|
.make_channel(
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use assistant::{ContextStore, PromptBuilder};
|
|
||||||
use call::{room, ActiveCall, ParticipantLocation, Room};
|
use call::{room, ActiveCall, ParticipantLocation, Room};
|
||||||
use client::{User, RECEIVE_TIMEOUT};
|
use client::{User, RECEIVE_TIMEOUT};
|
||||||
use collections::{HashMap, HashSet};
|
use collections::{HashMap, HashSet};
|
||||||
@@ -48,6 +47,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
use unindent::Unindent as _;
|
use unindent::Unindent as _;
|
||||||
use workspace::Pane;
|
use workspace::Pane;
|
||||||
|
use zed_common::assistant::{ContextStore, PromptBuilder, SlashCommandWorkingSet, ToolWorkingSet};
|
||||||
|
|
||||||
#[ctor::ctor]
|
#[ctor::ctor]
|
||||||
fn init_logger() {
|
fn init_logger() {
|
||||||
@@ -5130,11 +5130,10 @@ async fn test_lsp_hover(
|
|||||||
});
|
});
|
||||||
let new_server_name = new_server.server.name();
|
let new_server_name = new_server.server.name();
|
||||||
assert!(
|
assert!(
|
||||||
!servers_with_hover_requests.contains_key(new_server_name),
|
!servers_with_hover_requests.contains_key(&new_server_name),
|
||||||
"Unexpected: initialized server with the same name twice. Name: `{new_server_name}`"
|
"Unexpected: initialized server with the same name twice. Name: `{new_server_name}`"
|
||||||
);
|
);
|
||||||
let new_server_name = new_server_name.to_string();
|
match new_server_name.as_ref() {
|
||||||
match new_server_name.as_str() {
|
|
||||||
"CrabLang-ls" => {
|
"CrabLang-ls" => {
|
||||||
servers_with_hover_requests.insert(
|
servers_with_hover_requests.insert(
|
||||||
new_server_name.clone(),
|
new_server_name.clone(),
|
||||||
@@ -6489,15 +6488,31 @@ async fn test_context_collaboration_with_reconnect(
|
|||||||
|
|
||||||
let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap());
|
let prompt_builder = Arc::new(PromptBuilder::new(None).unwrap());
|
||||||
let context_store_a = cx_a
|
let context_store_a = cx_a
|
||||||
.update(|cx| ContextStore::new(project_a.clone(), prompt_builder.clone(), cx))
|
.update(|cx| {
|
||||||
|
ContextStore::new(
|
||||||
|
project_a.clone(),
|
||||||
|
prompt_builder.clone(),
|
||||||
|
Arc::new(SlashCommandWorkingSet::default()),
|
||||||
|
Arc::new(ToolWorkingSet::default()),
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let context_store_b = cx_b
|
let context_store_b = cx_b
|
||||||
.update(|cx| ContextStore::new(project_b.clone(), prompt_builder.clone(), cx))
|
.update(|cx| {
|
||||||
|
ContextStore::new(
|
||||||
|
project_b.clone(),
|
||||||
|
prompt_builder.clone(),
|
||||||
|
Arc::new(SlashCommandWorkingSet::default()),
|
||||||
|
Arc::new(ToolWorkingSet::default()),
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Client A creates a new context.
|
// Client A creates a new chats.
|
||||||
let context_a = context_store_a.update(cx_a, |store, cx| store.create(cx));
|
let context_a = context_store_a.update(cx_a, |store, cx| store.create(cx));
|
||||||
executor.run_until_parked();
|
executor.run_until_parked();
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use call::ActiveCall;
|
|||||||
use collections::HashSet;
|
use collections::HashSet;
|
||||||
use fs::{FakeFs, Fs as _};
|
use fs::{FakeFs, Fs as _};
|
||||||
use futures::StreamExt as _;
|
use futures::StreamExt as _;
|
||||||
use gpui::{BackgroundExecutor, Context as _, TestAppContext, UpdateGlobal as _};
|
use gpui::{BackgroundExecutor, Context as _, SemanticVersion, TestAppContext, UpdateGlobal as _};
|
||||||
use http_client::BlockedHttpClient;
|
use http_client::BlockedHttpClient;
|
||||||
use language::{
|
use language::{
|
||||||
language_settings::{
|
language_settings::{
|
||||||
@@ -31,6 +31,12 @@ async fn test_sharing_an_ssh_remote_project(
|
|||||||
server_cx: &mut TestAppContext,
|
server_cx: &mut TestAppContext,
|
||||||
) {
|
) {
|
||||||
let executor = cx_a.executor();
|
let executor = cx_a.executor();
|
||||||
|
cx_a.update(|cx| {
|
||||||
|
release_channel::init(SemanticVersion::default(), cx);
|
||||||
|
});
|
||||||
|
server_cx.update(|cx| {
|
||||||
|
release_channel::init(SemanticVersion::default(), cx);
|
||||||
|
});
|
||||||
let mut server = TestServer::start(executor.clone()).await;
|
let mut server = TestServer::start(executor.clone()).await;
|
||||||
let client_a = server.create_client(cx_a, "user_a").await;
|
let client_a = server.create_client(cx_a, "user_a").await;
|
||||||
let client_b = server.create_client(cx_b, "user_b").await;
|
let client_b = server.create_client(cx_b, "user_b").await;
|
||||||
@@ -199,6 +205,13 @@ async fn test_ssh_collaboration_git_branches(
|
|||||||
cx_b.set_name("b");
|
cx_b.set_name("b");
|
||||||
server_cx.set_name("server");
|
server_cx.set_name("server");
|
||||||
|
|
||||||
|
cx_a.update(|cx| {
|
||||||
|
release_channel::init(SemanticVersion::default(), cx);
|
||||||
|
});
|
||||||
|
server_cx.update(|cx| {
|
||||||
|
release_channel::init(SemanticVersion::default(), cx);
|
||||||
|
});
|
||||||
|
|
||||||
let mut server = TestServer::start(executor.clone()).await;
|
let mut server = TestServer::start(executor.clone()).await;
|
||||||
let client_a = server.create_client(cx_a, "user_a").await;
|
let client_a = server.create_client(cx_a, "user_a").await;
|
||||||
let client_b = server.create_client(cx_b, "user_b").await;
|
let client_b = server.create_client(cx_b, "user_b").await;
|
||||||
@@ -329,6 +342,13 @@ async fn test_ssh_collaboration_formatting_with_prettier(
|
|||||||
cx_b.set_name("b");
|
cx_b.set_name("b");
|
||||||
server_cx.set_name("server");
|
server_cx.set_name("server");
|
||||||
|
|
||||||
|
cx_a.update(|cx| {
|
||||||
|
release_channel::init(SemanticVersion::default(), cx);
|
||||||
|
});
|
||||||
|
server_cx.update(|cx| {
|
||||||
|
release_channel::init(SemanticVersion::default(), cx);
|
||||||
|
});
|
||||||
|
|
||||||
let mut server = TestServer::start(executor.clone()).await;
|
let mut server = TestServer::start(executor.clone()).await;
|
||||||
let client_a = server.create_client(cx_a, "user_a").await;
|
let client_a = server.create_client(cx_a, "user_a").await;
|
||||||
let client_b = server.create_client(cx_b, "user_b").await;
|
let client_b = server.create_client(cx_b, "user_b").await;
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ use client::{
|
|||||||
UserStore,
|
UserStore,
|
||||||
};
|
};
|
||||||
use clock::FakeSystemClock;
|
use clock::FakeSystemClock;
|
||||||
use collab_ui::channel_view::ChannelView;
|
|
||||||
use collections::{HashMap, HashSet};
|
use collections::{HashMap, HashSet};
|
||||||
use fs::FakeFs;
|
use fs::FakeFs;
|
||||||
use futures::{channel::oneshot, StreamExt as _};
|
use futures::{channel::oneshot, StreamExt as _};
|
||||||
@@ -44,6 +43,7 @@ use std::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use workspace::{Workspace, WorkspaceStore};
|
use workspace::{Workspace, WorkspaceStore};
|
||||||
|
use zed_common::collab_ui::channel_view::ChannelView;
|
||||||
|
|
||||||
pub struct TestServer {
|
pub struct TestServer {
|
||||||
pub app_state: Arc<AppState>,
|
pub app_state: Arc<AppState>,
|
||||||
@@ -293,12 +293,12 @@ impl TestServer {
|
|||||||
call::init(client.clone(), user_store.clone(), cx);
|
call::init(client.clone(), user_store.clone(), cx);
|
||||||
channel::init(&client, user_store.clone(), cx);
|
channel::init(&client, user_store.clone(), cx);
|
||||||
notifications::init(client.clone(), user_store, cx);
|
notifications::init(client.clone(), user_store, cx);
|
||||||
collab_ui::init(&app_state, cx);
|
zed_common::collab_ui::init(&app_state, cx);
|
||||||
file_finder::init(cx);
|
zed_common::file_finder::init(cx);
|
||||||
menu::init();
|
menu::init();
|
||||||
settings::KeymapFile::load_asset(os_keymap, cx).unwrap();
|
settings::KeymapFile::load_asset(os_keymap, cx).unwrap();
|
||||||
language_model::LanguageModelRegistry::test(cx);
|
zed_common::language_model::LanguageModelRegistry::test(cx);
|
||||||
assistant::context_store::init(&client.clone().into());
|
zed_common::assistant::context_store::init(&client.clone().into());
|
||||||
});
|
});
|
||||||
|
|
||||||
client
|
client
|
||||||
|
|||||||
@@ -1,83 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "collab_ui"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
publish = false
|
|
||||||
license = "GPL-3.0-or-later"
|
|
||||||
|
|
||||||
[lints]
|
|
||||||
workspace = true
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
path = "src/collab_ui.rs"
|
|
||||||
doctest = false
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = []
|
|
||||||
stories = ["dep:story"]
|
|
||||||
test-support = [
|
|
||||||
"call/test-support",
|
|
||||||
"client/test-support",
|
|
||||||
"collections/test-support",
|
|
||||||
"editor/test-support",
|
|
||||||
"gpui/test-support",
|
|
||||||
"project/test-support",
|
|
||||||
"settings/test-support",
|
|
||||||
"util/test-support",
|
|
||||||
"workspace/test-support",
|
|
||||||
"http_client/test-support",
|
|
||||||
]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
anyhow.workspace = true
|
|
||||||
call.workspace = true
|
|
||||||
channel.workspace = true
|
|
||||||
chrono.workspace = true
|
|
||||||
client.workspace = true
|
|
||||||
collections.workspace = true
|
|
||||||
db.workspace = true
|
|
||||||
editor.workspace = true
|
|
||||||
emojis.workspace = true
|
|
||||||
futures.workspace = true
|
|
||||||
fuzzy.workspace = true
|
|
||||||
gpui.workspace = true
|
|
||||||
language.workspace = true
|
|
||||||
menu.workspace = true
|
|
||||||
notifications.workspace = true
|
|
||||||
parking_lot.workspace = true
|
|
||||||
picker.workspace = true
|
|
||||||
project.workspace = true
|
|
||||||
release_channel.workspace = true
|
|
||||||
rich_text.workspace = true
|
|
||||||
rpc.workspace = true
|
|
||||||
schemars.workspace = true
|
|
||||||
serde.workspace = true
|
|
||||||
serde_derive.workspace = true
|
|
||||||
serde_json.workspace = true
|
|
||||||
settings.workspace = true
|
|
||||||
smallvec.workspace = true
|
|
||||||
story = { workspace = true, optional = true }
|
|
||||||
theme.workspace = true
|
|
||||||
time_format.workspace = true
|
|
||||||
time.workspace = true
|
|
||||||
title_bar.workspace = true
|
|
||||||
ui.workspace = true
|
|
||||||
util.workspace = true
|
|
||||||
vcs_menu.workspace = true
|
|
||||||
workspace.workspace = true
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
call = { workspace = true, features = ["test-support"] }
|
|
||||||
client = { workspace = true, features = ["test-support"] }
|
|
||||||
collections = { workspace = true, features = ["test-support"] }
|
|
||||||
editor = { workspace = true, features = ["test-support"] }
|
|
||||||
gpui = { workspace = true, features = ["test-support"] }
|
|
||||||
notifications = { workspace = true, features = ["test-support"] }
|
|
||||||
pretty_assertions.workspace = true
|
|
||||||
project = { workspace = true, features = ["test-support"] }
|
|
||||||
rpc = { workspace = true, features = ["test-support"] }
|
|
||||||
settings = { workspace = true, features = ["test-support"] }
|
|
||||||
tree-sitter-md.workspace = true
|
|
||||||
util = { workspace = true, features = ["test-support"] }
|
|
||||||
http_client = { workspace = true, features = ["test-support"] }
|
|
||||||
workspace = { workspace = true, features = ["test-support"] }
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../LICENSE-GPL
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "command_palette"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
publish = false
|
|
||||||
license = "GPL-3.0-or-later"
|
|
||||||
|
|
||||||
[lints]
|
|
||||||
workspace = true
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
path = "src/command_palette.rs"
|
|
||||||
doctest = false
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
client.workspace = true
|
|
||||||
collections.workspace = true
|
|
||||||
command_palette_hooks.workspace = true
|
|
||||||
fuzzy.workspace = true
|
|
||||||
gpui.workspace = true
|
|
||||||
picker.workspace = true
|
|
||||||
postage.workspace = true
|
|
||||||
serde.workspace = true
|
|
||||||
settings.workspace = true
|
|
||||||
theme.workspace = true
|
|
||||||
ui.workspace = true
|
|
||||||
util.workspace = true
|
|
||||||
workspace.workspace = true
|
|
||||||
zed_actions.workspace = true
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
ctor.workspace = true
|
|
||||||
editor = { workspace = true, features = ["test-support"] }
|
|
||||||
env_logger.workspace = true
|
|
||||||
go_to_line.workspace = true
|
|
||||||
gpui = { workspace = true, features = ["test-support"] }
|
|
||||||
language = { workspace = true, features = ["test-support"] }
|
|
||||||
menu.workspace = true
|
|
||||||
project = { workspace = true, features = ["test-support"] }
|
|
||||||
serde_json.workspace = true
|
|
||||||
workspace = { workspace = true, features = ["test-support"] }
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../LICENSE-GPL
|
|
||||||
@@ -13,6 +13,7 @@ path = "src/context_servers.rs"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
|
async-trait.workspace = true
|
||||||
collections.workspace = true
|
collections.workspace = true
|
||||||
command_palette_hooks.workspace = true
|
command_palette_hooks.workspace = true
|
||||||
futures.workspace = true
|
futures.workspace = true
|
||||||
@@ -27,4 +28,3 @@ settings.workspace = true
|
|||||||
smol.workspace = true
|
smol.workspace = true
|
||||||
url = { workspace = true, features = ["serde"] }
|
url = { workspace = true, features = ["serde"] }
|
||||||
util.workspace = true
|
util.workspace = true
|
||||||
workspace.workspace = true
|
|
||||||
|
|||||||
@@ -55,11 +55,20 @@ pub struct Client {
|
|||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct ContextServerId(pub String);
|
pub struct ContextServerId(pub String);
|
||||||
|
|
||||||
|
fn is_null_value<T: Serialize>(value: &T) -> bool {
|
||||||
|
if let Ok(Value::Null) = serde_json::to_value(value) {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct Request<'a, T> {
|
struct Request<'a, T> {
|
||||||
jsonrpc: &'static str,
|
jsonrpc: &'static str,
|
||||||
id: RequestId,
|
id: RequestId,
|
||||||
method: &'a str,
|
method: &'a str,
|
||||||
|
#[serde(skip_serializing_if = "is_null_value")]
|
||||||
params: T,
|
params: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,40 +1,27 @@
|
|||||||
use gpui::{actions, AppContext, Context, ViewContext};
|
|
||||||
use manager::ContextServerManager;
|
|
||||||
use workspace::Workspace;
|
|
||||||
|
|
||||||
pub mod client;
|
pub mod client;
|
||||||
pub mod manager;
|
pub mod manager;
|
||||||
pub mod protocol;
|
pub mod protocol;
|
||||||
mod registry;
|
mod registry;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
pub use registry::*;
|
use command_palette_hooks::CommandPaletteFilter;
|
||||||
|
use gpui::{actions, AppContext};
|
||||||
|
use settings::Settings;
|
||||||
|
|
||||||
|
pub use crate::manager::ContextServer;
|
||||||
|
use crate::manager::ContextServerSettings;
|
||||||
|
pub use crate::registry::ContextServerFactoryRegistry;
|
||||||
|
|
||||||
actions!(context_servers, [Restart]);
|
actions!(context_servers, [Restart]);
|
||||||
|
|
||||||
/// The namespace for the context servers actions.
|
/// The namespace for the context servers actions.
|
||||||
const CONTEXT_SERVERS_NAMESPACE: &'static str = "context_servers";
|
pub const CONTEXT_SERVERS_NAMESPACE: &'static str = "context_servers";
|
||||||
|
|
||||||
pub fn init(cx: &mut AppContext) {
|
pub fn init(cx: &mut AppContext) {
|
||||||
log::info!("initializing context server client");
|
ContextServerSettings::register(cx);
|
||||||
manager::init(cx);
|
ContextServerFactoryRegistry::default_global(cx);
|
||||||
ContextServerRegistry::register(cx);
|
|
||||||
|
|
||||||
cx.observe_new_views(
|
CommandPaletteFilter::update_global(cx, |filter, _cx| {
|
||||||
|workspace: &mut Workspace, _cx: &mut ViewContext<Workspace>| {
|
filter.hide_namespace(CONTEXT_SERVERS_NAMESPACE);
|
||||||
workspace.register_action(restart_servers);
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.detach();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn restart_servers(_workspace: &mut Workspace, _action: &Restart, cx: &mut ViewContext<Workspace>) {
|
|
||||||
let model = ContextServerManager::global(cx);
|
|
||||||
cx.update_model(&model, |manager, cx| {
|
|
||||||
for server in manager.servers() {
|
|
||||||
manager
|
|
||||||
.restart_server(&server.id, cx)
|
|
||||||
.detach_and_log_err(cx);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,18 +14,21 @@
|
|||||||
//! The module also includes initialization logic to set up the context server system
|
//! The module also includes initialization logic to set up the context server system
|
||||||
//! and react to changes in settings.
|
//! and react to changes in settings.
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
|
use std::pin::Pin;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use async_trait::async_trait;
|
||||||
use collections::{HashMap, HashSet};
|
use collections::{HashMap, HashSet};
|
||||||
use command_palette_hooks::CommandPaletteFilter;
|
use futures::{Future, FutureExt};
|
||||||
use gpui::{AppContext, AsyncAppContext, Context, EventEmitter, Global, Model, ModelContext, Task};
|
use gpui::{AsyncAppContext, EventEmitter, ModelContext, Task};
|
||||||
use log;
|
use log;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use settings::{Settings, SettingsSources, SettingsStore};
|
use settings::{Settings, SettingsSources};
|
||||||
use std::path::Path;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use crate::CONTEXT_SERVERS_NAMESPACE;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
client::{self, Client},
|
client::{self, Client},
|
||||||
types,
|
types,
|
||||||
@@ -57,51 +60,84 @@ impl Settings for ContextServerSettings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ContextServer {
|
#[async_trait(?Send)]
|
||||||
pub id: String,
|
pub trait ContextServer: Send + Sync + 'static {
|
||||||
pub config: ServerConfig,
|
fn id(&self) -> Arc<str>;
|
||||||
|
fn config(&self) -> Arc<ServerConfig>;
|
||||||
|
fn client(&self) -> Option<Arc<crate::protocol::InitializedContextServerProtocol>>;
|
||||||
|
fn start<'a>(
|
||||||
|
self: Arc<Self>,
|
||||||
|
cx: &'a AsyncAppContext,
|
||||||
|
) -> Pin<Box<dyn 'a + Future<Output = Result<()>>>>;
|
||||||
|
fn stop(&self) -> Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct NativeContextServer {
|
||||||
|
pub id: Arc<str>,
|
||||||
|
pub config: Arc<ServerConfig>,
|
||||||
pub client: RwLock<Option<Arc<crate::protocol::InitializedContextServerProtocol>>>,
|
pub client: RwLock<Option<Arc<crate::protocol::InitializedContextServerProtocol>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContextServer {
|
impl NativeContextServer {
|
||||||
fn new(config: ServerConfig) -> Self {
|
pub fn new(config: Arc<ServerConfig>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id: config.id.clone(),
|
id: config.id.clone().into(),
|
||||||
config,
|
config,
|
||||||
client: RwLock::new(None),
|
client: RwLock::new(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn start(&self, cx: &AsyncAppContext) -> anyhow::Result<()> {
|
#[async_trait(?Send)]
|
||||||
log::info!("starting context server {}", self.config.id,);
|
impl ContextServer for NativeContextServer {
|
||||||
let client = Client::new(
|
fn id(&self) -> Arc<str> {
|
||||||
client::ContextServerId(self.config.id.clone()),
|
self.id.clone()
|
||||||
client::ModelContextServerBinary {
|
|
||||||
executable: Path::new(&self.config.executable).to_path_buf(),
|
|
||||||
args: self.config.args.clone(),
|
|
||||||
env: self.config.env.clone(),
|
|
||||||
},
|
|
||||||
cx.clone(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let protocol = crate::protocol::ModelContextProtocol::new(client);
|
|
||||||
let client_info = types::Implementation {
|
|
||||||
name: "Zed".to_string(),
|
|
||||||
version: env!("CARGO_PKG_VERSION").to_string(),
|
|
||||||
};
|
|
||||||
let initialized_protocol = protocol.initialize(client_info).await?;
|
|
||||||
|
|
||||||
log::debug!(
|
|
||||||
"context server {} initialized: {:?}",
|
|
||||||
self.config.id,
|
|
||||||
initialized_protocol.initialize,
|
|
||||||
);
|
|
||||||
|
|
||||||
*self.client.write() = Some(Arc::new(initialized_protocol));
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn stop(&self) -> anyhow::Result<()> {
|
fn config(&self) -> Arc<ServerConfig> {
|
||||||
|
self.config.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn client(&self) -> Option<Arc<crate::protocol::InitializedContextServerProtocol>> {
|
||||||
|
self.client.read().clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start<'a>(
|
||||||
|
self: Arc<Self>,
|
||||||
|
cx: &'a AsyncAppContext,
|
||||||
|
) -> Pin<Box<dyn 'a + Future<Output = Result<()>>>> {
|
||||||
|
async move {
|
||||||
|
log::info!("starting context server {}", self.config.id,);
|
||||||
|
let client = Client::new(
|
||||||
|
client::ContextServerId(self.config.id.clone()),
|
||||||
|
client::ModelContextServerBinary {
|
||||||
|
executable: Path::new(&self.config.executable).to_path_buf(),
|
||||||
|
args: self.config.args.clone(),
|
||||||
|
env: self.config.env.clone(),
|
||||||
|
},
|
||||||
|
cx.clone(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let protocol = crate::protocol::ModelContextProtocol::new(client);
|
||||||
|
let client_info = types::Implementation {
|
||||||
|
name: "Zed".to_string(),
|
||||||
|
version: env!("CARGO_PKG_VERSION").to_string(),
|
||||||
|
};
|
||||||
|
let initialized_protocol = protocol.initialize(client_info).await?;
|
||||||
|
|
||||||
|
log::debug!(
|
||||||
|
"context server {} initialized: {:?}",
|
||||||
|
self.config.id,
|
||||||
|
initialized_protocol.initialize,
|
||||||
|
);
|
||||||
|
|
||||||
|
*self.client.write() = Some(Arc::new(initialized_protocol));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
.boxed_local()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stop(&self) -> Result<()> {
|
||||||
let mut client = self.client.write();
|
let mut client = self.client.write();
|
||||||
if let Some(protocol) = client.take() {
|
if let Some(protocol) = client.take() {
|
||||||
drop(protocol);
|
drop(protocol);
|
||||||
@@ -115,16 +151,15 @@ impl ContextServer {
|
|||||||
/// must go through the `GlobalContextServerManager` which holds
|
/// must go through the `GlobalContextServerManager` which holds
|
||||||
/// a model to the ContextServerManager.
|
/// a model to the ContextServerManager.
|
||||||
pub struct ContextServerManager {
|
pub struct ContextServerManager {
|
||||||
servers: HashMap<String, Arc<ContextServer>>,
|
servers: HashMap<Arc<str>, Arc<dyn ContextServer>>,
|
||||||
pending_servers: HashSet<String>,
|
pending_servers: HashSet<Arc<str>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
ServerStarted { server_id: String },
|
ServerStarted { server_id: Arc<str> },
|
||||||
ServerStopped { server_id: String },
|
ServerStopped { server_id: Arc<str> },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Global for ContextServerManager {}
|
|
||||||
impl EventEmitter<Event> for ContextServerManager {}
|
impl EventEmitter<Event> for ContextServerManager {}
|
||||||
|
|
||||||
impl Default for ContextServerManager {
|
impl Default for ContextServerManager {
|
||||||
@@ -140,16 +175,13 @@ impl ContextServerManager {
|
|||||||
pending_servers: HashSet::default(),
|
pending_servers: HashSet::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn global(cx: &AppContext) -> Model<Self> {
|
|
||||||
cx.global::<GlobalContextServerManager>().0.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_server(
|
pub fn add_server(
|
||||||
&mut self,
|
&mut self,
|
||||||
config: ServerConfig,
|
server: Arc<dyn ContextServer>,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &ModelContext<Self>,
|
||||||
) -> Task<anyhow::Result<()>> {
|
) -> Task<anyhow::Result<()>> {
|
||||||
let server_id = config.id.clone();
|
let server_id = server.id();
|
||||||
|
|
||||||
if self.servers.contains_key(&server_id) || self.pending_servers.contains(&server_id) {
|
if self.servers.contains_key(&server_id) || self.pending_servers.contains(&server_id) {
|
||||||
return Task::ready(Ok(()));
|
return Task::ready(Ok(()));
|
||||||
@@ -158,8 +190,7 @@ impl ContextServerManager {
|
|||||||
let task = {
|
let task = {
|
||||||
let server_id = server_id.clone();
|
let server_id = server_id.clone();
|
||||||
cx.spawn(|this, mut cx| async move {
|
cx.spawn(|this, mut cx| async move {
|
||||||
let server = Arc::new(ContextServer::new(config));
|
server.clone().start(&cx).await?;
|
||||||
server.start(&cx).await?;
|
|
||||||
this.update(&mut cx, |this, cx| {
|
this.update(&mut cx, |this, cx| {
|
||||||
this.servers.insert(server_id.clone(), server);
|
this.servers.insert(server_id.clone(), server);
|
||||||
this.pending_servers.remove(&server_id);
|
this.pending_servers.remove(&server_id);
|
||||||
@@ -175,22 +206,24 @@ impl ContextServerManager {
|
|||||||
task
|
task
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_server(&self, id: &str) -> Option<Arc<ContextServer>> {
|
pub fn get_server(&self, id: &str) -> Option<Arc<dyn ContextServer>> {
|
||||||
self.servers.get(id).cloned()
|
self.servers.get(id).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_server(
|
pub fn remove_server(
|
||||||
&mut self,
|
&mut self,
|
||||||
id: &str,
|
id: &Arc<str>,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &ModelContext<Self>,
|
||||||
) -> Task<anyhow::Result<()>> {
|
) -> Task<anyhow::Result<()>> {
|
||||||
let id = id.to_string();
|
let id = id.clone();
|
||||||
cx.spawn(|this, mut cx| async move {
|
cx.spawn(|this, mut cx| async move {
|
||||||
if let Some(server) = this.update(&mut cx, |this, _cx| this.servers.remove(&id))? {
|
if let Some(server) =
|
||||||
server.stop().await?;
|
this.update(&mut cx, |this, _cx| this.servers.remove(id.as_ref()))?
|
||||||
|
{
|
||||||
|
server.stop()?;
|
||||||
}
|
}
|
||||||
this.update(&mut cx, |this, cx| {
|
this.update(&mut cx, |this, cx| {
|
||||||
this.pending_servers.remove(&id);
|
this.pending_servers.remove(id.as_ref());
|
||||||
cx.emit(Event::ServerStopped {
|
cx.emit(Event::ServerStopped {
|
||||||
server_id: id.clone(),
|
server_id: id.clone(),
|
||||||
})
|
})
|
||||||
@@ -201,16 +234,16 @@ impl ContextServerManager {
|
|||||||
|
|
||||||
pub fn restart_server(
|
pub fn restart_server(
|
||||||
&mut self,
|
&mut self,
|
||||||
id: &str,
|
id: &Arc<str>,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) -> Task<anyhow::Result<()>> {
|
) -> Task<anyhow::Result<()>> {
|
||||||
let id = id.to_string();
|
let id = id.clone();
|
||||||
cx.spawn(|this, mut cx| async move {
|
cx.spawn(|this, mut cx| async move {
|
||||||
if let Some(server) = this.update(&mut cx, |this, _cx| this.servers.remove(&id))? {
|
if let Some(server) = this.update(&mut cx, |this, _cx| this.servers.remove(&id))? {
|
||||||
server.stop().await?;
|
server.stop()?;
|
||||||
let config = server.config.clone();
|
let config = server.config();
|
||||||
let new_server = Arc::new(ContextServer::new(config));
|
let new_server = Arc::new(NativeContextServer::new(config));
|
||||||
new_server.start(&cx).await?;
|
new_server.clone().start(&cx).await?;
|
||||||
this.update(&mut cx, |this, cx| {
|
this.update(&mut cx, |this, cx| {
|
||||||
this.servers.insert(id.clone(), new_server);
|
this.servers.insert(id.clone(), new_server);
|
||||||
cx.emit(Event::ServerStopped {
|
cx.emit(Event::ServerStopped {
|
||||||
@@ -225,79 +258,43 @@ impl ContextServerManager {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn servers(&self) -> Vec<Arc<ContextServer>> {
|
pub fn servers(&self) -> Vec<Arc<dyn ContextServer>> {
|
||||||
self.servers.values().cloned().collect()
|
self.servers.values().cloned().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn model(cx: &mut AppContext) -> Model<Self> {
|
pub fn maintain_servers(&mut self, settings: &ContextServerSettings, cx: &ModelContext<Self>) {
|
||||||
cx.new_model(|_cx| ContextServerManager::new())
|
let current_servers = self
|
||||||
|
.servers()
|
||||||
|
.into_iter()
|
||||||
|
.map(|server| (server.id(), server.config()))
|
||||||
|
.collect::<HashMap<_, _>>();
|
||||||
|
|
||||||
|
let new_servers = settings
|
||||||
|
.servers
|
||||||
|
.iter()
|
||||||
|
.map(|config| (config.id.clone(), config.clone()))
|
||||||
|
.collect::<HashMap<_, _>>();
|
||||||
|
|
||||||
|
let servers_to_add = new_servers
|
||||||
|
.values()
|
||||||
|
.filter(|config| !current_servers.contains_key(config.id.as_str()))
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let servers_to_remove = current_servers
|
||||||
|
.keys()
|
||||||
|
.filter(|id| !new_servers.contains_key(id.as_ref()))
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
log::trace!("servers_to_add={:?}", servers_to_add);
|
||||||
|
for config in servers_to_add {
|
||||||
|
let server = Arc::new(NativeContextServer::new(Arc::new(config)));
|
||||||
|
self.add_server(server, cx).detach_and_log_err(cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
for id in servers_to_remove {
|
||||||
|
self.remove_server(&id, cx).detach_and_log_err(cx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GlobalContextServerManager(Model<ContextServerManager>);
|
|
||||||
impl Global for GlobalContextServerManager {}
|
|
||||||
|
|
||||||
impl GlobalContextServerManager {
|
|
||||||
fn register(cx: &mut AppContext) {
|
|
||||||
let model = ContextServerManager::model(cx);
|
|
||||||
cx.set_global(Self(model));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init(cx: &mut AppContext) {
|
|
||||||
ContextServerSettings::register(cx);
|
|
||||||
GlobalContextServerManager::register(cx);
|
|
||||||
|
|
||||||
CommandPaletteFilter::update_global(cx, |filter, _cx| {
|
|
||||||
filter.hide_namespace(CONTEXT_SERVERS_NAMESPACE);
|
|
||||||
});
|
|
||||||
|
|
||||||
cx.observe_global::<SettingsStore>(|cx| {
|
|
||||||
let manager = ContextServerManager::global(cx);
|
|
||||||
cx.update_model(&manager, |manager, cx| {
|
|
||||||
let settings = ContextServerSettings::get_global(cx);
|
|
||||||
let current_servers = manager
|
|
||||||
.servers()
|
|
||||||
.into_iter()
|
|
||||||
.map(|server| (server.id.clone(), server.config.clone()))
|
|
||||||
.collect::<HashMap<_, _>>();
|
|
||||||
|
|
||||||
let new_servers = settings
|
|
||||||
.servers
|
|
||||||
.iter()
|
|
||||||
.map(|config| (config.id.clone(), config.clone()))
|
|
||||||
.collect::<HashMap<_, _>>();
|
|
||||||
|
|
||||||
let servers_to_add = new_servers
|
|
||||||
.values()
|
|
||||||
.filter(|config| !current_servers.contains_key(&config.id))
|
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let servers_to_remove = current_servers
|
|
||||||
.keys()
|
|
||||||
.filter(|id| !new_servers.contains_key(*id))
|
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
log::trace!("servers_to_add={:?}", servers_to_add);
|
|
||||||
for config in servers_to_add {
|
|
||||||
manager.add_server(config, cx).detach_and_log_err(cx);
|
|
||||||
}
|
|
||||||
|
|
||||||
for id in servers_to_remove {
|
|
||||||
manager.remove_server(&id, cx).detach_and_log_err(cx);
|
|
||||||
}
|
|
||||||
|
|
||||||
let has_any_context_servers = !manager.servers().is_empty();
|
|
||||||
CommandPaletteFilter::update_global(cx, |filter, _cx| {
|
|
||||||
if has_any_context_servers {
|
|
||||||
filter.show_namespace(CONTEXT_SERVERS_NAMESPACE);
|
|
||||||
} else {
|
|
||||||
filter.hide_namespace(CONTEXT_SERVERS_NAMESPACE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.detach();
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -113,7 +113,10 @@ impl InitializedContextServerProtocol {
|
|||||||
|
|
||||||
let response: types::PromptsListResponse = self
|
let response: types::PromptsListResponse = self
|
||||||
.inner
|
.inner
|
||||||
.request(types::RequestType::PromptsList.as_str(), ())
|
.request(
|
||||||
|
types::RequestType::PromptsList.as_str(),
|
||||||
|
serde_json::json!({}),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(response.prompts)
|
Ok(response.prompts)
|
||||||
@@ -125,7 +128,10 @@ impl InitializedContextServerProtocol {
|
|||||||
|
|
||||||
let response: types::ResourcesListResponse = self
|
let response: types::ResourcesListResponse = self
|
||||||
.inner
|
.inner
|
||||||
.request(types::RequestType::ResourcesList.as_str(), ())
|
.request(
|
||||||
|
types::RequestType::ResourcesList.as_str(),
|
||||||
|
serde_json::json!({}),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(response)
|
Ok(response)
|
||||||
|
|||||||
@@ -1,69 +1,72 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use gpui::{AppContext, Global, ReadGlobal};
|
use gpui::{AppContext, AsyncAppContext, ReadGlobal};
|
||||||
|
use gpui::{Global, Task};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
|
|
||||||
struct GlobalContextServerRegistry(Arc<ContextServerRegistry>);
|
use crate::ContextServer;
|
||||||
|
|
||||||
impl Global for GlobalContextServerRegistry {}
|
pub type ContextServerFactory =
|
||||||
|
Arc<dyn Fn(&AsyncAppContext) -> Task<Result<Arc<dyn ContextServer>>> + Send + Sync + 'static>;
|
||||||
|
|
||||||
pub struct ContextServerRegistry {
|
#[derive(Default)]
|
||||||
command_registry: RwLock<HashMap<String, Vec<Arc<str>>>>,
|
struct GlobalContextServerFactoryRegistry(Arc<ContextServerFactoryRegistry>);
|
||||||
tool_registry: RwLock<HashMap<String, Vec<Arc<str>>>>,
|
|
||||||
|
impl Global for GlobalContextServerFactoryRegistry {}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct ContextServerFactoryRegistryState {
|
||||||
|
context_servers: HashMap<Arc<str>, ContextServerFactory>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContextServerRegistry {
|
#[derive(Default)]
|
||||||
|
pub struct ContextServerFactoryRegistry {
|
||||||
|
state: RwLock<ContextServerFactoryRegistryState>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ContextServerFactoryRegistry {
|
||||||
|
/// Returns the global [`ContextServerFactoryRegistry`].
|
||||||
pub fn global(cx: &AppContext) -> Arc<Self> {
|
pub fn global(cx: &AppContext) -> Arc<Self> {
|
||||||
GlobalContextServerRegistry::global(cx).0.clone()
|
GlobalContextServerFactoryRegistry::global(cx).0.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register(cx: &mut AppContext) {
|
/// Returns the global [`ContextServerFactoryRegistry`].
|
||||||
cx.set_global(GlobalContextServerRegistry(Arc::new(
|
///
|
||||||
ContextServerRegistry {
|
/// Inserts a default [`ContextServerFactoryRegistry`] if one does not yet exist.
|
||||||
command_registry: RwLock::new(HashMap::default()),
|
pub fn default_global(cx: &mut AppContext) -> Arc<Self> {
|
||||||
tool_registry: RwLock::new(HashMap::default()),
|
cx.default_global::<GlobalContextServerFactoryRegistry>()
|
||||||
},
|
.0
|
||||||
)))
|
.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_command(&self, server_id: String, command_name: &str) {
|
pub fn new() -> Arc<Self> {
|
||||||
let mut registry = self.command_registry.write();
|
Arc::new(Self {
|
||||||
registry
|
state: RwLock::new(ContextServerFactoryRegistryState {
|
||||||
.entry(server_id)
|
context_servers: HashMap::default(),
|
||||||
.or_default()
|
}),
|
||||||
.push(command_name.into());
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unregister_command(&self, server_id: &str, command_name: &str) {
|
pub fn context_server_factories(&self) -> Vec<(Arc<str>, ContextServerFactory)> {
|
||||||
let mut registry = self.command_registry.write();
|
self.state
|
||||||
if let Some(commands) = registry.get_mut(server_id) {
|
.read()
|
||||||
commands.retain(|name| name.as_ref() != command_name);
|
.context_servers
|
||||||
}
|
.iter()
|
||||||
|
.map(|(id, factory)| (id.clone(), factory.clone()))
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_commands(&self, server_id: &str) -> Option<Vec<Arc<str>>> {
|
/// Registers the provided [`ContextServerFactory`].
|
||||||
let registry = self.command_registry.read();
|
pub fn register_server_factory(&self, id: Arc<str>, factory: ContextServerFactory) {
|
||||||
registry.get(server_id).cloned()
|
let mut state = self.state.write();
|
||||||
|
state.context_servers.insert(id, factory);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_tool(&self, server_id: String, tool_name: &str) {
|
/// Unregisters the [`ContextServerFactory`] for the server with the given ID.
|
||||||
let mut registry = self.tool_registry.write();
|
pub fn unregister_server_factory_by_id(&self, server_id: &str) {
|
||||||
registry
|
let mut state = self.state.write();
|
||||||
.entry(server_id)
|
state.context_servers.remove(server_id);
|
||||||
.or_default()
|
|
||||||
.push(tool_name.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unregister_tool(&self, server_id: &str, tool_name: &str) {
|
|
||||||
let mut registry = self.tool_registry.write();
|
|
||||||
if let Some(tools) = registry.get_mut(server_id) {
|
|
||||||
tools.retain(|name| name.as_ref() != tool_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_tools(&self, server_id: &str) -> Option<Vec<Arc<str>>> {
|
|
||||||
let registry = self.tool_registry.read();
|
|
||||||
registry.get(server_id).cloned()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ use language::{
|
|||||||
point_from_lsp, point_to_lsp, Anchor, Bias, Buffer, BufferSnapshot, Language, PointUtf16,
|
point_from_lsp, point_to_lsp, Anchor, Bias, Buffer, BufferSnapshot, Language, PointUtf16,
|
||||||
ToPointUtf16,
|
ToPointUtf16,
|
||||||
};
|
};
|
||||||
use lsp::{LanguageServer, LanguageServerBinary, LanguageServerId};
|
use lsp::{LanguageServer, LanguageServerBinary, LanguageServerId, LanguageServerName};
|
||||||
use node_runtime::NodeRuntime;
|
use node_runtime::NodeRuntime;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use request::StatusNotification;
|
use request::StatusNotification;
|
||||||
@@ -446,9 +446,11 @@ impl Copilot {
|
|||||||
Path::new("/")
|
Path::new("/")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let server_name = LanguageServerName("copilot".into());
|
||||||
let server = LanguageServer::new(
|
let server = LanguageServer::new(
|
||||||
Arc::new(Mutex::new(None)),
|
Arc::new(Mutex::new(None)),
|
||||||
new_server_id,
|
new_server_id,
|
||||||
|
server_name,
|
||||||
binary,
|
binary,
|
||||||
root_path,
|
root_path,
|
||||||
None,
|
None,
|
||||||
@@ -1272,5 +1274,9 @@ mod tests {
|
|||||||
fn load(&self, _: &AppContext) -> Task<Result<String>> {
|
fn load(&self, _: &AppContext) -> Task<Result<String>> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load_bytes(&self, _cx: &AppContext) -> Task<Result<Vec<u8>>> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,14 +35,30 @@ pub enum Model {
|
|||||||
Gpt4,
|
Gpt4,
|
||||||
#[serde(alias = "gpt-3.5-turbo", rename = "gpt-3.5-turbo")]
|
#[serde(alias = "gpt-3.5-turbo", rename = "gpt-3.5-turbo")]
|
||||||
Gpt3_5Turbo,
|
Gpt3_5Turbo,
|
||||||
|
#[serde(alias = "o1-preview", rename = "o1-preview-2024-09-12")]
|
||||||
|
O1Preview,
|
||||||
|
#[serde(alias = "o1-mini", rename = "o1-mini-2024-09-12")]
|
||||||
|
O1Mini,
|
||||||
|
#[serde(alias = "claude-3-5-sonnet", rename = "claude-3.5-sonnet")]
|
||||||
|
Claude3_5Sonnet,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Model {
|
impl Model {
|
||||||
|
pub fn uses_streaming(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Gpt4o | Self::Gpt4 | Self::Gpt3_5Turbo | Self::Claude3_5Sonnet => true,
|
||||||
|
Self::O1Mini | Self::O1Preview => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn from_id(id: &str) -> Result<Self> {
|
pub fn from_id(id: &str) -> Result<Self> {
|
||||||
match id {
|
match id {
|
||||||
"gpt-4o" => Ok(Self::Gpt4o),
|
"gpt-4o" => Ok(Self::Gpt4o),
|
||||||
"gpt-4" => Ok(Self::Gpt4),
|
"gpt-4" => Ok(Self::Gpt4),
|
||||||
"gpt-3.5-turbo" => Ok(Self::Gpt3_5Turbo),
|
"gpt-3.5-turbo" => Ok(Self::Gpt3_5Turbo),
|
||||||
|
"o1-preview" => Ok(Self::O1Preview),
|
||||||
|
"o1-mini" => Ok(Self::O1Mini),
|
||||||
|
"claude-3-5-sonnet" => Ok(Self::Claude3_5Sonnet),
|
||||||
_ => Err(anyhow!("Invalid model id: {}", id)),
|
_ => Err(anyhow!("Invalid model id: {}", id)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,6 +68,9 @@ impl Model {
|
|||||||
Self::Gpt3_5Turbo => "gpt-3.5-turbo",
|
Self::Gpt3_5Turbo => "gpt-3.5-turbo",
|
||||||
Self::Gpt4 => "gpt-4",
|
Self::Gpt4 => "gpt-4",
|
||||||
Self::Gpt4o => "gpt-4o",
|
Self::Gpt4o => "gpt-4o",
|
||||||
|
Self::O1Mini => "o1-mini",
|
||||||
|
Self::O1Preview => "o1-preview",
|
||||||
|
Self::Claude3_5Sonnet => "claude-3-5-sonnet",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,14 +79,20 @@ impl Model {
|
|||||||
Self::Gpt3_5Turbo => "GPT-3.5",
|
Self::Gpt3_5Turbo => "GPT-3.5",
|
||||||
Self::Gpt4 => "GPT-4",
|
Self::Gpt4 => "GPT-4",
|
||||||
Self::Gpt4o => "GPT-4o",
|
Self::Gpt4o => "GPT-4o",
|
||||||
|
Self::O1Mini => "o1-mini",
|
||||||
|
Self::O1Preview => "o1-preview",
|
||||||
|
Self::Claude3_5Sonnet => "Claude 3.5 Sonnet",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn max_token_count(&self) -> usize {
|
pub fn max_token_count(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
Self::Gpt4o => 128000,
|
Self::Gpt4o => 64000,
|
||||||
Self::Gpt4 => 8192,
|
Self::Gpt4 => 32768,
|
||||||
Self::Gpt3_5Turbo => 16385,
|
Self::Gpt3_5Turbo => 12288,
|
||||||
|
Self::O1Mini => 20000,
|
||||||
|
Self::O1Preview => 20000,
|
||||||
|
Self::Claude3_5Sonnet => 200_000,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,7 +112,7 @@ impl Request {
|
|||||||
Self {
|
Self {
|
||||||
intent: true,
|
intent: true,
|
||||||
n: 1,
|
n: 1,
|
||||||
stream: true,
|
stream: model.uses_streaming(),
|
||||||
temperature: 0.1,
|
temperature: 0.1,
|
||||||
model,
|
model,
|
||||||
messages,
|
messages,
|
||||||
@@ -113,7 +138,8 @@ pub struct ResponseEvent {
|
|||||||
pub struct ResponseChoice {
|
pub struct ResponseChoice {
|
||||||
pub index: usize,
|
pub index: usize,
|
||||||
pub finish_reason: Option<String>,
|
pub finish_reason: Option<String>,
|
||||||
pub delta: ResponseDelta,
|
pub delta: Option<ResponseDelta>,
|
||||||
|
pub message: Option<ResponseDelta>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
@@ -333,9 +359,23 @@ async fn stream_completion(
|
|||||||
if let Some(low_speed_timeout) = low_speed_timeout {
|
if let Some(low_speed_timeout) = low_speed_timeout {
|
||||||
request_builder = request_builder.read_timeout(low_speed_timeout);
|
request_builder = request_builder.read_timeout(low_speed_timeout);
|
||||||
}
|
}
|
||||||
|
let is_streaming = request.stream;
|
||||||
|
|
||||||
let request = request_builder.body(AsyncBody::from(serde_json::to_string(&request)?))?;
|
let request = request_builder.body(AsyncBody::from(serde_json::to_string(&request)?))?;
|
||||||
let mut response = client.send(request).await?;
|
let mut response = client.send(request).await?;
|
||||||
if response.status().is_success() {
|
|
||||||
|
if !response.status().is_success() {
|
||||||
|
let mut body = Vec::new();
|
||||||
|
response.body_mut().read_to_end(&mut body).await?;
|
||||||
|
let body_str = std::str::from_utf8(&body)?;
|
||||||
|
return Err(anyhow!(
|
||||||
|
"Failed to connect to API: {} {}",
|
||||||
|
response.status(),
|
||||||
|
body_str
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_streaming {
|
||||||
let reader = BufReader::new(response.into_body());
|
let reader = BufReader::new(response.into_body());
|
||||||
Ok(reader
|
Ok(reader
|
||||||
.lines()
|
.lines()
|
||||||
@@ -367,19 +407,9 @@ async fn stream_completion(
|
|||||||
} else {
|
} else {
|
||||||
let mut body = Vec::new();
|
let mut body = Vec::new();
|
||||||
response.body_mut().read_to_end(&mut body).await?;
|
response.body_mut().read_to_end(&mut body).await?;
|
||||||
|
|
||||||
let body_str = std::str::from_utf8(&body)?;
|
let body_str = std::str::from_utf8(&body)?;
|
||||||
|
let response: ResponseEvent = serde_json::from_str(body_str)?;
|
||||||
|
|
||||||
match serde_json::from_str::<ResponseEvent>(body_str) {
|
Ok(futures::stream::once(async move { Ok(response) }).boxed())
|
||||||
Ok(_) => Err(anyhow!(
|
|
||||||
"Unexpected success response while expecting an error: {}",
|
|
||||||
body_str,
|
|
||||||
)),
|
|
||||||
Err(_) => Err(anyhow!(
|
|
||||||
"Failed to connect to API: {} {}",
|
|
||||||
response.status(),
|
|
||||||
body_str,
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ collections.workspace = true
|
|||||||
ctor.workspace = true
|
ctor.workspace = true
|
||||||
editor.workspace = true
|
editor.workspace = true
|
||||||
env_logger.workspace = true
|
env_logger.workspace = true
|
||||||
futures.workspace = true
|
|
||||||
gpui.workspace = true
|
gpui.workspace = true
|
||||||
language.workspace = true
|
language.workspace = true
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
|
|||||||
@@ -14,10 +14,6 @@ use editor::{
|
|||||||
scroll::Autoscroll,
|
scroll::Autoscroll,
|
||||||
Editor, EditorEvent, ExcerptId, ExcerptRange, MultiBuffer, ToOffset,
|
Editor, EditorEvent, ExcerptId, ExcerptRange, MultiBuffer, ToOffset,
|
||||||
};
|
};
|
||||||
use futures::{
|
|
||||||
channel::mpsc::{self, UnboundedSender},
|
|
||||||
StreamExt as _,
|
|
||||||
};
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, div, svg, AnyElement, AnyView, AppContext, Context, EventEmitter, FocusHandle,
|
actions, div, svg, AnyElement, AnyView, AppContext, Context, EventEmitter, FocusHandle,
|
||||||
FocusableView, HighlightStyle, InteractiveElement, IntoElement, Model, ParentElement, Render,
|
FocusableView, HighlightStyle, InteractiveElement, IntoElement, Model, ParentElement, Render,
|
||||||
@@ -62,11 +58,10 @@ struct ProjectDiagnosticsEditor {
|
|||||||
summary: DiagnosticSummary,
|
summary: DiagnosticSummary,
|
||||||
excerpts: Model<MultiBuffer>,
|
excerpts: Model<MultiBuffer>,
|
||||||
path_states: Vec<PathState>,
|
path_states: Vec<PathState>,
|
||||||
paths_to_update: BTreeSet<(ProjectPath, LanguageServerId)>,
|
paths_to_update: BTreeSet<(ProjectPath, Option<LanguageServerId>)>,
|
||||||
include_warnings: bool,
|
include_warnings: bool,
|
||||||
context: u32,
|
context: u32,
|
||||||
update_paths_tx: UnboundedSender<(ProjectPath, Option<LanguageServerId>)>,
|
update_excerpts_task: Option<Task<Result<()>>>,
|
||||||
_update_excerpts_task: Task<Result<()>>,
|
|
||||||
_subscription: Subscription,
|
_subscription: Subscription,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,14 +124,14 @@ impl ProjectDiagnosticsEditor {
|
|||||||
}
|
}
|
||||||
project::Event::DiskBasedDiagnosticsFinished { language_server_id } => {
|
project::Event::DiskBasedDiagnosticsFinished { language_server_id } => {
|
||||||
log::debug!("disk based diagnostics finished for server {language_server_id}");
|
log::debug!("disk based diagnostics finished for server {language_server_id}");
|
||||||
this.enqueue_update_stale_excerpts(Some(*language_server_id));
|
this.update_stale_excerpts(cx);
|
||||||
}
|
}
|
||||||
project::Event::DiagnosticsUpdated {
|
project::Event::DiagnosticsUpdated {
|
||||||
language_server_id,
|
language_server_id,
|
||||||
path,
|
path,
|
||||||
} => {
|
} => {
|
||||||
this.paths_to_update
|
this.paths_to_update
|
||||||
.insert((path.clone(), *language_server_id));
|
.insert((path.clone(), Some(*language_server_id)));
|
||||||
this.summary = project.read(cx).diagnostic_summary(false, cx);
|
this.summary = project.read(cx).diagnostic_summary(false, cx);
|
||||||
cx.emit(EditorEvent::TitleChanged);
|
cx.emit(EditorEvent::TitleChanged);
|
||||||
|
|
||||||
@@ -144,7 +139,7 @@ impl ProjectDiagnosticsEditor {
|
|||||||
log::debug!("diagnostics updated for server {language_server_id}, path {path:?}. recording change");
|
log::debug!("diagnostics updated for server {language_server_id}, path {path:?}. recording change");
|
||||||
} else {
|
} else {
|
||||||
log::debug!("diagnostics updated for server {language_server_id}, path {path:?}. updating excerpts");
|
log::debug!("diagnostics updated for server {language_server_id}, path {path:?}. updating excerpts");
|
||||||
this.enqueue_update_stale_excerpts(Some(*language_server_id));
|
this.update_stale_excerpts(cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -171,14 +166,12 @@ impl ProjectDiagnosticsEditor {
|
|||||||
cx.focus(&this.focus_handle);
|
cx.focus(&this.focus_handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EditorEvent::Blurred => this.enqueue_update_stale_excerpts(None),
|
EditorEvent::Blurred => this.update_stale_excerpts(cx),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
|
|
||||||
let (update_excerpts_tx, mut update_excerpts_rx) = mpsc::unbounded();
|
|
||||||
|
|
||||||
let project = project_handle.read(cx);
|
let project = project_handle.read(cx);
|
||||||
let mut this = Self {
|
let mut this = Self {
|
||||||
project: project_handle.clone(),
|
project: project_handle.clone(),
|
||||||
@@ -191,27 +184,45 @@ impl ProjectDiagnosticsEditor {
|
|||||||
path_states: Default::default(),
|
path_states: Default::default(),
|
||||||
paths_to_update: Default::default(),
|
paths_to_update: Default::default(),
|
||||||
include_warnings: ProjectDiagnosticsSettings::get_global(cx).include_warnings,
|
include_warnings: ProjectDiagnosticsSettings::get_global(cx).include_warnings,
|
||||||
update_paths_tx: update_excerpts_tx,
|
update_excerpts_task: None,
|
||||||
_update_excerpts_task: cx.spawn(move |this, mut cx| async move {
|
|
||||||
while let Some((path, language_server_id)) = update_excerpts_rx.next().await {
|
|
||||||
if let Some(buffer) = project_handle
|
|
||||||
.update(&mut cx, |project, cx| project.open_buffer(path.clone(), cx))?
|
|
||||||
.await
|
|
||||||
.log_err()
|
|
||||||
{
|
|
||||||
this.update(&mut cx, |this, cx| {
|
|
||||||
this.update_excerpts(path, language_server_id, buffer, cx);
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
anyhow::Ok(())
|
|
||||||
}),
|
|
||||||
_subscription: project_event_subscription,
|
_subscription: project_event_subscription,
|
||||||
};
|
};
|
||||||
this.enqueue_update_all_excerpts(cx);
|
this.update_all_excerpts(cx);
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_stale_excerpts(&mut self, cx: &mut ViewContext<Self>) {
|
||||||
|
if self.update_excerpts_task.is_some() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let project_handle = self.project.clone();
|
||||||
|
self.update_excerpts_task = Some(cx.spawn(|this, mut cx| async move {
|
||||||
|
loop {
|
||||||
|
let Some((path, language_server_id)) = this.update(&mut cx, |this, _| {
|
||||||
|
let Some((path, language_server_id)) = this.paths_to_update.pop_first() else {
|
||||||
|
this.update_excerpts_task.take();
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
Some((path, language_server_id))
|
||||||
|
})?
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(buffer) = project_handle
|
||||||
|
.update(&mut cx, |project, cx| project.open_buffer(path.clone(), cx))?
|
||||||
|
.await
|
||||||
|
.log_err()
|
||||||
|
{
|
||||||
|
this.update(&mut cx, |this, cx| {
|
||||||
|
this.update_excerpts(path, language_server_id, buffer, cx);
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
fn new(
|
fn new(
|
||||||
project_handle: Model<Project>,
|
project_handle: Model<Project>,
|
||||||
workspace: WeakView<Workspace>,
|
workspace: WeakView<Workspace>,
|
||||||
@@ -239,7 +250,7 @@ impl ProjectDiagnosticsEditor {
|
|||||||
|
|
||||||
fn toggle_warnings(&mut self, _: &ToggleWarnings, cx: &mut ViewContext<Self>) {
|
fn toggle_warnings(&mut self, _: &ToggleWarnings, cx: &mut ViewContext<Self>) {
|
||||||
self.include_warnings = !self.include_warnings;
|
self.include_warnings = !self.include_warnings;
|
||||||
self.enqueue_update_all_excerpts(cx);
|
self.update_all_excerpts(cx);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,37 +262,28 @@ impl ProjectDiagnosticsEditor {
|
|||||||
|
|
||||||
fn focus_out(&mut self, cx: &mut ViewContext<Self>) {
|
fn focus_out(&mut self, cx: &mut ViewContext<Self>) {
|
||||||
if !self.focus_handle.is_focused(cx) && !self.editor.focus_handle(cx).is_focused(cx) {
|
if !self.focus_handle.is_focused(cx) && !self.editor.focus_handle(cx).is_focused(cx) {
|
||||||
self.enqueue_update_stale_excerpts(None);
|
self.update_stale_excerpts(cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enqueue an update of all excerpts. Updates all paths that either
|
/// Enqueue an update of all excerpts. Updates all paths that either
|
||||||
/// currently have diagnostics or are currently present in this view.
|
/// currently have diagnostics or are currently present in this view.
|
||||||
fn enqueue_update_all_excerpts(&mut self, cx: &mut ViewContext<Self>) {
|
fn update_all_excerpts(&mut self, cx: &mut ViewContext<Self>) {
|
||||||
self.project.update(cx, |project, cx| {
|
self.project.update(cx, |project, cx| {
|
||||||
let mut paths = project
|
let mut paths = project
|
||||||
.diagnostic_summaries(false, cx)
|
.diagnostic_summaries(false, cx)
|
||||||
.map(|(path, _, _)| path)
|
.map(|(path, _, _)| (path, None))
|
||||||
.collect::<BTreeSet<_>>();
|
.collect::<BTreeSet<_>>();
|
||||||
paths.extend(self.path_states.iter().map(|state| state.path.clone()));
|
paths.extend(
|
||||||
for path in paths {
|
self.path_states
|
||||||
self.update_paths_tx.unbounded_send((path, None)).unwrap();
|
.iter()
|
||||||
}
|
.map(|state| (state.path.clone(), None)),
|
||||||
|
);
|
||||||
|
let paths_to_update = std::mem::take(&mut self.paths_to_update);
|
||||||
|
paths.extend(paths_to_update.into_iter().map(|(path, _)| (path, None)));
|
||||||
|
self.paths_to_update = paths;
|
||||||
});
|
});
|
||||||
}
|
self.update_stale_excerpts(cx);
|
||||||
|
|
||||||
/// Enqueue an update of the excerpts for any path whose diagnostics are known
|
|
||||||
/// to have changed. If a language server id is passed, then only the excerpts for
|
|
||||||
/// that language server's diagnostics will be updated. Otherwise, all stale excerpts
|
|
||||||
/// will be refreshed.
|
|
||||||
fn enqueue_update_stale_excerpts(&mut self, language_server_id: Option<LanguageServerId>) {
|
|
||||||
for (path, server_id) in &self.paths_to_update {
|
|
||||||
if language_server_id.map_or(true, |id| id == *server_id) {
|
|
||||||
self.update_paths_tx
|
|
||||||
.unbounded_send((path.clone(), Some(*server_id)))
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_excerpts(
|
fn update_excerpts(
|
||||||
@@ -291,11 +293,6 @@ impl ProjectDiagnosticsEditor {
|
|||||||
buffer: Model<Buffer>,
|
buffer: Model<Buffer>,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) {
|
) {
|
||||||
self.paths_to_update.retain(|(path, server_id)| {
|
|
||||||
*path != path_to_update
|
|
||||||
|| server_to_update.map_or(false, |to_update| *server_id != to_update)
|
|
||||||
});
|
|
||||||
|
|
||||||
let was_empty = self.path_states.is_empty();
|
let was_empty = self.path_states.is_empty();
|
||||||
let snapshot = buffer.read(cx).snapshot();
|
let snapshot = buffer.read(cx).snapshot();
|
||||||
let path_ix = match self
|
let path_ix = match self
|
||||||
|
|||||||
@@ -800,7 +800,7 @@ async fn test_random_diagnostics(cx: &mut TestAppContext, mut rng: StdRng) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log::info!("updating mutated diagnostics view");
|
log::info!("updating mutated diagnostics view");
|
||||||
mutated_view.update(cx, |view, _| view.enqueue_update_stale_excerpts(None));
|
mutated_view.update(cx, |view, cx| view.update_stale_excerpts(cx));
|
||||||
cx.run_until_parked();
|
cx.run_until_parked();
|
||||||
|
|
||||||
log::info!("constructing reference diagnostics view");
|
log::info!("constructing reference diagnostics view");
|
||||||
@@ -986,6 +986,7 @@ fn editor_blocks(
|
|||||||
em_width: px(0.),
|
em_width: px(0.),
|
||||||
max_width: px(0.),
|
max_width: px(0.),
|
||||||
block_id,
|
block_id,
|
||||||
|
selected: false,
|
||||||
editor_style: &editor::EditorStyle::default(),
|
editor_style: &editor::EditorStyle::default(),
|
||||||
});
|
});
|
||||||
let element = element.downcast_mut::<Stateful<Div>>().unwrap();
|
let element = element.downcast_mut::<Stateful<Div>>().unwrap();
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ impl Render for ToolbarControls {
|
|||||||
let mut has_stale_excerpts = false;
|
let mut has_stale_excerpts = false;
|
||||||
let mut is_updating = false;
|
let mut is_updating = false;
|
||||||
|
|
||||||
if let Some(editor) = self.editor() {
|
if let Some(editor) = self.diagnostics() {
|
||||||
let editor = editor.read(cx);
|
let diagnostics = editor.read(cx);
|
||||||
include_warnings = editor.include_warnings;
|
include_warnings = diagnostics.include_warnings;
|
||||||
has_stale_excerpts = !editor.paths_to_update.is_empty();
|
has_stale_excerpts = !diagnostics.paths_to_update.is_empty();
|
||||||
is_updating = !editor.update_paths_tx.is_empty()
|
is_updating = diagnostics.update_excerpts_task.is_some()
|
||||||
|| editor
|
|| diagnostics
|
||||||
.project
|
.project
|
||||||
.read(cx)
|
.read(cx)
|
||||||
.language_servers_running_disk_based_diagnostics(cx)
|
.language_servers_running_disk_based_diagnostics(cx)
|
||||||
@@ -49,9 +49,9 @@ impl Render for ToolbarControls {
|
|||||||
.disabled(is_updating)
|
.disabled(is_updating)
|
||||||
.tooltip(move |cx| Tooltip::text("Update excerpts", cx))
|
.tooltip(move |cx| Tooltip::text("Update excerpts", cx))
|
||||||
.on_click(cx.listener(|this, _, cx| {
|
.on_click(cx.listener(|this, _, cx| {
|
||||||
if let Some(editor) = this.editor() {
|
if let Some(diagnostics) = this.diagnostics() {
|
||||||
editor.update(cx, |editor, _| {
|
diagnostics.update(cx, |diagnostics, cx| {
|
||||||
editor.enqueue_update_stale_excerpts(None);
|
diagnostics.update_all_excerpts(cx);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
@@ -63,7 +63,7 @@ impl Render for ToolbarControls {
|
|||||||
.shape(IconButtonShape::Square)
|
.shape(IconButtonShape::Square)
|
||||||
.tooltip(move |cx| Tooltip::text(tooltip, cx))
|
.tooltip(move |cx| Tooltip::text(tooltip, cx))
|
||||||
.on_click(cx.listener(|this, _, cx| {
|
.on_click(cx.listener(|this, _, cx| {
|
||||||
if let Some(editor) = this.editor() {
|
if let Some(editor) = this.diagnostics() {
|
||||||
editor.update(cx, |editor, cx| {
|
editor.update(cx, |editor, cx| {
|
||||||
editor.toggle_warnings(&Default::default(), cx);
|
editor.toggle_warnings(&Default::default(), cx);
|
||||||
});
|
});
|
||||||
@@ -105,7 +105,7 @@ impl ToolbarControls {
|
|||||||
ToolbarControls { editor: None }
|
ToolbarControls { editor: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn editor(&self) -> Option<View<ProjectDiagnosticsEditor>> {
|
fn diagnostics(&self) -> Option<View<ProjectDiagnosticsEditor>> {
|
||||||
self.editor.as_ref()?.upgrade()
|
self.editor.as_ref()?.upgrade()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ tree-sitter-html = { workspace = true, optional = true }
|
|||||||
tree-sitter-rust = { workspace = true, optional = true }
|
tree-sitter-rust = { workspace = true, optional = true }
|
||||||
tree-sitter-typescript = { workspace = true, optional = true }
|
tree-sitter-typescript = { workspace = true, optional = true }
|
||||||
unicode-segmentation.workspace = true
|
unicode-segmentation.workspace = true
|
||||||
|
unicode-script.workspace = true
|
||||||
unindent = { workspace = true, optional = true }
|
unindent = { workspace = true, optional = true }
|
||||||
ui.workspace = true
|
ui.workspace = true
|
||||||
url.workspace = true
|
url.workspace = true
|
||||||
|
|||||||
@@ -80,6 +80,8 @@ pub struct ConfirmCodeAction {
|
|||||||
pub struct ToggleComments {
|
pub struct ToggleComments {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub advance_downwards: bool,
|
pub advance_downwards: bool,
|
||||||
|
#[serde(default)]
|
||||||
|
pub ignore_indent: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Deserialize, Default)]
|
#[derive(PartialEq, Clone, Deserialize, Default)]
|
||||||
@@ -157,6 +159,13 @@ pub struct DeleteToPreviousWordStart {
|
|||||||
pub struct FoldAtLevel {
|
pub struct FoldAtLevel {
|
||||||
pub level: u32,
|
pub level: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Clone, Deserialize, Default)]
|
||||||
|
pub struct SpawnNearestTask {
|
||||||
|
#[serde(default)]
|
||||||
|
pub reveal: task::RevealStrategy,
|
||||||
|
}
|
||||||
|
|
||||||
impl_actions!(
|
impl_actions!(
|
||||||
editor,
|
editor,
|
||||||
[
|
[
|
||||||
@@ -182,6 +191,7 @@ impl_actions!(
|
|||||||
SelectToBeginningOfLine,
|
SelectToBeginningOfLine,
|
||||||
SelectToEndOfLine,
|
SelectToEndOfLine,
|
||||||
SelectUpByLines,
|
SelectUpByLines,
|
||||||
|
SpawnNearestTask,
|
||||||
ShowCompletions,
|
ShowCompletions,
|
||||||
ToggleCodeActions,
|
ToggleCodeActions,
|
||||||
ToggleComments,
|
ToggleComments,
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ use block_map::{BlockRow, BlockSnapshot};
|
|||||||
use collections::{HashMap, HashSet};
|
use collections::{HashMap, HashSet};
|
||||||
pub use crease_map::*;
|
pub use crease_map::*;
|
||||||
pub use fold_map::{Fold, FoldId, FoldPlaceholder, FoldPoint};
|
pub use fold_map::{Fold, FoldId, FoldPlaceholder, FoldPoint};
|
||||||
use fold_map::{FoldMap, FoldSnapshot};
|
use fold_map::{FoldMap, FoldMapWriter, FoldOffset, FoldSnapshot};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
AnyElement, Font, HighlightStyle, LineLayout, Model, ModelContext, Pixels, UnderlineStyle,
|
AnyElement, Font, HighlightStyle, LineLayout, Model, ModelContext, Pixels, UnderlineStyle,
|
||||||
};
|
};
|
||||||
@@ -65,7 +65,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
use sum_tree::{Bias, TreeMap};
|
use sum_tree::{Bias, TreeMap};
|
||||||
use tab_map::{TabMap, TabSnapshot};
|
use tab_map::{TabMap, TabSnapshot};
|
||||||
use text::LineIndent;
|
use text::{Edit, LineIndent};
|
||||||
use ui::{div, px, IntoElement, ParentElement, SharedString, Styled, WindowContext};
|
use ui::{div, px, IntoElement, ParentElement, SharedString, Styled, WindowContext};
|
||||||
use unicode_segmentation::UnicodeSegmentation;
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
use wrap_map::{WrapMap, WrapSnapshot};
|
use wrap_map::{WrapMap, WrapSnapshot};
|
||||||
@@ -206,34 +206,41 @@ impl DisplayMap {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates folds for the given ranges.
|
||||||
pub fn fold<T: ToOffset>(
|
pub fn fold<T: ToOffset>(
|
||||||
&mut self,
|
&mut self,
|
||||||
ranges: impl IntoIterator<Item = (Range<T>, FoldPlaceholder)>,
|
ranges: impl IntoIterator<Item = (Range<T>, FoldPlaceholder)>,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) {
|
) {
|
||||||
let snapshot = self.buffer.read(cx).snapshot(cx);
|
self.update_fold_map(cx, |fold_map| fold_map.fold(ranges))
|
||||||
let edits = self.buffer_subscription.consume().into_inner();
|
|
||||||
let tab_size = Self::tab_size(&self.buffer, cx);
|
|
||||||
let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
|
|
||||||
let (mut fold_map, snapshot, edits) = self.fold_map.write(snapshot, edits);
|
|
||||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
|
|
||||||
let (snapshot, edits) = self
|
|
||||||
.wrap_map
|
|
||||||
.update(cx, |map, cx| map.sync(snapshot, edits, cx));
|
|
||||||
self.block_map.read(snapshot, edits);
|
|
||||||
let (snapshot, edits) = fold_map.fold(ranges);
|
|
||||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
|
|
||||||
let (snapshot, edits) = self
|
|
||||||
.wrap_map
|
|
||||||
.update(cx, |map, cx| map.sync(snapshot, edits, cx));
|
|
||||||
self.block_map.read(snapshot, edits);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unfold<T: ToOffset>(
|
/// Removes any folds with the given ranges.
|
||||||
|
pub fn remove_folds_with_type<T: ToOffset>(
|
||||||
|
&mut self,
|
||||||
|
ranges: impl IntoIterator<Item = Range<T>>,
|
||||||
|
type_id: TypeId,
|
||||||
|
cx: &mut ModelContext<Self>,
|
||||||
|
) {
|
||||||
|
self.update_fold_map(cx, |fold_map| fold_map.remove_folds(ranges, type_id))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes any folds whose ranges intersect any of the given ranges.
|
||||||
|
pub fn unfold_intersecting<T: ToOffset>(
|
||||||
&mut self,
|
&mut self,
|
||||||
ranges: impl IntoIterator<Item = Range<T>>,
|
ranges: impl IntoIterator<Item = Range<T>>,
|
||||||
inclusive: bool,
|
inclusive: bool,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
|
) {
|
||||||
|
self.update_fold_map(cx, |fold_map| {
|
||||||
|
fold_map.unfold_intersecting(ranges, inclusive)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_fold_map(
|
||||||
|
&mut self,
|
||||||
|
cx: &mut ModelContext<Self>,
|
||||||
|
callback: impl FnOnce(&mut FoldMapWriter) -> (FoldSnapshot, Vec<Edit<FoldOffset>>),
|
||||||
) {
|
) {
|
||||||
let snapshot = self.buffer.read(cx).snapshot(cx);
|
let snapshot = self.buffer.read(cx).snapshot(cx);
|
||||||
let edits = self.buffer_subscription.consume().into_inner();
|
let edits = self.buffer_subscription.consume().into_inner();
|
||||||
@@ -245,7 +252,7 @@ impl DisplayMap {
|
|||||||
.wrap_map
|
.wrap_map
|
||||||
.update(cx, |map, cx| map.sync(snapshot, edits, cx));
|
.update(cx, |map, cx| map.sync(snapshot, edits, cx));
|
||||||
self.block_map.read(snapshot, edits);
|
self.block_map.read(snapshot, edits);
|
||||||
let (snapshot, edits) = fold_map.unfold(ranges, inclusive);
|
let (snapshot, edits) = callback(&mut fold_map);
|
||||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
|
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
|
||||||
let (snapshot, edits) = self
|
let (snapshot, edits) = self
|
||||||
.wrap_map
|
.wrap_map
|
||||||
@@ -660,7 +667,7 @@ impl DisplaySnapshot {
|
|||||||
new_start..new_end
|
new_start..new_end
|
||||||
}
|
}
|
||||||
|
|
||||||
fn point_to_display_point(&self, point: MultiBufferPoint, bias: Bias) -> DisplayPoint {
|
pub fn point_to_display_point(&self, point: MultiBufferPoint, bias: Bias) -> DisplayPoint {
|
||||||
let inlay_point = self.inlay_snapshot.to_inlay_point(point);
|
let inlay_point = self.inlay_snapshot.to_inlay_point(point);
|
||||||
let fold_point = self.fold_snapshot.to_fold_point(inlay_point, bias);
|
let fold_point = self.fold_snapshot.to_fold_point(inlay_point, bias);
|
||||||
let tab_point = self.tab_snapshot.to_tab_point(fold_point);
|
let tab_point = self.tab_snapshot.to_tab_point(fold_point);
|
||||||
@@ -669,7 +676,7 @@ impl DisplaySnapshot {
|
|||||||
DisplayPoint(block_point)
|
DisplayPoint(block_point)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn display_point_to_point(&self, point: DisplayPoint, bias: Bias) -> Point {
|
pub fn display_point_to_point(&self, point: DisplayPoint, bias: Bias) -> Point {
|
||||||
self.inlay_snapshot
|
self.inlay_snapshot
|
||||||
.to_buffer_point(self.display_point_to_inlay_point(point, bias))
|
.to_buffer_point(self.display_point_to_inlay_point(point, bias))
|
||||||
}
|
}
|
||||||
@@ -691,7 +698,7 @@ impl DisplaySnapshot {
|
|||||||
|
|
||||||
fn display_point_to_inlay_point(&self, point: DisplayPoint, bias: Bias) -> InlayPoint {
|
fn display_point_to_inlay_point(&self, point: DisplayPoint, bias: Bias) -> InlayPoint {
|
||||||
let block_point = point.0;
|
let block_point = point.0;
|
||||||
let wrap_point = self.block_snapshot.to_wrap_point(block_point);
|
let wrap_point = self.block_snapshot.to_wrap_point(block_point, bias);
|
||||||
let tab_point = self.wrap_snapshot.to_tab_point(wrap_point);
|
let tab_point = self.wrap_snapshot.to_tab_point(wrap_point);
|
||||||
let fold_point = self.tab_snapshot.to_fold_point(tab_point, bias).0;
|
let fold_point = self.tab_snapshot.to_fold_point(tab_point, bias).0;
|
||||||
fold_point.to_inlay_point(&self.fold_snapshot)
|
fold_point.to_inlay_point(&self.fold_snapshot)
|
||||||
@@ -699,7 +706,7 @@ impl DisplaySnapshot {
|
|||||||
|
|
||||||
pub fn display_point_to_fold_point(&self, point: DisplayPoint, bias: Bias) -> FoldPoint {
|
pub fn display_point_to_fold_point(&self, point: DisplayPoint, bias: Bias) -> FoldPoint {
|
||||||
let block_point = point.0;
|
let block_point = point.0;
|
||||||
let wrap_point = self.block_snapshot.to_wrap_point(block_point);
|
let wrap_point = self.block_snapshot.to_wrap_point(block_point, bias);
|
||||||
let tab_point = self.wrap_snapshot.to_tab_point(wrap_point);
|
let tab_point = self.wrap_snapshot.to_tab_point(wrap_point);
|
||||||
self.tab_snapshot.to_fold_point(tab_point, bias).0
|
self.tab_snapshot.to_fold_point(tab_point, bias).0
|
||||||
}
|
}
|
||||||
@@ -990,7 +997,7 @@ impl DisplaySnapshot {
|
|||||||
pub fn soft_wrap_indent(&self, display_row: DisplayRow) -> Option<u32> {
|
pub fn soft_wrap_indent(&self, display_row: DisplayRow) -> Option<u32> {
|
||||||
let wrap_row = self
|
let wrap_row = self
|
||||||
.block_snapshot
|
.block_snapshot
|
||||||
.to_wrap_point(BlockPoint::new(display_row.0, 0))
|
.to_wrap_point(BlockPoint::new(display_row.0, 0), Bias::Left)
|
||||||
.row();
|
.row();
|
||||||
self.wrap_snapshot.soft_wrap_indent(wrap_row)
|
self.wrap_snapshot.soft_wrap_indent(wrap_row)
|
||||||
}
|
}
|
||||||
@@ -1172,7 +1179,7 @@ impl Sub for DisplayPoint {
|
|||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct DisplayRow(pub u32);
|
pub struct DisplayRow(pub u32);
|
||||||
|
|
||||||
impl Add for DisplayRow {
|
impl Add<DisplayRow> for DisplayRow {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
fn add(self, other: Self) -> Self::Output {
|
fn add(self, other: Self) -> Self::Output {
|
||||||
@@ -1180,7 +1187,15 @@ impl Add for DisplayRow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sub for DisplayRow {
|
impl Add<u32> for DisplayRow {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, other: u32) -> Self::Output {
|
||||||
|
DisplayRow(self.0 + other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub<DisplayRow> for DisplayRow {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
fn sub(self, other: Self) -> Self::Output {
|
fn sub(self, other: Self) -> Self::Output {
|
||||||
@@ -1188,6 +1203,14 @@ impl Sub for DisplayRow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Sub<u32> for DisplayRow {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn sub(self, other: u32) -> Self::Output {
|
||||||
|
DisplayRow(self.0 - other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl DisplayPoint {
|
impl DisplayPoint {
|
||||||
pub fn new(row: DisplayRow, column: u32) -> Self {
|
pub fn new(row: DisplayRow, column: u32) -> Self {
|
||||||
Self(BlockPoint(Point::new(row.0, column)))
|
Self(BlockPoint(Point::new(row.0, column)))
|
||||||
@@ -1222,7 +1245,7 @@ impl DisplayPoint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_offset(self, map: &DisplaySnapshot, bias: Bias) -> usize {
|
pub fn to_offset(self, map: &DisplaySnapshot, bias: Bias) -> usize {
|
||||||
let wrap_point = map.block_snapshot.to_wrap_point(self.0);
|
let wrap_point = map.block_snapshot.to_wrap_point(self.0, bias);
|
||||||
let tab_point = map.wrap_snapshot.to_tab_point(wrap_point);
|
let tab_point = map.wrap_snapshot.to_tab_point(wrap_point);
|
||||||
let fold_point = map.tab_snapshot.to_fold_point(tab_point, bias).0;
|
let fold_point = map.tab_snapshot.to_fold_point(tab_point, bias).0;
|
||||||
let inlay_point = fold_point.to_inlay_point(&map.fold_snapshot);
|
let inlay_point = fold_point.to_inlay_point(&map.fold_snapshot);
|
||||||
@@ -1426,7 +1449,7 @@ pub mod tests {
|
|||||||
if rng.gen() && fold_count > 0 {
|
if rng.gen() && fold_count > 0 {
|
||||||
log::info!("unfolding ranges: {:?}", ranges);
|
log::info!("unfolding ranges: {:?}", ranges);
|
||||||
map.update(cx, |map, cx| {
|
map.update(cx, |map, cx| {
|
||||||
map.unfold(ranges, true, cx);
|
map.unfold_intersecting(ranges, true, cx);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
log::info!("folding ranges: {:?}", ranges);
|
log::info!("folding ranges: {:?}", ranges);
|
||||||
@@ -2048,6 +2071,112 @@ pub mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_point_translation_with_replace_blocks(cx: &mut gpui::TestAppContext) {
|
||||||
|
cx.background_executor
|
||||||
|
.set_block_on_ticks(usize::MAX..=usize::MAX);
|
||||||
|
|
||||||
|
cx.update(|cx| init_test(cx, |_| {}));
|
||||||
|
|
||||||
|
let buffer = cx.update(|cx| MultiBuffer::build_simple("abcde\nfghij\nklmno\npqrst", cx));
|
||||||
|
let buffer_snapshot = buffer.read_with(cx, |buffer, cx| buffer.snapshot(cx));
|
||||||
|
let map = cx.new_model(|cx| {
|
||||||
|
DisplayMap::new(
|
||||||
|
buffer.clone(),
|
||||||
|
font("Courier"),
|
||||||
|
px(16.0),
|
||||||
|
None,
|
||||||
|
true,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
FoldPlaceholder::test(),
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let snapshot = map.update(cx, |map, cx| {
|
||||||
|
map.insert_blocks(
|
||||||
|
[BlockProperties {
|
||||||
|
placement: BlockPlacement::Replace(
|
||||||
|
buffer_snapshot.anchor_before(Point::new(1, 2))
|
||||||
|
..buffer_snapshot.anchor_after(Point::new(2, 3)),
|
||||||
|
),
|
||||||
|
height: 4,
|
||||||
|
style: BlockStyle::Fixed,
|
||||||
|
render: Box::new(|_| div().into_any()),
|
||||||
|
priority: 0,
|
||||||
|
}],
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
map.snapshot(cx)
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(snapshot.text(), "abcde\n\n\n\n\npqrst");
|
||||||
|
|
||||||
|
let point_to_display_points = [
|
||||||
|
(Point::new(1, 0), DisplayPoint::new(DisplayRow(1), 0)),
|
||||||
|
(Point::new(2, 0), DisplayPoint::new(DisplayRow(1), 0)),
|
||||||
|
(Point::new(3, 0), DisplayPoint::new(DisplayRow(5), 0)),
|
||||||
|
];
|
||||||
|
for (buffer_point, display_point) in point_to_display_points {
|
||||||
|
assert_eq!(
|
||||||
|
snapshot.point_to_display_point(buffer_point, Bias::Left),
|
||||||
|
display_point,
|
||||||
|
"point_to_display_point({:?}, Bias::Left)",
|
||||||
|
buffer_point
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
snapshot.point_to_display_point(buffer_point, Bias::Right),
|
||||||
|
display_point,
|
||||||
|
"point_to_display_point({:?}, Bias::Right)",
|
||||||
|
buffer_point
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let display_points_to_points = [
|
||||||
|
(
|
||||||
|
DisplayPoint::new(DisplayRow(1), 0),
|
||||||
|
Point::new(1, 0),
|
||||||
|
Point::new(2, 5),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
DisplayPoint::new(DisplayRow(2), 0),
|
||||||
|
Point::new(1, 0),
|
||||||
|
Point::new(2, 5),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
DisplayPoint::new(DisplayRow(3), 0),
|
||||||
|
Point::new(1, 0),
|
||||||
|
Point::new(2, 5),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
DisplayPoint::new(DisplayRow(4), 0),
|
||||||
|
Point::new(1, 0),
|
||||||
|
Point::new(2, 5),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
DisplayPoint::new(DisplayRow(5), 0),
|
||||||
|
Point::new(3, 0),
|
||||||
|
Point::new(3, 0),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
for (display_point, left_buffer_point, right_buffer_point) in display_points_to_points {
|
||||||
|
assert_eq!(
|
||||||
|
snapshot.display_point_to_point(display_point, Bias::Left),
|
||||||
|
left_buffer_point,
|
||||||
|
"display_point_to_point({:?}, Bias::Left)",
|
||||||
|
display_point
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
snapshot.display_point_to_point(display_point, Bias::Right),
|
||||||
|
right_buffer_point,
|
||||||
|
"display_point_to_point({:?}, Bias::Right)",
|
||||||
|
display_point
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// todo(linux) fails due to pixel differences in text rendering
|
// todo(linux) fails due to pixel differences in text rendering
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
|
|||||||
@@ -265,6 +265,7 @@ pub struct BlockContext<'a, 'b> {
|
|||||||
pub em_width: Pixels,
|
pub em_width: Pixels,
|
||||||
pub line_height: Pixels,
|
pub line_height: Pixels,
|
||||||
pub block_id: BlockId,
|
pub block_id: BlockId,
|
||||||
|
pub selected: bool,
|
||||||
pub editor_style: &'b EditorStyle,
|
pub editor_style: &'b EditorStyle,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1311,7 +1312,6 @@ impl BlockSnapshot {
|
|||||||
let (output_start_row, input_start_row) = cursor.start();
|
let (output_start_row, input_start_row) = cursor.start();
|
||||||
let (output_end_row, input_end_row) = cursor.end(&());
|
let (output_end_row, input_end_row) = cursor.end(&());
|
||||||
let output_start = Point::new(output_start_row.0, 0);
|
let output_start = Point::new(output_start_row.0, 0);
|
||||||
let output_end = Point::new(output_end_row.0, 0);
|
|
||||||
let input_start = Point::new(input_start_row.0, 0);
|
let input_start = Point::new(input_start_row.0, 0);
|
||||||
let input_end = Point::new(input_end_row.0, 0);
|
let input_end = Point::new(input_end_row.0, 0);
|
||||||
|
|
||||||
@@ -1319,10 +1319,10 @@ impl BlockSnapshot {
|
|||||||
Some(Block::Custom(block))
|
Some(Block::Custom(block))
|
||||||
if matches!(block.placement, BlockPlacement::Replace(_)) =>
|
if matches!(block.placement, BlockPlacement::Replace(_)) =>
|
||||||
{
|
{
|
||||||
if bias == Bias::Left {
|
if ((bias == Bias::Left || search_left) && output_start <= point.0)
|
||||||
|
|| (!search_left && output_start >= point.0)
|
||||||
|
{
|
||||||
return BlockPoint(output_start);
|
return BlockPoint(output_start);
|
||||||
} else {
|
|
||||||
return BlockPoint(Point::new(output_end.row - 1, 0));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
@@ -1364,12 +1364,7 @@ impl BlockSnapshot {
|
|||||||
cursor.seek(&WrapRow(wrap_point.row()), Bias::Right, &());
|
cursor.seek(&WrapRow(wrap_point.row()), Bias::Right, &());
|
||||||
if let Some(transform) = cursor.item() {
|
if let Some(transform) = cursor.item() {
|
||||||
if transform.block.is_some() {
|
if transform.block.is_some() {
|
||||||
let wrap_start = WrapPoint::new(cursor.start().0 .0, 0);
|
BlockPoint::new(cursor.start().1 .0, 0)
|
||||||
if wrap_start == wrap_point {
|
|
||||||
BlockPoint::new(cursor.start().1 .0, 0)
|
|
||||||
} else {
|
|
||||||
BlockPoint::new(cursor.end(&()).1 .0 - 1, 0)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let (input_start_row, output_start_row) = cursor.start();
|
let (input_start_row, output_start_row) = cursor.start();
|
||||||
let input_start = Point::new(input_start_row.0, 0);
|
let input_start = Point::new(input_start_row.0, 0);
|
||||||
@@ -1382,7 +1377,7 @@ impl BlockSnapshot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_wrap_point(&self, block_point: BlockPoint) -> WrapPoint {
|
pub fn to_wrap_point(&self, block_point: BlockPoint, bias: Bias) -> WrapPoint {
|
||||||
let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>(&());
|
let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>(&());
|
||||||
cursor.seek(&BlockRow(block_point.row), Bias::Right, &());
|
cursor.seek(&BlockRow(block_point.row), Bias::Right, &());
|
||||||
if let Some(transform) = cursor.item() {
|
if let Some(transform) = cursor.item() {
|
||||||
@@ -1391,7 +1386,9 @@ impl BlockSnapshot {
|
|||||||
if block.place_below() {
|
if block.place_below() {
|
||||||
let wrap_row = cursor.start().1 .0 - 1;
|
let wrap_row = cursor.start().1 .0 - 1;
|
||||||
WrapPoint::new(wrap_row, self.wrap_snapshot.line_len(wrap_row))
|
WrapPoint::new(wrap_row, self.wrap_snapshot.line_len(wrap_row))
|
||||||
} else if block.place_above() || block_point.row == cursor.start().0 .0 {
|
} else if block.place_above() {
|
||||||
|
WrapPoint::new(cursor.start().1 .0, 0)
|
||||||
|
} else if bias == Bias::Left {
|
||||||
WrapPoint::new(cursor.start().1 .0, 0)
|
WrapPoint::new(cursor.start().1 .0, 0)
|
||||||
} else {
|
} else {
|
||||||
let wrap_row = cursor.end(&()).1 .0 - 1;
|
let wrap_row = cursor.end(&()).1 .0 - 1;
|
||||||
@@ -1766,19 +1763,19 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
snapshot.to_wrap_point(BlockPoint::new(0, 3)),
|
snapshot.to_wrap_point(BlockPoint::new(0, 3), Bias::Left),
|
||||||
WrapPoint::new(0, 3)
|
WrapPoint::new(0, 3)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
snapshot.to_wrap_point(BlockPoint::new(1, 0)),
|
snapshot.to_wrap_point(BlockPoint::new(1, 0), Bias::Left),
|
||||||
WrapPoint::new(1, 0)
|
WrapPoint::new(1, 0)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
snapshot.to_wrap_point(BlockPoint::new(3, 0)),
|
snapshot.to_wrap_point(BlockPoint::new(3, 0), Bias::Left),
|
||||||
WrapPoint::new(1, 0)
|
WrapPoint::new(1, 0)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
snapshot.to_wrap_point(BlockPoint::new(7, 0)),
|
snapshot.to_wrap_point(BlockPoint::new(7, 0), Bias::Left),
|
||||||
WrapPoint::new(3, 3)
|
WrapPoint::new(3, 3)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -2616,10 +2613,15 @@ mod tests {
|
|||||||
|
|
||||||
// Ensure that conversion between block points and wrap points is stable.
|
// Ensure that conversion between block points and wrap points is stable.
|
||||||
for row in 0..=blocks_snapshot.wrap_snapshot.max_point().row() {
|
for row in 0..=blocks_snapshot.wrap_snapshot.max_point().row() {
|
||||||
let original_wrap_point = WrapPoint::new(row, 0);
|
let wrap_point = WrapPoint::new(row, 0);
|
||||||
let block_point = blocks_snapshot.to_block_point(original_wrap_point);
|
let block_point = blocks_snapshot.to_block_point(wrap_point);
|
||||||
let wrap_point = blocks_snapshot.to_wrap_point(block_point);
|
let left_wrap_point = blocks_snapshot.to_wrap_point(block_point, Bias::Left);
|
||||||
assert_eq!(blocks_snapshot.to_block_point(wrap_point), block_point);
|
let right_wrap_point = blocks_snapshot.to_wrap_point(block_point, Bias::Right);
|
||||||
|
assert_eq!(blocks_snapshot.to_block_point(left_wrap_point), block_point);
|
||||||
|
assert_eq!(
|
||||||
|
blocks_snapshot.to_block_point(right_wrap_point),
|
||||||
|
block_point
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut block_point = BlockPoint::new(0, 0);
|
let mut block_point = BlockPoint::new(0, 0);
|
||||||
@@ -2627,10 +2629,12 @@ mod tests {
|
|||||||
let left_point = blocks_snapshot.clip_point(block_point, Bias::Left);
|
let left_point = blocks_snapshot.clip_point(block_point, Bias::Left);
|
||||||
let left_buffer_point = blocks_snapshot.to_point(left_point, Bias::Left);
|
let left_buffer_point = blocks_snapshot.to_point(left_point, Bias::Left);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
blocks_snapshot.to_block_point(blocks_snapshot.to_wrap_point(left_point)),
|
blocks_snapshot
|
||||||
|
.to_block_point(blocks_snapshot.to_wrap_point(left_point, Bias::Left)),
|
||||||
left_point,
|
left_point,
|
||||||
"wrap point: {:?}",
|
"block point: {:?}, wrap point: {:?}",
|
||||||
blocks_snapshot.to_wrap_point(left_point)
|
block_point,
|
||||||
|
blocks_snapshot.to_wrap_point(left_point, Bias::Left)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
left_buffer_point,
|
left_buffer_point,
|
||||||
@@ -2642,10 +2646,12 @@ mod tests {
|
|||||||
let right_point = blocks_snapshot.clip_point(block_point, Bias::Right);
|
let right_point = blocks_snapshot.clip_point(block_point, Bias::Right);
|
||||||
let right_buffer_point = blocks_snapshot.to_point(right_point, Bias::Right);
|
let right_buffer_point = blocks_snapshot.to_point(right_point, Bias::Right);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
blocks_snapshot.to_block_point(blocks_snapshot.to_wrap_point(right_point)),
|
blocks_snapshot
|
||||||
|
.to_block_point(blocks_snapshot.to_wrap_point(right_point, Bias::Right)),
|
||||||
right_point,
|
right_point,
|
||||||
"wrap point: {:?}",
|
"block point: {:?}, wrap point: {:?}",
|
||||||
blocks_snapshot.to_wrap_point(right_point)
|
block_point,
|
||||||
|
blocks_snapshot.to_wrap_point(right_point, Bias::Right)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
right_buffer_point,
|
right_buffer_point,
|
||||||
@@ -2681,7 +2687,8 @@ mod tests {
|
|||||||
|
|
||||||
impl BlockSnapshot {
|
impl BlockSnapshot {
|
||||||
fn to_point(&self, point: BlockPoint, bias: Bias) -> Point {
|
fn to_point(&self, point: BlockPoint, bias: Bias) -> Point {
|
||||||
self.wrap_snapshot.to_point(self.to_wrap_point(point), bias)
|
self.wrap_snapshot
|
||||||
|
.to_point(self.to_wrap_point(point, bias), bias)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,14 @@ use gpui::{AnyElement, ElementId, WindowContext};
|
|||||||
use language::{Chunk, ChunkRenderer, Edit, Point, TextSummary};
|
use language::{Chunk, ChunkRenderer, Edit, Point, TextSummary};
|
||||||
use multi_buffer::{Anchor, AnchorRangeExt, MultiBufferRow, MultiBufferSnapshot, ToOffset};
|
use multi_buffer::{Anchor, AnchorRangeExt, MultiBufferRow, MultiBufferSnapshot, ToOffset};
|
||||||
use std::{
|
use std::{
|
||||||
|
any::TypeId,
|
||||||
cmp::{self, Ordering},
|
cmp::{self, Ordering},
|
||||||
fmt, iter,
|
fmt, iter,
|
||||||
ops::{Add, AddAssign, Deref, DerefMut, Range, Sub},
|
ops::{Add, AddAssign, Deref, DerefMut, Range, Sub},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
use sum_tree::{Bias, Cursor, FilterCursor, SumTree, Summary};
|
use sum_tree::{Bias, Cursor, FilterCursor, SumTree, Summary};
|
||||||
|
use ui::IntoElement as _;
|
||||||
use util::post_inc;
|
use util::post_inc;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -22,17 +24,29 @@ pub struct FoldPlaceholder {
|
|||||||
pub constrain_width: bool,
|
pub constrain_width: bool,
|
||||||
/// If true, merges the fold with an adjacent one.
|
/// If true, merges the fold with an adjacent one.
|
||||||
pub merge_adjacent: bool,
|
pub merge_adjacent: bool,
|
||||||
|
/// Category of the fold. Useful for carefully removing from overlapping folds.
|
||||||
|
pub type_tag: Option<TypeId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for FoldPlaceholder {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
render: Arc::new(|_, _, _| gpui::Empty.into_any_element()),
|
||||||
|
constrain_width: true,
|
||||||
|
merge_adjacent: true,
|
||||||
|
type_tag: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FoldPlaceholder {
|
impl FoldPlaceholder {
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
pub fn test() -> Self {
|
pub fn test() -> Self {
|
||||||
use gpui::IntoElement;
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
render: Arc::new(|_id, _range, _cx| gpui::Empty.into_any_element()),
|
render: Arc::new(|_id, _range, _cx| gpui::Empty.into_any_element()),
|
||||||
constrain_width: true,
|
constrain_width: true,
|
||||||
merge_adjacent: true,
|
merge_adjacent: true,
|
||||||
|
type_tag: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,9 +187,34 @@ impl<'a> FoldMapWriter<'a> {
|
|||||||
(self.0.snapshot.clone(), edits)
|
(self.0.snapshot.clone(), edits)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn unfold<T: ToOffset>(
|
/// Removes any folds with the given ranges.
|
||||||
|
pub(crate) fn remove_folds<T: ToOffset>(
|
||||||
&mut self,
|
&mut self,
|
||||||
ranges: impl IntoIterator<Item = Range<T>>,
|
ranges: impl IntoIterator<Item = Range<T>>,
|
||||||
|
type_id: TypeId,
|
||||||
|
) -> (FoldSnapshot, Vec<FoldEdit>) {
|
||||||
|
self.remove_folds_with(
|
||||||
|
ranges,
|
||||||
|
|fold| fold.placeholder.type_tag == Some(type_id),
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes any folds whose ranges intersect the given ranges.
|
||||||
|
pub(crate) fn unfold_intersecting<T: ToOffset>(
|
||||||
|
&mut self,
|
||||||
|
ranges: impl IntoIterator<Item = Range<T>>,
|
||||||
|
inclusive: bool,
|
||||||
|
) -> (FoldSnapshot, Vec<FoldEdit>) {
|
||||||
|
self.remove_folds_with(ranges, |_| true, inclusive)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes any folds that intersect the given ranges and for which the given predicate
|
||||||
|
/// returns true.
|
||||||
|
fn remove_folds_with<T: ToOffset>(
|
||||||
|
&mut self,
|
||||||
|
ranges: impl IntoIterator<Item = Range<T>>,
|
||||||
|
should_unfold: impl Fn(&Fold) -> bool,
|
||||||
inclusive: bool,
|
inclusive: bool,
|
||||||
) -> (FoldSnapshot, Vec<FoldEdit>) {
|
) -> (FoldSnapshot, Vec<FoldEdit>) {
|
||||||
let mut edits = Vec::new();
|
let mut edits = Vec::new();
|
||||||
@@ -183,21 +222,23 @@ impl<'a> FoldMapWriter<'a> {
|
|||||||
let snapshot = self.0.snapshot.inlay_snapshot.clone();
|
let snapshot = self.0.snapshot.inlay_snapshot.clone();
|
||||||
let buffer = &snapshot.buffer;
|
let buffer = &snapshot.buffer;
|
||||||
for range in ranges.into_iter() {
|
for range in ranges.into_iter() {
|
||||||
// Remove intersecting folds and add their ranges to edits that are passed to sync.
|
let range = range.start.to_offset(buffer)..range.end.to_offset(buffer);
|
||||||
let mut folds_cursor =
|
let mut folds_cursor =
|
||||||
intersecting_folds(&snapshot, &self.0.snapshot.folds, range, inclusive);
|
intersecting_folds(&snapshot, &self.0.snapshot.folds, range.clone(), inclusive);
|
||||||
while let Some(fold) = folds_cursor.item() {
|
while let Some(fold) = folds_cursor.item() {
|
||||||
let offset_range =
|
let offset_range =
|
||||||
fold.range.start.to_offset(buffer)..fold.range.end.to_offset(buffer);
|
fold.range.start.to_offset(buffer)..fold.range.end.to_offset(buffer);
|
||||||
if offset_range.end > offset_range.start {
|
if should_unfold(fold) {
|
||||||
let inlay_range = snapshot.to_inlay_offset(offset_range.start)
|
if offset_range.end > offset_range.start {
|
||||||
..snapshot.to_inlay_offset(offset_range.end);
|
let inlay_range = snapshot.to_inlay_offset(offset_range.start)
|
||||||
edits.push(InlayEdit {
|
..snapshot.to_inlay_offset(offset_range.end);
|
||||||
old: inlay_range.clone(),
|
edits.push(InlayEdit {
|
||||||
new: inlay_range,
|
old: inlay_range.clone(),
|
||||||
});
|
new: inlay_range,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fold_ixs_to_delete.push(*folds_cursor.start());
|
||||||
}
|
}
|
||||||
fold_ixs_to_delete.push(*folds_cursor.start());
|
|
||||||
folds_cursor.next(buffer);
|
folds_cursor.next(buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -665,6 +706,8 @@ impl FoldSnapshot {
|
|||||||
where
|
where
|
||||||
T: ToOffset,
|
T: ToOffset,
|
||||||
{
|
{
|
||||||
|
let buffer = &self.inlay_snapshot.buffer;
|
||||||
|
let range = range.start.to_offset(buffer)..range.end.to_offset(buffer);
|
||||||
let mut folds = intersecting_folds(&self.inlay_snapshot, &self.folds, range, false);
|
let mut folds = intersecting_folds(&self.inlay_snapshot, &self.folds, range, false);
|
||||||
iter::from_fn(move || {
|
iter::from_fn(move || {
|
||||||
let item = folds.item();
|
let item = folds.item();
|
||||||
@@ -821,15 +864,12 @@ fn push_isomorphic(transforms: &mut SumTree<Transform>, summary: TextSummary) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn intersecting_folds<'a, T>(
|
fn intersecting_folds<'a>(
|
||||||
inlay_snapshot: &'a InlaySnapshot,
|
inlay_snapshot: &'a InlaySnapshot,
|
||||||
folds: &'a SumTree<Fold>,
|
folds: &'a SumTree<Fold>,
|
||||||
range: Range<T>,
|
range: Range<usize>,
|
||||||
inclusive: bool,
|
inclusive: bool,
|
||||||
) -> FilterCursor<'a, impl 'a + FnMut(&FoldSummary) -> bool, Fold, usize>
|
) -> FilterCursor<'a, impl 'a + FnMut(&FoldSummary) -> bool, Fold, usize> {
|
||||||
where
|
|
||||||
T: ToOffset,
|
|
||||||
{
|
|
||||||
let buffer = &inlay_snapshot.buffer;
|
let buffer = &inlay_snapshot.buffer;
|
||||||
let start = buffer.anchor_before(range.start.to_offset(buffer));
|
let start = buffer.anchor_before(range.start.to_offset(buffer));
|
||||||
let end = buffer.anchor_after(range.end.to_offset(buffer));
|
let end = buffer.anchor_after(range.end.to_offset(buffer));
|
||||||
@@ -1419,12 +1459,12 @@ mod tests {
|
|||||||
assert_eq!(snapshot4.text(), "123a⋯c123456eee");
|
assert_eq!(snapshot4.text(), "123a⋯c123456eee");
|
||||||
|
|
||||||
let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]);
|
let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]);
|
||||||
writer.unfold(Some(Point::new(0, 4)..Point::new(0, 4)), false);
|
writer.unfold_intersecting(Some(Point::new(0, 4)..Point::new(0, 4)), false);
|
||||||
let (snapshot5, _) = map.read(inlay_snapshot.clone(), vec![]);
|
let (snapshot5, _) = map.read(inlay_snapshot.clone(), vec![]);
|
||||||
assert_eq!(snapshot5.text(), "123a⋯c123456eee");
|
assert_eq!(snapshot5.text(), "123a⋯c123456eee");
|
||||||
|
|
||||||
let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]);
|
let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]);
|
||||||
writer.unfold(Some(Point::new(0, 4)..Point::new(0, 4)), true);
|
writer.unfold_intersecting(Some(Point::new(0, 4)..Point::new(0, 4)), true);
|
||||||
let (snapshot6, _) = map.read(inlay_snapshot, vec![]);
|
let (snapshot6, _) = map.read(inlay_snapshot, vec![]);
|
||||||
assert_eq!(snapshot6.text(), "123aaaaa\nbbbbbb\nccc123456eee");
|
assert_eq!(snapshot6.text(), "123aaaaa\nbbbbbb\nccc123456eee");
|
||||||
}
|
}
|
||||||
@@ -1913,7 +1953,7 @@ mod tests {
|
|||||||
log::info!("unfolding {:?} (inclusive: {})", to_unfold, inclusive);
|
log::info!("unfolding {:?} (inclusive: {})", to_unfold, inclusive);
|
||||||
let (mut writer, snapshot, edits) = self.write(inlay_snapshot, vec![]);
|
let (mut writer, snapshot, edits) = self.write(inlay_snapshot, vec![]);
|
||||||
snapshot_edits.push((snapshot, edits));
|
snapshot_edits.push((snapshot, edits));
|
||||||
let (snapshot, edits) = writer.unfold(to_unfold, inclusive);
|
let (snapshot, edits) = writer.unfold_intersecting(to_unfold, inclusive);
|
||||||
snapshot_edits.push((snapshot, edits));
|
snapshot_edits.push((snapshot, edits));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -169,8 +169,12 @@ fn test_undo_redo_with_selection_restoration(cx: &mut TestAppContext) {
|
|||||||
init_test(cx, |_| {});
|
init_test(cx, |_| {});
|
||||||
|
|
||||||
let mut now = Instant::now();
|
let mut now = Instant::now();
|
||||||
let buffer = cx.new_model(|cx| language::Buffer::local("123456", cx));
|
let group_interval = Duration::from_millis(1);
|
||||||
let group_interval = buffer.update(cx, |buffer, _| buffer.transaction_group_interval());
|
let buffer = cx.new_model(|cx| {
|
||||||
|
let mut buf = language::Buffer::local("123456", cx);
|
||||||
|
buf.set_group_interval(group_interval);
|
||||||
|
buf
|
||||||
|
});
|
||||||
let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
|
let buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer, cx));
|
||||||
let editor = cx.add_window(|cx| build_editor(buffer.clone(), cx));
|
let editor = cx.add_window(|cx| build_editor(buffer.clone(), cx));
|
||||||
|
|
||||||
@@ -3989,6 +3993,76 @@ fn test_move_line_up_down_with_blocks(cx: &mut TestAppContext) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_selections_and_replace_blocks(cx: &mut TestAppContext) {
|
||||||
|
init_test(cx, |_| {});
|
||||||
|
|
||||||
|
let mut cx = EditorTestContext::new(cx).await;
|
||||||
|
cx.set_state(
|
||||||
|
&"
|
||||||
|
ˇzero
|
||||||
|
one
|
||||||
|
two
|
||||||
|
three
|
||||||
|
four
|
||||||
|
five
|
||||||
|
"
|
||||||
|
.unindent(),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create a four-line block that replaces three lines of text.
|
||||||
|
cx.update_editor(|editor, cx| {
|
||||||
|
let snapshot = editor.snapshot(cx);
|
||||||
|
let snapshot = &snapshot.buffer_snapshot;
|
||||||
|
let placement = BlockPlacement::Replace(
|
||||||
|
snapshot.anchor_after(Point::new(1, 0))..snapshot.anchor_after(Point::new(3, 0)),
|
||||||
|
);
|
||||||
|
editor.insert_blocks(
|
||||||
|
[BlockProperties {
|
||||||
|
placement,
|
||||||
|
height: 4,
|
||||||
|
style: BlockStyle::Sticky,
|
||||||
|
render: Box::new(|_| gpui::div().into_any_element()),
|
||||||
|
priority: 0,
|
||||||
|
}],
|
||||||
|
None,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Move down so that the cursor touches the block.
|
||||||
|
cx.update_editor(|editor, cx| {
|
||||||
|
editor.move_down(&Default::default(), cx);
|
||||||
|
});
|
||||||
|
cx.assert_editor_state(
|
||||||
|
&"
|
||||||
|
zero
|
||||||
|
«one
|
||||||
|
two
|
||||||
|
threeˇ»
|
||||||
|
four
|
||||||
|
five
|
||||||
|
"
|
||||||
|
.unindent(),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Move down past the block.
|
||||||
|
cx.update_editor(|editor, cx| {
|
||||||
|
editor.move_down(&Default::default(), cx);
|
||||||
|
});
|
||||||
|
cx.assert_editor_state(
|
||||||
|
&"
|
||||||
|
zero
|
||||||
|
one
|
||||||
|
two
|
||||||
|
three
|
||||||
|
ˇfour
|
||||||
|
five
|
||||||
|
"
|
||||||
|
.unindent(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
fn test_transpose(cx: &mut TestAppContext) {
|
fn test_transpose(cx: &mut TestAppContext) {
|
||||||
init_test(cx, |_| {});
|
init_test(cx, |_| {});
|
||||||
@@ -4089,21 +4163,48 @@ async fn test_rewrap(cx: &mut TestAppContext) {
|
|||||||
|
|
||||||
let mut cx = EditorTestContext::new(cx).await;
|
let mut cx = EditorTestContext::new(cx).await;
|
||||||
|
|
||||||
{
|
let language_with_c_comments = Arc::new(Language::new(
|
||||||
let language = Arc::new(Language::new(
|
LanguageConfig {
|
||||||
LanguageConfig {
|
line_comments: vec!["// ".into()],
|
||||||
line_comments: vec!["// ".into()],
|
..LanguageConfig::default()
|
||||||
..LanguageConfig::default()
|
},
|
||||||
},
|
None,
|
||||||
None,
|
));
|
||||||
));
|
let language_with_pound_comments = Arc::new(Language::new(
|
||||||
cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx));
|
LanguageConfig {
|
||||||
|
line_comments: vec!["# ".into()],
|
||||||
|
..LanguageConfig::default()
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
));
|
||||||
|
let markdown_language = Arc::new(Language::new(
|
||||||
|
LanguageConfig {
|
||||||
|
name: "Markdown".into(),
|
||||||
|
..LanguageConfig::default()
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
));
|
||||||
|
let language_with_doc_comments = Arc::new(Language::new(
|
||||||
|
LanguageConfig {
|
||||||
|
line_comments: vec!["// ".into(), "/// ".into()],
|
||||||
|
..LanguageConfig::default()
|
||||||
|
},
|
||||||
|
Some(tree_sitter_rust::LANGUAGE.into()),
|
||||||
|
));
|
||||||
|
|
||||||
let unwrapped_text = indoc! {"
|
let plaintext_language = Arc::new(Language::new(
|
||||||
|
LanguageConfig {
|
||||||
|
name: "Plain Text".into(),
|
||||||
|
..LanguageConfig::default()
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
));
|
||||||
|
|
||||||
|
assert_rewrap(
|
||||||
|
indoc! {"
|
||||||
// ˇLorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit purus, a ornare lacus gravida vitae. Proin consectetur felis vel purus auctor, eu lacinia sapien scelerisque. Vivamus sit amet neque et quam tincidunt hendrerit. Praesent semper egestas tellus id dignissim. Pellentesque odio lectus, iaculis ac volutpat et, blandit quis urna. Sed vestibulum nisi sit amet nisl venenatis tempus. Donec molestie blandit quam, et porta nunc laoreet in. Integer sit amet scelerisque nisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras egestas porta metus, eu viverra ipsum efficitur quis. Donec luctus eros turpis, id vulputate turpis porttitor id. Aliquam id accumsan eros.
|
// ˇLorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit purus, a ornare lacus gravida vitae. Proin consectetur felis vel purus auctor, eu lacinia sapien scelerisque. Vivamus sit amet neque et quam tincidunt hendrerit. Praesent semper egestas tellus id dignissim. Pellentesque odio lectus, iaculis ac volutpat et, blandit quis urna. Sed vestibulum nisi sit amet nisl venenatis tempus. Donec molestie blandit quam, et porta nunc laoreet in. Integer sit amet scelerisque nisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras egestas porta metus, eu viverra ipsum efficitur quis. Donec luctus eros turpis, id vulputate turpis porttitor id. Aliquam id accumsan eros.
|
||||||
"};
|
"},
|
||||||
|
indoc! {"
|
||||||
let wrapped_text = indoc! {"
|
|
||||||
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit
|
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit
|
||||||
// purus, a ornare lacus gravida vitae. Proin consectetur felis vel purus
|
// purus, a ornare lacus gravida vitae. Proin consectetur felis vel purus
|
||||||
// auctor, eu lacinia sapien scelerisque. Vivamus sit amet neque et quam
|
// auctor, eu lacinia sapien scelerisque. Vivamus sit amet neque et quam
|
||||||
@@ -4114,29 +4215,17 @@ async fn test_rewrap(cx: &mut TestAppContext) {
|
|||||||
// dolor sit amet, consectetur adipiscing elit. Cras egestas porta metus, eu
|
// dolor sit amet, consectetur adipiscing elit. Cras egestas porta metus, eu
|
||||||
// viverra ipsum efficitur quis. Donec luctus eros turpis, id vulputate turpis
|
// viverra ipsum efficitur quis. Donec luctus eros turpis, id vulputate turpis
|
||||||
// porttitor id. Aliquam id accumsan eros.ˇ
|
// porttitor id. Aliquam id accumsan eros.ˇ
|
||||||
"};
|
"},
|
||||||
|
language_with_c_comments.clone(),
|
||||||
cx.set_state(unwrapped_text);
|
&mut cx,
|
||||||
cx.update_editor(|e, cx| e.rewrap(&Rewrap, cx));
|
);
|
||||||
cx.assert_editor_state(wrapped_text);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that rewrapping works inside of a selection
|
// Test that rewrapping works inside of a selection
|
||||||
{
|
assert_rewrap(
|
||||||
let language = Arc::new(Language::new(
|
indoc! {"
|
||||||
LanguageConfig {
|
|
||||||
line_comments: vec!["// ".into()],
|
|
||||||
..LanguageConfig::default()
|
|
||||||
},
|
|
||||||
None,
|
|
||||||
));
|
|
||||||
cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx));
|
|
||||||
|
|
||||||
let unwrapped_text = indoc! {"
|
|
||||||
«// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit purus, a ornare lacus gravida vitae. Proin consectetur felis vel purus auctor, eu lacinia sapien scelerisque. Vivamus sit amet neque et quam tincidunt hendrerit. Praesent semper egestas tellus id dignissim. Pellentesque odio lectus, iaculis ac volutpat et, blandit quis urna. Sed vestibulum nisi sit amet nisl venenatis tempus. Donec molestie blandit quam, et porta nunc laoreet in. Integer sit amet scelerisque nisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras egestas porta metus, eu viverra ipsum efficitur quis. Donec luctus eros turpis, id vulputate turpis porttitor id. Aliquam id accumsan eros.ˇ»
|
«// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit purus, a ornare lacus gravida vitae. Proin consectetur felis vel purus auctor, eu lacinia sapien scelerisque. Vivamus sit amet neque et quam tincidunt hendrerit. Praesent semper egestas tellus id dignissim. Pellentesque odio lectus, iaculis ac volutpat et, blandit quis urna. Sed vestibulum nisi sit amet nisl venenatis tempus. Donec molestie blandit quam, et porta nunc laoreet in. Integer sit amet scelerisque nisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras egestas porta metus, eu viverra ipsum efficitur quis. Donec luctus eros turpis, id vulputate turpis porttitor id. Aliquam id accumsan eros.ˇ»
|
||||||
"};
|
"},
|
||||||
|
indoc! {"
|
||||||
let wrapped_text = indoc! {"
|
|
||||||
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit
|
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit
|
||||||
// purus, a ornare lacus gravida vitae. Proin consectetur felis vel purus
|
// purus, a ornare lacus gravida vitae. Proin consectetur felis vel purus
|
||||||
// auctor, eu lacinia sapien scelerisque. Vivamus sit amet neque et quam
|
// auctor, eu lacinia sapien scelerisque. Vivamus sit amet neque et quam
|
||||||
@@ -4147,32 +4236,20 @@ async fn test_rewrap(cx: &mut TestAppContext) {
|
|||||||
// dolor sit amet, consectetur adipiscing elit. Cras egestas porta metus, eu
|
// dolor sit amet, consectetur adipiscing elit. Cras egestas porta metus, eu
|
||||||
// viverra ipsum efficitur quis. Donec luctus eros turpis, id vulputate turpis
|
// viverra ipsum efficitur quis. Donec luctus eros turpis, id vulputate turpis
|
||||||
// porttitor id. Aliquam id accumsan eros.ˇ
|
// porttitor id. Aliquam id accumsan eros.ˇ
|
||||||
"};
|
"},
|
||||||
|
language_with_c_comments.clone(),
|
||||||
cx.set_state(unwrapped_text);
|
&mut cx,
|
||||||
cx.update_editor(|e, cx| e.rewrap(&Rewrap, cx));
|
);
|
||||||
cx.assert_editor_state(wrapped_text);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that cursors that expand to the same region are collapsed.
|
// Test that cursors that expand to the same region are collapsed.
|
||||||
{
|
assert_rewrap(
|
||||||
let language = Arc::new(Language::new(
|
indoc! {"
|
||||||
LanguageConfig {
|
|
||||||
line_comments: vec!["// ".into()],
|
|
||||||
..LanguageConfig::default()
|
|
||||||
},
|
|
||||||
None,
|
|
||||||
));
|
|
||||||
cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx));
|
|
||||||
|
|
||||||
let unwrapped_text = indoc! {"
|
|
||||||
// ˇLorem ipsum dolor sit amet, consectetur adipiscing elit.
|
// ˇLorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
// ˇVivamus mollis elit purus, a ornare lacus gravida vitae. Proin consectetur felis vel purus auctor, eu lacinia sapien scelerisque.
|
// ˇVivamus mollis elit purus, a ornare lacus gravida vitae. Proin consectetur felis vel purus auctor, eu lacinia sapien scelerisque.
|
||||||
// ˇVivamus sit amet neque et quam tincidunt hendrerit. Praesent semper egestas tellus id dignissim. Pellentesque odio lectus, iaculis ac volutpat et,
|
// ˇVivamus sit amet neque et quam tincidunt hendrerit. Praesent semper egestas tellus id dignissim. Pellentesque odio lectus, iaculis ac volutpat et,
|
||||||
// ˇblandit quis urna. Sed vestibulum nisi sit amet nisl venenatis tempus. Donec molestie blandit quam, et porta nunc laoreet in. Integer sit amet scelerisque nisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras egestas porta metus, eu viverra ipsum efficitur quis. Donec luctus eros turpis, id vulputate turpis porttitor id. Aliquam id accumsan eros.
|
// ˇblandit quis urna. Sed vestibulum nisi sit amet nisl venenatis tempus. Donec molestie blandit quam, et porta nunc laoreet in. Integer sit amet scelerisque nisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras egestas porta metus, eu viverra ipsum efficitur quis. Donec luctus eros turpis, id vulputate turpis porttitor id. Aliquam id accumsan eros.
|
||||||
"};
|
"},
|
||||||
|
indoc! {"
|
||||||
let wrapped_text = indoc! {"
|
|
||||||
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit
|
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit
|
||||||
// purus, a ornare lacus gravida vitae. Proin consectetur felis vel purus
|
// purus, a ornare lacus gravida vitae. Proin consectetur felis vel purus
|
||||||
// auctor, eu lacinia sapien scelerisque. Vivamus sit amet neque et quam
|
// auctor, eu lacinia sapien scelerisque. Vivamus sit amet neque et quam
|
||||||
@@ -4182,37 +4259,25 @@ async fn test_rewrap(cx: &mut TestAppContext) {
|
|||||||
// et porta nunc laoreet in. Integer sit amet scelerisque nisi. Lorem ipsum
|
// et porta nunc laoreet in. Integer sit amet scelerisque nisi. Lorem ipsum
|
||||||
// dolor sit amet, consectetur adipiscing elit. Cras egestas porta metus, eu
|
// dolor sit amet, consectetur adipiscing elit. Cras egestas porta metus, eu
|
||||||
// viverra ipsum efficitur quis. Donec luctus eros turpis, id vulputate turpis
|
// viverra ipsum efficitur quis. Donec luctus eros turpis, id vulputate turpis
|
||||||
// porttitor id. Aliquam id accumsan eros.ˇˇˇˇ
|
// porttitor id. Aliquam id accumsan eros.ˇ
|
||||||
"};
|
"},
|
||||||
|
language_with_c_comments.clone(),
|
||||||
cx.set_state(unwrapped_text);
|
&mut cx,
|
||||||
cx.update_editor(|e, cx| e.rewrap(&Rewrap, cx));
|
);
|
||||||
cx.assert_editor_state(wrapped_text);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that non-contiguous selections are treated separately.
|
// Test that non-contiguous selections are treated separately.
|
||||||
{
|
assert_rewrap(
|
||||||
let language = Arc::new(Language::new(
|
indoc! {"
|
||||||
LanguageConfig {
|
|
||||||
line_comments: vec!["// ".into()],
|
|
||||||
..LanguageConfig::default()
|
|
||||||
},
|
|
||||||
None,
|
|
||||||
));
|
|
||||||
cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx));
|
|
||||||
|
|
||||||
let unwrapped_text = indoc! {"
|
|
||||||
// ˇLorem ipsum dolor sit amet, consectetur adipiscing elit.
|
// ˇLorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
// ˇVivamus mollis elit purus, a ornare lacus gravida vitae. Proin consectetur felis vel purus auctor, eu lacinia sapien scelerisque.
|
// ˇVivamus mollis elit purus, a ornare lacus gravida vitae. Proin consectetur felis vel purus auctor, eu lacinia sapien scelerisque.
|
||||||
//
|
//
|
||||||
// ˇVivamus sit amet neque et quam tincidunt hendrerit. Praesent semper egestas tellus id dignissim. Pellentesque odio lectus, iaculis ac volutpat et,
|
// ˇVivamus sit amet neque et quam tincidunt hendrerit. Praesent semper egestas tellus id dignissim. Pellentesque odio lectus, iaculis ac volutpat et,
|
||||||
// ˇblandit quis urna. Sed vestibulum nisi sit amet nisl venenatis tempus. Donec molestie blandit quam, et porta nunc laoreet in. Integer sit amet scelerisque nisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras egestas porta metus, eu viverra ipsum efficitur quis. Donec luctus eros turpis, id vulputate turpis porttitor id. Aliquam id accumsan eros.
|
// ˇblandit quis urna. Sed vestibulum nisi sit amet nisl venenatis tempus. Donec molestie blandit quam, et porta nunc laoreet in. Integer sit amet scelerisque nisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras egestas porta metus, eu viverra ipsum efficitur quis. Donec luctus eros turpis, id vulputate turpis porttitor id. Aliquam id accumsan eros.
|
||||||
"};
|
"},
|
||||||
|
indoc! {"
|
||||||
let wrapped_text = indoc! {"
|
|
||||||
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit
|
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit
|
||||||
// purus, a ornare lacus gravida vitae. Proin consectetur felis vel purus
|
// purus, a ornare lacus gravida vitae. Proin consectetur felis vel purus
|
||||||
// auctor, eu lacinia sapien scelerisque.ˇˇ
|
// auctor, eu lacinia sapien scelerisque.ˇ
|
||||||
//
|
//
|
||||||
// Vivamus sit amet neque et quam tincidunt hendrerit. Praesent semper egestas
|
// Vivamus sit amet neque et quam tincidunt hendrerit. Praesent semper egestas
|
||||||
// tellus id dignissim. Pellentesque odio lectus, iaculis ac volutpat et,
|
// tellus id dignissim. Pellentesque odio lectus, iaculis ac volutpat et,
|
||||||
@@ -4220,30 +4285,18 @@ async fn test_rewrap(cx: &mut TestAppContext) {
|
|||||||
// molestie blandit quam, et porta nunc laoreet in. Integer sit amet scelerisque
|
// molestie blandit quam, et porta nunc laoreet in. Integer sit amet scelerisque
|
||||||
// nisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras egestas
|
// nisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras egestas
|
||||||
// porta metus, eu viverra ipsum efficitur quis. Donec luctus eros turpis, id
|
// porta metus, eu viverra ipsum efficitur quis. Donec luctus eros turpis, id
|
||||||
// vulputate turpis porttitor id. Aliquam id accumsan eros.ˇˇ
|
// vulputate turpis porttitor id. Aliquam id accumsan eros.ˇ
|
||||||
"};
|
"},
|
||||||
|
language_with_c_comments.clone(),
|
||||||
cx.set_state(unwrapped_text);
|
&mut cx,
|
||||||
cx.update_editor(|e, cx| e.rewrap(&Rewrap, cx));
|
);
|
||||||
cx.assert_editor_state(wrapped_text);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that different comment prefixes are supported.
|
// Test that different comment prefixes are supported.
|
||||||
{
|
assert_rewrap(
|
||||||
let language = Arc::new(Language::new(
|
indoc! {"
|
||||||
LanguageConfig {
|
|
||||||
line_comments: vec!["# ".into()],
|
|
||||||
..LanguageConfig::default()
|
|
||||||
},
|
|
||||||
None,
|
|
||||||
));
|
|
||||||
cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx));
|
|
||||||
|
|
||||||
let unwrapped_text = indoc! {"
|
|
||||||
# ˇLorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit purus, a ornare lacus gravida vitae. Proin consectetur felis vel purus auctor, eu lacinia sapien scelerisque. Vivamus sit amet neque et quam tincidunt hendrerit. Praesent semper egestas tellus id dignissim. Pellentesque odio lectus, iaculis ac volutpat et, blandit quis urna. Sed vestibulum nisi sit amet nisl venenatis tempus. Donec molestie blandit quam, et porta nunc laoreet in. Integer sit amet scelerisque nisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras egestas porta metus, eu viverra ipsum efficitur quis. Donec luctus eros turpis, id vulputate turpis porttitor id. Aliquam id accumsan eros.
|
# ˇLorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit purus, a ornare lacus gravida vitae. Proin consectetur felis vel purus auctor, eu lacinia sapien scelerisque. Vivamus sit amet neque et quam tincidunt hendrerit. Praesent semper egestas tellus id dignissim. Pellentesque odio lectus, iaculis ac volutpat et, blandit quis urna. Sed vestibulum nisi sit amet nisl venenatis tempus. Donec molestie blandit quam, et porta nunc laoreet in. Integer sit amet scelerisque nisi. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras egestas porta metus, eu viverra ipsum efficitur quis. Donec luctus eros turpis, id vulputate turpis porttitor id. Aliquam id accumsan eros.
|
||||||
"};
|
"},
|
||||||
|
indoc! {"
|
||||||
let wrapped_text = indoc! {"
|
|
||||||
# Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit
|
# Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit
|
||||||
# purus, a ornare lacus gravida vitae. Proin consectetur felis vel purus auctor,
|
# purus, a ornare lacus gravida vitae. Proin consectetur felis vel purus auctor,
|
||||||
# eu lacinia sapien scelerisque. Vivamus sit amet neque et quam tincidunt
|
# eu lacinia sapien scelerisque. Vivamus sit amet neque et quam tincidunt
|
||||||
@@ -4254,63 +4307,39 @@ async fn test_rewrap(cx: &mut TestAppContext) {
|
|||||||
# adipiscing elit. Cras egestas porta metus, eu viverra ipsum efficitur quis.
|
# adipiscing elit. Cras egestas porta metus, eu viverra ipsum efficitur quis.
|
||||||
# Donec luctus eros turpis, id vulputate turpis porttitor id. Aliquam id
|
# Donec luctus eros turpis, id vulputate turpis porttitor id. Aliquam id
|
||||||
# accumsan eros.ˇ
|
# accumsan eros.ˇ
|
||||||
"};
|
"},
|
||||||
|
language_with_pound_comments.clone(),
|
||||||
cx.set_state(unwrapped_text);
|
&mut cx,
|
||||||
cx.update_editor(|e, cx| e.rewrap(&Rewrap, cx));
|
);
|
||||||
cx.assert_editor_state(wrapped_text);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that rewrapping is ignored outside of comments in most languages.
|
// Test that rewrapping is ignored outside of comments in most languages.
|
||||||
{
|
assert_rewrap(
|
||||||
let language = Arc::new(Language::new(
|
indoc! {"
|
||||||
LanguageConfig {
|
|
||||||
line_comments: vec!["// ".into(), "/// ".into()],
|
|
||||||
..LanguageConfig::default()
|
|
||||||
},
|
|
||||||
Some(tree_sitter_rust::LANGUAGE.into()),
|
|
||||||
));
|
|
||||||
cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx));
|
|
||||||
|
|
||||||
let unwrapped_text = indoc! {"
|
|
||||||
/// Adds two numbers.
|
/// Adds two numbers.
|
||||||
/// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit purus, a ornare lacus gravida vitae.ˇ
|
/// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit purus, a ornare lacus gravida vitae.ˇ
|
||||||
fn add(a: u32, b: u32) -> u32 {
|
fn add(a: u32, b: u32) -> u32 {
|
||||||
a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + bˇ
|
a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + bˇ
|
||||||
}
|
}
|
||||||
"};
|
"},
|
||||||
|
indoc! {"
|
||||||
let wrapped_text = indoc! {"
|
|
||||||
/// Adds two numbers. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
/// Adds two numbers. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
/// Vivamus mollis elit purus, a ornare lacus gravida vitae.ˇ
|
/// Vivamus mollis elit purus, a ornare lacus gravida vitae.ˇ
|
||||||
fn add(a: u32, b: u32) -> u32 {
|
fn add(a: u32, b: u32) -> u32 {
|
||||||
a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + bˇ
|
a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + b + a + bˇ
|
||||||
}
|
}
|
||||||
"};
|
"},
|
||||||
|
language_with_doc_comments.clone(),
|
||||||
cx.set_state(unwrapped_text);
|
&mut cx,
|
||||||
cx.update_editor(|e, cx| e.rewrap(&Rewrap, cx));
|
);
|
||||||
cx.assert_editor_state(wrapped_text);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that rewrapping works in Markdown and Plain Text languages.
|
// Test that rewrapping works in Markdown and Plain Text languages.
|
||||||
{
|
assert_rewrap(
|
||||||
let markdown_language = Arc::new(Language::new(
|
indoc! {"
|
||||||
LanguageConfig {
|
|
||||||
name: "Markdown".into(),
|
|
||||||
..LanguageConfig::default()
|
|
||||||
},
|
|
||||||
None,
|
|
||||||
));
|
|
||||||
cx.update_buffer(|buffer, cx| buffer.set_language(Some(markdown_language), cx));
|
|
||||||
|
|
||||||
let unwrapped_text = indoc! {"
|
|
||||||
# Hello
|
# Hello
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, ˇconsectetur adipiscing elit. Vivamus mollis elit purus, a ornare lacus gravida vitae. Proin consectetur felis vel purus auctor, eu lacinia sapien scelerisque. Vivamus sit amet neque et quam tincidunt hendrerit. Praesent semper egestas tellus id dignissim. Pellentesque odio lectus, iaculis ac volutpat et, blandit quis urna. Sed vestibulum nisi sit amet nisl venenatis tempus. Donec molestie blandit quam, et porta nunc laoreet in. Integer sit amet scelerisque nisi.
|
Lorem ipsum dolor sit amet, ˇconsectetur adipiscing elit. Vivamus mollis elit purus, a ornare lacus gravida vitae. Proin consectetur felis vel purus auctor, eu lacinia sapien scelerisque. Vivamus sit amet neque et quam tincidunt hendrerit. Praesent semper egestas tellus id dignissim. Pellentesque odio lectus, iaculis ac volutpat et, blandit quis urna. Sed vestibulum nisi sit amet nisl venenatis tempus. Donec molestie blandit quam, et porta nunc laoreet in. Integer sit amet scelerisque nisi.
|
||||||
"};
|
"},
|
||||||
|
indoc! {"
|
||||||
let wrapped_text = indoc! {"
|
|
||||||
# Hello
|
# Hello
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit
|
||||||
@@ -4320,26 +4349,16 @@ async fn test_rewrap(cx: &mut TestAppContext) {
|
|||||||
lectus, iaculis ac volutpat et, blandit quis urna. Sed vestibulum nisi sit amet
|
lectus, iaculis ac volutpat et, blandit quis urna. Sed vestibulum nisi sit amet
|
||||||
nisl venenatis tempus. Donec molestie blandit quam, et porta nunc laoreet in.
|
nisl venenatis tempus. Donec molestie blandit quam, et porta nunc laoreet in.
|
||||||
Integer sit amet scelerisque nisi.ˇ
|
Integer sit amet scelerisque nisi.ˇ
|
||||||
"};
|
"},
|
||||||
|
markdown_language,
|
||||||
|
&mut cx,
|
||||||
|
);
|
||||||
|
|
||||||
cx.set_state(unwrapped_text);
|
assert_rewrap(
|
||||||
cx.update_editor(|e, cx| e.rewrap(&Rewrap, cx));
|
indoc! {"
|
||||||
cx.assert_editor_state(wrapped_text);
|
|
||||||
|
|
||||||
let plaintext_language = Arc::new(Language::new(
|
|
||||||
LanguageConfig {
|
|
||||||
name: "Plain Text".into(),
|
|
||||||
..LanguageConfig::default()
|
|
||||||
},
|
|
||||||
None,
|
|
||||||
));
|
|
||||||
cx.update_buffer(|buffer, cx| buffer.set_language(Some(plaintext_language), cx));
|
|
||||||
|
|
||||||
let unwrapped_text = indoc! {"
|
|
||||||
Lorem ipsum dolor sit amet, ˇconsectetur adipiscing elit. Vivamus mollis elit purus, a ornare lacus gravida vitae. Proin consectetur felis vel purus auctor, eu lacinia sapien scelerisque. Vivamus sit amet neque et quam tincidunt hendrerit. Praesent semper egestas tellus id dignissim. Pellentesque odio lectus, iaculis ac volutpat et, blandit quis urna. Sed vestibulum nisi sit amet nisl venenatis tempus. Donec molestie blandit quam, et porta nunc laoreet in. Integer sit amet scelerisque nisi.
|
Lorem ipsum dolor sit amet, ˇconsectetur adipiscing elit. Vivamus mollis elit purus, a ornare lacus gravida vitae. Proin consectetur felis vel purus auctor, eu lacinia sapien scelerisque. Vivamus sit amet neque et quam tincidunt hendrerit. Praesent semper egestas tellus id dignissim. Pellentesque odio lectus, iaculis ac volutpat et, blandit quis urna. Sed vestibulum nisi sit amet nisl venenatis tempus. Donec molestie blandit quam, et porta nunc laoreet in. Integer sit amet scelerisque nisi.
|
||||||
"};
|
"},
|
||||||
|
indoc! {"
|
||||||
let wrapped_text = indoc! {"
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit
|
||||||
purus, a ornare lacus gravida vitae. Proin consectetur felis vel purus auctor,
|
purus, a ornare lacus gravida vitae. Proin consectetur felis vel purus auctor,
|
||||||
eu lacinia sapien scelerisque. Vivamus sit amet neque et quam tincidunt
|
eu lacinia sapien scelerisque. Vivamus sit amet neque et quam tincidunt
|
||||||
@@ -4347,25 +4366,14 @@ async fn test_rewrap(cx: &mut TestAppContext) {
|
|||||||
lectus, iaculis ac volutpat et, blandit quis urna. Sed vestibulum nisi sit amet
|
lectus, iaculis ac volutpat et, blandit quis urna. Sed vestibulum nisi sit amet
|
||||||
nisl venenatis tempus. Donec molestie blandit quam, et porta nunc laoreet in.
|
nisl venenatis tempus. Donec molestie blandit quam, et porta nunc laoreet in.
|
||||||
Integer sit amet scelerisque nisi.ˇ
|
Integer sit amet scelerisque nisi.ˇ
|
||||||
"};
|
"},
|
||||||
|
plaintext_language,
|
||||||
cx.set_state(unwrapped_text);
|
&mut cx,
|
||||||
cx.update_editor(|e, cx| e.rewrap(&Rewrap, cx));
|
);
|
||||||
cx.assert_editor_state(wrapped_text);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test rewrapping unaligned comments in a selection.
|
// Test rewrapping unaligned comments in a selection.
|
||||||
{
|
assert_rewrap(
|
||||||
let language = Arc::new(Language::new(
|
indoc! {"
|
||||||
LanguageConfig {
|
|
||||||
line_comments: vec!["// ".into(), "/// ".into()],
|
|
||||||
..LanguageConfig::default()
|
|
||||||
},
|
|
||||||
Some(tree_sitter_rust::LANGUAGE.into()),
|
|
||||||
));
|
|
||||||
cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx));
|
|
||||||
|
|
||||||
let unwrapped_text = indoc! {"
|
|
||||||
fn foo() {
|
fn foo() {
|
||||||
if true {
|
if true {
|
||||||
« // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit purus, a ornare lacus gravida vitae.
|
« // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit purus, a ornare lacus gravida vitae.
|
||||||
@@ -4375,9 +4383,8 @@ async fn test_rewrap(cx: &mut TestAppContext) {
|
|||||||
//
|
//
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"};
|
"},
|
||||||
|
indoc! {"
|
||||||
let wrapped_text = indoc! {"
|
|
||||||
fn foo() {
|
fn foo() {
|
||||||
if true {
|
if true {
|
||||||
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
|
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
|
||||||
@@ -4388,13 +4395,13 @@ async fn test_rewrap(cx: &mut TestAppContext) {
|
|||||||
//
|
//
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"};
|
"},
|
||||||
|
language_with_doc_comments.clone(),
|
||||||
|
&mut cx,
|
||||||
|
);
|
||||||
|
|
||||||
cx.set_state(unwrapped_text);
|
assert_rewrap(
|
||||||
cx.update_editor(|e, cx| e.rewrap(&Rewrap, cx));
|
indoc! {"
|
||||||
cx.assert_editor_state(wrapped_text);
|
|
||||||
|
|
||||||
let unwrapped_text = indoc! {"
|
|
||||||
fn foo() {
|
fn foo() {
|
||||||
if true {
|
if true {
|
||||||
«ˇ // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit purus, a ornare lacus gravida vitae.
|
«ˇ // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus mollis elit purus, a ornare lacus gravida vitae.
|
||||||
@@ -4405,9 +4412,8 @@ async fn test_rewrap(cx: &mut TestAppContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
"};
|
"},
|
||||||
|
indoc! {"
|
||||||
let wrapped_text = indoc! {"
|
|
||||||
fn foo() {
|
fn foo() {
|
||||||
if true {
|
if true {
|
||||||
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
|
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus
|
||||||
@@ -4419,8 +4425,19 @@ async fn test_rewrap(cx: &mut TestAppContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
"};
|
"},
|
||||||
|
language_with_doc_comments.clone(),
|
||||||
|
&mut cx,
|
||||||
|
);
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn assert_rewrap(
|
||||||
|
unwrapped_text: &str,
|
||||||
|
wrapped_text: &str,
|
||||||
|
language: Arc<Language>,
|
||||||
|
cx: &mut EditorTestContext,
|
||||||
|
) {
|
||||||
|
cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx));
|
||||||
cx.set_state(unwrapped_text);
|
cx.set_state(unwrapped_text);
|
||||||
cx.update_editor(|e, cx| e.rewrap(&Rewrap, cx));
|
cx.update_editor(|e, cx| e.rewrap(&Rewrap, cx));
|
||||||
cx.assert_editor_state(wrapped_text);
|
cx.assert_editor_state(wrapped_text);
|
||||||
@@ -8315,6 +8332,74 @@ async fn test_completion_page_up_down_keys(cx: &mut gpui::TestAppContext) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_completion_sort(cx: &mut gpui::TestAppContext) {
|
||||||
|
init_test(cx, |_| {});
|
||||||
|
let mut cx = EditorLspTestContext::new_rust(
|
||||||
|
lsp::ServerCapabilities {
|
||||||
|
completion_provider: Some(lsp::CompletionOptions {
|
||||||
|
trigger_characters: Some(vec![".".to_string()]),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
cx.lsp
|
||||||
|
.handle_request::<lsp::request::Completion, _, _>(move |_, _| async move {
|
||||||
|
Ok(Some(lsp::CompletionResponse::Array(vec![
|
||||||
|
lsp::CompletionItem {
|
||||||
|
label: "Range".into(),
|
||||||
|
sort_text: Some("a".into()),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
lsp::CompletionItem {
|
||||||
|
label: "r".into(),
|
||||||
|
sort_text: Some("b".into()),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
lsp::CompletionItem {
|
||||||
|
label: "ret".into(),
|
||||||
|
sort_text: Some("c".into()),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
lsp::CompletionItem {
|
||||||
|
label: "return".into(),
|
||||||
|
sort_text: Some("d".into()),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
lsp::CompletionItem {
|
||||||
|
label: "slice".into(),
|
||||||
|
sort_text: Some("d".into()),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
])))
|
||||||
|
});
|
||||||
|
cx.set_state("rˇ");
|
||||||
|
cx.executor().run_until_parked();
|
||||||
|
cx.update_editor(|editor, cx| {
|
||||||
|
editor.show_completions(
|
||||||
|
&ShowCompletions {
|
||||||
|
trigger: Some("r".into()),
|
||||||
|
},
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
cx.executor().run_until_parked();
|
||||||
|
|
||||||
|
cx.update_editor(|editor, _| {
|
||||||
|
if let Some(ContextMenu::Completions(menu)) = editor.context_menu.read().as_ref() {
|
||||||
|
assert_eq!(
|
||||||
|
menu.matches.iter().map(|m| &m.string).collect::<Vec<_>>(),
|
||||||
|
&["r", "ret", "Range", "return"]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
panic!("expected completion menu to be open");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_no_duplicated_completion_requests(cx: &mut gpui::TestAppContext) {
|
async fn test_no_duplicated_completion_requests(cx: &mut gpui::TestAppContext) {
|
||||||
init_test(cx, |_| {});
|
init_test(cx, |_| {});
|
||||||
@@ -8533,6 +8618,131 @@ async fn test_toggle_comment(cx: &mut gpui::TestAppContext) {
|
|||||||
"});
|
"});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_toggle_comment_ignore_indent(cx: &mut gpui::TestAppContext) {
|
||||||
|
init_test(cx, |_| {});
|
||||||
|
let mut cx = EditorTestContext::new(cx).await;
|
||||||
|
let language = Arc::new(Language::new(
|
||||||
|
LanguageConfig {
|
||||||
|
line_comments: vec!["// ".into(), "//! ".into(), "/// ".into()],
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
Some(tree_sitter_rust::LANGUAGE.into()),
|
||||||
|
));
|
||||||
|
cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx));
|
||||||
|
|
||||||
|
let toggle_comments = &ToggleComments {
|
||||||
|
advance_downwards: false,
|
||||||
|
ignore_indent: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
// If multiple selections intersect a line, the line is only toggled once.
|
||||||
|
cx.set_state(indoc! {"
|
||||||
|
fn a() {
|
||||||
|
// «b();
|
||||||
|
// c();
|
||||||
|
// ˇ» d();
|
||||||
|
}
|
||||||
|
"});
|
||||||
|
|
||||||
|
cx.update_editor(|e, cx| e.toggle_comments(toggle_comments, cx));
|
||||||
|
|
||||||
|
cx.assert_editor_state(indoc! {"
|
||||||
|
fn a() {
|
||||||
|
«b();
|
||||||
|
c();
|
||||||
|
ˇ» d();
|
||||||
|
}
|
||||||
|
"});
|
||||||
|
|
||||||
|
// The comment prefix is inserted at the beginning of each line
|
||||||
|
cx.update_editor(|e, cx| e.toggle_comments(toggle_comments, cx));
|
||||||
|
|
||||||
|
cx.assert_editor_state(indoc! {"
|
||||||
|
fn a() {
|
||||||
|
// «b();
|
||||||
|
// c();
|
||||||
|
// ˇ» d();
|
||||||
|
}
|
||||||
|
"});
|
||||||
|
|
||||||
|
// If a selection ends at the beginning of a line, that line is not toggled.
|
||||||
|
cx.set_selections_state(indoc! {"
|
||||||
|
fn a() {
|
||||||
|
// b();
|
||||||
|
// «c();
|
||||||
|
ˇ»// d();
|
||||||
|
}
|
||||||
|
"});
|
||||||
|
|
||||||
|
cx.update_editor(|e, cx| e.toggle_comments(toggle_comments, cx));
|
||||||
|
|
||||||
|
cx.assert_editor_state(indoc! {"
|
||||||
|
fn a() {
|
||||||
|
// b();
|
||||||
|
«c();
|
||||||
|
ˇ»// d();
|
||||||
|
}
|
||||||
|
"});
|
||||||
|
|
||||||
|
// If a selection span a single line and is empty, the line is toggled.
|
||||||
|
cx.set_state(indoc! {"
|
||||||
|
fn a() {
|
||||||
|
a();
|
||||||
|
b();
|
||||||
|
ˇ
|
||||||
|
}
|
||||||
|
"});
|
||||||
|
|
||||||
|
cx.update_editor(|e, cx| e.toggle_comments(toggle_comments, cx));
|
||||||
|
|
||||||
|
cx.assert_editor_state(indoc! {"
|
||||||
|
fn a() {
|
||||||
|
a();
|
||||||
|
b();
|
||||||
|
//ˇ
|
||||||
|
}
|
||||||
|
"});
|
||||||
|
|
||||||
|
// If a selection span multiple lines, empty lines are not toggled.
|
||||||
|
cx.set_state(indoc! {"
|
||||||
|
fn a() {
|
||||||
|
«a();
|
||||||
|
|
||||||
|
c();ˇ»
|
||||||
|
}
|
||||||
|
"});
|
||||||
|
|
||||||
|
cx.update_editor(|e, cx| e.toggle_comments(toggle_comments, cx));
|
||||||
|
|
||||||
|
cx.assert_editor_state(indoc! {"
|
||||||
|
fn a() {
|
||||||
|
// «a();
|
||||||
|
|
||||||
|
// c();ˇ»
|
||||||
|
}
|
||||||
|
"});
|
||||||
|
|
||||||
|
// If a selection includes multiple comment prefixes, all lines are uncommented.
|
||||||
|
cx.set_state(indoc! {"
|
||||||
|
fn a() {
|
||||||
|
// «a();
|
||||||
|
/// b();
|
||||||
|
//! c();ˇ»
|
||||||
|
}
|
||||||
|
"});
|
||||||
|
|
||||||
|
cx.update_editor(|e, cx| e.toggle_comments(toggle_comments, cx));
|
||||||
|
|
||||||
|
cx.assert_editor_state(indoc! {"
|
||||||
|
fn a() {
|
||||||
|
«a();
|
||||||
|
b();
|
||||||
|
c();ˇ»
|
||||||
|
}
|
||||||
|
"});
|
||||||
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_advance_downward_on_toggle_comment(cx: &mut gpui::TestAppContext) {
|
async fn test_advance_downward_on_toggle_comment(cx: &mut gpui::TestAppContext) {
|
||||||
init_test(cx, |_| {});
|
init_test(cx, |_| {});
|
||||||
@@ -8554,6 +8764,7 @@ async fn test_advance_downward_on_toggle_comment(cx: &mut gpui::TestAppContext)
|
|||||||
|
|
||||||
let toggle_comments = &ToggleComments {
|
let toggle_comments = &ToggleComments {
|
||||||
advance_downwards: true,
|
advance_downwards: true,
|
||||||
|
ignore_indent: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Single cursor on one line -> advance
|
// Single cursor on one line -> advance
|
||||||
@@ -13204,6 +13415,89 @@ async fn test_goto_definition_with_find_all_references_fallback(cx: &mut gpui::T
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_find_enclosing_node_with_task(cx: &mut gpui::TestAppContext) {
|
||||||
|
init_test(cx, |_| {});
|
||||||
|
|
||||||
|
let language = Arc::new(Language::new(
|
||||||
|
LanguageConfig::default(),
|
||||||
|
Some(tree_sitter_rust::LANGUAGE.into()),
|
||||||
|
));
|
||||||
|
|
||||||
|
let text = r#"
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests() {
|
||||||
|
#[test]
|
||||||
|
fn runnable_1() {
|
||||||
|
let a = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn runnable_2() {
|
||||||
|
let a = 1;
|
||||||
|
let b = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#
|
||||||
|
.unindent();
|
||||||
|
|
||||||
|
let fs = FakeFs::new(cx.executor());
|
||||||
|
fs.insert_file("/file.rs", Default::default()).await;
|
||||||
|
|
||||||
|
let project = Project::test(fs, ["/a".as_ref()], cx).await;
|
||||||
|
let workspace = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
|
||||||
|
let cx = &mut VisualTestContext::from_window(*workspace.deref(), cx);
|
||||||
|
let buffer = cx.new_model(|cx| Buffer::local(text, cx).with_language(language, cx));
|
||||||
|
let multi_buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer.clone(), cx));
|
||||||
|
|
||||||
|
let editor = cx.new_view(|cx| {
|
||||||
|
Editor::new(
|
||||||
|
EditorMode::Full,
|
||||||
|
multi_buffer,
|
||||||
|
Some(project.clone()),
|
||||||
|
true,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
editor.update(cx, |editor, cx| {
|
||||||
|
editor.tasks.insert(
|
||||||
|
(buffer.read(cx).remote_id(), 3),
|
||||||
|
RunnableTasks {
|
||||||
|
templates: vec![],
|
||||||
|
offset: MultiBufferOffset(43),
|
||||||
|
column: 0,
|
||||||
|
extra_variables: HashMap::default(),
|
||||||
|
context_range: BufferOffset(43)..BufferOffset(85),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
editor.tasks.insert(
|
||||||
|
(buffer.read(cx).remote_id(), 8),
|
||||||
|
RunnableTasks {
|
||||||
|
templates: vec![],
|
||||||
|
offset: MultiBufferOffset(86),
|
||||||
|
column: 0,
|
||||||
|
extra_variables: HashMap::default(),
|
||||||
|
context_range: BufferOffset(86)..BufferOffset(191),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Test finding task when cursor is inside function body
|
||||||
|
editor.change_selections(None, cx, |s| {
|
||||||
|
s.select_ranges([Point::new(4, 5)..Point::new(4, 5)])
|
||||||
|
});
|
||||||
|
let (_, row, _) = editor.find_enclosing_node_task(cx).unwrap();
|
||||||
|
assert_eq!(row, 3, "Should find task for cursor inside runnable_1");
|
||||||
|
|
||||||
|
// Test finding task when cursor is on function name
|
||||||
|
editor.change_selections(None, cx, |s| {
|
||||||
|
s.select_ranges([Point::new(8, 4)..Point::new(8, 4)])
|
||||||
|
});
|
||||||
|
let (_, row, _) = editor.find_enclosing_node_task(cx).unwrap();
|
||||||
|
assert_eq!(row, 8, "Should find task when cursor is on function name");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn empty_range(row: usize, column: usize) -> Range<DisplayPoint> {
|
fn empty_range(row: usize, column: usize) -> Range<DisplayPoint> {
|
||||||
let point = DisplayPoint::new(DisplayRow(row as u32), column as u32);
|
let point = DisplayPoint::new(DisplayRow(row as u32), column as u32);
|
||||||
point..point
|
point..point
|
||||||
|
|||||||
@@ -19,15 +19,14 @@ use crate::{
|
|||||||
BlockId, CodeActionsMenu, CursorShape, CustomBlockId, DisplayPoint, DisplayRow,
|
BlockId, CodeActionsMenu, CursorShape, CustomBlockId, DisplayPoint, DisplayRow,
|
||||||
DocumentHighlightRead, DocumentHighlightWrite, Editor, EditorMode, EditorSettings,
|
DocumentHighlightRead, DocumentHighlightWrite, Editor, EditorMode, EditorSettings,
|
||||||
EditorSnapshot, EditorStyle, ExpandExcerpts, FocusedBlock, GutterDimensions, HalfPageDown,
|
EditorSnapshot, EditorStyle, ExpandExcerpts, FocusedBlock, GutterDimensions, HalfPageDown,
|
||||||
HalfPageUp, HandleInput, HoveredCursor, HoveredHunk, LineDown, LineUp, OpenExcerpts, PageDown,
|
HalfPageUp, HandleInput, HoveredCursor, HoveredHunk, JumpData, LineDown, LineUp, OpenExcerpts,
|
||||||
PageUp, Point, RowExt, RowRangeExt, SelectPhase, Selection, SoftWrap, ToPoint,
|
PageDown, PageUp, Point, RowExt, RowRangeExt, SelectPhase, Selection, SoftWrap, ToPoint,
|
||||||
CURSORS_VISIBLE_FOR, FILE_HEADER_HEIGHT, GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED, MAX_LINE_LEN,
|
CURSORS_VISIBLE_FOR, FILE_HEADER_HEIGHT, GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED, MAX_LINE_LEN,
|
||||||
MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
|
MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
|
||||||
};
|
};
|
||||||
use client::ParticipantIndex;
|
use client::ParticipantIndex;
|
||||||
use collections::{BTreeMap, HashMap};
|
use collections::{BTreeMap, HashMap, HashSet};
|
||||||
use git::{blame::BlameEntry, diff::DiffHunkStatus, Oid};
|
use git::{blame::BlameEntry, diff::DiffHunkStatus, Oid};
|
||||||
use gpui::Subscription;
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
anchored, deferred, div, fill, outline, point, px, quad, relative, size, svg,
|
anchored, deferred, div, fill, outline, point, px, quad, relative, size, svg,
|
||||||
transparent_black, Action, AnchorCorner, AnyElement, AvailableSpace, Bounds, ClipboardItem,
|
transparent_black, Action, AnchorCorner, AnyElement, AvailableSpace, Bounds, ClipboardItem,
|
||||||
@@ -38,6 +37,7 @@ use gpui::{
|
|||||||
StatefulInteractiveElement, Style, Styled, TextRun, TextStyle, TextStyleRefinement, View,
|
StatefulInteractiveElement, Style, Styled, TextRun, TextStyle, TextStyleRefinement, View,
|
||||||
ViewContext, WeakView, WindowContext,
|
ViewContext, WeakView, WindowContext,
|
||||||
};
|
};
|
||||||
|
use gpui::{ClickEvent, Subscription};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use language::{
|
use language::{
|
||||||
language_settings::{
|
language_settings::{
|
||||||
@@ -449,7 +449,8 @@ impl EditorElement {
|
|||||||
register_action(view, cx, Editor::apply_all_diff_hunks);
|
register_action(view, cx, Editor::apply_all_diff_hunks);
|
||||||
register_action(view, cx, Editor::apply_selected_diff_hunks);
|
register_action(view, cx, Editor::apply_selected_diff_hunks);
|
||||||
register_action(view, cx, Editor::open_active_item_in_terminal);
|
register_action(view, cx, Editor::open_active_item_in_terminal);
|
||||||
register_action(view, cx, Editor::reload_file)
|
register_action(view, cx, Editor::reload_file);
|
||||||
|
register_action(view, cx, Editor::spawn_nearest_task);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_key_listeners(&self, cx: &mut WindowContext, layout: &EditorLayout) {
|
fn register_key_listeners(&self, cx: &mut WindowContext, layout: &EditorLayout) {
|
||||||
@@ -649,12 +650,14 @@ impl EditorElement {
|
|||||||
cx.stop_propagation();
|
cx.stop_propagation();
|
||||||
} else if end_selection && pending_nonempty_selections {
|
} else if end_selection && pending_nonempty_selections {
|
||||||
cx.stop_propagation();
|
cx.stop_propagation();
|
||||||
} else if cfg!(target_os = "linux") && event.button == MouseButton::Middle {
|
} else if cfg!(any(target_os = "linux", target_os = "freebsd"))
|
||||||
|
&& event.button == MouseButton::Middle
|
||||||
|
{
|
||||||
if !text_hitbox.is_hovered(cx) || editor.read_only(cx) {
|
if !text_hitbox.is_hovered(cx) || editor.read_only(cx) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
||||||
if EditorSettings::get_global(cx).middle_click_paste {
|
if EditorSettings::get_global(cx).middle_click_paste {
|
||||||
if let Some(text) = cx.read_from_primary().and_then(|item| item.text()) {
|
if let Some(text) = cx.read_from_primary().and_then(|item| item.text()) {
|
||||||
let point_for_position =
|
let point_for_position =
|
||||||
@@ -808,10 +811,12 @@ impl EditorElement {
|
|||||||
cx.notify()
|
cx.notify()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn layout_selections(
|
fn layout_selections(
|
||||||
&self,
|
&self,
|
||||||
start_anchor: Anchor,
|
start_anchor: Anchor,
|
||||||
end_anchor: Anchor,
|
end_anchor: Anchor,
|
||||||
|
local_selections: &[Selection<Point>],
|
||||||
snapshot: &EditorSnapshot,
|
snapshot: &EditorSnapshot,
|
||||||
start_row: DisplayRow,
|
start_row: DisplayRow,
|
||||||
end_row: DisplayRow,
|
end_row: DisplayRow,
|
||||||
@@ -826,13 +831,9 @@ impl EditorElement {
|
|||||||
let mut newest_selection_head = None;
|
let mut newest_selection_head = None;
|
||||||
self.editor.update(cx, |editor, cx| {
|
self.editor.update(cx, |editor, cx| {
|
||||||
if editor.show_local_selections {
|
if editor.show_local_selections {
|
||||||
let mut local_selections: Vec<Selection<Point>> = editor
|
|
||||||
.selections
|
|
||||||
.disjoint_in_range(start_anchor..end_anchor, cx);
|
|
||||||
local_selections.extend(editor.selections.pending(cx));
|
|
||||||
let mut layouts = Vec::new();
|
let mut layouts = Vec::new();
|
||||||
let newest = editor.selections.newest(cx);
|
let newest = editor.selections.newest(cx);
|
||||||
for selection in local_selections.drain(..) {
|
for selection in local_selections.iter().cloned() {
|
||||||
let is_empty = selection.start == selection.end;
|
let is_empty = selection.start == selection.end;
|
||||||
let is_newest = selection == newest;
|
let is_newest = selection == newest;
|
||||||
|
|
||||||
@@ -995,6 +996,7 @@ impl EditorElement {
|
|||||||
&self,
|
&self,
|
||||||
snapshot: &EditorSnapshot,
|
snapshot: &EditorSnapshot,
|
||||||
selections: &[(PlayerColor, Vec<SelectionLayout>)],
|
selections: &[(PlayerColor, Vec<SelectionLayout>)],
|
||||||
|
block_start_rows: &HashSet<DisplayRow>,
|
||||||
visible_display_row_range: Range<DisplayRow>,
|
visible_display_row_range: Range<DisplayRow>,
|
||||||
line_layouts: &[LineWithInvisibles],
|
line_layouts: &[LineWithInvisibles],
|
||||||
text_hitbox: &Hitbox,
|
text_hitbox: &Hitbox,
|
||||||
@@ -1014,7 +1016,10 @@ impl EditorElement {
|
|||||||
let cursor_position = selection.head;
|
let cursor_position = selection.head;
|
||||||
|
|
||||||
let in_range = visible_display_row_range.contains(&cursor_position.row());
|
let in_range = visible_display_row_range.contains(&cursor_position.row());
|
||||||
if (selection.is_local && !editor.show_local_cursors(cx)) || !in_range {
|
if (selection.is_local && !editor.show_local_cursors(cx))
|
||||||
|
|| !in_range
|
||||||
|
|| block_start_rows.contains(&cursor_position.row())
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1965,10 +1970,10 @@ impl EditorElement {
|
|||||||
|
|
||||||
fn layout_lines(
|
fn layout_lines(
|
||||||
rows: Range<DisplayRow>,
|
rows: Range<DisplayRow>,
|
||||||
line_number_layouts: &[Option<ShapedLine>],
|
|
||||||
snapshot: &EditorSnapshot,
|
snapshot: &EditorSnapshot,
|
||||||
style: &EditorStyle,
|
style: &EditorStyle,
|
||||||
editor_width: Pixels,
|
editor_width: Pixels,
|
||||||
|
is_row_soft_wrapped: impl Copy + Fn(usize) -> bool,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> Vec<LineWithInvisibles> {
|
) -> Vec<LineWithInvisibles> {
|
||||||
if rows.start >= rows.end {
|
if rows.start >= rows.end {
|
||||||
@@ -2017,9 +2022,9 @@ impl EditorElement {
|
|||||||
&style.text,
|
&style.text,
|
||||||
MAX_LINE_LEN,
|
MAX_LINE_LEN,
|
||||||
rows.len(),
|
rows.len(),
|
||||||
line_number_layouts,
|
|
||||||
snapshot.mode,
|
snapshot.mode,
|
||||||
editor_width,
|
editor_width,
|
||||||
|
is_row_soft_wrapped,
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -2067,23 +2072,43 @@ impl EditorElement {
|
|||||||
editor_width: Pixels,
|
editor_width: Pixels,
|
||||||
scroll_width: &mut Pixels,
|
scroll_width: &mut Pixels,
|
||||||
resized_blocks: &mut HashMap<CustomBlockId, u32>,
|
resized_blocks: &mut HashMap<CustomBlockId, u32>,
|
||||||
|
selections: &[Selection<Point>],
|
||||||
|
is_row_soft_wrapped: impl Copy + Fn(usize) -> bool,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> (AnyElement, Size<Pixels>) {
|
) -> (AnyElement, Size<Pixels>) {
|
||||||
let mut element = match block {
|
let mut element = match block {
|
||||||
Block::Custom(block) => {
|
Block::Custom(block) => {
|
||||||
let align_to = block
|
let block_start = block.start().to_point(&snapshot.buffer_snapshot);
|
||||||
.start()
|
let block_end = block.end().to_point(&snapshot.buffer_snapshot);
|
||||||
.to_point(&snapshot.buffer_snapshot)
|
let align_to = block_start.to_display_point(snapshot);
|
||||||
.to_display_point(snapshot);
|
|
||||||
let anchor_x = text_x
|
let anchor_x = text_x
|
||||||
+ if rows.contains(&align_to.row()) {
|
+ if rows.contains(&align_to.row()) {
|
||||||
line_layouts[align_to.row().minus(rows.start) as usize]
|
line_layouts[align_to.row().minus(rows.start) as usize]
|
||||||
.x_for_index(align_to.column() as usize)
|
.x_for_index(align_to.column() as usize)
|
||||||
} else {
|
} else {
|
||||||
layout_line(align_to.row(), snapshot, &self.style, editor_width, cx)
|
layout_line(
|
||||||
.x_for_index(align_to.column() as usize)
|
align_to.row(),
|
||||||
|
snapshot,
|
||||||
|
&self.style,
|
||||||
|
editor_width,
|
||||||
|
is_row_soft_wrapped,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
.x_for_index(align_to.column() as usize)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let selected = selections
|
||||||
|
.binary_search_by(|selection| {
|
||||||
|
if selection.end <= block_start {
|
||||||
|
Ordering::Less
|
||||||
|
} else if selection.start >= block_end {
|
||||||
|
Ordering::Greater
|
||||||
|
} else {
|
||||||
|
Ordering::Equal
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.is_ok();
|
||||||
|
|
||||||
div()
|
div()
|
||||||
.size_full()
|
.size_full()
|
||||||
.child(block.render(&mut BlockContext {
|
.child(block.render(&mut BlockContext {
|
||||||
@@ -2093,6 +2118,7 @@ impl EditorElement {
|
|||||||
line_height,
|
line_height,
|
||||||
em_width,
|
em_width,
|
||||||
block_id,
|
block_id,
|
||||||
|
selected,
|
||||||
max_width: text_hitbox.size.width.max(*scroll_width),
|
max_width: text_hitbox.size.width.max(*scroll_width),
|
||||||
editor_style: &self.style,
|
editor_style: &self.style,
|
||||||
}))
|
}))
|
||||||
@@ -2109,14 +2135,6 @@ impl EditorElement {
|
|||||||
height,
|
height,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
#[derive(Clone)]
|
|
||||||
struct JumpData {
|
|
||||||
position: Point,
|
|
||||||
anchor: text::Anchor,
|
|
||||||
path: ProjectPath,
|
|
||||||
line_offset_from_top: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
let icon_offset = gutter_dimensions.width
|
let icon_offset = gutter_dimensions.width
|
||||||
- (gutter_dimensions.left_padding + gutter_dimensions.margin);
|
- (gutter_dimensions.left_padding + gutter_dimensions.margin);
|
||||||
|
|
||||||
@@ -2145,11 +2163,12 @@ impl EditorElement {
|
|||||||
if let Some(next_excerpt) = next_excerpt {
|
if let Some(next_excerpt) = next_excerpt {
|
||||||
let buffer = &next_excerpt.buffer;
|
let buffer = &next_excerpt.buffer;
|
||||||
let range = &next_excerpt.range;
|
let range = &next_excerpt.range;
|
||||||
let jump_data = project::File::from_dyn(buffer.file()).map(|file| {
|
let jump_data = {
|
||||||
let jump_path = ProjectPath {
|
let jump_path =
|
||||||
worktree_id: file.worktree_id(cx),
|
project::File::from_dyn(buffer.file()).map(|file| ProjectPath {
|
||||||
path: file.path.clone(),
|
worktree_id: file.worktree_id(cx),
|
||||||
};
|
path: file.path.clone(),
|
||||||
|
});
|
||||||
let jump_anchor = range
|
let jump_anchor = range
|
||||||
.primary
|
.primary
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@@ -2164,21 +2183,20 @@ impl EditorElement {
|
|||||||
language::ToPoint::to_point(&jump_anchor, buffer).row;
|
language::ToPoint::to_point(&jump_anchor, buffer).row;
|
||||||
jump_position.row - excerpt_start_row
|
jump_position.row - excerpt_start_row
|
||||||
};
|
};
|
||||||
|
|
||||||
let line_offset_from_top =
|
let line_offset_from_top =
|
||||||
block_row_start.0 + *height + offset_from_excerpt_start
|
block_row_start.0 + *height + offset_from_excerpt_start
|
||||||
- snapshot
|
- snapshot
|
||||||
.scroll_anchor
|
.scroll_anchor
|
||||||
.scroll_position(&snapshot.display_snapshot)
|
.scroll_position(&snapshot.display_snapshot)
|
||||||
.y as u32;
|
.y as u32;
|
||||||
|
|
||||||
JumpData {
|
JumpData {
|
||||||
position: jump_position,
|
excerpt_id: next_excerpt.id,
|
||||||
anchor: jump_anchor,
|
anchor: jump_anchor,
|
||||||
|
position: language::ToPoint::to_point(&jump_anchor, buffer),
|
||||||
path: jump_path,
|
path: jump_path,
|
||||||
line_offset_from_top,
|
line_offset_from_top,
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
if *starts_new_buffer {
|
if *starts_new_buffer {
|
||||||
let include_root = self
|
let include_root = self
|
||||||
@@ -2233,31 +2251,23 @@ impl EditorElement {
|
|||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.when_some(jump_data, |el, jump_data| {
|
.child(Icon::new(IconName::ArrowUpRight))
|
||||||
el.child(Icon::new(IconName::ArrowUpRight))
|
.cursor_pointer()
|
||||||
.cursor_pointer()
|
.tooltip(|cx| {
|
||||||
.tooltip(|cx| {
|
Tooltip::for_action("Jump to File", &OpenExcerpts, cx)
|
||||||
Tooltip::for_action(
|
})
|
||||||
"Jump to File",
|
.on_mouse_down(MouseButton::Left, |_, cx| {
|
||||||
&OpenExcerpts,
|
cx.stop_propagation()
|
||||||
cx,
|
})
|
||||||
)
|
.on_click(cx.listener_for(&self.editor, {
|
||||||
})
|
move |editor, e: &ClickEvent, cx| {
|
||||||
.on_mouse_down(MouseButton::Left, |_, cx| {
|
editor.open_excerpts_common(
|
||||||
cx.stop_propagation()
|
Some(jump_data.clone()),
|
||||||
})
|
e.down.modifiers.secondary(),
|
||||||
.on_click(cx.listener_for(&self.editor, {
|
cx,
|
||||||
move |editor, _, cx| {
|
);
|
||||||
editor.jump(
|
}
|
||||||
jump_data.path.clone(),
|
})),
|
||||||
jump_data.position,
|
|
||||||
jump_data.anchor,
|
|
||||||
jump_data.line_offset_from_top,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
}),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if *show_excerpt_controls {
|
if *show_excerpt_controls {
|
||||||
@@ -2276,6 +2286,7 @@ impl EditorElement {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
let editor = self.editor.clone();
|
||||||
result = result.child(
|
result = result.child(
|
||||||
h_flex()
|
h_flex()
|
||||||
.id("excerpt header block")
|
.id("excerpt header block")
|
||||||
@@ -2296,33 +2307,52 @@ impl EditorElement {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.cursor_pointer()
|
.cursor_pointer()
|
||||||
.when_some(jump_data.clone(), |this, jump_data| {
|
.on_click({
|
||||||
this.on_click(cx.listener_for(&self.editor, {
|
let jump_data = jump_data.clone();
|
||||||
let path = jump_data.path.clone();
|
cx.listener_for(&self.editor, {
|
||||||
move |editor, _, cx| {
|
let jump_data = jump_data.clone();
|
||||||
|
move |editor, e: &ClickEvent, cx| {
|
||||||
cx.stop_propagation();
|
cx.stop_propagation();
|
||||||
|
editor.open_excerpts_common(
|
||||||
editor.jump(
|
Some(jump_data.clone()),
|
||||||
path.clone(),
|
e.down.modifiers.secondary(),
|
||||||
jump_data.position,
|
|
||||||
jump_data.anchor,
|
|
||||||
jump_data.line_offset_from_top,
|
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}))
|
|
||||||
.tooltip(move |cx| {
|
|
||||||
Tooltip::for_action(
|
|
||||||
format!(
|
|
||||||
"Jump to {}:L{}",
|
|
||||||
jump_data.path.path.display(),
|
|
||||||
jump_data.position.row + 1
|
|
||||||
),
|
|
||||||
&OpenExcerpts,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
.tooltip({
|
||||||
|
let jump_data = jump_data.clone();
|
||||||
|
move |cx| {
|
||||||
|
let jump_message = format!(
|
||||||
|
"Jump to {}:L{}",
|
||||||
|
match &jump_data.path {
|
||||||
|
Some(project_path) =>
|
||||||
|
project_path.path.display().to_string(),
|
||||||
|
None => {
|
||||||
|
let editor = editor.read(cx);
|
||||||
|
editor
|
||||||
|
.file_at(jump_data.position, cx)
|
||||||
|
.map(|file| {
|
||||||
|
file.full_path(cx).display().to_string()
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
Some(
|
||||||
|
editor
|
||||||
|
.tab_description(0, cx)?
|
||||||
|
.to_string(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
"Unknown buffer".to_string()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
jump_data.position.row + 1
|
||||||
|
);
|
||||||
|
Tooltip::for_action(jump_message, &OpenExcerpts, cx)
|
||||||
|
}
|
||||||
|
})
|
||||||
.child(
|
.child(
|
||||||
h_flex()
|
h_flex()
|
||||||
.w(icon_offset)
|
.w(icon_offset)
|
||||||
@@ -2430,6 +2460,8 @@ impl EditorElement {
|
|||||||
text_x: Pixels,
|
text_x: Pixels,
|
||||||
line_height: Pixels,
|
line_height: Pixels,
|
||||||
line_layouts: &[LineWithInvisibles],
|
line_layouts: &[LineWithInvisibles],
|
||||||
|
selections: &[Selection<Point>],
|
||||||
|
is_row_soft_wrapped: impl Copy + Fn(usize) -> bool,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> Result<Vec<BlockLayout>, HashMap<CustomBlockId, u32>> {
|
) -> Result<Vec<BlockLayout>, HashMap<CustomBlockId, u32>> {
|
||||||
let (fixed_blocks, non_fixed_blocks) = snapshot
|
let (fixed_blocks, non_fixed_blocks) = snapshot
|
||||||
@@ -2466,6 +2498,8 @@ impl EditorElement {
|
|||||||
editor_width,
|
editor_width,
|
||||||
scroll_width,
|
scroll_width,
|
||||||
&mut resized_blocks,
|
&mut resized_blocks,
|
||||||
|
selections,
|
||||||
|
is_row_soft_wrapped,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
fixed_block_max_width = fixed_block_max_width.max(element_size.width + em_width);
|
fixed_block_max_width = fixed_block_max_width.max(element_size.width + em_width);
|
||||||
@@ -2510,6 +2544,8 @@ impl EditorElement {
|
|||||||
editor_width,
|
editor_width,
|
||||||
scroll_width,
|
scroll_width,
|
||||||
&mut resized_blocks,
|
&mut resized_blocks,
|
||||||
|
selections,
|
||||||
|
is_row_soft_wrapped,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -2555,6 +2591,8 @@ impl EditorElement {
|
|||||||
editor_width,
|
editor_width,
|
||||||
scroll_width,
|
scroll_width,
|
||||||
&mut resized_blocks,
|
&mut resized_blocks,
|
||||||
|
selections,
|
||||||
|
is_row_soft_wrapped,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -2583,6 +2621,7 @@ impl EditorElement {
|
|||||||
fn layout_blocks(
|
fn layout_blocks(
|
||||||
&self,
|
&self,
|
||||||
blocks: &mut Vec<BlockLayout>,
|
blocks: &mut Vec<BlockLayout>,
|
||||||
|
block_starts: &mut HashSet<DisplayRow>,
|
||||||
hitbox: &Hitbox,
|
hitbox: &Hitbox,
|
||||||
line_height: Pixels,
|
line_height: Pixels,
|
||||||
scroll_pixel_position: gpui::Point<Pixels>,
|
scroll_pixel_position: gpui::Point<Pixels>,
|
||||||
@@ -2590,6 +2629,7 @@ impl EditorElement {
|
|||||||
) {
|
) {
|
||||||
for block in blocks {
|
for block in blocks {
|
||||||
let mut origin = if let Some(row) = block.row {
|
let mut origin = if let Some(row) = block.row {
|
||||||
|
block_starts.insert(row);
|
||||||
hitbox.origin
|
hitbox.origin
|
||||||
+ point(
|
+ point(
|
||||||
Pixels::ZERO,
|
Pixels::ZERO,
|
||||||
@@ -4337,9 +4377,9 @@ impl LineWithInvisibles {
|
|||||||
text_style: &TextStyle,
|
text_style: &TextStyle,
|
||||||
max_line_len: usize,
|
max_line_len: usize,
|
||||||
max_line_count: usize,
|
max_line_count: usize,
|
||||||
line_number_layouts: &[Option<ShapedLine>],
|
|
||||||
editor_mode: EditorMode,
|
editor_mode: EditorMode,
|
||||||
text_width: Pixels,
|
text_width: Pixels,
|
||||||
|
is_row_soft_wrapped: impl Copy + Fn(usize) -> bool,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> Vec<Self> {
|
) -> Vec<Self> {
|
||||||
let mut layouts = Vec::with_capacity(max_line_count);
|
let mut layouts = Vec::with_capacity(max_line_count);
|
||||||
@@ -4467,12 +4507,9 @@ impl LineWithInvisibles {
|
|||||||
if editor_mode == EditorMode::Full {
|
if editor_mode == EditorMode::Full {
|
||||||
// Line wrap pads its contents with fake whitespaces,
|
// Line wrap pads its contents with fake whitespaces,
|
||||||
// avoid printing them
|
// avoid printing them
|
||||||
let inside_wrapped_string = line_number_layouts
|
let is_soft_wrapped = is_row_soft_wrapped(row);
|
||||||
.get(row)
|
|
||||||
.and_then(|layout| layout.as_ref())
|
|
||||||
.is_none();
|
|
||||||
if highlighted_chunk.is_tab {
|
if highlighted_chunk.is_tab {
|
||||||
if non_whitespace_added || !inside_wrapped_string {
|
if non_whitespace_added || !is_soft_wrapped {
|
||||||
invisibles.push(Invisible::Tab {
|
invisibles.push(Invisible::Tab {
|
||||||
line_start_offset: line.len(),
|
line_start_offset: line.len(),
|
||||||
line_end_offset: line.len() + line_chunk.len(),
|
line_end_offset: line.len() + line_chunk.len(),
|
||||||
@@ -4488,7 +4525,7 @@ impl LineWithInvisibles {
|
|||||||
(*line_byte as char).is_whitespace();
|
(*line_byte as char).is_whitespace();
|
||||||
non_whitespace_added |= !is_whitespace;
|
non_whitespace_added |= !is_whitespace;
|
||||||
is_whitespace
|
is_whitespace
|
||||||
&& (non_whitespace_added || !inside_wrapped_string)
|
&& (non_whitespace_added || !is_soft_wrapped)
|
||||||
})
|
})
|
||||||
.map(|(whitespace_index, _)| Invisible::Whitespace {
|
.map(|(whitespace_index, _)| Invisible::Whitespace {
|
||||||
line_offset: line.len() + whitespace_index,
|
line_offset: line.len() + whitespace_index,
|
||||||
@@ -4851,10 +4888,10 @@ impl Element for EditorElement {
|
|||||||
editor_handle.update(cx, |editor, cx| editor.snapshot(cx));
|
editor_handle.update(cx, |editor, cx| editor.snapshot(cx));
|
||||||
let line = Self::layout_lines(
|
let line = Self::layout_lines(
|
||||||
DisplayRow(0)..DisplayRow(1),
|
DisplayRow(0)..DisplayRow(1),
|
||||||
&[],
|
|
||||||
&editor_snapshot,
|
&editor_snapshot,
|
||||||
&style,
|
&style,
|
||||||
px(f32::MAX),
|
px(f32::MAX),
|
||||||
|
|_| false, // Single lines never soft wrap
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
.pop()
|
.pop()
|
||||||
@@ -5063,6 +5100,8 @@ impl Element for EditorElement {
|
|||||||
.buffer_rows(start_row)
|
.buffer_rows(start_row)
|
||||||
.take((start_row..end_row).len())
|
.take((start_row..end_row).len())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
let is_row_soft_wrapped =
|
||||||
|
|row| buffer_rows.get(row).copied().flatten().is_none();
|
||||||
|
|
||||||
let start_anchor = if start_row == Default::default() {
|
let start_anchor = if start_row == Default::default() {
|
||||||
Anchor::min()
|
Anchor::min()
|
||||||
@@ -5100,9 +5139,19 @@ impl Element for EditorElement {
|
|||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let local_selections: Vec<Selection<Point>> =
|
||||||
|
self.editor.update(cx, |editor, cx| {
|
||||||
|
let mut selections = editor
|
||||||
|
.selections
|
||||||
|
.disjoint_in_range(start_anchor..end_anchor, cx);
|
||||||
|
selections.extend(editor.selections.pending(cx));
|
||||||
|
selections
|
||||||
|
});
|
||||||
|
|
||||||
let (selections, active_rows, newest_selection_head) = self.layout_selections(
|
let (selections, active_rows, newest_selection_head) = self.layout_selections(
|
||||||
start_anchor,
|
start_anchor,
|
||||||
end_anchor,
|
end_anchor,
|
||||||
|
&local_selections,
|
||||||
&snapshot,
|
&snapshot,
|
||||||
start_row,
|
start_row,
|
||||||
end_row,
|
end_row,
|
||||||
@@ -5144,10 +5193,10 @@ impl Element for EditorElement {
|
|||||||
let mut max_visible_line_width = Pixels::ZERO;
|
let mut max_visible_line_width = Pixels::ZERO;
|
||||||
let mut line_layouts = Self::layout_lines(
|
let mut line_layouts = Self::layout_lines(
|
||||||
start_row..end_row,
|
start_row..end_row,
|
||||||
&line_numbers,
|
|
||||||
&snapshot,
|
&snapshot,
|
||||||
&self.style,
|
&self.style,
|
||||||
editor_width,
|
editor_width,
|
||||||
|
is_row_soft_wrapped,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
for line_with_invisibles in &line_layouts {
|
for line_with_invisibles in &line_layouts {
|
||||||
@@ -5156,9 +5205,15 @@ impl Element for EditorElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let longest_line_width =
|
let longest_line_width = layout_line(
|
||||||
layout_line(snapshot.longest_row(), &snapshot, &style, editor_width, cx)
|
snapshot.longest_row(),
|
||||||
.width;
|
&snapshot,
|
||||||
|
&style,
|
||||||
|
editor_width,
|
||||||
|
is_row_soft_wrapped,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
.width;
|
||||||
let mut scroll_width =
|
let mut scroll_width =
|
||||||
longest_line_width.max(max_visible_line_width) + overscroll.width;
|
longest_line_width.max(max_visible_line_width) + overscroll.width;
|
||||||
|
|
||||||
@@ -5175,6 +5230,8 @@ impl Element for EditorElement {
|
|||||||
gutter_dimensions.full_width(),
|
gutter_dimensions.full_width(),
|
||||||
line_height,
|
line_height,
|
||||||
&line_layouts,
|
&line_layouts,
|
||||||
|
&local_selections,
|
||||||
|
is_row_soft_wrapped,
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
@@ -5314,9 +5371,11 @@ impl Element for EditorElement {
|
|||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let mut block_start_rows = HashSet::default();
|
||||||
cx.with_element_namespace("blocks", |cx| {
|
cx.with_element_namespace("blocks", |cx| {
|
||||||
self.layout_blocks(
|
self.layout_blocks(
|
||||||
&mut blocks,
|
&mut blocks,
|
||||||
|
&mut block_start_rows,
|
||||||
&hitbox,
|
&hitbox,
|
||||||
line_height,
|
line_height,
|
||||||
scroll_pixel_position,
|
scroll_pixel_position,
|
||||||
@@ -5333,6 +5392,7 @@ impl Element for EditorElement {
|
|||||||
let visible_cursors = self.layout_visible_cursors(
|
let visible_cursors = self.layout_visible_cursors(
|
||||||
&snapshot,
|
&snapshot,
|
||||||
&selections,
|
&selections,
|
||||||
|
&block_start_rows,
|
||||||
start_row..end_row,
|
start_row..end_row,
|
||||||
&line_layouts,
|
&line_layouts,
|
||||||
&text_hitbox,
|
&text_hitbox,
|
||||||
@@ -5930,6 +5990,7 @@ fn layout_line(
|
|||||||
snapshot: &EditorSnapshot,
|
snapshot: &EditorSnapshot,
|
||||||
style: &EditorStyle,
|
style: &EditorStyle,
|
||||||
text_width: Pixels,
|
text_width: Pixels,
|
||||||
|
is_row_soft_wrapped: impl Copy + Fn(usize) -> bool,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) -> LineWithInvisibles {
|
) -> LineWithInvisibles {
|
||||||
let chunks = snapshot.highlighted_chunks(row..row + DisplayRow(1), true, style);
|
let chunks = snapshot.highlighted_chunks(row..row + DisplayRow(1), true, style);
|
||||||
@@ -5938,9 +5999,9 @@ fn layout_line(
|
|||||||
&style.text,
|
&style.text,
|
||||||
MAX_LINE_LEN,
|
MAX_LINE_LEN,
|
||||||
1,
|
1,
|
||||||
&[],
|
|
||||||
snapshot.mode,
|
snapshot.mode,
|
||||||
text_width,
|
text_width,
|
||||||
|
is_row_soft_wrapped,
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
.pop()
|
.pop()
|
||||||
@@ -6625,15 +6686,22 @@ mod tests {
|
|||||||
"Hardcoded expected invisibles differ from the actual ones in '{input_text}'"
|
"Hardcoded expected invisibles differ from the actual ones in '{input_text}'"
|
||||||
);
|
);
|
||||||
|
|
||||||
init_test(cx, |s| {
|
for show_line_numbers in [true, false] {
|
||||||
s.defaults.show_whitespaces = Some(ShowWhitespaceSetting::All);
|
init_test(cx, |s| {
|
||||||
s.defaults.tab_size = NonZeroU32::new(TAB_SIZE);
|
s.defaults.show_whitespaces = Some(ShowWhitespaceSetting::All);
|
||||||
});
|
s.defaults.tab_size = NonZeroU32::new(TAB_SIZE);
|
||||||
|
});
|
||||||
|
|
||||||
let actual_invisibles =
|
let actual_invisibles = collect_invisibles_from_new_editor(
|
||||||
collect_invisibles_from_new_editor(cx, EditorMode::Full, input_text, px(500.0));
|
cx,
|
||||||
|
EditorMode::Full,
|
||||||
|
input_text,
|
||||||
|
px(500.0),
|
||||||
|
show_line_numbers,
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(expected_invisibles, actual_invisibles);
|
assert_eq!(expected_invisibles, actual_invisibles);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
@@ -6647,14 +6715,17 @@ mod tests {
|
|||||||
EditorMode::SingleLine { auto_width: false },
|
EditorMode::SingleLine { auto_width: false },
|
||||||
EditorMode::AutoHeight { max_lines: 100 },
|
EditorMode::AutoHeight { max_lines: 100 },
|
||||||
] {
|
] {
|
||||||
let invisibles = collect_invisibles_from_new_editor(
|
for show_line_numbers in [true, false] {
|
||||||
cx,
|
let invisibles = collect_invisibles_from_new_editor(
|
||||||
editor_mode_without_invisibles,
|
cx,
|
||||||
"\t\t\t| | a b",
|
editor_mode_without_invisibles,
|
||||||
px(500.0),
|
"\t\t\t| | a b",
|
||||||
);
|
px(500.0),
|
||||||
assert!(invisibles.is_empty(),
|
show_line_numbers,
|
||||||
|
);
|
||||||
|
assert!(invisibles.is_empty(),
|
||||||
"For editor mode {editor_mode_without_invisibles:?} no invisibles was expected but got {invisibles:?}");
|
"For editor mode {editor_mode_without_invisibles:?} no invisibles was expected but got {invisibles:?}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6705,43 +6776,48 @@ mod tests {
|
|||||||
let resize_step = 10.0;
|
let resize_step = 10.0;
|
||||||
let mut editor_width = 200.0;
|
let mut editor_width = 200.0;
|
||||||
while editor_width <= 1000.0 {
|
while editor_width <= 1000.0 {
|
||||||
update_test_language_settings(cx, |s| {
|
for show_line_numbers in [true, false] {
|
||||||
s.defaults.tab_size = NonZeroU32::new(tab_size);
|
update_test_language_settings(cx, |s| {
|
||||||
s.defaults.show_whitespaces = Some(ShowWhitespaceSetting::All);
|
s.defaults.tab_size = NonZeroU32::new(tab_size);
|
||||||
s.defaults.preferred_line_length = Some(editor_width as u32);
|
s.defaults.show_whitespaces = Some(ShowWhitespaceSetting::All);
|
||||||
s.defaults.soft_wrap = Some(language_settings::SoftWrap::PreferredLineLength);
|
s.defaults.preferred_line_length = Some(editor_width as u32);
|
||||||
});
|
s.defaults.soft_wrap = Some(language_settings::SoftWrap::PreferredLineLength);
|
||||||
|
});
|
||||||
|
|
||||||
let actual_invisibles = collect_invisibles_from_new_editor(
|
let actual_invisibles = collect_invisibles_from_new_editor(
|
||||||
cx,
|
cx,
|
||||||
EditorMode::Full,
|
EditorMode::Full,
|
||||||
&input_text,
|
&input_text,
|
||||||
px(editor_width),
|
px(editor_width),
|
||||||
);
|
show_line_numbers,
|
||||||
|
);
|
||||||
|
|
||||||
// Whatever the editor size is, ensure it has the same invisible kinds in the same order
|
// Whatever the editor size is, ensure it has the same invisible kinds in the same order
|
||||||
// (no good guarantees about the offsets: wrapping could trigger padding and its tests should check the offsets).
|
// (no good guarantees about the offsets: wrapping could trigger padding and its tests should check the offsets).
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
for (actual_index, actual_invisible) in actual_invisibles.iter().enumerate() {
|
for (actual_index, actual_invisible) in actual_invisibles.iter().enumerate() {
|
||||||
i = actual_index;
|
i = actual_index;
|
||||||
match expected_invisibles.get(i) {
|
match expected_invisibles.get(i) {
|
||||||
Some(expected_invisible) => match (expected_invisible, actual_invisible) {
|
Some(expected_invisible) => match (expected_invisible, actual_invisible) {
|
||||||
(Invisible::Whitespace { .. }, Invisible::Whitespace { .. })
|
(Invisible::Whitespace { .. }, Invisible::Whitespace { .. })
|
||||||
| (Invisible::Tab { .. }, Invisible::Tab { .. }) => {}
|
| (Invisible::Tab { .. }, Invisible::Tab { .. }) => {}
|
||||||
_ => {
|
_ => {
|
||||||
panic!("At index {i}, expected invisible {expected_invisible:?} does not match actual {actual_invisible:?} by kind. Actual invisibles: {actual_invisibles:?}")
|
panic!("At index {i}, expected invisible {expected_invisible:?} does not match actual {actual_invisible:?} by kind. Actual invisibles: {actual_invisibles:?}")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
panic!("Unexpected extra invisible {actual_invisible:?} at index {i}")
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
None => panic!("Unexpected extra invisible {actual_invisible:?} at index {i}"),
|
|
||||||
}
|
}
|
||||||
}
|
let missing_expected_invisibles = &expected_invisibles[i + 1..];
|
||||||
let missing_expected_invisibles = &expected_invisibles[i + 1..];
|
assert!(
|
||||||
assert!(
|
missing_expected_invisibles.is_empty(),
|
||||||
missing_expected_invisibles.is_empty(),
|
"Missing expected invisibles after index {i}: {missing_expected_invisibles:?}"
|
||||||
"Missing expected invisibles after index {i}: {missing_expected_invisibles:?}"
|
);
|
||||||
);
|
|
||||||
|
|
||||||
editor_width += resize_step;
|
editor_width += resize_step;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6750,6 +6826,7 @@ mod tests {
|
|||||||
editor_mode: EditorMode,
|
editor_mode: EditorMode,
|
||||||
input_text: &str,
|
input_text: &str,
|
||||||
editor_width: Pixels,
|
editor_width: Pixels,
|
||||||
|
show_line_numbers: bool,
|
||||||
) -> Vec<Invisible> {
|
) -> Vec<Invisible> {
|
||||||
info!(
|
info!(
|
||||||
"Creating editor with mode {editor_mode:?}, width {}px and text '{input_text}'",
|
"Creating editor with mode {editor_mode:?}, width {}px and text '{input_text}'",
|
||||||
@@ -6761,11 +6838,13 @@ mod tests {
|
|||||||
});
|
});
|
||||||
let cx = &mut VisualTestContext::from_window(*window, cx);
|
let cx = &mut VisualTestContext::from_window(*window, cx);
|
||||||
let editor = window.root(cx).unwrap();
|
let editor = window.root(cx).unwrap();
|
||||||
|
|
||||||
let style = cx.update(|cx| editor.read(cx).style().unwrap().clone());
|
let style = cx.update(|cx| editor.read(cx).style().unwrap().clone());
|
||||||
window
|
window
|
||||||
.update(cx, |editor, cx| {
|
.update(cx, |editor, cx| {
|
||||||
editor.set_soft_wrap_mode(language_settings::SoftWrap::EditorWidth, cx);
|
editor.set_soft_wrap_mode(language_settings::SoftWrap::EditorWidth, cx);
|
||||||
editor.set_wrap_width(Some(editor_width), cx);
|
editor.set_wrap_width(Some(editor_width), cx);
|
||||||
|
editor.set_show_line_numbers(show_line_numbers, cx);
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let (_, state) = cx.draw(point(px(500.), px(500.)), size(px(500.), px(500.)), |_| {
|
let (_, state) = cx.draw(point(px(500.), px(500.)), size(px(500.), px(500.)), |_| {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, px, AnyElement, AsyncWindowContext, FontWeight, Hsla, InteractiveElement, IntoElement,
|
div, px, AnyElement, AsyncWindowContext, FontWeight, Hsla, InteractiveElement, IntoElement,
|
||||||
MouseButton, ParentElement, Pixels, ScrollHandle, Size, StatefulInteractiveElement,
|
MouseButton, ParentElement, Pixels, ScrollHandle, Size, Stateful, StatefulInteractiveElement,
|
||||||
StyleRefinement, Styled, Task, TextStyleRefinement, View, ViewContext,
|
StyleRefinement, Styled, Task, TextStyleRefinement, View, ViewContext,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
@@ -21,7 +21,7 @@ use std::rc::Rc;
|
|||||||
use std::{borrow::Cow, cell::RefCell};
|
use std::{borrow::Cow, cell::RefCell};
|
||||||
use std::{ops::Range, sync::Arc, time::Duration};
|
use std::{ops::Range, sync::Arc, time::Duration};
|
||||||
use theme::ThemeSettings;
|
use theme::ThemeSettings;
|
||||||
use ui::{prelude::*, window_is_transparent};
|
use ui::{prelude::*, window_is_transparent, Scrollbar, ScrollbarState};
|
||||||
use util::TryFutureExt;
|
use util::TryFutureExt;
|
||||||
pub const HOVER_DELAY_MILLIS: u64 = 350;
|
pub const HOVER_DELAY_MILLIS: u64 = 350;
|
||||||
pub const HOVER_REQUEST_DELAY_MILLIS: u64 = 200;
|
pub const HOVER_REQUEST_DELAY_MILLIS: u64 = 200;
|
||||||
@@ -144,10 +144,12 @@ pub fn hover_at_inlay(editor: &mut Editor, inlay_hover: InlayHover, cx: &mut Vie
|
|||||||
let blocks = vec![inlay_hover.tooltip];
|
let blocks = vec![inlay_hover.tooltip];
|
||||||
let parsed_content = parse_blocks(&blocks, &language_registry, None, &mut cx).await;
|
let parsed_content = parse_blocks(&blocks, &language_registry, None, &mut cx).await;
|
||||||
|
|
||||||
|
let scroll_handle = ScrollHandle::new();
|
||||||
let hover_popover = InfoPopover {
|
let hover_popover = InfoPopover {
|
||||||
symbol_range: RangeInEditor::Inlay(inlay_hover.range.clone()),
|
symbol_range: RangeInEditor::Inlay(inlay_hover.range.clone()),
|
||||||
parsed_content,
|
parsed_content,
|
||||||
scroll_handle: ScrollHandle::new(),
|
scrollbar_state: ScrollbarState::new(scroll_handle.clone()),
|
||||||
|
scroll_handle,
|
||||||
keyboard_grace: Rc::new(RefCell::new(false)),
|
keyboard_grace: Rc::new(RefCell::new(false)),
|
||||||
anchor: None,
|
anchor: None,
|
||||||
};
|
};
|
||||||
@@ -435,12 +437,14 @@ fn show_hover(
|
|||||||
let language = hover_result.language;
|
let language = hover_result.language;
|
||||||
let parsed_content =
|
let parsed_content =
|
||||||
parse_blocks(&blocks, &language_registry, language, &mut cx).await;
|
parse_blocks(&blocks, &language_registry, language, &mut cx).await;
|
||||||
|
let scroll_handle = ScrollHandle::new();
|
||||||
info_popover_tasks.push((
|
info_popover_tasks.push((
|
||||||
range.clone(),
|
range.clone(),
|
||||||
InfoPopover {
|
InfoPopover {
|
||||||
symbol_range: RangeInEditor::Text(range),
|
symbol_range: RangeInEditor::Text(range),
|
||||||
parsed_content,
|
parsed_content,
|
||||||
scroll_handle: ScrollHandle::new(),
|
scrollbar_state: ScrollbarState::new(scroll_handle.clone()),
|
||||||
|
scroll_handle,
|
||||||
keyboard_grace: Rc::new(RefCell::new(ignore_timeout)),
|
keyboard_grace: Rc::new(RefCell::new(ignore_timeout)),
|
||||||
anchor: Some(anchor),
|
anchor: Some(anchor),
|
||||||
},
|
},
|
||||||
@@ -611,7 +615,7 @@ impl HoverState {
|
|||||||
!self.info_popovers.is_empty() || self.diagnostic_popover.is_some()
|
!self.info_popovers.is_empty() || self.diagnostic_popover.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(
|
pub(crate) fn render(
|
||||||
&mut self,
|
&mut self,
|
||||||
snapshot: &EditorSnapshot,
|
snapshot: &EditorSnapshot,
|
||||||
visible_rows: Range<DisplayRow>,
|
visible_rows: Range<DisplayRow>,
|
||||||
@@ -680,25 +684,25 @@ impl HoverState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) struct InfoPopover {
|
||||||
pub struct InfoPopover {
|
pub(crate) symbol_range: RangeInEditor,
|
||||||
pub symbol_range: RangeInEditor,
|
pub(crate) parsed_content: Option<View<Markdown>>,
|
||||||
pub parsed_content: Option<View<Markdown>>,
|
pub(crate) scroll_handle: ScrollHandle,
|
||||||
pub scroll_handle: ScrollHandle,
|
pub(crate) scrollbar_state: ScrollbarState,
|
||||||
pub keyboard_grace: Rc<RefCell<bool>>,
|
pub(crate) keyboard_grace: Rc<RefCell<bool>>,
|
||||||
pub anchor: Option<Anchor>,
|
pub(crate) anchor: Option<Anchor>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InfoPopover {
|
impl InfoPopover {
|
||||||
pub fn render(&mut self, max_size: Size<Pixels>, cx: &mut ViewContext<Editor>) -> AnyElement {
|
pub(crate) fn render(
|
||||||
|
&mut self,
|
||||||
|
max_size: Size<Pixels>,
|
||||||
|
cx: &mut ViewContext<Editor>,
|
||||||
|
) -> AnyElement {
|
||||||
let keyboard_grace = Rc::clone(&self.keyboard_grace);
|
let keyboard_grace = Rc::clone(&self.keyboard_grace);
|
||||||
let mut d = div()
|
let mut d = div()
|
||||||
.id("info_popover")
|
.id("info_popover")
|
||||||
.elevation_2(cx)
|
.elevation_2(cx)
|
||||||
.overflow_y_scroll()
|
|
||||||
.track_scroll(&self.scroll_handle)
|
|
||||||
.max_w(max_size.width)
|
|
||||||
.max_h(max_size.height)
|
|
||||||
// Prevent a mouse down/move on the popover from being propagated to the editor,
|
// Prevent a mouse down/move on the popover from being propagated to the editor,
|
||||||
// because that would dismiss the popover.
|
// because that would dismiss the popover.
|
||||||
.on_mouse_move(|_, cx| cx.stop_propagation())
|
.on_mouse_move(|_, cx| cx.stop_propagation())
|
||||||
@@ -706,11 +710,21 @@ impl InfoPopover {
|
|||||||
let mut keyboard_grace = keyboard_grace.borrow_mut();
|
let mut keyboard_grace = keyboard_grace.borrow_mut();
|
||||||
*keyboard_grace = false;
|
*keyboard_grace = false;
|
||||||
cx.stop_propagation();
|
cx.stop_propagation();
|
||||||
})
|
});
|
||||||
.p_2();
|
|
||||||
|
|
||||||
if let Some(markdown) = &self.parsed_content {
|
if let Some(markdown) = &self.parsed_content {
|
||||||
d = d.child(markdown.clone());
|
d = d
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.id("info-md-container")
|
||||||
|
.overflow_y_scroll()
|
||||||
|
.max_w(max_size.width)
|
||||||
|
.max_h(max_size.height)
|
||||||
|
.p_2()
|
||||||
|
.track_scroll(&self.scroll_handle)
|
||||||
|
.child(markdown.clone()),
|
||||||
|
)
|
||||||
|
.child(self.render_vertical_scrollbar(cx));
|
||||||
}
|
}
|
||||||
d.into_any_element()
|
d.into_any_element()
|
||||||
}
|
}
|
||||||
@@ -724,6 +738,38 @@ impl InfoPopover {
|
|||||||
cx.notify();
|
cx.notify();
|
||||||
self.scroll_handle.set_offset(current);
|
self.scroll_handle.set_offset(current);
|
||||||
}
|
}
|
||||||
|
fn render_vertical_scrollbar(&self, cx: &mut ViewContext<Editor>) -> Stateful<Div> {
|
||||||
|
div()
|
||||||
|
.occlude()
|
||||||
|
.id("info-popover-vertical-scroll")
|
||||||
|
.on_mouse_move(cx.listener(|_, _, cx| {
|
||||||
|
cx.notify();
|
||||||
|
cx.stop_propagation()
|
||||||
|
}))
|
||||||
|
.on_hover(|_, cx| {
|
||||||
|
cx.stop_propagation();
|
||||||
|
})
|
||||||
|
.on_any_mouse_down(|_, cx| {
|
||||||
|
cx.stop_propagation();
|
||||||
|
})
|
||||||
|
.on_mouse_up(
|
||||||
|
MouseButton::Left,
|
||||||
|
cx.listener(|_, _, cx| {
|
||||||
|
cx.stop_propagation();
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.on_scroll_wheel(cx.listener(|_, _, cx| {
|
||||||
|
cx.notify();
|
||||||
|
}))
|
||||||
|
.h_full()
|
||||||
|
.absolute()
|
||||||
|
.right_1()
|
||||||
|
.top_1()
|
||||||
|
.bottom_0()
|
||||||
|
.w(px(12.))
|
||||||
|
.cursor_default()
|
||||||
|
.children(Scrollbar::vertical(self.scrollbar_state.clone()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -1351,6 +1397,61 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
// https://github.com/zed-industries/zed/issues/15498
|
||||||
|
async fn test_info_hover_with_hrs(cx: &mut gpui::TestAppContext) {
|
||||||
|
init_test(cx, |_| {});
|
||||||
|
|
||||||
|
let mut cx = EditorLspTestContext::new_rust(
|
||||||
|
lsp::ServerCapabilities {
|
||||||
|
hover_provider: Some(lsp::HoverProviderCapability::Simple(true)),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
cx.set_state(indoc! {"
|
||||||
|
fn fuˇnc(abc def: i32) -> u32 {
|
||||||
|
}
|
||||||
|
"});
|
||||||
|
|
||||||
|
cx.lsp.handle_request::<lsp::request::HoverRequest, _, _>({
|
||||||
|
|_, _| async move {
|
||||||
|
Ok(Some(lsp::Hover {
|
||||||
|
contents: lsp::HoverContents::Markup(lsp::MarkupContent {
|
||||||
|
kind: lsp::MarkupKind::Markdown,
|
||||||
|
value: indoc!(
|
||||||
|
r#"
|
||||||
|
### function `errands_data_read`
|
||||||
|
|
||||||
|
---
|
||||||
|
→ `char *`
|
||||||
|
Function to read a file into a string
|
||||||
|
|
||||||
|
---
|
||||||
|
```cpp
|
||||||
|
static char *errands_data_read()
|
||||||
|
```
|
||||||
|
"#
|
||||||
|
)
|
||||||
|
.to_string(),
|
||||||
|
}),
|
||||||
|
range: None,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
cx.update_editor(|editor, cx| hover(editor, &Default::default(), cx));
|
||||||
|
cx.run_until_parked();
|
||||||
|
|
||||||
|
cx.update_editor(|editor, cx| {
|
||||||
|
let popover = editor.hover_state.info_popovers.first().unwrap();
|
||||||
|
let content = popover.get_rendered_text(cx);
|
||||||
|
|
||||||
|
assert!(content.contains("Function to read a file"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_hover_inlay_label_parts(cx: &mut gpui::TestAppContext) {
|
async fn test_hover_inlay_label_parts(cx: &mut gpui::TestAppContext) {
|
||||||
init_test(cx, |settings| {
|
init_test(cx, |settings| {
|
||||||
|
|||||||
@@ -992,12 +992,15 @@ impl SerializableItem for Editor {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// First create the empty buffer
|
// First create the empty buffer
|
||||||
let buffer = project.update(&mut cx, |project, cx| {
|
let buffer = project
|
||||||
project.create_local_buffer("", language, cx)
|
.update(&mut cx, |project, cx| project.create_buffer(cx))?
|
||||||
})?;
|
.await?;
|
||||||
|
|
||||||
// Then set the text so that the dirty bit is set correctly
|
// Then set the text so that the dirty bit is set correctly
|
||||||
buffer.update(&mut cx, |buffer, cx| {
|
buffer.update(&mut cx, |buffer, cx| {
|
||||||
|
if let Some(language) = language {
|
||||||
|
buffer.set_language(Some(language), cx);
|
||||||
|
}
|
||||||
buffer.set_text(contents, cx);
|
buffer.set_text(contents, cx);
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
@@ -1277,7 +1280,7 @@ impl SearchableItem for Editor {
|
|||||||
matches: &[Range<Anchor>],
|
matches: &[Range<Anchor>],
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) {
|
) {
|
||||||
self.unfold_ranges([matches[index].clone()], false, true, cx);
|
self.unfold_ranges(&[matches[index].clone()], false, true, cx);
|
||||||
let range = self.range_for_match(&matches[index]);
|
let range = self.range_for_match(&matches[index]);
|
||||||
self.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
self.change_selections(Some(Autoscroll::fit()), cx, |s| {
|
||||||
s.select_ranges([range]);
|
s.select_ranges([range]);
|
||||||
@@ -1285,7 +1288,7 @@ impl SearchableItem for Editor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn select_matches(&mut self, matches: &[Self::Match], cx: &mut ViewContext<Self>) {
|
fn select_matches(&mut self, matches: &[Self::Match], cx: &mut ViewContext<Self>) {
|
||||||
self.unfold_ranges(matches.to_vec(), false, false, cx);
|
self.unfold_ranges(matches, false, false, cx);
|
||||||
let mut ranges = Vec::new();
|
let mut ranges = Vec::new();
|
||||||
for m in matches {
|
for m in matches {
|
||||||
ranges.push(self.range_for_match(m))
|
ranges.push(self.range_for_match(m))
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use std::ops::Range;
|
use std::{ops::Range, time::Duration};
|
||||||
|
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
@@ -36,35 +36,53 @@ impl LinkedEditingRanges {
|
|||||||
self.0.is_empty()
|
self.0.is_empty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub(super) fn refresh_linked_ranges(this: &mut Editor, cx: &mut ViewContext<Editor>) -> Option<()> {
|
|
||||||
if this.pending_rename.is_some() {
|
const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
|
||||||
|
|
||||||
|
// TODO do not refresh anything at all, if the settings/capabilities do not have it enabled.
|
||||||
|
pub(super) fn refresh_linked_ranges(
|
||||||
|
editor: &mut Editor,
|
||||||
|
cx: &mut ViewContext<Editor>,
|
||||||
|
) -> Option<()> {
|
||||||
|
if editor.pending_rename.is_some() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let project = this.project.clone()?;
|
let project = editor.project.as_ref()?.downgrade();
|
||||||
let selections = this.selections.all::<usize>(cx);
|
|
||||||
let buffer = this.buffer.read(cx);
|
editor.linked_editing_range_task = Some(cx.spawn(|editor, mut cx| async move {
|
||||||
let mut applicable_selections = vec![];
|
cx.background_executor().timer(UPDATE_DEBOUNCE).await;
|
||||||
let snapshot = buffer.snapshot(cx);
|
|
||||||
for selection in selections {
|
let mut applicable_selections = Vec::new();
|
||||||
let cursor_position = selection.head();
|
editor
|
||||||
let start_position = snapshot.anchor_before(cursor_position);
|
.update(&mut cx, |editor, cx| {
|
||||||
let end_position = snapshot.anchor_after(selection.tail());
|
let selections = editor.selections.all::<usize>(cx);
|
||||||
if start_position.buffer_id != end_position.buffer_id || end_position.buffer_id.is_none() {
|
let snapshot = editor.buffer.read(cx).snapshot(cx);
|
||||||
// Throw away selections spanning multiple buffers.
|
let buffer = editor.buffer.read(cx);
|
||||||
continue;
|
for selection in selections {
|
||||||
|
let cursor_position = selection.head();
|
||||||
|
let start_position = snapshot.anchor_before(cursor_position);
|
||||||
|
let end_position = snapshot.anchor_after(selection.tail());
|
||||||
|
if start_position.buffer_id != end_position.buffer_id
|
||||||
|
|| end_position.buffer_id.is_none()
|
||||||
|
{
|
||||||
|
// Throw away selections spanning multiple buffers.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let Some(buffer) = end_position.buffer_id.and_then(|id| buffer.buffer(id)) {
|
||||||
|
applicable_selections.push((
|
||||||
|
buffer,
|
||||||
|
start_position.text_anchor,
|
||||||
|
end_position.text_anchor,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.ok()?;
|
||||||
|
|
||||||
|
if applicable_selections.is_empty() {
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
if let Some(buffer) = end_position.buffer_id.and_then(|id| buffer.buffer(id)) {
|
|
||||||
applicable_selections.push((
|
|
||||||
buffer,
|
|
||||||
start_position.text_anchor,
|
|
||||||
end_position.text_anchor,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if applicable_selections.is_empty() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
this.linked_editing_range_task = Some(cx.spawn(|this, mut cx| async move {
|
|
||||||
let highlights = project
|
let highlights = project
|
||||||
.update(&mut cx, |project, cx| {
|
.update(&mut cx, |project, cx| {
|
||||||
let mut linked_edits_tasks = vec![];
|
let mut linked_edits_tasks = vec![];
|
||||||
@@ -110,37 +128,38 @@ pub(super) fn refresh_linked_ranges(this: &mut Editor, cx: &mut ViewContext<Edit
|
|||||||
}
|
}
|
||||||
linked_edits_tasks
|
linked_edits_tasks
|
||||||
})
|
})
|
||||||
.log_err()?;
|
.ok()?;
|
||||||
|
|
||||||
let highlights = futures::future::join_all(highlights).await;
|
let highlights = futures::future::join_all(highlights).await;
|
||||||
|
|
||||||
this.update(&mut cx, |this, cx| {
|
editor
|
||||||
this.linked_edit_ranges.0.clear();
|
.update(&mut cx, |this, cx| {
|
||||||
if this.pending_rename.is_some() {
|
this.linked_edit_ranges.0.clear();
|
||||||
return;
|
if this.pending_rename.is_some() {
|
||||||
}
|
return;
|
||||||
for (buffer_id, ranges) in highlights.into_iter().flatten() {
|
}
|
||||||
this.linked_edit_ranges
|
for (buffer_id, ranges) in highlights.into_iter().flatten() {
|
||||||
.0
|
this.linked_edit_ranges
|
||||||
.entry(buffer_id)
|
.0
|
||||||
.or_default()
|
.entry(buffer_id)
|
||||||
.extend(ranges);
|
.or_default()
|
||||||
}
|
.extend(ranges);
|
||||||
for (buffer_id, values) in this.linked_edit_ranges.0.iter_mut() {
|
}
|
||||||
let Some(snapshot) = this
|
for (buffer_id, values) in this.linked_edit_ranges.0.iter_mut() {
|
||||||
.buffer
|
let Some(snapshot) = this
|
||||||
.read(cx)
|
.buffer
|
||||||
.buffer(*buffer_id)
|
.read(cx)
|
||||||
.map(|buffer| buffer.read(cx).snapshot())
|
.buffer(*buffer_id)
|
||||||
else {
|
.map(|buffer| buffer.read(cx).snapshot())
|
||||||
continue;
|
else {
|
||||||
};
|
continue;
|
||||||
values.sort_by(|lhs, rhs| lhs.0.cmp(&rhs.0, &snapshot));
|
};
|
||||||
}
|
values.sort_by(|lhs, rhs| lhs.0.cmp(&rhs.0, &snapshot));
|
||||||
|
}
|
||||||
|
|
||||||
cx.notify();
|
cx.notify();
|
||||||
})
|
})
|
||||||
.log_err();
|
.ok()?;
|
||||||
|
|
||||||
Some(())
|
Some(())
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::{
|
use std::{
|
||||||
cell::Ref,
|
cell::Ref,
|
||||||
iter, mem,
|
cmp, iter, mem,
|
||||||
ops::{Deref, DerefMut, Range, Sub},
|
ops::{Deref, DerefMut, Range, Sub},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
@@ -98,9 +98,9 @@ impl SelectionsCollection {
|
|||||||
&self,
|
&self,
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Option<Selection<D>> {
|
) -> Option<Selection<D>> {
|
||||||
self.pending_anchor()
|
let map = self.display_map(cx);
|
||||||
.as_ref()
|
let selection = resolve_selections(self.pending_anchor().as_ref(), &map).next();
|
||||||
.map(|pending| pending.map(|p| p.summary::<D>(&self.buffer(cx))))
|
selection
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn pending_mode(&self) -> Option<SelectMode> {
|
pub(crate) fn pending_mode(&self) -> Option<SelectMode> {
|
||||||
@@ -111,12 +111,10 @@ impl SelectionsCollection {
|
|||||||
where
|
where
|
||||||
D: 'a + TextDimension + Ord + Sub<D, Output = D>,
|
D: 'a + TextDimension + Ord + Sub<D, Output = D>,
|
||||||
{
|
{
|
||||||
|
let map = self.display_map(cx);
|
||||||
let disjoint_anchors = &self.disjoint;
|
let disjoint_anchors = &self.disjoint;
|
||||||
let mut disjoint =
|
let mut disjoint = resolve_selections::<D, _>(disjoint_anchors.iter(), &map).peekable();
|
||||||
resolve_multiple::<D, _>(disjoint_anchors.iter(), &self.buffer(cx)).peekable();
|
|
||||||
|
|
||||||
let mut pending_opt = self.pending::<D>(cx);
|
let mut pending_opt = self.pending::<D>(cx);
|
||||||
|
|
||||||
iter::from_fn(move || {
|
iter::from_fn(move || {
|
||||||
if let Some(pending) = pending_opt.as_mut() {
|
if let Some(pending) = pending_opt.as_mut() {
|
||||||
while let Some(next_selection) = disjoint.peek() {
|
while let Some(next_selection) = disjoint.peek() {
|
||||||
@@ -199,34 +197,57 @@ impl SelectionsCollection {
|
|||||||
where
|
where
|
||||||
D: 'a + TextDimension + Ord + Sub<D, Output = D> + std::fmt::Debug,
|
D: 'a + TextDimension + Ord + Sub<D, Output = D> + std::fmt::Debug,
|
||||||
{
|
{
|
||||||
let buffer = self.buffer(cx);
|
let map = self.display_map(cx);
|
||||||
let start_ix = match self
|
let start_ix = match self
|
||||||
.disjoint
|
.disjoint
|
||||||
.binary_search_by(|probe| probe.end.cmp(&range.start, &buffer))
|
.binary_search_by(|probe| probe.end.cmp(&range.start, &map.buffer_snapshot))
|
||||||
{
|
{
|
||||||
Ok(ix) | Err(ix) => ix,
|
Ok(ix) | Err(ix) => ix,
|
||||||
};
|
};
|
||||||
let end_ix = match self
|
let end_ix = match self
|
||||||
.disjoint
|
.disjoint
|
||||||
.binary_search_by(|probe| probe.start.cmp(&range.end, &buffer))
|
.binary_search_by(|probe| probe.start.cmp(&range.end, &map.buffer_snapshot))
|
||||||
{
|
{
|
||||||
Ok(ix) => ix + 1,
|
Ok(ix) => ix + 1,
|
||||||
Err(ix) => ix,
|
Err(ix) => ix,
|
||||||
};
|
};
|
||||||
resolve_multiple(&self.disjoint[start_ix..end_ix], &buffer).collect()
|
resolve_selections(&self.disjoint[start_ix..end_ix], &map).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn all_display(
|
pub fn all_display(
|
||||||
&self,
|
&self,
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
) -> (DisplaySnapshot, Vec<Selection<DisplayPoint>>) {
|
) -> (DisplaySnapshot, Vec<Selection<DisplayPoint>>) {
|
||||||
let display_map = self.display_map(cx);
|
let map = self.display_map(cx);
|
||||||
let selections = self
|
let disjoint_anchors = &self.disjoint;
|
||||||
.all::<Point>(cx)
|
let mut disjoint = resolve_selections_display(disjoint_anchors.iter(), &map).peekable();
|
||||||
.into_iter()
|
let mut pending_opt =
|
||||||
.map(|selection| selection.map(|point| point.to_display_point(&display_map)))
|
resolve_selections_display(self.pending_anchor().as_ref(), &map).next();
|
||||||
.collect();
|
let selections = iter::from_fn(move || {
|
||||||
(display_map, selections)
|
if let Some(pending) = pending_opt.as_mut() {
|
||||||
|
while let Some(next_selection) = disjoint.peek() {
|
||||||
|
if pending.start <= next_selection.end && pending.end >= next_selection.start {
|
||||||
|
let next_selection = disjoint.next().unwrap();
|
||||||
|
if next_selection.start < pending.start {
|
||||||
|
pending.start = next_selection.start;
|
||||||
|
}
|
||||||
|
if next_selection.end > pending.end {
|
||||||
|
pending.end = next_selection.end;
|
||||||
|
}
|
||||||
|
} else if next_selection.end < pending.start {
|
||||||
|
return disjoint.next();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pending_opt.take()
|
||||||
|
} else {
|
||||||
|
disjoint.next()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
(map, selections)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn newest_anchor(&self) -> &Selection<Anchor> {
|
pub fn newest_anchor(&self) -> &Selection<Anchor> {
|
||||||
@@ -241,15 +262,18 @@ impl SelectionsCollection {
|
|||||||
&self,
|
&self,
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Selection<D> {
|
) -> Selection<D> {
|
||||||
let buffer = self.buffer(cx);
|
let map = self.display_map(cx);
|
||||||
self.newest_anchor().map(|p| p.summary::<D>(&buffer))
|
let selection = resolve_selections([self.newest_anchor()], &map)
|
||||||
|
.next()
|
||||||
|
.unwrap();
|
||||||
|
selection
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn newest_display(&self, cx: &mut AppContext) -> Selection<DisplayPoint> {
|
pub fn newest_display(&self, cx: &mut AppContext) -> Selection<DisplayPoint> {
|
||||||
let display_map = self.display_map(cx);
|
let map = self.display_map(cx);
|
||||||
let selection = self
|
let selection = resolve_selections_display([self.newest_anchor()], &map)
|
||||||
.newest_anchor()
|
.next()
|
||||||
.map(|point| point.to_display_point(&display_map));
|
.unwrap();
|
||||||
selection
|
selection
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,8 +289,11 @@ impl SelectionsCollection {
|
|||||||
&self,
|
&self,
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Selection<D> {
|
) -> Selection<D> {
|
||||||
let buffer = self.buffer(cx);
|
let map = self.display_map(cx);
|
||||||
self.oldest_anchor().map(|p| p.summary::<D>(&buffer))
|
let selection = resolve_selections([self.oldest_anchor()], &map)
|
||||||
|
.next()
|
||||||
|
.unwrap();
|
||||||
|
selection
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn first_anchor(&self) -> Selection<Anchor> {
|
pub fn first_anchor(&self) -> Selection<Anchor> {
|
||||||
@@ -538,9 +565,9 @@ impl<'a> MutableSelectionsCollection<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn select_anchors(&mut self, selections: Vec<Selection<Anchor>>) {
|
pub fn select_anchors(&mut self, selections: Vec<Selection<Anchor>>) {
|
||||||
let buffer = self.buffer.read(self.cx).snapshot(self.cx);
|
let map = self.display_map();
|
||||||
let resolved_selections =
|
let resolved_selections =
|
||||||
resolve_multiple::<usize, _>(&selections, &buffer).collect::<Vec<_>>();
|
resolve_selections::<usize, _>(&selections, &map).collect::<Vec<_>>();
|
||||||
self.select(resolved_selections);
|
self.select(resolved_selections);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -650,20 +677,16 @@ impl<'a> MutableSelectionsCollection<'a> {
|
|||||||
) {
|
) {
|
||||||
let mut changed = false;
|
let mut changed = false;
|
||||||
let display_map = self.display_map();
|
let display_map = self.display_map();
|
||||||
let selections = self
|
let (_, selections) = self.collection.all_display(self.cx);
|
||||||
.collection
|
let selections = selections
|
||||||
.all::<Point>(self.cx)
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|selection| {
|
.map(|selection| {
|
||||||
let mut moved_selection =
|
let mut moved_selection = selection.clone();
|
||||||
selection.map(|point| point.to_display_point(&display_map));
|
|
||||||
move_selection(&display_map, &mut moved_selection);
|
move_selection(&display_map, &mut moved_selection);
|
||||||
let moved_selection =
|
|
||||||
moved_selection.map(|display_point| display_point.to_point(&display_map));
|
|
||||||
if selection != moved_selection {
|
if selection != moved_selection {
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
moved_selection
|
moved_selection.map(|display_point| display_point.to_point(&display_map))
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@@ -804,8 +827,8 @@ impl<'a> MutableSelectionsCollection<'a> {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if !adjusted_disjoint.is_empty() {
|
if !adjusted_disjoint.is_empty() {
|
||||||
let resolved_selections =
|
let map = self.display_map();
|
||||||
resolve_multiple(adjusted_disjoint.iter(), &self.buffer()).collect();
|
let resolved_selections = resolve_selections(adjusted_disjoint.iter(), &map).collect();
|
||||||
self.select::<usize>(resolved_selections);
|
self.select::<usize>(resolved_selections);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -849,27 +872,76 @@ impl<'a> DerefMut for MutableSelectionsCollection<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Panics if passed selections are not in order
|
// Panics if passed selections are not in order
|
||||||
pub(crate) fn resolve_multiple<'a, D, I>(
|
fn resolve_selections_display<'a>(
|
||||||
selections: I,
|
selections: impl 'a + IntoIterator<Item = &'a Selection<Anchor>>,
|
||||||
snapshot: &MultiBufferSnapshot,
|
map: &'a DisplaySnapshot,
|
||||||
) -> impl 'a + Iterator<Item = Selection<D>>
|
) -> impl 'a + Iterator<Item = Selection<DisplayPoint>> {
|
||||||
where
|
|
||||||
D: TextDimension + Ord + Sub<D, Output = D>,
|
|
||||||
I: 'a + IntoIterator<Item = &'a Selection<Anchor>>,
|
|
||||||
{
|
|
||||||
let (to_summarize, selections) = selections.into_iter().tee();
|
let (to_summarize, selections) = selections.into_iter().tee();
|
||||||
let mut summaries = snapshot
|
let mut summaries = map
|
||||||
.summaries_for_anchors::<D, _>(
|
.buffer_snapshot
|
||||||
to_summarize
|
.summaries_for_anchors::<Point, _>(to_summarize.flat_map(|s| [&s.start, &s.end]))
|
||||||
.flat_map(|s| [&s.start, &s.end])
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
)
|
|
||||||
.into_iter();
|
.into_iter();
|
||||||
selections.map(move |s| Selection {
|
let mut selections = selections
|
||||||
id: s.id,
|
.map(move |s| {
|
||||||
start: summaries.next().unwrap(),
|
let start = summaries.next().unwrap();
|
||||||
end: summaries.next().unwrap(),
|
let end = summaries.next().unwrap();
|
||||||
reversed: s.reversed,
|
|
||||||
goal: s.goal,
|
let display_start = map.point_to_display_point(start, Bias::Left);
|
||||||
|
let display_end = if start == end {
|
||||||
|
map.point_to_display_point(end, Bias::Right)
|
||||||
|
} else {
|
||||||
|
map.point_to_display_point(end, Bias::Left)
|
||||||
|
};
|
||||||
|
|
||||||
|
Selection {
|
||||||
|
id: s.id,
|
||||||
|
start: display_start,
|
||||||
|
end: display_end,
|
||||||
|
reversed: s.reversed,
|
||||||
|
goal: s.goal,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.peekable();
|
||||||
|
iter::from_fn(move || {
|
||||||
|
let mut selection = selections.next()?;
|
||||||
|
while let Some(next_selection) = selections.peek() {
|
||||||
|
if selection.end >= next_selection.start {
|
||||||
|
selection.end = cmp::max(selection.end, next_selection.end);
|
||||||
|
selections.next();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(selection)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panics if passed selections are not in order
|
||||||
|
pub(crate) fn resolve_selections<'a, D, I>(
|
||||||
|
selections: I,
|
||||||
|
map: &'a DisplaySnapshot,
|
||||||
|
) -> impl 'a + Iterator<Item = Selection<D>>
|
||||||
|
where
|
||||||
|
D: TextDimension + Clone + Ord + Sub<D, Output = D>,
|
||||||
|
I: 'a + IntoIterator<Item = &'a Selection<Anchor>>,
|
||||||
|
{
|
||||||
|
let (to_convert, selections) = resolve_selections_display(selections, map).tee();
|
||||||
|
let mut converted_endpoints =
|
||||||
|
map.buffer_snapshot
|
||||||
|
.dimensions_from_points::<D>(to_convert.flat_map(|s| {
|
||||||
|
let start = map.display_point_to_point(s.start, Bias::Left);
|
||||||
|
let end = map.display_point_to_point(s.end, Bias::Right);
|
||||||
|
[start, end]
|
||||||
|
}));
|
||||||
|
selections.map(move |s| {
|
||||||
|
let start = converted_endpoints.next().unwrap();
|
||||||
|
let end = converted_endpoints.next().unwrap();
|
||||||
|
Selection {
|
||||||
|
id: s.id,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
reversed: s.reversed,
|
||||||
|
goal: s.goal,
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ languages.workspace = true
|
|||||||
node_runtime.workspace = true
|
node_runtime.workspace = true
|
||||||
open_ai.workspace = true
|
open_ai.workspace = true
|
||||||
project.workspace = true
|
project.workspace = true
|
||||||
semantic_index.workspace = true
|
reqwest_client.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
settings.workspace = true
|
settings.workspace = true
|
||||||
smol.workspace = true
|
smol.workspace = true
|
||||||
reqwest_client.workspace = true
|
zed_common.workspace = true
|
||||||
|
|||||||
@@ -13,9 +13,6 @@ use node_runtime::NodeRuntime;
|
|||||||
use open_ai::OpenAiEmbeddingModel;
|
use open_ai::OpenAiEmbeddingModel;
|
||||||
use project::Project;
|
use project::Project;
|
||||||
use reqwest_client::ReqwestClient;
|
use reqwest_client::ReqwestClient;
|
||||||
use semantic_index::{
|
|
||||||
EmbeddingProvider, OpenAiEmbeddingProvider, ProjectIndex, SemanticDb, Status,
|
|
||||||
};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use settings::SettingsStore;
|
use settings::SettingsStore;
|
||||||
use smol::channel::bounded;
|
use smol::channel::bounded;
|
||||||
@@ -33,6 +30,9 @@ use std::{
|
|||||||
Arc,
|
Arc,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use zed_common::semantic_index::{
|
||||||
|
EmbeddingProvider, OpenAiEmbeddingProvider, ProjectIndex, SemanticDb, Status,
|
||||||
|
};
|
||||||
|
|
||||||
const CODESEARCH_NET_DIR: &'static str = "target/datasets/code-search-net";
|
const CODESEARCH_NET_DIR: &'static str = "target/datasets/code-search-net";
|
||||||
const EVAL_REPOS_DIR: &'static str = "target/datasets/eval-repos";
|
const EVAL_REPOS_DIR: &'static str = "target/datasets/eval-repos";
|
||||||
|
|||||||
@@ -9,59 +9,23 @@ license = "GPL-3.0-or-later"
|
|||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
path = "src/extension_store.rs"
|
path = "src/extension.rs"
|
||||||
doctest = false
|
|
||||||
|
|
||||||
[features]
|
|
||||||
no-webrtc = ["workspace/no-webrtc"]
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
assistant_slash_command.workspace = true
|
|
||||||
async-compression.workspace = true
|
async-compression.workspace = true
|
||||||
async-tar.workspace = true
|
async-tar.workspace = true
|
||||||
async-trait.workspace = true
|
|
||||||
client.workspace = true
|
|
||||||
collections.workspace = true
|
collections.workspace = true
|
||||||
fs.workspace = true
|
fs.workspace = true
|
||||||
futures.workspace = true
|
futures.workspace = true
|
||||||
gpui.workspace = true
|
|
||||||
http_client.workspace = true
|
http_client.workspace = true
|
||||||
indexed_docs.workspace = true
|
|
||||||
language.workspace = true
|
language.workspace = true
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
lsp.workspace = true
|
lsp.workspace = true
|
||||||
node_runtime.workspace = true
|
|
||||||
paths.workspace = true
|
|
||||||
project.workspace = true
|
|
||||||
release_channel.workspace = true
|
|
||||||
schemars.workspace = true
|
|
||||||
semantic_version.workspace = true
|
semantic_version.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
serde_json_lenient.workspace = true
|
|
||||||
settings.workspace = true
|
|
||||||
snippet_provider.workspace = true
|
|
||||||
task.workspace = true
|
|
||||||
theme.workspace = true
|
|
||||||
toml.workspace = true
|
toml.workspace = true
|
||||||
ui.workspace = true
|
|
||||||
url.workspace = true
|
|
||||||
util.workspace = true
|
|
||||||
wasm-encoder.workspace = true
|
wasm-encoder.workspace = true
|
||||||
wasmparser.workspace = true
|
wasmparser.workspace = true
|
||||||
wasmtime-wasi.workspace = true
|
|
||||||
wasmtime.workspace = true
|
|
||||||
wit-component.workspace = true
|
wit-component.workspace = true
|
||||||
workspace.workspace = true
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
ctor.workspace = true
|
|
||||||
env_logger.workspace = true
|
|
||||||
fs = { workspace = true, features = ["test-support"] }
|
|
||||||
gpui = { workspace = true, features = ["test-support"] }
|
|
||||||
language = { workspace = true, features = ["test-support"] }
|
|
||||||
parking_lot.workspace = true
|
|
||||||
project = { workspace = true, features = ["test-support"] }
|
|
||||||
reqwest_client.workspace = true
|
|
||||||
workspace = { workspace = true, features = ["test-support"] }
|
|
||||||
|
|||||||
50
crates/extension/src/extension.rs
Normal file
50
crates/extension/src/extension.rs
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
pub mod extension_builder;
|
||||||
|
mod extension_manifest;
|
||||||
|
|
||||||
|
use anyhow::{anyhow, bail, Context as _, Result};
|
||||||
|
use semantic_version::SemanticVersion;
|
||||||
|
|
||||||
|
pub use crate::extension_manifest::*;
|
||||||
|
|
||||||
|
pub fn parse_wasm_extension_version(
|
||||||
|
extension_id: &str,
|
||||||
|
wasm_bytes: &[u8],
|
||||||
|
) -> Result<SemanticVersion> {
|
||||||
|
let mut version = None;
|
||||||
|
|
||||||
|
for part in wasmparser::Parser::new(0).parse_all(wasm_bytes) {
|
||||||
|
if let wasmparser::Payload::CustomSection(s) =
|
||||||
|
part.context("error parsing wasm extension")?
|
||||||
|
{
|
||||||
|
if s.name() == "zed:api-version" {
|
||||||
|
version = parse_wasm_extension_version_custom_section(s.data());
|
||||||
|
if version.is_none() {
|
||||||
|
bail!(
|
||||||
|
"extension {} has invalid zed:api-version section: {:?}",
|
||||||
|
extension_id,
|
||||||
|
s.data()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The reason we wait until we're done parsing all of the Wasm bytes to return the version
|
||||||
|
// is to work around a panic that can happen inside of Wasmtime when the bytes are invalid.
|
||||||
|
//
|
||||||
|
// By parsing the entirety of the Wasm bytes before we return, we're able to detect this problem
|
||||||
|
// earlier as an `Err` rather than as a panic.
|
||||||
|
version.ok_or_else(|| anyhow!("extension {} has no zed:api-version section", extension_id))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_wasm_extension_version_custom_section(data: &[u8]) -> Option<SemanticVersion> {
|
||||||
|
if data.len() == 6 {
|
||||||
|
Some(SemanticVersion::new(
|
||||||
|
u16::from_be_bytes([data[0], data[1]]) as _,
|
||||||
|
u16::from_be_bytes([data[2], data[3]]) as _,
|
||||||
|
u16::from_be_bytes([data[4], data[5]]) as _,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::wasm_host::parse_wasm_extension_version;
|
use crate::{
|
||||||
use crate::ExtensionManifest;
|
parse_wasm_extension_version, ExtensionLibraryKind, ExtensionManifest, GrammarManifestEntry,
|
||||||
use crate::{extension_manifest::ExtensionLibraryKind, GrammarManifestEntry};
|
};
|
||||||
use anyhow::{anyhow, bail, Context as _, Result};
|
use anyhow::{anyhow, bail, Context as _, Result};
|
||||||
use async_compression::futures::bufread::GzipDecoder;
|
use async_compression::futures::bufread::GzipDecoder;
|
||||||
use async_tar::Archive;
|
use async_tar::Archive;
|
||||||
@@ -36,7 +36,7 @@ const WASI_ADAPTER_URL: &str =
|
|||||||
const WASI_SDK_URL: &str = "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-21/";
|
const WASI_SDK_URL: &str = "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-21/";
|
||||||
const WASI_SDK_ASSET_NAME: Option<&str> = if cfg!(target_os = "macos") {
|
const WASI_SDK_ASSET_NAME: Option<&str> = if cfg!(target_os = "macos") {
|
||||||
Some("wasi-sdk-21.0-macos.tar.gz")
|
Some("wasi-sdk-21.0-macos.tar.gz")
|
||||||
} else if cfg!(target_os = "linux") {
|
} else if cfg!(any(target_os = "linux", target_os = "freebsd")) {
|
||||||
Some("wasi-sdk-21.0-linux.tar.gz")
|
Some("wasi-sdk-21.0-linux.tar.gz")
|
||||||
} else if cfg!(target_os = "windows") {
|
} else if cfg!(target_os = "windows") {
|
||||||
Some("wasi-sdk-21.0.m-mingw.tar.gz")
|
Some("wasi-sdk-21.0.m-mingw.tar.gz")
|
||||||
@@ -135,6 +135,8 @@ impl ExtensionBuilder {
|
|||||||
.args(options.release.then_some("--release"))
|
.args(options.release.then_some("--release"))
|
||||||
.arg("--target-dir")
|
.arg("--target-dir")
|
||||||
.arg(extension_dir.join("target"))
|
.arg(extension_dir.join("target"))
|
||||||
|
// WASI builds do not work with sccache and just stuck, so disable it.
|
||||||
|
.env("RUSTC_WRAPPER", "")
|
||||||
.current_dir(extension_dir)
|
.current_dir(extension_dir)
|
||||||
.output()
|
.output()
|
||||||
.context("failed to run `cargo`")?;
|
.context("failed to run `cargo`")?;
|
||||||
@@ -363,12 +365,15 @@ impl ExtensionBuilder {
|
|||||||
|
|
||||||
let output = Command::new("rustup")
|
let output = Command::new("rustup")
|
||||||
.args(["target", "add", RUST_TARGET])
|
.args(["target", "add", RUST_TARGET])
|
||||||
.stderr(Stdio::inherit())
|
.stderr(Stdio::piped())
|
||||||
.stdout(Stdio::inherit())
|
.stdout(Stdio::inherit())
|
||||||
.output()
|
.output()
|
||||||
.context("failed to run `rustup target add`")?;
|
.context("failed to run `rustup target add`")?;
|
||||||
if !output.status.success() {
|
if !output.status.success() {
|
||||||
bail!("failed to install the `{RUST_TARGET}` target");
|
bail!(
|
||||||
|
"failed to install the `{RUST_TARGET}` target: {}",
|
||||||
|
String::from_utf8_lossy(&rustc_output.stderr)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use collections::{BTreeMap, HashMap};
|
use collections::{BTreeMap, HashMap};
|
||||||
use fs::Fs;
|
use fs::Fs;
|
||||||
use language::{LanguageName, LanguageServerName};
|
use language::LanguageName;
|
||||||
|
use lsp::LanguageServerName;
|
||||||
use semantic_version::SemanticVersion;
|
use semantic_version::SemanticVersion;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
@@ -75,6 +76,8 @@ pub struct ExtensionManifest {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub language_servers: BTreeMap<LanguageServerName, LanguageServerManifestEntry>,
|
pub language_servers: BTreeMap<LanguageServerName, LanguageServerManifestEntry>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
pub context_servers: BTreeMap<Arc<str>, ContextServerManifestEntry>,
|
||||||
|
#[serde(default)]
|
||||||
pub slash_commands: BTreeMap<Arc<str>, SlashCommandManifestEntry>,
|
pub slash_commands: BTreeMap<Arc<str>, SlashCommandManifestEntry>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub indexed_docs_providers: BTreeMap<Arc<str>, IndexedDocsProviderEntry>,
|
pub indexed_docs_providers: BTreeMap<Arc<str>, IndexedDocsProviderEntry>,
|
||||||
@@ -134,6 +137,9 @@ impl LanguageServerManifestEntry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
|
||||||
|
pub struct ContextServerManifestEntry {}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
|
#[derive(Clone, PartialEq, Eq, Debug, Deserialize, Serialize)]
|
||||||
pub struct SlashCommandManifestEntry {
|
pub struct SlashCommandManifestEntry {
|
||||||
pub description: String,
|
pub description: String,
|
||||||
@@ -205,6 +211,7 @@ fn manifest_from_old_manifest(
|
|||||||
.map(|grammar_name| (grammar_name, Default::default()))
|
.map(|grammar_name| (grammar_name, Default::default()))
|
||||||
.collect(),
|
.collect(),
|
||||||
language_servers: Default::default(),
|
language_servers: Default::default(),
|
||||||
|
context_servers: BTreeMap::default(),
|
||||||
slash_commands: BTreeMap::default(),
|
slash_commands: BTreeMap::default(),
|
||||||
indexed_docs_providers: BTreeMap::default(),
|
indexed_docs_providers: BTreeMap::default(),
|
||||||
snippets: None,
|
snippets: None,
|
||||||
|
|||||||
@@ -129,6 +129,11 @@ pub trait Extension: Send + Sync {
|
|||||||
Err("`run_slash_command` not implemented".to_string())
|
Err("`run_slash_command` not implemented".to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the command used to start a context server.
|
||||||
|
fn context_server_command(&mut self, _context_server_id: &ContextServerId) -> Result<Command> {
|
||||||
|
Err("`context_server_command` not implemented".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a list of package names as suggestions to be included in the
|
/// Returns a list of package names as suggestions to be included in the
|
||||||
/// search results of the `/docs` slash command.
|
/// search results of the `/docs` slash command.
|
||||||
///
|
///
|
||||||
@@ -270,6 +275,11 @@ impl wit::Guest for Component {
|
|||||||
extension().run_slash_command(command, args, worktree)
|
extension().run_slash_command(command, args, worktree)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn context_server_command(context_server_id: String) -> Result<wit::Command> {
|
||||||
|
let context_server_id = ContextServerId(context_server_id);
|
||||||
|
extension().context_server_command(&context_server_id)
|
||||||
|
}
|
||||||
|
|
||||||
fn suggest_docs_packages(provider: String) -> Result<Vec<String>, String> {
|
fn suggest_docs_packages(provider: String) -> Result<Vec<String>, String> {
|
||||||
extension().suggest_docs_packages(provider)
|
extension().suggest_docs_packages(provider)
|
||||||
}
|
}
|
||||||
@@ -299,6 +309,22 @@ impl fmt::Display for LanguageServerId {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The ID of a context server.
|
||||||
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
|
||||||
|
pub struct ContextServerId(String);
|
||||||
|
|
||||||
|
impl AsRef<str> for ContextServerId {
|
||||||
|
fn as_ref(&self) -> &str {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ContextServerId {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl CodeLabelSpan {
|
impl CodeLabelSpan {
|
||||||
/// Returns a [`CodeLabelSpan::CodeRange`].
|
/// Returns a [`CodeLabelSpan::CodeRange`].
|
||||||
pub fn code_range(range: impl Into<wit::Range>) -> Self {
|
pub fn code_range(range: impl Into<wit::Range>) -> Self {
|
||||||
|
|||||||
@@ -135,6 +135,9 @@ world extension {
|
|||||||
/// Returns the output from running the provided slash command.
|
/// Returns the output from running the provided slash command.
|
||||||
export run-slash-command: func(command: slash-command, args: list<string>, worktree: option<borrow<worktree>>) -> result<slash-command-output, string>;
|
export run-slash-command: func(command: slash-command, args: list<string>, worktree: option<borrow<worktree>>) -> result<slash-command-output, string>;
|
||||||
|
|
||||||
|
/// Returns the command used to start up a context server.
|
||||||
|
export context-server-command: func(context-server-id: string) -> result<command, string>;
|
||||||
|
|
||||||
/// Returns a list of packages as suggestions to be included in the `/docs`
|
/// Returns a list of packages as suggestions to be included in the `/docs`
|
||||||
/// search results.
|
/// search results.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ interface lsp {
|
|||||||
/// An LSP completion.
|
/// An LSP completion.
|
||||||
record completion {
|
record completion {
|
||||||
label: string,
|
label: string,
|
||||||
|
label-details: option<completion-label-details>,
|
||||||
detail: option<string>,
|
detail: option<string>,
|
||||||
kind: option<completion-kind>,
|
kind: option<completion-kind>,
|
||||||
insert-text-format: option<insert-text-format>,
|
insert-text-format: option<insert-text-format>,
|
||||||
@@ -37,6 +38,12 @@ interface lsp {
|
|||||||
other(s32),
|
other(s32),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Label details for an LSP completion.
|
||||||
|
record completion-label-details {
|
||||||
|
detail: option<string>,
|
||||||
|
description: option<string>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Defines how to interpret the insert text in a completion item.
|
/// Defines how to interpret the insert text in a completion item.
|
||||||
variant insert-text-format {
|
variant insert-text-format {
|
||||||
plain-text,
|
plain-text,
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ path = "src/main.rs"
|
|||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
clap = { workspace = true, features = ["derive"] }
|
clap = { workspace = true, features = ["derive"] }
|
||||||
env_logger.workspace = true
|
env_logger.workspace = true
|
||||||
extension = { workspace = true, features = ["no-webrtc"] }
|
extension.workspace = true
|
||||||
fs.workspace = true
|
fs.workspace = true
|
||||||
language.workspace = true
|
language.workspace = true
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ use extension::{
|
|||||||
};
|
};
|
||||||
use language::LanguageConfig;
|
use language::LanguageConfig;
|
||||||
use reqwest_client::ReqwestClient;
|
use reqwest_client::ReqwestClient;
|
||||||
use theme::ThemeRegistry;
|
|
||||||
use tree_sitter::{Language, Query, WasmStore};
|
use tree_sitter::{Language, Query, WasmStore};
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
@@ -267,7 +266,7 @@ async fn test_themes(
|
|||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
for relative_theme_path in &manifest.themes {
|
for relative_theme_path in &manifest.themes {
|
||||||
let theme_path = extension_path.join(relative_theme_path);
|
let theme_path = extension_path.join(relative_theme_path);
|
||||||
let theme_family = ThemeRegistry::read_user_theme(&theme_path, fs.clone()).await?;
|
let theme_family = theme::read_user_theme(&theme_path, fs.clone()).await?;
|
||||||
log::info!("loaded theme family {}", theme_family.name);
|
log::info!("loaded theme family {}", theme_family.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
59
crates/extension_host/Cargo.toml
Normal file
59
crates/extension_host/Cargo.toml
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
[package]
|
||||||
|
name = "extension_host"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
publish = false
|
||||||
|
license = "GPL-3.0-or-later"
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
path = "src/extension_host.rs"
|
||||||
|
doctest = false
|
||||||
|
|
||||||
|
[features]
|
||||||
|
test-support = []
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow.workspace = true
|
||||||
|
async-compression.workspace = true
|
||||||
|
async-tar.workspace = true
|
||||||
|
async-trait.workspace = true
|
||||||
|
client.workspace = true
|
||||||
|
collections.workspace = true
|
||||||
|
extension.workspace = true
|
||||||
|
fs.workspace = true
|
||||||
|
futures.workspace = true
|
||||||
|
gpui.workspace = true
|
||||||
|
http_client.workspace = true
|
||||||
|
language.workspace = true
|
||||||
|
log.workspace = true
|
||||||
|
lsp.workspace = true
|
||||||
|
node_runtime.workspace = true
|
||||||
|
paths.workspace = true
|
||||||
|
project.workspace = true
|
||||||
|
release_channel.workspace = true
|
||||||
|
schemars.workspace = true
|
||||||
|
semantic_version.workspace = true
|
||||||
|
serde.workspace = true
|
||||||
|
serde_json.workspace = true
|
||||||
|
serde_json_lenient.workspace = true
|
||||||
|
settings.workspace = true
|
||||||
|
task.workspace = true
|
||||||
|
toml.workspace = true
|
||||||
|
url.workspace = true
|
||||||
|
util.workspace = true
|
||||||
|
wasmparser.workspace = true
|
||||||
|
wasmtime-wasi.workspace = true
|
||||||
|
wasmtime.workspace = true
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
ctor.workspace = true
|
||||||
|
env_logger.workspace = true
|
||||||
|
fs = { workspace = true, features = ["test-support"] }
|
||||||
|
gpui = { workspace = true, features = ["test-support"] }
|
||||||
|
language = { workspace = true, features = ["test-support"] }
|
||||||
|
parking_lot.workspace = true
|
||||||
|
project = { workspace = true, features = ["test-support"] }
|
||||||
|
reqwest_client.workspace = true
|
||||||
@@ -1,25 +1,15 @@
|
|||||||
pub mod extension_builder;
|
pub mod extension_lsp_adapter;
|
||||||
mod extension_indexed_docs_provider;
|
pub mod extension_settings;
|
||||||
mod extension_lsp_adapter;
|
pub mod wasm_host;
|
||||||
mod extension_manifest;
|
|
||||||
mod extension_settings;
|
|
||||||
mod extension_slash_command;
|
|
||||||
mod wasm_host;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod extension_store_test;
|
|
||||||
|
|
||||||
use crate::extension_indexed_docs_provider::ExtensionIndexedDocsProvider;
|
|
||||||
use crate::extension_manifest::SchemaVersion;
|
|
||||||
use crate::extension_slash_command::ExtensionSlashCommand;
|
|
||||||
use crate::{extension_lsp_adapter::ExtensionLspAdapter, wasm_host::wit};
|
use crate::{extension_lsp_adapter::ExtensionLspAdapter, wasm_host::wit};
|
||||||
use anyhow::{anyhow, bail, Context as _, Result};
|
use anyhow::{anyhow, bail, Context as _, Result};
|
||||||
use assistant_slash_command::SlashCommandRegistry;
|
|
||||||
use async_compression::futures::bufread::GzipDecoder;
|
use async_compression::futures::bufread::GzipDecoder;
|
||||||
use async_tar::Archive;
|
use async_tar::Archive;
|
||||||
use client::{telemetry::Telemetry, Client, ExtensionMetadata, GetExtensionsResponse};
|
use client::{telemetry::Telemetry, Client, ExtensionMetadata, GetExtensionsResponse};
|
||||||
use collections::{btree_map, BTreeMap, HashSet};
|
use collections::{btree_map, BTreeMap, HashSet};
|
||||||
use extension_builder::{CompileExtensionOptions, ExtensionBuilder};
|
use extension::extension_builder::{CompileExtensionOptions, ExtensionBuilder};
|
||||||
|
pub use extension::ExtensionManifest;
|
||||||
use fs::{Fs, RemoveOptions};
|
use fs::{Fs, RemoveOptions};
|
||||||
use futures::{
|
use futures::{
|
||||||
channel::{
|
channel::{
|
||||||
@@ -30,22 +20,21 @@ use futures::{
|
|||||||
select_biased, AsyncReadExt as _, Future, FutureExt as _, StreamExt as _,
|
select_biased, AsyncReadExt as _, Future, FutureExt as _, StreamExt as _,
|
||||||
};
|
};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, AppContext, AsyncAppContext, Context, EventEmitter, Global, Model, ModelContext, Task,
|
actions, AppContext, AsyncAppContext, Context, EventEmitter, Global, Model, ModelContext,
|
||||||
WeakModel,
|
SharedString, Task, WeakModel,
|
||||||
};
|
};
|
||||||
use http_client::{AsyncBody, HttpClient, HttpClientWithUrl};
|
use http_client::{AsyncBody, HttpClient, HttpClientWithUrl};
|
||||||
use indexed_docs::{IndexedDocsRegistry, ProviderId};
|
|
||||||
use language::{
|
use language::{
|
||||||
LanguageConfig, LanguageMatcher, LanguageName, LanguageQueries, LanguageRegistry,
|
LanguageConfig, LanguageMatcher, LanguageName, LanguageQueries, LoadedLanguage,
|
||||||
LoadedLanguage, QUERY_FILENAME_PREFIXES,
|
QUERY_FILENAME_PREFIXES,
|
||||||
};
|
};
|
||||||
|
use lsp::LanguageServerName;
|
||||||
use node_runtime::NodeRuntime;
|
use node_runtime::NodeRuntime;
|
||||||
use project::ContextProviderWithTasks;
|
use project::ContextProviderWithTasks;
|
||||||
use release_channel::ReleaseChannel;
|
use release_channel::ReleaseChannel;
|
||||||
use semantic_version::SemanticVersion;
|
use semantic_version::SemanticVersion;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
use snippet_provider::SnippetRegistry;
|
|
||||||
use std::ops::RangeInclusive;
|
use std::ops::RangeInclusive;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::{
|
use std::{
|
||||||
@@ -54,20 +43,19 @@ use std::{
|
|||||||
sync::Arc,
|
sync::Arc,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
use theme::{ThemeRegistry, ThemeSettings};
|
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use util::{maybe, ResultExt};
|
use util::ResultExt;
|
||||||
use wasm_host::{
|
use wasm_host::{
|
||||||
wit::{is_supported_wasm_api_version, wasm_api_version_range},
|
wit::{is_supported_wasm_api_version, wasm_api_version_range},
|
||||||
WasmExtension, WasmHost,
|
WasmExtension, WasmHost,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use extension_manifest::{
|
pub use extension::{
|
||||||
ExtensionLibraryKind, ExtensionManifest, GrammarManifestEntry, OldExtensionManifest,
|
ExtensionLibraryKind, GrammarManifestEntry, OldExtensionManifest, SchemaVersion,
|
||||||
};
|
};
|
||||||
pub use extension_settings::ExtensionSettings;
|
pub use extension_settings::ExtensionSettings;
|
||||||
|
|
||||||
const RELOAD_DEBOUNCE_DURATION: Duration = Duration::from_millis(200);
|
pub const RELOAD_DEBOUNCE_DURATION: Duration = Duration::from_millis(200);
|
||||||
const FS_WATCH_LATENCY: Duration = Duration::from_millis(100);
|
const FS_WATCH_LATENCY: Duration = Duration::from_millis(100);
|
||||||
|
|
||||||
/// The current extension [`SchemaVersion`] supported by Zed.
|
/// The current extension [`SchemaVersion`] supported by Zed.
|
||||||
@@ -102,26 +90,101 @@ pub fn is_version_compatible(
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait DocsDatabase: Send + Sync + 'static {
|
||||||
|
fn insert(&self, key: String, docs: String) -> Task<Result<()>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ExtensionRegistrationHooks: Send + Sync + 'static {
|
||||||
|
fn remove_user_themes(&self, _themes: Vec<SharedString>) {}
|
||||||
|
|
||||||
|
fn load_user_theme(&self, _theme_path: PathBuf, _fs: Arc<dyn Fs>) -> Task<Result<()>> {
|
||||||
|
Task::ready(Ok(()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn list_theme_names(
|
||||||
|
&self,
|
||||||
|
_theme_path: PathBuf,
|
||||||
|
_fs: Arc<dyn Fs>,
|
||||||
|
) -> Task<Result<Vec<String>>> {
|
||||||
|
Task::ready(Ok(Vec::new()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reload_current_theme(&self, _cx: &mut AppContext) {}
|
||||||
|
|
||||||
|
fn register_language(
|
||||||
|
&self,
|
||||||
|
_language: LanguageName,
|
||||||
|
_grammar: Option<Arc<str>>,
|
||||||
|
_matcher: language::LanguageMatcher,
|
||||||
|
_load: Arc<dyn Fn() -> Result<LoadedLanguage> + 'static + Send + Sync>,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_lsp_adapter(&self, _language: LanguageName, _adapter: ExtensionLspAdapter) {}
|
||||||
|
|
||||||
|
fn remove_lsp_adapter(&self, _language: &LanguageName, _server_name: &LanguageServerName) {}
|
||||||
|
|
||||||
|
fn register_wasm_grammars(&self, _grammars: Vec<(Arc<str>, PathBuf)>) {}
|
||||||
|
|
||||||
|
fn remove_languages(
|
||||||
|
&self,
|
||||||
|
_languages_to_remove: &[LanguageName],
|
||||||
|
_grammars_to_remove: &[Arc<str>],
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_slash_command(
|
||||||
|
&self,
|
||||||
|
_slash_command: wit::SlashCommand,
|
||||||
|
_extension: WasmExtension,
|
||||||
|
_host: Arc<WasmHost>,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_context_server(
|
||||||
|
&self,
|
||||||
|
_id: Arc<str>,
|
||||||
|
_extension: WasmExtension,
|
||||||
|
_host: Arc<WasmHost>,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_docs_provider(
|
||||||
|
&self,
|
||||||
|
_extension: WasmExtension,
|
||||||
|
_host: Arc<WasmHost>,
|
||||||
|
_provider_id: Arc<str>,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_snippets(&self, _path: &PathBuf, _snippet_contents: &str) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_lsp_status(
|
||||||
|
&self,
|
||||||
|
_server_name: lsp::LanguageServerName,
|
||||||
|
_status: language::LanguageServerBinaryStatus,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ExtensionStore {
|
pub struct ExtensionStore {
|
||||||
builder: Arc<ExtensionBuilder>,
|
pub registration_hooks: Arc<dyn ExtensionRegistrationHooks>,
|
||||||
extension_index: ExtensionIndex,
|
pub builder: Arc<ExtensionBuilder>,
|
||||||
fs: Arc<dyn Fs>,
|
pub extension_index: ExtensionIndex,
|
||||||
http_client: Arc<HttpClientWithUrl>,
|
pub fs: Arc<dyn Fs>,
|
||||||
telemetry: Option<Arc<Telemetry>>,
|
pub http_client: Arc<HttpClientWithUrl>,
|
||||||
reload_tx: UnboundedSender<Option<Arc<str>>>,
|
pub telemetry: Option<Arc<Telemetry>>,
|
||||||
reload_complete_senders: Vec<oneshot::Sender<()>>,
|
pub reload_tx: UnboundedSender<Option<Arc<str>>>,
|
||||||
installed_dir: PathBuf,
|
pub reload_complete_senders: Vec<oneshot::Sender<()>>,
|
||||||
outstanding_operations: BTreeMap<Arc<str>, ExtensionOperation>,
|
pub installed_dir: PathBuf,
|
||||||
index_path: PathBuf,
|
pub outstanding_operations: BTreeMap<Arc<str>, ExtensionOperation>,
|
||||||
language_registry: Arc<LanguageRegistry>,
|
pub index_path: PathBuf,
|
||||||
theme_registry: Arc<ThemeRegistry>,
|
pub modified_extensions: HashSet<Arc<str>>,
|
||||||
slash_command_registry: Arc<SlashCommandRegistry>,
|
pub wasm_host: Arc<WasmHost>,
|
||||||
indexed_docs_registry: Arc<IndexedDocsRegistry>,
|
pub wasm_extensions: Vec<(Arc<ExtensionManifest>, WasmExtension)>,
|
||||||
snippet_registry: Arc<SnippetRegistry>,
|
pub tasks: Vec<Task<()>>,
|
||||||
modified_extensions: HashSet<Arc<str>>,
|
|
||||||
wasm_host: Arc<WasmHost>,
|
|
||||||
wasm_extensions: Vec<(Arc<ExtensionManifest>, WasmExtension)>,
|
|
||||||
tasks: Vec<Task<()>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
@@ -160,26 +223,25 @@ pub struct ExtensionIndexEntry {
|
|||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Deserialize, Serialize)]
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Deserialize, Serialize)]
|
||||||
pub struct ExtensionIndexThemeEntry {
|
pub struct ExtensionIndexThemeEntry {
|
||||||
extension: Arc<str>,
|
pub extension: Arc<str>,
|
||||||
path: PathBuf,
|
pub path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Deserialize, Serialize)]
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Deserialize, Serialize)]
|
||||||
pub struct ExtensionIndexLanguageEntry {
|
pub struct ExtensionIndexLanguageEntry {
|
||||||
extension: Arc<str>,
|
pub extension: Arc<str>,
|
||||||
path: PathBuf,
|
pub path: PathBuf,
|
||||||
matcher: LanguageMatcher,
|
pub matcher: LanguageMatcher,
|
||||||
grammar: Option<Arc<str>>,
|
pub grammar: Option<Arc<str>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
actions!(zed, [ReloadExtensions]);
|
actions!(zed, [ReloadExtensions]);
|
||||||
|
|
||||||
pub fn init(
|
pub fn init(
|
||||||
|
registration_hooks: Arc<dyn ExtensionRegistrationHooks>,
|
||||||
fs: Arc<dyn Fs>,
|
fs: Arc<dyn Fs>,
|
||||||
client: Arc<Client>,
|
client: Arc<Client>,
|
||||||
node_runtime: NodeRuntime,
|
node_runtime: NodeRuntime,
|
||||||
language_registry: Arc<LanguageRegistry>,
|
|
||||||
theme_registry: Arc<ThemeRegistry>,
|
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
) {
|
) {
|
||||||
ExtensionSettings::register(cx);
|
ExtensionSettings::register(cx);
|
||||||
@@ -188,16 +250,12 @@ pub fn init(
|
|||||||
ExtensionStore::new(
|
ExtensionStore::new(
|
||||||
paths::extensions_dir().clone(),
|
paths::extensions_dir().clone(),
|
||||||
None,
|
None,
|
||||||
|
registration_hooks,
|
||||||
fs,
|
fs,
|
||||||
client.http_client().clone(),
|
client.http_client().clone(),
|
||||||
client.http_client().clone(),
|
client.http_client().clone(),
|
||||||
Some(client.telemetry().clone()),
|
Some(client.telemetry().clone()),
|
||||||
node_runtime,
|
node_runtime,
|
||||||
language_registry,
|
|
||||||
theme_registry,
|
|
||||||
SlashCommandRegistry::global(cx),
|
|
||||||
IndexedDocsRegistry::global(cx),
|
|
||||||
SnippetRegistry::global(cx),
|
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
@@ -224,16 +282,12 @@ impl ExtensionStore {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
extensions_dir: PathBuf,
|
extensions_dir: PathBuf,
|
||||||
build_dir: Option<PathBuf>,
|
build_dir: Option<PathBuf>,
|
||||||
|
extension_api: Arc<dyn ExtensionRegistrationHooks>,
|
||||||
fs: Arc<dyn Fs>,
|
fs: Arc<dyn Fs>,
|
||||||
http_client: Arc<HttpClientWithUrl>,
|
http_client: Arc<HttpClientWithUrl>,
|
||||||
builder_client: Arc<dyn HttpClient>,
|
builder_client: Arc<dyn HttpClient>,
|
||||||
telemetry: Option<Arc<Telemetry>>,
|
telemetry: Option<Arc<Telemetry>>,
|
||||||
node_runtime: NodeRuntime,
|
node_runtime: NodeRuntime,
|
||||||
language_registry: Arc<LanguageRegistry>,
|
|
||||||
theme_registry: Arc<ThemeRegistry>,
|
|
||||||
slash_command_registry: Arc<SlashCommandRegistry>,
|
|
||||||
indexed_docs_registry: Arc<IndexedDocsRegistry>,
|
|
||||||
snippet_registry: Arc<SnippetRegistry>,
|
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let work_dir = extensions_dir.join("work");
|
let work_dir = extensions_dir.join("work");
|
||||||
@@ -243,6 +297,7 @@ impl ExtensionStore {
|
|||||||
|
|
||||||
let (reload_tx, mut reload_rx) = unbounded();
|
let (reload_tx, mut reload_rx) = unbounded();
|
||||||
let mut this = Self {
|
let mut this = Self {
|
||||||
|
registration_hooks: extension_api.clone(),
|
||||||
extension_index: Default::default(),
|
extension_index: Default::default(),
|
||||||
installed_dir,
|
installed_dir,
|
||||||
index_path,
|
index_path,
|
||||||
@@ -254,7 +309,7 @@ impl ExtensionStore {
|
|||||||
fs.clone(),
|
fs.clone(),
|
||||||
http_client.clone(),
|
http_client.clone(),
|
||||||
node_runtime,
|
node_runtime,
|
||||||
language_registry.clone(),
|
extension_api,
|
||||||
work_dir,
|
work_dir,
|
||||||
cx,
|
cx,
|
||||||
),
|
),
|
||||||
@@ -262,11 +317,6 @@ impl ExtensionStore {
|
|||||||
fs,
|
fs,
|
||||||
http_client,
|
http_client,
|
||||||
telemetry,
|
telemetry,
|
||||||
language_registry,
|
|
||||||
theme_registry,
|
|
||||||
slash_command_registry,
|
|
||||||
indexed_docs_registry,
|
|
||||||
snippet_registry,
|
|
||||||
reload_tx,
|
reload_tx,
|
||||||
tasks: Vec::new(),
|
tasks: Vec::new(),
|
||||||
};
|
};
|
||||||
@@ -327,6 +377,7 @@ impl ExtensionStore {
|
|||||||
async move {
|
async move {
|
||||||
load_initial_extensions.await;
|
load_initial_extensions.await;
|
||||||
|
|
||||||
|
let mut index_changed = false;
|
||||||
let mut debounce_timer = cx
|
let mut debounce_timer = cx
|
||||||
.background_executor()
|
.background_executor()
|
||||||
.spawn(futures::future::pending())
|
.spawn(futures::future::pending())
|
||||||
@@ -334,17 +385,21 @@ impl ExtensionStore {
|
|||||||
loop {
|
loop {
|
||||||
select_biased! {
|
select_biased! {
|
||||||
_ = debounce_timer => {
|
_ = debounce_timer => {
|
||||||
let index = this
|
if index_changed {
|
||||||
.update(&mut cx, |this, cx| this.rebuild_extension_index(cx))?
|
let index = this
|
||||||
.await;
|
.update(&mut cx, |this, cx| this.rebuild_extension_index(cx))?
|
||||||
this.update(&mut cx, |this, cx| this.extensions_updated(index, cx))?
|
.await;
|
||||||
.await;
|
this.update(&mut cx, |this, cx| this.extensions_updated(index, cx))?
|
||||||
|
.await;
|
||||||
|
index_changed = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
extension_id = reload_rx.next() => {
|
extension_id = reload_rx.next() => {
|
||||||
let Some(extension_id) = extension_id else { break; };
|
let Some(extension_id) = extension_id else { break; };
|
||||||
this.update(&mut cx, |this, _| {
|
this.update(&mut cx, |this, _| {
|
||||||
this.modified_extensions.extend(extension_id);
|
this.modified_extensions.extend(extension_id);
|
||||||
})?;
|
})?;
|
||||||
|
index_changed = true;
|
||||||
debounce_timer = cx
|
debounce_timer = cx
|
||||||
.background_executor()
|
.background_executor()
|
||||||
.timer(RELOAD_DEBOUNCE_DURATION)
|
.timer(RELOAD_DEBOUNCE_DURATION)
|
||||||
@@ -388,7 +443,7 @@ impl ExtensionStore {
|
|||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reload(
|
pub fn reload(
|
||||||
&mut self,
|
&mut self,
|
||||||
modified_extension: Option<Arc<str>>,
|
modified_extension: Option<Arc<str>>,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
@@ -1041,7 +1096,7 @@ impl ExtensionStore {
|
|||||||
grammars_to_remove.extend(extension.manifest.grammars.keys().cloned());
|
grammars_to_remove.extend(extension.manifest.grammars.keys().cloned());
|
||||||
for (language_server_name, config) in extension.manifest.language_servers.iter() {
|
for (language_server_name, config) in extension.manifest.language_servers.iter() {
|
||||||
for language in config.languages() {
|
for language in config.languages() {
|
||||||
self.language_registry
|
self.registration_hooks
|
||||||
.remove_lsp_adapter(&language, language_server_name);
|
.remove_lsp_adapter(&language, language_server_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1049,8 +1104,8 @@ impl ExtensionStore {
|
|||||||
|
|
||||||
self.wasm_extensions
|
self.wasm_extensions
|
||||||
.retain(|(extension, _)| !extensions_to_unload.contains(&extension.id));
|
.retain(|(extension, _)| !extensions_to_unload.contains(&extension.id));
|
||||||
self.theme_registry.remove_user_themes(&themes_to_remove);
|
self.registration_hooks.remove_user_themes(themes_to_remove);
|
||||||
self.language_registry
|
self.registration_hooks
|
||||||
.remove_languages(&languages_to_remove, &grammars_to_remove);
|
.remove_languages(&languages_to_remove, &grammars_to_remove);
|
||||||
|
|
||||||
let languages_to_add = new_index
|
let languages_to_add = new_index
|
||||||
@@ -1085,7 +1140,7 @@ impl ExtensionStore {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.language_registry
|
self.registration_hooks
|
||||||
.register_wasm_grammars(grammars_to_add);
|
.register_wasm_grammars(grammars_to_add);
|
||||||
|
|
||||||
for (language_name, language) in languages_to_add {
|
for (language_name, language) in languages_to_add {
|
||||||
@@ -1094,11 +1149,11 @@ impl ExtensionStore {
|
|||||||
Path::new(language.extension.as_ref()),
|
Path::new(language.extension.as_ref()),
|
||||||
language.path.as_path(),
|
language.path.as_path(),
|
||||||
]);
|
]);
|
||||||
self.language_registry.register_language(
|
self.registration_hooks.register_language(
|
||||||
language_name.clone(),
|
language_name.clone(),
|
||||||
language.grammar.clone(),
|
language.grammar.clone(),
|
||||||
language.matcher.clone(),
|
language.matcher.clone(),
|
||||||
move || {
|
Arc::new(move || {
|
||||||
let config = std::fs::read_to_string(language_path.join("config.toml"))?;
|
let config = std::fs::read_to_string(language_path.join("config.toml"))?;
|
||||||
let config: LanguageConfig = ::toml::from_str(&config)?;
|
let config: LanguageConfig = ::toml::from_str(&config)?;
|
||||||
let queries = load_plugin_queries(&language_path);
|
let queries = load_plugin_queries(&language_path);
|
||||||
@@ -1117,15 +1172,14 @@ impl ExtensionStore {
|
|||||||
context_provider,
|
context_provider,
|
||||||
toolchain_provider: None,
|
toolchain_provider: None,
|
||||||
})
|
})
|
||||||
},
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let fs = self.fs.clone();
|
let fs = self.fs.clone();
|
||||||
let wasm_host = self.wasm_host.clone();
|
let wasm_host = self.wasm_host.clone();
|
||||||
let root_dir = self.installed_dir.clone();
|
let root_dir = self.installed_dir.clone();
|
||||||
let theme_registry = self.theme_registry.clone();
|
let api = self.registration_hooks.clone();
|
||||||
let snippet_registry = self.snippet_registry.clone();
|
|
||||||
let extension_entries = extensions_to_load
|
let extension_entries = extensions_to_load
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|name| new_index.extensions.get(name).cloned())
|
.filter_map(|name| new_index.extensions.get(name).cloned())
|
||||||
@@ -1140,18 +1194,14 @@ impl ExtensionStore {
|
|||||||
.spawn({
|
.spawn({
|
||||||
let fs = fs.clone();
|
let fs = fs.clone();
|
||||||
async move {
|
async move {
|
||||||
for theme_path in &themes_to_add {
|
for theme_path in themes_to_add.into_iter() {
|
||||||
theme_registry
|
api.load_user_theme(theme_path, fs.clone()).await.log_err();
|
||||||
.load_user_theme(theme_path, fs.clone())
|
|
||||||
.await
|
|
||||||
.log_err();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for snippets_path in &snippets_to_add {
|
for snippets_path in &snippets_to_add {
|
||||||
if let Some(snippets_contents) = fs.load(snippets_path).await.log_err()
|
if let Some(snippets_contents) = fs.load(snippets_path).await.log_err()
|
||||||
{
|
{
|
||||||
snippet_registry
|
api.register_snippets(snippets_path, &snippets_contents)
|
||||||
.register_snippets(snippets_path, &snippets_contents)
|
|
||||||
.log_err();
|
.log_err();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1165,30 +1215,13 @@ impl ExtensionStore {
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
let wasm_extension = maybe!(async {
|
let extension_path = root_dir.join(extension.manifest.id.as_ref());
|
||||||
let mut path = root_dir.clone();
|
let wasm_extension = WasmExtension::load(
|
||||||
path.extend([extension.manifest.clone().id.as_ref(), "extension.wasm"]);
|
extension_path,
|
||||||
let mut wasm_file = fs
|
&extension.manifest,
|
||||||
.open_sync(&path)
|
wasm_host.clone(),
|
||||||
.await
|
&cx,
|
||||||
.context("failed to open wasm file")?;
|
)
|
||||||
|
|
||||||
let mut wasm_bytes = Vec::new();
|
|
||||||
wasm_file
|
|
||||||
.read_to_end(&mut wasm_bytes)
|
|
||||||
.context("failed to read wasm")?;
|
|
||||||
|
|
||||||
wasm_host
|
|
||||||
.load_extension(
|
|
||||||
wasm_bytes,
|
|
||||||
extension.manifest.clone().clone(),
|
|
||||||
cx.background_executor().clone(),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.with_context(|| {
|
|
||||||
format!("failed to load wasm extension {}", extension.manifest.id)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
if let Some(wasm_extension) = wasm_extension.log_err() {
|
if let Some(wasm_extension) = wasm_extension.log_err() {
|
||||||
@@ -1207,9 +1240,9 @@ impl ExtensionStore {
|
|||||||
for (manifest, wasm_extension) in &wasm_extensions {
|
for (manifest, wasm_extension) in &wasm_extensions {
|
||||||
for (language_server_id, language_server_config) in &manifest.language_servers {
|
for (language_server_id, language_server_config) in &manifest.language_servers {
|
||||||
for language in language_server_config.languages() {
|
for language in language_server_config.languages() {
|
||||||
this.language_registry.register_lsp_adapter(
|
this.registration_hooks.register_lsp_adapter(
|
||||||
language.clone(),
|
language.clone(),
|
||||||
Arc::new(ExtensionLspAdapter {
|
ExtensionLspAdapter {
|
||||||
extension: wasm_extension.clone(),
|
extension: wasm_extension.clone(),
|
||||||
host: this.wasm_host.clone(),
|
host: this.wasm_host.clone(),
|
||||||
language_server_id: language_server_id.clone(),
|
language_server_id: language_server_id.clone(),
|
||||||
@@ -1217,43 +1250,46 @@ impl ExtensionStore {
|
|||||||
name: language_server_id.0.to_string(),
|
name: language_server_id.0.to_string(),
|
||||||
language_name: language.to_string(),
|
language_name: language.to_string(),
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (slash_command_name, slash_command) in &manifest.slash_commands {
|
for (slash_command_name, slash_command) in &manifest.slash_commands {
|
||||||
this.slash_command_registry.register_command(
|
this.registration_hooks.register_slash_command(
|
||||||
ExtensionSlashCommand {
|
crate::wit::SlashCommand {
|
||||||
command: crate::wit::SlashCommand {
|
name: slash_command_name.to_string(),
|
||||||
name: slash_command_name.to_string(),
|
description: slash_command.description.to_string(),
|
||||||
description: slash_command.description.to_string(),
|
// We don't currently expose this as a configurable option, as it currently drives
|
||||||
// We don't currently expose this as a configurable option, as it currently drives
|
// the `menu_text` on the `SlashCommand` trait, which is not used for slash commands
|
||||||
// the `menu_text` on the `SlashCommand` trait, which is not used for slash commands
|
// defined in extensions, as they are not able to be added to the menu.
|
||||||
// defined in extensions, as they are not able to be added to the menu.
|
tooltip_text: String::new(),
|
||||||
tooltip_text: String::new(),
|
requires_argument: slash_command.requires_argument,
|
||||||
requires_argument: slash_command.requires_argument,
|
|
||||||
},
|
|
||||||
extension: wasm_extension.clone(),
|
|
||||||
host: this.wasm_host.clone(),
|
|
||||||
},
|
},
|
||||||
false,
|
wasm_extension.clone(),
|
||||||
|
this.wasm_host.clone(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (id, _context_server_entry) in &manifest.context_servers {
|
||||||
|
this.registration_hooks.register_context_server(
|
||||||
|
id.clone(),
|
||||||
|
wasm_extension.clone(),
|
||||||
|
this.wasm_host.clone(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (provider_id, _provider) in &manifest.indexed_docs_providers {
|
for (provider_id, _provider) in &manifest.indexed_docs_providers {
|
||||||
this.indexed_docs_registry.register_provider(Box::new(
|
this.registration_hooks.register_docs_provider(
|
||||||
ExtensionIndexedDocsProvider {
|
wasm_extension.clone(),
|
||||||
extension: wasm_extension.clone(),
|
this.wasm_host.clone(),
|
||||||
host: this.wasm_host.clone(),
|
provider_id.clone(),
|
||||||
id: ProviderId(provider_id.clone()),
|
);
|
||||||
},
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.wasm_extensions.extend(wasm_extensions);
|
this.wasm_extensions.extend(wasm_extensions);
|
||||||
ThemeSettings::reload_current_theme(cx)
|
this.registration_hooks.reload_current_theme(cx);
|
||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
})
|
})
|
||||||
@@ -1264,6 +1300,7 @@ impl ExtensionStore {
|
|||||||
let work_dir = self.wasm_host.work_dir.clone();
|
let work_dir = self.wasm_host.work_dir.clone();
|
||||||
let extensions_dir = self.installed_dir.clone();
|
let extensions_dir = self.installed_dir.clone();
|
||||||
let index_path = self.index_path.clone();
|
let index_path = self.index_path.clone();
|
||||||
|
let extension_api = self.registration_hooks.clone();
|
||||||
cx.background_executor().spawn(async move {
|
cx.background_executor().spawn(async move {
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
let mut index = ExtensionIndex::default();
|
let mut index = ExtensionIndex::default();
|
||||||
@@ -1285,9 +1322,14 @@ impl ExtensionStore {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::add_extension_to_index(fs.clone(), extension_dir, &mut index)
|
Self::add_extension_to_index(
|
||||||
.await
|
fs.clone(),
|
||||||
.log_err();
|
extension_dir,
|
||||||
|
&mut index,
|
||||||
|
extension_api.clone(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.log_err();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1307,6 +1349,7 @@ impl ExtensionStore {
|
|||||||
fs: Arc<dyn Fs>,
|
fs: Arc<dyn Fs>,
|
||||||
extension_dir: PathBuf,
|
extension_dir: PathBuf,
|
||||||
index: &mut ExtensionIndex,
|
index: &mut ExtensionIndex,
|
||||||
|
extension_api: Arc<dyn ExtensionRegistrationHooks>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut extension_manifest = ExtensionManifest::load(fs.clone(), &extension_dir).await?;
|
let mut extension_manifest = ExtensionManifest::load(fs.clone(), &extension_dir).await?;
|
||||||
let extension_id = extension_manifest.id.clone();
|
let extension_id = extension_manifest.id.clone();
|
||||||
@@ -1358,7 +1401,8 @@ impl ExtensionStore {
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(theme_family) = ThemeRegistry::read_user_theme(&theme_path, fs.clone())
|
let Some(theme_families) = extension_api
|
||||||
|
.list_theme_names(theme_path.clone(), fs.clone())
|
||||||
.await
|
.await
|
||||||
.log_err()
|
.log_err()
|
||||||
else {
|
else {
|
||||||
@@ -1370,9 +1414,9 @@ impl ExtensionStore {
|
|||||||
extension_manifest.themes.push(relative_path.clone());
|
extension_manifest.themes.push(relative_path.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
for theme in theme_family.themes {
|
for theme_name in theme_families {
|
||||||
index.themes.insert(
|
index.themes.insert(
|
||||||
theme.name.into(),
|
theme_name.into(),
|
||||||
ExtensionIndexThemeEntry {
|
ExtensionIndexThemeEntry {
|
||||||
extension: extension_id.clone(),
|
extension: extension_id.clone(),
|
||||||
path: relative_path.clone(),
|
path: relative_path.clone(),
|
||||||
@@ -8,10 +8,9 @@ use collections::HashMap;
|
|||||||
use futures::{Future, FutureExt};
|
use futures::{Future, FutureExt};
|
||||||
use gpui::AsyncAppContext;
|
use gpui::AsyncAppContext;
|
||||||
use language::{
|
use language::{
|
||||||
CodeLabel, HighlightId, Language, LanguageServerName, LanguageToolchainStore, LspAdapter,
|
CodeLabel, HighlightId, Language, LanguageToolchainStore, LspAdapter, LspAdapterDelegate,
|
||||||
LspAdapterDelegate,
|
|
||||||
};
|
};
|
||||||
use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerBinaryOptions};
|
use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerName};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
@@ -387,6 +386,7 @@ impl From<lsp::CompletionItem> for wit::Completion {
|
|||||||
fn from(value: lsp::CompletionItem) -> Self {
|
fn from(value: lsp::CompletionItem) -> Self {
|
||||||
Self {
|
Self {
|
||||||
label: value.label,
|
label: value.label,
|
||||||
|
label_details: value.label_details.map(Into::into),
|
||||||
detail: value.detail,
|
detail: value.detail,
|
||||||
kind: value.kind.map(Into::into),
|
kind: value.kind.map(Into::into),
|
||||||
insert_text_format: value.insert_text_format.map(Into::into),
|
insert_text_format: value.insert_text_format.map(Into::into),
|
||||||
@@ -394,6 +394,15 @@ impl From<lsp::CompletionItem> for wit::Completion {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<lsp::CompletionItemLabelDetails> for wit::CompletionLabelDetails {
|
||||||
|
fn from(value: lsp::CompletionItemLabelDetails) -> Self {
|
||||||
|
Self {
|
||||||
|
detail: value.detail,
|
||||||
|
description: value.description,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<lsp::CompletionItemKind> for wit::CompletionKind {
|
impl From<lsp::CompletionItemKind> for wit::CompletionKind {
|
||||||
fn from(value: lsp::CompletionItemKind) -> Self {
|
fn from(value: lsp::CompletionItemKind) -> Self {
|
||||||
match value {
|
match value {
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
pub(crate) mod wit;
|
pub mod wit;
|
||||||
|
|
||||||
use crate::ExtensionManifest;
|
use crate::{ExtensionManifest, ExtensionRegistrationHooks};
|
||||||
use anyhow::{anyhow, bail, Context as _, Result};
|
use anyhow::{anyhow, bail, Context as _, Result};
|
||||||
use fs::{normalize_path, Fs};
|
use fs::{normalize_path, Fs};
|
||||||
use futures::future::LocalBoxFuture;
|
use futures::future::LocalBoxFuture;
|
||||||
@@ -14,7 +14,6 @@ use futures::{
|
|||||||
};
|
};
|
||||||
use gpui::{AppContext, AsyncAppContext, BackgroundExecutor, Task};
|
use gpui::{AppContext, AsyncAppContext, BackgroundExecutor, Task};
|
||||||
use http_client::HttpClient;
|
use http_client::HttpClient;
|
||||||
use language::LanguageRegistry;
|
|
||||||
use node_runtime::NodeRuntime;
|
use node_runtime::NodeRuntime;
|
||||||
use release_channel::ReleaseChannel;
|
use release_channel::ReleaseChannel;
|
||||||
use semantic_version::SemanticVersion;
|
use semantic_version::SemanticVersion;
|
||||||
@@ -28,15 +27,16 @@ use wasmtime::{
|
|||||||
};
|
};
|
||||||
use wasmtime_wasi as wasi;
|
use wasmtime_wasi as wasi;
|
||||||
use wit::Extension;
|
use wit::Extension;
|
||||||
|
pub use wit::SlashCommand;
|
||||||
|
|
||||||
pub(crate) struct WasmHost {
|
pub struct WasmHost {
|
||||||
engine: Engine,
|
engine: Engine,
|
||||||
release_channel: ReleaseChannel,
|
release_channel: ReleaseChannel,
|
||||||
http_client: Arc<dyn HttpClient>,
|
http_client: Arc<dyn HttpClient>,
|
||||||
node_runtime: NodeRuntime,
|
node_runtime: NodeRuntime,
|
||||||
pub(crate) language_registry: Arc<LanguageRegistry>,
|
pub registration_hooks: Arc<dyn ExtensionRegistrationHooks>,
|
||||||
fs: Arc<dyn Fs>,
|
fs: Arc<dyn Fs>,
|
||||||
pub(crate) work_dir: PathBuf,
|
pub work_dir: PathBuf,
|
||||||
_main_thread_message_task: Task<()>,
|
_main_thread_message_task: Task<()>,
|
||||||
main_thread_message_tx: mpsc::UnboundedSender<MainThreadCall>,
|
main_thread_message_tx: mpsc::UnboundedSender<MainThreadCall>,
|
||||||
}
|
}
|
||||||
@@ -44,16 +44,16 @@ pub(crate) struct WasmHost {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct WasmExtension {
|
pub struct WasmExtension {
|
||||||
tx: UnboundedSender<ExtensionCall>,
|
tx: UnboundedSender<ExtensionCall>,
|
||||||
pub(crate) manifest: Arc<ExtensionManifest>,
|
pub manifest: Arc<ExtensionManifest>,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub zed_api_version: SemanticVersion,
|
pub zed_api_version: SemanticVersion,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct WasmState {
|
pub struct WasmState {
|
||||||
manifest: Arc<ExtensionManifest>,
|
manifest: Arc<ExtensionManifest>,
|
||||||
pub(crate) table: ResourceTable,
|
pub table: ResourceTable,
|
||||||
ctx: wasi::WasiCtx,
|
ctx: wasi::WasiCtx,
|
||||||
pub(crate) host: Arc<WasmHost>,
|
pub host: Arc<WasmHost>,
|
||||||
}
|
}
|
||||||
|
|
||||||
type MainThreadCall =
|
type MainThreadCall =
|
||||||
@@ -81,7 +81,7 @@ impl WasmHost {
|
|||||||
fs: Arc<dyn Fs>,
|
fs: Arc<dyn Fs>,
|
||||||
http_client: Arc<dyn HttpClient>,
|
http_client: Arc<dyn HttpClient>,
|
||||||
node_runtime: NodeRuntime,
|
node_runtime: NodeRuntime,
|
||||||
language_registry: Arc<LanguageRegistry>,
|
registration_hooks: Arc<dyn ExtensionRegistrationHooks>,
|
||||||
work_dir: PathBuf,
|
work_dir: PathBuf,
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Arc<Self> {
|
) -> Arc<Self> {
|
||||||
@@ -97,7 +97,7 @@ impl WasmHost {
|
|||||||
work_dir,
|
work_dir,
|
||||||
http_client,
|
http_client,
|
||||||
node_runtime,
|
node_runtime,
|
||||||
language_registry,
|
registration_hooks,
|
||||||
release_channel: ReleaseChannel::global(cx),
|
release_channel: ReleaseChannel::global(cx),
|
||||||
_main_thread_message_task: task,
|
_main_thread_message_task: task,
|
||||||
main_thread_message_tx: tx,
|
main_thread_message_tx: tx,
|
||||||
@@ -107,10 +107,11 @@ impl WasmHost {
|
|||||||
pub fn load_extension(
|
pub fn load_extension(
|
||||||
self: &Arc<Self>,
|
self: &Arc<Self>,
|
||||||
wasm_bytes: Vec<u8>,
|
wasm_bytes: Vec<u8>,
|
||||||
manifest: Arc<ExtensionManifest>,
|
manifest: &Arc<ExtensionManifest>,
|
||||||
executor: BackgroundExecutor,
|
executor: BackgroundExecutor,
|
||||||
) -> Task<Result<WasmExtension>> {
|
) -> Task<Result<WasmExtension>> {
|
||||||
let this = self.clone();
|
let this = self.clone();
|
||||||
|
let manifest = manifest.clone();
|
||||||
executor.clone().spawn(async move {
|
executor.clone().spawn(async move {
|
||||||
let zed_api_version = parse_wasm_extension_version(&manifest.id, &wasm_bytes)?;
|
let zed_api_version = parse_wasm_extension_version(&manifest.id, &wasm_bytes)?;
|
||||||
|
|
||||||
@@ -150,7 +151,7 @@ impl WasmHost {
|
|||||||
.detach();
|
.detach();
|
||||||
|
|
||||||
Ok(WasmExtension {
|
Ok(WasmExtension {
|
||||||
manifest,
|
manifest: manifest.clone(),
|
||||||
tx,
|
tx,
|
||||||
zed_api_version,
|
zed_api_version,
|
||||||
})
|
})
|
||||||
@@ -241,6 +242,31 @@ fn parse_wasm_extension_version_custom_section(data: &[u8]) -> Option<SemanticVe
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl WasmExtension {
|
impl WasmExtension {
|
||||||
|
pub async fn load(
|
||||||
|
extension_dir: PathBuf,
|
||||||
|
manifest: &Arc<ExtensionManifest>,
|
||||||
|
wasm_host: Arc<WasmHost>,
|
||||||
|
cx: &AsyncAppContext,
|
||||||
|
) -> Result<Self> {
|
||||||
|
let path = extension_dir.join("extension.wasm");
|
||||||
|
|
||||||
|
let mut wasm_file = wasm_host
|
||||||
|
.fs
|
||||||
|
.open_sync(&path)
|
||||||
|
.await
|
||||||
|
.context("failed to open wasm file")?;
|
||||||
|
|
||||||
|
let mut wasm_bytes = Vec::new();
|
||||||
|
wasm_file
|
||||||
|
.read_to_end(&mut wasm_bytes)
|
||||||
|
.context("failed to read wasm")?;
|
||||||
|
|
||||||
|
wasm_host
|
||||||
|
.load_extension(wasm_bytes, manifest, cx.background_executor().clone())
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("failed to load wasm extension {}", manifest.id))
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn call<T, Fn>(&self, f: Fn) -> T
|
pub async fn call<T, Fn>(&self, f: Fn) -> T
|
||||||
where
|
where
|
||||||
T: 'static + Send,
|
T: 'static + Send,
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user