Compare commits

..

178 Commits

Author SHA1 Message Date
Nate Butler
3772a467e0 Remove logs 2024-10-07 15:14:54 -04:00
Nate Butler
1be27e7270 wip first approach at advanced entries 2024-10-07 15:14:34 -04:00
Marshall Bowers
7d380e9e18 Temporarily prevent deploying collab to production (#18825)
This PR adds a temporary measure to prevent deploying collab to
production, while we investigate some issues stemming from the HTTP
client change.

Release Notes:

- N/A
2024-10-07 14:31:23 -04:00
Piotr Osiewicz
60c12a8d06 ssh: Remove old dev servers code paths (#18823)
Closes #ISSUE

Release Notes:

- N/A
2024-10-07 19:18:44 +02:00
Marshall Bowers
11206a8444 ui: Fix avatar indicators getting cut off (#18821)
This PR fixes an issue introduced in #18810 that was causing the avatar
indicators to get cut off.

Release Notes:

- N/A
2024-10-07 12:53:11 -04:00
Marshall Bowers
c83690ff14 storybook: Wire up HTTP client (#18818)
This PR wires up the HTTP client in the Storybook.

Release Notes:

- N/A
2024-10-07 12:29:10 -04:00
Marshall Bowers
d1a758708d php: Bump to v0.2.1 (#18815)
This PR bumps the PHP extension to v0.2.1.

Changes:

- https://github.com/zed-industries/zed/pull/18368
- https://github.com/zed-industries/zed/pull/18774

Release Notes:

- N/A
2024-10-07 10:23:16 -04:00
Marshall Bowers
7c7151551a proto: Bump to v0.2.0 (#18814)
This PR bumps the Protobuf extension to v0.2.0.

Changes:

- https://github.com/zed-industries/zed/pull/18763

Release Notes:

- N/A
2024-10-07 10:11:12 -04:00
Bennet Bo Fenner
a3b63448df ssh: Do not cancel connection process if user is typing password (#18812)
Previously, the connection process would be cancelled after 10 seconds,
even if the connection was established successfully but the user was
still typing in a password.
We know recognize when the user is prompted for a password, and cancel
the timeout task.

Co-Authored-by: Thorsten <thorsten@zed.dev>

Release Notes:

- N/A

---------

Co-authored-by: Thorsten <thorsten@zed.dev>
2024-10-07 15:53:32 +02:00
Nate Butler
65c9b15796 Remove avatar shape (#18810)
This PR re-removes `AvatarShape` as it is unused. The previous time it
was removed incorrectly, resulting in square avatars!

Release Notes:

- N/A
2024-10-07 09:23:40 -04:00
Bennet Bo Fenner
25a97a6a2b ssh: Detect timeouts when server is unresponsive (#18808)
To detect connection timeouts we ping the remote server every X seconds
and attempt to reconnect if the server failed to respond.
Next up is showing some feedback in the UI to make this visible to the
user, and stop reconnecting after X amount of retries.

Release Notes:

- N/A

---------

Co-authored-by: Thorsten <thorsten@zed.dev>
2024-10-07 15:08:16 +02:00
Piotr Osiewicz
5aa165c530 ssh: Overhaul remoting UI (#18727)
Release Notes:

- N/A

---------

Co-authored-by: Danilo Leal <67129314+danilo-leal@users.noreply.github.com>
2024-10-07 15:01:50 +02:00
Thorsten Ball
9c5bec5efb formatting: Use project environment to find external formatters (#18611)
Closes #18261

This makes sure that we find external formatters in the project
environment.

TODO:

- [x] Use a different type for the triplet of `(buffer_handle,
buffer_path, buffer_env)`. Something like `FormattableBuffer`.
- [x] Test this!!

Release Notes:

- Fixed external formatters not being found, even when they were
available in the `$PATH` of a project.

---------

Co-authored-by: Bennet <bennet@zed.dev>
2024-10-07 12:24:12 +02:00
Thorsten Ball
c03b8d6c48 ssh remoting: Enable reconnecting after connection losses (#18586)
Release Notes:

- N/A

---------

Co-authored-by: Bennet <bennet@zed.dev>
2024-10-07 11:40:59 +02:00
Danilo Leal
67fbdbbed6 Put back code that makes the avatar rounded (#18799)
Follow-up to https://github.com/zed-industries/zed/pull/18768

---

Release Notes:

- N/A
2024-10-07 05:42:48 -03:00
Piotr Osiewicz
03c84466c2 chore: Fix some violations of 'needless_pass_by_ref_mut' lint (#18795)
While this lint is allow-by-default, it seems pretty useful to get rid
of mutable borrows when they're not needed.

Closes #ISSUE

Release Notes:

- N/A
2024-10-07 01:29:58 +02:00
Agustin Gomes
59f0f4ac42 Fix script/linux on RHEL/Fedora (#18788)
- Add missing `/etc/os-release` from a grep call
- Remove typo `grep grep` from another.

Co-authored-by: Peter Tripp <peter@zed.dev>
2024-10-06 14:47:48 -04:00
Peter Tripp
bd746145b0 ci: Make docs-only PRs only trigger docs-related tests (#18744)
This should speed up any docs-only PRs so that they don't have to run the full 5 minute battery of tests.

Release Notes:

- N/A
2024-10-06 10:28:39 -04:00
Peter Tripp
1b06c70a76 Fix alt-t context (#18783)
- Fix incorrect context introduced in https://github.com/zed-industries/zed/pull/18749/

Release Notes:

- N/A
2024-10-06 10:26:26 -04:00
Peter
06bd2431d2 proto: Add language server support (#18763)
Closes #18762

Release Notes:

- N/A

---------

Co-authored-by: Marshall Bowers <elliott.codes@gmail.com>
2024-10-06 10:12:06 -04:00
Roman Zipp
200b2bf70a php: Add syntax highlighting for Intelephense completions (#18774)
Release Notes:

- N/A

This PR introduces syntax highlighting for intelephense autocomple. The
styling was selected to roughly match PHPStorm's default scheme.

Please note that I'm not very familiar with writing Rust, but I'm happy
to adapt to any requested changes!

## Examples

### Object attributes, methods and constants

![Screenshot 2024-10-06 at 13 38
03](https://github.com/user-attachments/assets/a91634ff-0f2e-41f0-b548-ecb09c40947c)
![Screenshot 2024-10-06 at 13 38
11](https://github.com/user-attachments/assets/b6f179f4-898b-4d82-9d36-a3e82328325c)

### Typed enum members

![Screenshot 2024-10-06 at 13 38
53](https://github.com/user-attachments/assets/7133b981-4f68-4210-b233-403cdf3ec9bb)
![Screenshot 2024-10-06 at 13 38
41](https://github.com/user-attachments/assets/2e806f3d-3538-45f2-b075-b8be5902b786)

### Variables

Includes altered highlighting for [reserved variable
names](https://www.php.net/manual/en/reserved.variables.php).

![Screenshot 2024-10-06 at 13 39
30](https://github.com/user-attachments/assets/be426eb8-5879-432d-b302-391c2c68a7cb)

---------

Co-authored-by: Marshall Bowers <elliott.codes@gmail.com>
2024-10-06 10:11:21 -04:00
Nate Butler
8376dd2011 ui crate docs & spring cleaning (#18768)
Similar to https://github.com/zed-industries/zed/pull/18690 &
https://github.com/zed-industries/zed/pull/18695, this PR enables
required docs for `ui` and does some cleanup.

Changes:
- Enables the `deny(missing_docs)` crate-wide.
- Adds `allow(missing_docs)` on many modules until folks pick them up to
document them
- Documents some modules (all in `ui/src/styles`)
- Crate root-level organization: Traits move to `traits`, other misc
organization
- Cleaned out a bunch of unused code.

Note: I'd like to remove `utils/format_distance` but the assistant panel
uses it. To move it over to use the `time_format` crate we may need to
update it to use `time` instead of `chrono`. Needs more investigation.

Release Notes:

- N/A
2024-10-05 23:28:34 -04:00
Chris Boette
c9bee9f81f docs: Note the need for Rust when developing extensions (#18753) 2024-10-05 12:26:28 -04:00
Kirill Bulatov
1f31022cbe Compare migrations formatted uniformly (#18760)
Otherwise old migrations may be formatted differently than new
migrations, causing comparison errors.

Follow-up of https://github.com/zed-industries/zed/pull/18676

Release Notes:

- N/A
2024-10-05 12:58:45 +03:00
Peter Tripp
7608000df8 Fix option-t and option-shift-t in terminal (#18749) 2024-10-04 16:56:01 -04:00
Remco Smits
8f27ffda4d gpui: Fix uniform list horizon offset for non-horizontal scrollable lists (#18748)
Closes #18739

/cc @osiewicz 
/cc @maxdeviant 

I'm not sure why the `+ padding.left` was added, but this was the cause
of the issue. I also tested removing the extra left padding but didn't
seem to see a difference inside the project panel. So we can maybe even
remove it?

**Before:**
![Screenshot 2024-10-04 at 21 43
34](https://github.com/user-attachments/assets/b5d67cd9-f92b-4301-880c-d351fe156c98)

**After:**
<img width="294" alt="Screenshot 2024-10-04 at 21 49 05"
src="https://github.com/user-attachments/assets/8cc84170-a86b-46b8-91c9-39def64f0bd0">

Release Notes:

- Fix code action list not horizontal aligned correctly
2024-10-04 23:07:58 +03:00
Marshall Bowers
cee019b1ea editor: Qualify RangeExt::overlaps call to prevent phantom diagnostics (#18743)
This PR qualifies a call to `RangeExt::overlaps` to avoid some confusion
in rust-analyzer not being able to distinguish between
`RangeExt::overlaps` and `AnchorRangeExt::overlaps` and producing
phantom diagnostics.

We may also want to consider renaming the method on `AnchorRangeExt` to
disambiguate them.

Release Notes:

- N/A
2024-10-04 15:06:05 -04:00
Boris Cherny
01ad22683d telemetry: Add language_name and model_provider (#18640)
This PR adds a bit more metadata for assistant logging.

Release Notes:

- Assistant: Added `language_name` and `model_provider` fields to
telemetry events.

---------

Co-authored-by: Marshall Bowers <elliott.codes@gmail.com>
Co-authored-by: Max <max@zed.dev>
2024-10-04 14:37:27 -04:00
Peter Tripp
dfe1e43832 docs: Linux XDG desktop secrets portals 2024-10-04 14:13:07 -04:00
Marshall Bowers
e3a6f89e2d Make report_assistant_event take an AssistantEvent struct (#18741)
This PR makes the `report_assistant_event` method take an
`AssistantEvent` struct instead of all of the struct fields as
individual parameters.

Release Notes:

- N/A
2024-10-04 13:19:18 -04:00
Peter Tripp
07e808d16f Document File Scan Exclusions (#18738)
Release Notes:

- N/A
2024-10-04 12:07:43 -04:00
Muhammad Talal Anwar
2f7430af70 c: Add runnable for main function (#18720)
Release Notes:

- Added Runnable for C main function

This tags can then be used in tasks, for example:

```json
[
  {
    "label": "Run ${ZED_STEM}",
    "command": "gcc",
    "args": [
      "$ZED_FILE",
      "-o",
      "${ZED_DIRNAME}/${ZED_STEM}.out",
      "&&",
      "${ZED_DIRNAME}/${ZED_STEM}.out"
    ],
    "tags": ["c-main"]
  }
]

```
2024-10-04 17:28:12 +02:00
renovate[bot]
d012e35b04 Update Rust crate parking to v2.2.1 (#18664)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [parking](https://redirect.github.com/smol-rs/parking) | dependencies
| patch | `2.2.0` -> `2.2.1` |

---

### Release Notes

<details>
<summary>smol-rs/parking (parking)</summary>

###
[`v2.2.1`](https://redirect.github.com/smol-rs/parking/blob/HEAD/CHANGELOG.md#Version-221)

[Compare
Source](https://redirect.github.com/smol-rs/parking/compare/v2.2.0...v2.2.1)

- Specify the reason for using `parking` in the docs.
([#&#8203;25](https://redirect.github.com/smol-rs/parking/issues/25))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "after 3pm on Wednesday" in timezone
America/New_York, Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOC45Ny4wIiwidXBkYXRlZEluVmVyIjoiMzguOTcuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-04 11:09:20 -04:00
Daste
d695de4504 tab_switcher: Use git-aware colors for file icons (#18733)
Release Notes:

- Fixed tab switcher icons not respecting the `tabs.git_status` setting.

Fixes an issue mentioned in
https://github.com/zed-industries/zed/pull/17115#issuecomment-2378966170
- file icons in the tab switcher weren't colored according to git
status, even if `tabs.git_status` was set to true.

I used a similar approach I saw in other places of the project to get
the project entry and its git status, but maybe we could move the
coloring logic entirely to `tab_icon()`? Wouldn't this break anything?

---------

Co-authored-by: Marshall Bowers <elliott.codes@gmail.com>
2024-10-04 10:37:41 -04:00
renovate[bot]
9702310737 Update Rust crate sqlformat to v0.2.6 (#18676)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [sqlformat](https://redirect.github.com/shssoichiro/sqlformat-rs) |
dependencies | patch | `0.2.4` -> `0.2.6` |

---

### Release Notes

<details>
<summary>shssoichiro/sqlformat-rs (sqlformat)</summary>

###
[`v0.2.6`](https://redirect.github.com/shssoichiro/sqlformat-rs/blob/HEAD/CHANGELOG.md#Version-026)

[Compare
Source](https://redirect.github.com/shssoichiro/sqlformat-rs/compare/v0.2.5...v0.2.6)

- fix: ON UPDATE with two many blank formatted incorrectly
([#&#8203;46](https://redirect.github.com/shssoichiro/sqlformat-rs/issues/46))
-   fix: `EXCEPT` not handled well
- fix: REFERENCES xyz ON UPDATE .. causes formatter to treat the
remaining as an UPDATE statement
-   fix: Escaped strings formatted incorrectly
-   fix: RETURNING is not placed on a new line
- fix: fix the issue of misaligned comments after formatting
([#&#8203;40](https://redirect.github.com/shssoichiro/sqlformat-rs/issues/40))

###
[`v0.2.5`](https://redirect.github.com/shssoichiro/sqlformat-rs/compare/v0.2.4...v0.2.5)

[Compare
Source](https://redirect.github.com/shssoichiro/sqlformat-rs/compare/v0.2.4...v0.2.5)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "after 3pm on Wednesday" in timezone
America/New_York, Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOC45Ny4wIiwidXBkYXRlZEluVmVyIjoiMzguOTcuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-04 10:36:30 -04:00
Piotr Osiewicz
bafd7ed000 gpui: Store measure functions as context of taffy nodes (#18732)
Taffy maintains a mapping of NodeId <-> Context anyways (and does the
lookup), so it's redundant for us to store it separately. Tl;dr: we get
rid of one map and one map lookup per layout request.

Release Notes:

- N/A
2024-10-04 13:58:57 +02:00
Piotr Osiewicz
37ded190cf gpui: Use taffy to retrieve the parent for a given layout node (#18730)
Again. https://github.com/zed-industries/zed/pull/4070

Let's see how it goes this time around. The only thing that might've
been related to that revert on our Slack was about crashing in collab
panel.

Release Notes:

- N/A
2024-10-04 12:37:55 +02:00
Piotr Osiewicz
a99750fd35 chore: Bump taffy to 0.5.2 (#18729)
Release Notes:

- N/A
2024-10-04 12:37:44 +02:00
Ömer Sinan Ağacan
e2647025ac Add vim::MoveTo{Next,Prev} flags for regex and case sensitive search (#18429)
This makes the hard-coded regex and case-sensitive search flags in
`vim::MoveToNext` and `vim::MoveToPrev` commands configurable in key
bindings.

Example:

```json
{
  "context": "VimControl && !menu",
  "bindings": {
    "*": ["vim::MoveToNext", { "regex": false, "caseSensitive": false }],
    "#": ["vim::MoveToPrev", { "regex": false, "caseSensitive": false }]
  }
}
```

Closes #15837.

Release Notes:

- Added `regex` and `caseSensitive` arguments to `vim::MoveToNext` and
`vim ::MoveToPrev` commands, for toggling regex and case sensitive
search.
2024-10-04 09:10:26 +02:00
Marshall Bowers
6635758009 vcs_menu: Streamline branch creation from branch selector (#18712)
This PR streamlines the branch creation from the branch selector when
searching for a branch that does not exist.

The branch selector will show the available branches, as it does today:

<img width="576" alt="Screenshot 2024-10-03 at 4 01 25 PM"
src="https://github.com/user-attachments/assets/e1904f5b-4aad-4f88-901d-ab9422ec18bb">

When entering the name of a branch that does not exist, the picker will
be populated with an entry to create a new branch:

<img width="570" alt="Screenshot 2024-10-03 at 4 01 37 PM"
src="https://github.com/user-attachments/assets/07f8d12c-9422-4fd8-a6dc-ae450e297a13">

Selecting that entry will create the branch and switch to it.

Release Notes:

- Streamlined creating a new branch from the branch selector.
2024-10-03 16:18:28 -04:00
Junkui Zhang
8d6fa9526e windows: Fix sometimes log error messages don't show the crate name (#18706)
On windows, path could be something like `C:\path\to\the\crate`. Hence,
`split('/')` would refuse to work in this case.

### Before

![Screenshot 2024-10-04
023652](https://github.com/user-attachments/assets/9c14fb24-5ee0-4b56-8fbd-313abb28f134)

### After

![Screenshot 2024-10-04
024115](https://github.com/user-attachments/assets/217e175c-b0e1-4589-9c3d-98670882b185)


Release Notes:

- N/A
2024-10-03 13:00:33 -07:00
Marshall Bowers
fd22c9bef9 editor: Use predefined rounding value for color swatches (#18708)
This PR updates the color swatches added in #18665 to use a predefined
`rounding` value instead of a literal value.

The underlying values are the same, but we don't want to diverge from
our design system.

Release Notes:

- N/A
2024-10-03 15:20:41 -04:00
Joseph T. Lyons
43d05a432b Close stale issues out after 7 days (#18707)
Closes #ISSUE

Release Notes:

- N/A
2024-10-03 14:38:49 -04:00
Jordan Pittman
cac98b7bbf Show color swatches for LSP completions (#18665)
Closes #11991

Release Notes:

- Added support for color swatches for language server completions.

<img width="502" alt="Screenshot 2024-10-02 at 19 02 22"
src="https://github.com/user-attachments/assets/57e85492-3760-461a-9b17-a846dc40576b">

<img width="534" alt="Screenshot 2024-10-02 at 19 02 48"
src="https://github.com/user-attachments/assets/713ac41c-16f0-4ad3-9103-d2c9b3fa8b2e">

This implementation is mostly a port of the VSCode version of the
ColorExtractor. It seems reasonable the we should support _at least_
what VSCode does for detecting color swatches from LSP completions.

This implementation could definitely be better perf-wise by writing a
dedicated color parser. I also think it would be neat if, in the future,
Zed handled _more_ color formats — especially wide-gamut colors.

There are a few differences to the regexes in the VSCode implementation
but mainly so simplify the implementation :
- The hex vs rgb/hsl regexes were split into two parts
- The rgb/hsl regexes allow 3 or 4 color components whether hsla/rgba or
not and the parsing implementation accepts/rejects colors as needed

---------

Co-authored-by: Marshall Bowers <elliott.codes@gmail.com>
2024-10-03 14:38:17 -04:00
Marshall Bowers
cddd7875a4 Extract Protocol Buffers support into an extension (#18704)
This PR extracts the Protocol Buffers support into an extension.

Release Notes:

- Removed built-in support for Protocol Buffers, in favor of making it
available as an extension. The Protocol Buffers extension will be
suggested for download when you open a `.proto` file.
2024-10-03 13:37:43 -04:00
Nate Butler
8c95b8d89a theme crate spring cleaning (#18695)
This PR does some spring cleaning on the `theme` crate:

- Removed two unused stories and the story dep
- Removed the `one` theme family (from the `theme` crate, not the app),
this is now `zed_default_themes`.
- This will hopefully remove some confusion caused by this theme we
started in rust but didn't end up using
- Removed `theme::prelude` (it just re-exported scale colors, which we
don't use outside `theme`)
- Removed completely unused `zed_pro` themes (we started on these during
the gpui2 port and didn't finish them.)

Release Notes:

- N/A

---------

Co-authored-by: Marshall Bowers <elliott.codes@gmail.com>
2024-10-03 13:17:31 -04:00
Marshall Bowers
a9f816d5fb telemetry_events: Update crate-level docs (#18703)
This PR updates the `telemetry_events` crate to use module-level
documentation for its crate-level docs.

Release Notes:

- N/A
2024-10-03 12:38:51 -04:00
renovate[bot]
f7b3680e4d Update Rust crate pretty_assertions to v1.4.1 (#18668)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[pretty_assertions](https://redirect.github.com/rust-pretty-assertions/rust-pretty-assertions)
| workspace.dependencies | patch | `1.4.0` -> `1.4.1` |

---

### Release Notes

<details>
<summary>rust-pretty-assertions/rust-pretty-assertions
(pretty_assertions)</summary>

###
[`v1.4.1`](https://redirect.github.com/rust-pretty-assertions/rust-pretty-assertions/blob/HEAD/CHANGELOG.md#v141)

[Compare
Source](https://redirect.github.com/rust-pretty-assertions/rust-pretty-assertions/compare/v1.4.0...v1.4.1)

#### Fixed

- Show feature-flagged code in documentation. Thanks to
[@&#8203;sandydoo](https://redirect.github.com/sandydoo) for the fix!
([#&#8203;130](https://redirect.github.com/rust-pretty-assertions/rust-pretty-assertions/pull/130))

#### Internal

- Bump `yansi` version to `1.x`. Thanks to
[@&#8203;SergioBenitez](https://redirect.github.com/SergioBenitez) for
the update, and maintaining this library!
([#&#8203;121](https://redirect.github.com/rust-pretty-assertions/rust-pretty-assertions/pull/121))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "after 3pm on Wednesday" in timezone
America/New_York, Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOC45Ny4wIiwidXBkYXRlZEluVmVyIjoiMzguOTcuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-03 11:32:04 -04:00
renovate[bot]
ded3d3fc14 Update Python to v3.12.7 (#18652)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [python](https://redirect.github.com/containerbase/python-prebuild) |
dependencies | patch | `3.12.6` -> `3.12.7` |

---

### Release Notes

<details>
<summary>containerbase/python-prebuild (python)</summary>

###
[`v3.12.7`](https://redirect.github.com/containerbase/python-prebuild/releases/tag/3.12.7)

[Compare
Source](https://redirect.github.com/containerbase/python-prebuild/compare/3.12.6...3.12.7)

##### Bug Fixes

-   **deps:** update dependency python to v3.12.7

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "after 3pm on Wednesday" in timezone
America/New_York, Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOC45Ny4wIiwidXBkYXRlZEluVmVyIjoiMzguOTcuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-03 11:29:29 -04:00
Danilo Leal
ddcd45bb45 docs: Add tweaks to the outline panel page (#18697)
Thought we could be extra clear here with the meaning of "singleton
buffers".

Release Notes:

- N/A
2024-10-03 12:27:42 -03:00
renovate[bot]
29796aa412 Update Rust crate serde_json to v1.0.128 (#18669)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [serde_json](https://redirect.github.com/serde-rs/json) | dependencies
| patch | `1.0.127` -> `1.0.128` |
| [serde_json](https://redirect.github.com/serde-rs/json) |
workspace.dependencies | patch | `1.0.127` -> `1.0.128` |

---

### Release Notes

<details>
<summary>serde-rs/json (serde_json)</summary>

###
[`v1.0.128`](https://redirect.github.com/serde-rs/json/releases/tag/1.0.128)

[Compare
Source](https://redirect.github.com/serde-rs/json/compare/1.0.127...1.0.128)

- Support serializing maps containing 128-bit integer keys to
serde_json::Value
([#&#8203;1188](https://redirect.github.com/serde-rs/json/issues/1188),
thanks [@&#8203;Mrreadiness](https://redirect.github.com/Mrreadiness))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "after 3pm on Wednesday" in timezone
America/New_York, Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these
updates again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOC45Ny4wIiwidXBkYXRlZEluVmVyIjoiMzguOTcuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-03 11:14:22 -04:00
Nate Butler
773ad6bfd1 Document the theme crate (#18690)
This PR enables required documentation for the `theme` crate starts on
documenting it.

The end goal is to have all meaningful documentation in the crate filled
out – However I'm not sure that just adding `#![deny(missing_docs)]` to
the whole crate is the right approach.

I don't know that having 200+ "The color of the _ color" field docs is
useful however–In the short term I've excluded some of the modules that
contain structs with a ton of fields (`colors, `status`, etc.) until we
decide what the right solution here is.

Next steps are to clean up the crate, removing unused modules or those
with low usage in favor of other approaches.

Changes in this PR:
- Enable the `deny(missing_docs)` lint for the `theme` crate 
- Start documenting a subset of the crate.
- Enable `#![allow(missing_docs)]` for some modules.


Release Notes:

- N/A
2024-10-03 10:27:19 -04:00
Danilo Leal
dc85378b96 Clean up style properties on hunk controls (#18639)
This PR removes some duplicate style properties on the hunk controls,
namely padding, border, and background color.

Release Notes:

- N/A
2024-10-03 11:23:56 -03:00
Kirill Bulatov
1e8297a469 Remove a debug dev config line (#18689)
Follow-up of https://github.com/zed-industries/zed/pull/18645

Release Notes:

- N/A
2024-10-03 15:38:42 +03:00
renovate[bot]
9cd42427d8 Update Rust crate thiserror to v1.0.64 (#18677)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [thiserror](https://redirect.github.com/dtolnay/thiserror) |
workspace.dependencies | patch | `1.0.63` -> `1.0.64` |

---

### Release Notes

<details>
<summary>dtolnay/thiserror (thiserror)</summary>

###
[`v1.0.64`](https://redirect.github.com/dtolnay/thiserror/releases/tag/1.0.64)

[Compare
Source](https://redirect.github.com/dtolnay/thiserror/compare/1.0.63...1.0.64)

- Exclude derived impls from coverage instrumentation
([#&#8203;322](https://redirect.github.com/dtolnay/thiserror/issues/322),
thanks [@&#8203;oxalica](https://redirect.github.com/oxalica))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "after 3pm on Wednesday" in timezone
America/New_York, Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOC45Ny4wIiwidXBkYXRlZEluVmVyIjoiMzguOTcuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-02 23:28:00 -04:00
Joseph T. Lyons
df21fe174d Add command palette action name to outline panel docs (#18678)
Release Notes:

- N/A
2024-10-02 22:16:56 -04:00
Joseph T. Lyons
c48d4dbc6b Add basic outline panel docs (#18674)
Bandaid to: https://github.com/zed-industries/zed/issues/18672

Release Notes:

- Added basic outline panel docs
2024-10-02 22:06:07 -04:00
Piotr Osiewicz
19b186671b ssh: Add session state indicator to title bar (#18645)
![image](https://github.com/user-attachments/assets/0ed6f59c-e0e7-49e6-8db7-f09ec5cdf653)
The indicator turns yellow when ssh client is trying to reconnect. Note
that the state tracking is probably not ideal (we'll see how it pans out
once we start dog-fooding), but at the very least "green=good" should be
a decent mental model for now.

Release Notes:

- N/A
2024-10-03 00:35:56 +02:00
renovate[bot]
e2d613a803 Update Rust crate clap to v4.5.19 (#18660)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [clap](https://redirect.github.com/clap-rs/clap) |
workspace.dependencies | patch | `4.5.18` -> `4.5.19` |

---

### Release Notes

<details>
<summary>clap-rs/clap (clap)</summary>

###
[`v4.5.19`](https://redirect.github.com/clap-rs/clap/blob/HEAD/CHANGELOG.md#4519---2024-10-01)

[Compare
Source](https://redirect.github.com/clap-rs/clap/compare/v4.5.18...v4.5.19)

##### Internal

-   Update dependencies

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "after 3pm on Wednesday" in timezone
America/New_York, Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOC45Ny4wIiwidXBkYXRlZEluVmVyIjoiMzguOTcuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-02 17:39:32 -04:00
Marshall Bowers
6f4385e737 Sort dependencies in Cargo.toml files (#18657)
This PR sorts the dependencies in various `Cargo.toml` files after
#18414.

Release Notes:

- N/A
2024-10-02 16:26:48 -04:00
Marshall Bowers
9565a90528 collab: Revert changes to Clickhouse event rows (#18654)
This PR reverts the changes to the Clickhouse event rows that were
included in https://github.com/zed-industries/zed/pull/18414.

The changes don't seem to be correct, as they make the row structs
differ from the underlying table schema.

Release Notes:

- N/A
2024-10-02 16:10:25 -04:00
Conrad Irwin
3a5deb5c6f Replace isahc with async ureq (#18414)
REplace isahc with ureq everywhere gpui is used.

This should allow us to make http requests without libssl; and avoid a
long-tail of panics caused by ishac.

Release Notes:

- (potentially breaking change) updated our http client

---------

Co-authored-by: Mikayla <mikayla@zed.dev>
2024-10-02 12:30:48 -07:00
renovate[bot]
f809787275 Update cloudflare/wrangler-action digest to 168bc28 (#18651)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[cloudflare/wrangler-action](https://redirect.github.com/cloudflare/wrangler-action)
| action | digest | `f84a562` -> `168bc28` |

---

### Configuration

📅 **Schedule**: Branch creation - "after 3pm on Wednesday" in timezone
America/New_York, Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOC45Ny4wIiwidXBkYXRlZEluVmVyIjoiMzguOTcuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-02 15:23:22 -04:00
Kirill Bulatov
778dedec6c Prepare to sync other kinds of settings (#18616)
This PR does not change how things work for settings, but lays the
ground work for the future functionality.
After this change, Zed is prepared to sync more than just
`settings.json` files from local worktree and user config.

* ssh tasks

Part of this work is to streamline the task sync mechanism.
Instead of having an extra set of requests to fetch the task contents
from the server (as remote-via-collab does now and does not cover all
sync cases), we want to reuse the existing mechanism for synchronizing
user and local settings.

* editorconfig

Part of the task is to sync .editorconfig file changes to everyone which
involves sending and storing those configs.


Both ssh (and remove-over-collab) .zed/tasks.json and .editorconfig
files behave similar to .zed/settings.json local files: they belong to a
certain path in a certain worktree; may update over time, changing Zed's
functionality; can be merged hierarchically.
Settings sync follows the same "config file changed -> send to watchers
-> parse and merge locally and on watchers" path that's needed for both
new kinds of files, ergo the messaging layer is extended to send more
types of settings for future watch & parse and merge impls to follow.

Release Notes:

- N/A
2024-10-02 22:00:40 +03:00
Marshall Bowers
7c4615519b editor: Ensure proposed changes editor is syntax-highlighted when opened (#18648)
This PR fixes an issue where the proposed changes editor would not have
any syntax highlighting until a modification was made.

When creating the branch buffer we reparse the buffer to rebuild the
syntax map.

Release Notes:

- N/A
2024-10-02 14:23:59 -04:00
Marshall Bowers
0e8276560f language: Update buffer doc comments (#18646)
This PR updates the doc comments in `buffer.rs` to use the standard
style for linking to other items.

Release Notes:

- N/A
2024-10-02 14:10:19 -04:00
Mikayla Maki
209ebb0c65 Revert "Fix blurry cursor on Wayland at a scale other than 100%" (#18642)
Closes #17771

Reverts zed-industries/zed#17496

This PR turns out to need more work than I thought when I merged it. 

Release Notes:

- Linux: Fix a bug where the cursor would be the wrong size on Wayland
2024-10-02 10:44:16 -07:00
Danilo Leal
a5f50e5c1e Tweak warning diagnostic toggle (#18637)
This PR adds color to the warning diagnostic toggle, so that, if it's
turned on, the warning icon is yellow. And, in the opposite case, it's
muted.

| Turned on | Turned off |
|--------|--------|
| <img width="1136" alt="Screenshot 2024-10-02 at 6 08 30 PM"
src="https://github.com/user-attachments/assets/be64738b-4c14-41d4-b1d4-ad788cf9e72b">
| <img width="1136" alt="Screenshot 2024-10-02 at 6 08 36 PM"
src="https://github.com/user-attachments/assets/d144ff50-4bf6-4c23-925a-05bcbbcd8b9d">
|

---

Release Notes:

- N/A
2024-10-02 13:57:20 -03:00
Danilo Leal
5aaaed52fc Adjust spacing and sizing of buffer search bar icon buttons (#18638)
This PR mostly makes all of the search bar icon buttons all squared and
adjusts the spacing between them, as well as the additional input that
appears when you toggle the "Replace all" action.

<img width="900" alt="Screenshot 2024-10-02 at 6 08 30 PM"
src="https://github.com/user-attachments/assets/86d50a3b-94bd-4c6a-822e-5f7f7b2e2707">

---

Release Notes:

- N/A
2024-10-02 13:57:03 -03:00
Junseong Park
845991c0e5 docs: Add missing UI font settings to "Configuring Zed" (#18267)
- Add missing `ui_font` options in `configuring-zed.md`

Release Notes:

- N/A

---------

Co-authored-by: Marshall Bowers <elliott.codes@gmail.com>
2024-10-02 12:35:35 -04:00
Marshall Bowers
167af4bc1d Use const over static for string literals (#18635)
I noticed a few places where we were storing `&'static str`s in
`static`s instead of `const`s.

This PR updates them to use `const`.

Release Notes:

- N/A
2024-10-02 12:33:13 -04:00
Victor Roetman
2cd12f84de docs: Add FIPS mode error to Linux troubleshooting (#18407)
- Closes: #18335
Update linux.md with a workaround for the
```
crypto/fips/fips.c:154: OpenSSL internal error: FATAL FIPS SELFTEST FAILURE
```
error when using bundled libssl and libcrypto.

Co-authored-by: Peter Tripp <peter@zed.dev>
2024-10-02 12:18:41 -04:00
Joseph T Lyons
028d7a624f v0.157.x dev 2024-10-02 11:03:57 -04:00
Marshall Bowers
cfd61f9337 Clean up formatting in Cargo.toml (#18632)
This PR cleans up some formatting in some `Cargo.toml` files.

Release Notes:

- N/A
2024-10-02 10:38:23 -04:00
Marshall Bowers
21336eb124 docs: Add note about forking the extensions repo to a personal GitHub account (#18631)
This PR adds a note to the docs encouraging folks to fork the
`zed-industries/extensions` repo to a personal GitHub account rather
than a GitHub organization, as this makes life easier for everyone.

Release Notes:

- N/A
2024-10-02 10:10:53 -04:00
Danilo Leal
8a18c94f33 Make slash command descriptions consistent (#18595)
This PR adds a description constant in most of the slash command files
so that both the editor _and_ footer pickers use the same string. In
terms of copywriting, I did some tweaking to reduce the longer ones a
bit. Also standardized them all to use sentence case, as opposed to each
instance using a different convention. The editor picker needs more
work, though, given the arguments and descriptions are being cut at the
moment. This should happen in a follow-up!

<img width="900" alt="Screenshot 2024-10-01 at 7 25 19 PM"
src="https://github.com/user-attachments/assets/e8759eff-0de9-4a4d-a026-366d85507b3c">

---

Release Notes:

- N/A

---------

Co-authored-by: Marshall Bowers <elliott.codes@gmail.com>
2024-10-02 10:35:50 -03:00
Roy Williams
82d3fcdf4b Tweak assistant prompt to only fix diagnostic issues when requested to do so (#18596)
Release Notes:

- Assistant: Make the model less likely to incorporate diagnostic
information when not requested to fix any issues.
 
![CleanShot 2024-10-01 at 13 44
08](https://github.com/user-attachments/assets/f0e9a132-6cac-4dc6-889f-467e59ec8bbc)
2024-10-02 09:29:11 -04:00
Piotr Osiewicz
e01bc6765d editor: Fix "Reveal in File Manager" not working with multibuffers (#18626)
Additionally, mark context menu entry as disabled when the action would
fail (untitled buffer, collab sessions).

Supersedes #18584 

Release Notes:

- Fixed "Reveal in Finder/File Manager", "Copy Path", "Copy Relative
Path" and "Copy file location" actions not working with multibuffers.
2024-10-02 13:45:07 +02:00
Patrick
fd94c2b3fd Keep tab position when closing tabs (#18168)
- Closes #18036

Release Notes:

- N/A
2024-10-02 13:44:42 +02:00
loczek
0ee1d7ab26 Add snippet commands (#18453)
Closes #17860
Closes #15403

Release Notes:

- Added `snippets: configure snippets` command to create and modify
snippets
- Added `snippets: open folder` command for opening the
`~/.config/zed/snippets` directory


https://github.com/user-attachments/assets/fd9e664c-44b1-49bf-87a8-42b9e516f12f
2024-10-02 13:27:16 +02:00
Bennet Bo Fenner
b3cdd2ccff ssh remoting: Fix ssh process not being cleaned up when connection is closed (#18623)
We introduced a memory leak in #18572, which meant that `Drop` was never
called on `SshRemoteConnection`, meaning that the ssh process kept
running

Co-Authored-by: Thorsten <thorsten@zed.dev>

Release Notes:

- N/A

---------

Co-authored-by: Thorsten <thorsten@zed.dev>
2024-10-02 13:21:19 +02:00
Roman Zipp
e80cbab93f Fix docs format_on_save value is not a boolean (#18619)
Fixed [Configuring
Languages](https://zed.dev/docs/configuring-languages) docs using
boolean value for `format_on_save` option although it accepts string
values of `"on"` or `"off"`

Details:

The documentation on [configuring
languages](https://zed.dev/docs/configuring-languages) states the use of
boolean values for the `format_on_save` option although the
[configuration
reference](https://zed.dev/docs/configuring-zed#format-on-save) only
allows the usage of string values `"on"` or `"off"`. In fact using
boolean values will not work and won't translate to `on` or `off`

Release Notes:

- N/A
2024-10-02 14:03:23 +03:00
Max Brunsfeld
563a1dcbab Fix panic when opening proposed changes editor with reversed ranges (#18599)
Closes https://github.com/zed-industries/zed/issues/18589

Release Notes:

- N/A

Co-authored-by: Antonio <antonio@zed.dev>
2024-10-01 12:58:21 -06:00
Max Brunsfeld
7dcb0de28c Keep all hunks expanded in proposed change editor (#18598)
Also, fix visual bug when pressing escape with a non-empty selection in
a deleted text block.

Release Notes:

- N/A

Co-authored-by: Antonio <antonio@zed.dev>
2024-10-01 12:58:12 -06:00
Junkui Zhang
9b148f3dcc Limit the value can be set for font weight (#18594)
Closes #18531



This PR limits the range of values that can be set for `FontWeight`.
Since any value less than 1.0 or greater than 999.9 causes Zed to crash
on Windows, I’ve restricted `FontWeight` to this range.

I could apply this constraint only on Windows, but considering the
documentation at https://zed.dev/docs/configuring-zed#buffer-font-weight
indicates that `FontWeight` should be between 100 and 900, I thought it
might be a good idea to apply this restriction in the settings.


Release Notes:

- Changed `ui_font_weight` and `buffer_font_weight` settings to require
values to be between `100` and `950` (inclusive).

---------

Co-authored-by: Marshall Bowers <elliott.codes@gmail.com>
2024-10-01 13:32:31 -04:00
Max Brunsfeld
d14e36b323 Add an apply button to hunks in proposed changes editor (#18592)
Release Notes:

- N/A

---------

Co-authored-by: Antonio <antonio@zed.dev>
Co-authored-by: Nathan <nathan@zed.dev>
2024-10-01 11:07:52 -06:00
Marshall Bowers
eb962b7bfc editor: Include proposed changes editor in navigation history (#18593)
This PR makes it so the proposed changes editor works with the workspace
navigation history.

This allows for easily navigating back to the proposed changes editor
after opening one of the excerpts into the base buffer.

Release Notes:

- N/A
2024-10-01 13:05:50 -04:00
Marshall Bowers
280b8a89ea editor: Allow opening excerpts from proposed changes editor (#18591)
This PR adds the ability to open excerpts in the base buffer from the
proposed changes editor.

Release Notes:

- N/A
2024-10-01 12:40:18 -04:00
Kirill Bulatov
051627c449 Project panel horizontal scrollbar (#18513)
<img width="389" alt="image"
src="https://github.com/user-attachments/assets/c6718c6e-0fe1-40ed-b3db-7d576c4d98c8">


https://github.com/user-attachments/assets/734f1f52-70d9-4308-b1fc-36c7cfd4dd76

Closes https://github.com/zed-industries/zed/issues/7001
Closes https://github.com/zed-industries/zed/issues/4427
Part of https://github.com/zed-industries/zed/issues/15324
Part of https://github.com/zed-industries/zed/issues/14551

* Adjusts a `UniformList` to have a horizontal sizing behavior: the old
mode forced all items to have the size of the list exactly.
A new mode (with corresponding `ListItems` having `overflow_x` enabled)
lays out the uniform list elements with width of its widest element,
setting the same width to the list itself too.

* Using the new behavior, adds a new scrollbar into the project panel
and enhances its file name editor to scroll it during editing of long
file names

* Also restyles the scrollbar a bit, making it narrower and removing its
background

* Changes the project_panel.scrollbar.show settings to accept `null` and
be `null` by default, to inherit `editor`'s scrollbar settings. All
editor scrollbar settings are supported now.

Release Notes:

- Added a horizontal scrollbar to project panel
([#7001](https://github.com/zed-industries/zed/issues/7001))
([#4427](https://github.com/zed-industries/zed/issues/4427))

---------

Co-authored-by: Piotr Osiewicz <piotr@zed.dev>
2024-10-01 18:32:16 +03:00
pantheraleo-7
68d6177d37 docs: Correct typo in configuring-zed.md (#18580)
Release Notes:

- N/A
2024-10-01 18:09:34 +03:00
Peter Tripp
1be24f7739 Rename proto language to Proto (#18559)
All the other languages are capitalized. Proto should be too.
2024-10-01 09:31:03 -04:00
Junkui Zhang
6336248c1a windows: Revert "Fix hide, activate method on Windows to hide/show application" (#18571)
This PR reverts the changes introduced via #18164. As shown in the video
below, once you `hide` the app, there is essentially no way to bring it
back. I must emphasize that the window logic on Windows is entirely
different from macOS. On macOS, when you `hide` an app, its icon always
remains visible in the dock, and you can always bring the hidden app
back by clicking that icon. However, on Windows, there is no such
mechanism—the app is literally hidden.

I think the `hide` feature should be macOS-only.



https://github.com/user-attachments/assets/65c8a007-eedb-4444-9499-787b50f2d1e9



Release Notes:

- N/A
2024-10-01 13:58:40 +03:00
Thorsten Ball
7ce8797d78 ssh remoting: Add infrastructure to handle reconnects (#18572)
This restructures the code in `remote` so that it's easier to replace
the current SSH connection with a new one in case of
disconnects/reconnects.

Right now, it successfully reconnects, BUT we're still missing the big
piece on the server-side: keeping the server process alive and
reconnecting to the same process that keeps the project-state.

Release Notes:

- N/A

---------

Co-authored-by: Bennet <bennet@zed.dev>
2024-10-01 12:16:44 +02:00
Michael Sloan
527c9097f8 linux: Various X11 scroll improvements (#18484)
Closes  #14089, #14416, #15970, #17230, #18485

Release Notes:

- Fixed some cases where Linux X11 mouse scrolling doesn't work at all
(#14089, ##15970, #17230)
- Fixed handling of switching between Linux X11 devices used for
scrolling (#14416, #18485)

Change details:

Also includes the commit from PR #18317 so I don't have to deal with
merge conflicts.

* Now uses valuator info from slave pointers rather than master. This
hopefully fixes remaining cases where scrolling is fully
broken. https://github.com/zed-industries/zed/issues/14089,
https://github.com/zed-industries/zed/issues/15970,
https://github.com/zed-industries/zed/issues/17230

* Per-device recording of "last scroll position" used to calculate
deltas. This meant that swithing scroll devices would cause a sudden
jump of scroll position, often to the beginning or end of the
file (https://github.com/zed-industries/zed/issues/14416).

* Re-queries device metadata when devices change, so that newly
plugged in devices will work, and re-use of device-ids don't use old
metadata with a new device.

* xinput 2 documentation describes support for multiple master
devices. I believe this implementation will support that, since now it
just uses `DeviceInfo` from slave devices. The concept of master
devices is only used in registering for events.

* Uses popcount+bit masking to resolve axis indexes, instead of
iterating bit indices.

---------

Co-authored-by: Thorsten Ball <mrnugget@gmail.com>
2024-10-01 09:14:40 +02:00
Jason Lee
72be8c5d14 gpui: Fix hide, activate method on Windows to hide/show application (#18164)
Release Notes:

- N/A

Continue #18161 to fix `cx.hide`, `cx.activate` method on Windows to
hide/show application.

## After


https://github.com/user-attachments/assets/fe0070f9-7844-4c2a-b859-3e22ee4b8d22

---------

Co-authored-by: Mikayla Maki <mikayla@zed.dev>
2024-09-30 23:20:24 -07:00
Alvaro Parker
8d795ff882 Fix file watching for symlinks (#17609)
Closes #17605

Watches for target paths if file watched is a symlink in Linux. 
This will check if the generated `notify::Event` has any paths matching
the `root_path` and if the file is a symlink it will also check if the
path matches the `target_root_path` (the path that the symlink is
pointing to)

Release Notes:

- Added file watching for symlinks
2024-09-30 23:04:35 -07:00
Jason Lee
39be9e5949 gpui: Fix show: false support on Windows to create an invisible window (#18161)
Release Notes:

- N/A
- 
The `show` of WindowOptions is valid on macOS but not on Windows, this
changes to fix it to support create an invisible window.

```bash
cargo run -p gpui --example window
```

## Before



https://github.com/user-attachments/assets/4157bdaa-39a7-44df-bbdc-30b00e9c61e9


## After



https://github.com/user-attachments/assets/d48fa524-0caa-4f87-932d-01d7a468c488


https://github.com/user-attachments/assets/dd052f15-c8db-4a2a-a6af-a7c0ffecca84
2024-09-30 18:25:02 -07:00
Peter Tripp
1d2172aba8 docs: Correct glibc requirements (#18554) 2024-09-30 21:07:10 -04:00
Patrick MARIE
a752bbcee8 Fix linux double click (#18504)
Closes #17573

Release Notes:

- Check that double clicks on Linux are triggered by same button.
2024-09-30 16:51:05 -07:00
Jason Lee
938a0679c0 gpui: Fix img element to auto size when only have width or height (#17994)
Release Notes:

- N/A

---

We may only want to set the height of an image to limit the size and
make the width adaptive.

In HTML, we will only set width or height, and the other side will adapt
and maintain the original image ratio.

I changed this because I had a logo image that only to be limited in
height, and then I found that setting the height of the `img` alone
would not display correctly.

I also tried to set `ObjectFit` in this Demo, but it seems that none of
them can achieve the same effect as "After".

## Before
<img width="809" alt="before 2024-09-18 164029"
src="https://github.com/user-attachments/assets/7ba559ed-e53b-43e6-a072-93c8ba5b14ee">

## After
<img width="749" alt="after 2024-09-18 172003"
src="https://github.com/user-attachments/assets/51ee2eba-76b3-400a-abbf-de0e9c4021e2">
2024-09-30 16:39:19 -07:00
Junkui Zhang
77506afd83 windows: Implement copy/paste images (#17852)
**Clipboard Behavior on Windows Under This PR:**

| User Action | Zed’s Behavior |
| ------------------- |
-------------------------------------------------- |
| Paste PNG | Worked |
| Paste JPEG | Worked |
| Paste WebP | Worked, but not in the way you expect (see Issue section
below) |
| Paste GIF | Partially worked (see Issue section below) |
| Paste SVG | Partially worked (see Issue section below) |
| Paste BMP | Worked, but not in the way you expect (see Issue section
below) |
| Paste TIFF | Worked, but not in the way you expect (see Issue section
below) |
| Paste Files         | Worked, same behavior as macOS              |
| Copy image in Zed | Not tested, as I couldn’t find a way to copy
images |

---

**Differences Between the Windows and macOS Clipboard**

The clipboard functionality on Windows differs significantly from macOS.
On macOS, there can be multiple items in the clipboard, whereas, on
Windows, the clipboard holds only a single item. You can retrieve
different formats from the clipboard, but they are all just different
representations of the same item.

For example, when you copy a JPG image from Microsoft Word, the
clipboard will contain data in several formats:

- Microsoft Office proprietary data
- JPG format data
- PNG format data
- SVG format data

Please note that these formats all represent the same image, just in
different formats. This is due to compatibility concerns on Windows, as
various applications support different formats. Ideally, multiple
formats should be placed on the clipboard to support more software.
However, in general, supporting PNG will cover 99% of software, like
Chrome, which only supports PNG and BMP formats.

Additionally, since the clipboard on Windows only contains a single
item, special handling is required when copying multiple objects, such
as text and images. For instance, if you copy both text and an image
simultaneously in Microsoft Word, Microsoft places the following data on
the clipboard:

- Microsoft Office proprietary data containing a lot of content such as
text fonts, sizes, italics, positioning, image size, content, etc.
- RTF data representing the above content in RTF format
- HTML data representing the content in HTML format
- Plain text data

Therefore, for the current `ClipboardItem` implementation, if there are
multiple `ClipboardEntry` objects to be placed on the clipboard, RTF or
HTML formats are required. This PR does not support this scenario, and
only supports copying or pasting a single item from the clipboard.

---

**Known Issues**

- **WebP, BMP, TIFF**: These formats are not explicitly supported in
this PR. However, as mentioned earlier, in most cases, there are
corresponding PNG format data on the clipboard. This PR retrieves data
via PNG format, so users copying images in these formats from other
sources will still see the images displayed correctly.
  
- **GIF**: In this PR, GIFs are displayed, but for GIF images with
multiple frames, the image will not animate and will freeze on a single
frame. Since I observed the same behavior on macOS, I believe this is
not an issue with this PR.

- **SVG**: In this PR, only the top-left corner of the SVG image is
displayed. Again, I observed the same behavior on macOS, so I believe
this issue is not specific to this PR.

--- 

I hope this provides a clearer understanding. Any feedback or
suggestions on how to improve this are welcome.

Release Notes:

- N/A
2024-09-30 16:29:23 -07:00
Junkui Zhang
ecb7144b95 windows: Fix can not set folder for FileSaveDialog (#17708)
Closes #17622
Closes #17682

The story here is that `SHCreateItemFromParsingName` dose not accept UNC
path.

Video:



https://github.com/user-attachments/assets/f4f7f671-5ab5-4965-9158-e7a79ac02654



Release Notes:

- N/A
2024-09-30 16:26:20 -07:00
maan2003
837756198f linux/wayland: Add support for pasting images (#17671)
Release Notes:

- You can now paste images into the Assistant Panel to include them as
context on Linux wayland
2024-09-30 16:25:32 -07:00
Andrey Arutiunian
eb9fd62a90 Fix rendering of markdown tables (#18315)
- Closes: https://github.com/zed-industries/zed/issues/11024

## Release Notes:

- Improved Markdown Preview rendering of tables

## Before:


![image](https://github.com/user-attachments/assets/25f05604-38a9-4bde-901c-6d53a5d9d94d)

<img width="2035" alt="Screenshot 2024-09-25 at 05 47 19"
src="https://github.com/user-attachments/assets/a30c56f5-4793-44c2-8527-294189f9e724">

## Now:


![image](https://github.com/user-attachments/assets/ce06f045-d0db-4b8c-a1fc-2811d35f2683)


<img width="2040" alt="Screenshot 2024-09-25 at 05 47 48"
src="https://github.com/user-attachments/assets/76e5d217-9110-4c5d-9fad-dc63ae0b75f4">

## Note:

I'm not a Rust programmer and this is my first PR in Zed (because i just
want to fix this, so i can view my notes in Markdown in Zed, not slow
Visual Studio Code) - so there may be errors. I'm open for critic a
2024-09-30 15:50:30 -07:00
Peter Tripp
3010dfe038 Support More Linux (#18480)
- Add `script/build-docker`
- Add `script/install-cmake`
- Add `script/install-mold`
- Improve `script/linux` 
  - Add missing dependencies: `jq`, `git`, `tar`, `gzip` as required.
  - Add check for mold
  - Fix Redhat 8.x derivatives (RHEL, Centos, Almalinux, Rocky, Oracle, Amazon)
  - Fix perl libs to be Fedora only
  - Install the best `libstdc++` available on apt distros
  - ArchLinux: run `pacman -Syu` to update repos before installing. 
  - Should work on Raspbian (untested) 

This make it possible to test builds on other distros using docker:
```
./script/build-docker amazonlinux:2023
```
2024-09-30 17:46:21 -04:00
Peter Tripp
432de00e89 ci: Use BuildJet Ubuntu 20.04 runners for better glibc compatibility (#18442)
Use BuildJet Ubuntu 20.04 runners.
- Linux arm64 unchanged (glibc >= 2.35)
- Linux x64 glibc requirement becomes to >= 2.31 (from glibc >= 2.35).

Note: Ubuntu 20.04 repo cmake (3.16.3) is normally too old to build Zed, but `ubuntu-2004` [includes cmake
3.30.3](https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2004-Readme.md#tools).
2024-09-30 17:02:19 -04:00
Peter Tripp
09424edc35 ci: Add script/determine-release-channel (#18476)
- Refactor duplicated inline script from ci.yml to
`script/determine-release-channel`
- Remove references to non-existent '-nightly' release tags

Release Notes:

- N/A
2024-09-30 16:17:21 -04:00
Peter Tripp
74cba2407f ci: Move collab to Dockerfile-collab (#18515)
This makes it possible to have multiple Dockerfiles, each with their own
`.dockerignore`. Previously any docker builds would always include
anything inside `.dockerignore`. I believe this feature may require
`export DOCKER_BUILDKIT=1` but we use that in CI already.
2024-09-30 16:14:26 -04:00
Danilo Leal
053e31994f Fine-tune hunk controls block (#18543)
This PR changes the undo icon and adds a background color so that indent
lines don't bleed through the control block.

<img width="900" alt="Screenshot 2024-09-30 at 5 38 44 PM"
src="https://github.com/user-attachments/assets/4955f0f6-50ce-432f-85b9-1da0172d5e51">

Release Notes:

- N/A
2024-09-30 13:33:20 -03:00
Thorsten Ball
69e698c3be terminal: Fix blinking settings & blinking with custom shape (#18538)
This is a follow-up to #18530 thanks to this comment here:
https://github.com/zed-industries/zed/pull/18530#issuecomment-2382870564

In short: it fixes the `blinking` setting and the `cursor_shape` setting
as it relates to blinking.

Turns out our `blinking` setting was always the wrong value when using
`terminal_controlled` and the terminal _would_ control the blinking.

Example script to test with:

```bash
echo -e "0 normal \x1b[\x30 q"; sleep 2
echo -e "1 blink block \x1b[\x31 q"; sleep 2
echo -e "2 solid block \x1b[\x32 q"; sleep 2
echo -e "3 blink under \x1b[\x33 q"; sleep 2
echo -e "4 solid under \x1b[\x34 q"; sleep 2
echo -e "5 blink vert \x1b[\x35 q"; sleep 2
echo -e "6 solid vert \x1b[\x36 q"; sleep 2
echo -e "0 normal \x1b[\x30 q"; sleep 2

echo -e "color \x1b]12;#00ff00\x1b\\"; sleep 2
echo -e "reset \x1b]112\x1b\\ \x1b[\x30 q"
```

Before the changes in here, this script would set the cursor shape and
the blinking, but the blinking boolean would always be wrong.

This change here makes sure that it works consistently:

- `terminal.cursor_shape` only controls the *default* shape of the
terminal, not the blinking.
- `terminal.blinking = on` means that it's *always* blinking, regardless
of what terminal programs want
- `terminal.blinking = off` means that it's *never* blinking, regardless
of what terminal programs want
- `terminal.blinking = terminal_controlled (default)` means that it's
blinking depending on what terminal programs want. when a terminal
program resets the cursor to default, it sets it back to
`terminal.cursor_shape` if that is set.

Release Notes:

- Fixed the behavior of `{"terminal": {"blinking":
"[on|off|terminal_controlled]"}` to work correctly and to work correctly
when custom `cursor_shape` is set.
- `terminal.cursor_shape` only controls the *default* shape of the
terminal, not the blinking.
- `terminal.blinking = on` means that it's *always* blinking, regardless
of what terminal programs want
- `terminal.blinking = off` means that it's *never* blinking, regardless
of what terminal programs want
- `terminal.blinking = terminal_controlled (default)` means that it's
blinking depending on what terminal programs want. when a terminal
program resets the cursor to default, it sets it back to
`terminal.cursor_shape` if that is set.

Demo:


https://github.com/user-attachments/assets/b3fbeafd-ad58-41c8-9c07-1f03bc31771f

Co-authored-by: Bennet <bennet@zed.dev>
2024-09-30 15:36:35 +02:00
Stanislav Alekseev
215bce1974 Make direct direnv loading default (#18536)
I've been running with direct direnv loading for a while now and haven't
experienced any significant issues other than #18473. Making it default
would make direnv integration more reliable and consistent. I've also
updated the docs a bit to ensure that they represent current status of
direnv integration

Release Notes:

- Made direnv integration use direct (`direnv export json`) mode by
default instead of relying on a shell hook, improving consistency and
reliability of direnv detection
2024-09-30 15:35:36 +02:00
Kirill Bulatov
e64a86ce9f Fix a typo in the multi buffers documentation (#18535)
Closes https://github.com/zed-industries/zed/issues/18533

Release Notes:

- N/A
2024-09-30 15:28:46 +03:00
wannacu
8ae74bc6df gpui: Fix pre-edit position after applying scale factor (#18214)
before:

![image](https://github.com/user-attachments/assets/20590089-3333-4ca8-a371-b07acfbe43f9)

after:

![image](https://github.com/user-attachments/assets/2d25623e-0602-4d24-b563-64e1d2ec3492)

Release Notes:

- N/A
2024-09-30 12:57:59 +02:00
Thorsten Ball
65f6a7e5bc linux/x11: Give title bar inactive bg on mouse down (#18529)
This fixes something that I felt was off for a while. Previously, when
you'd click on the titlebar to move the window, the titlebar would only
change its background once the moving starts, but not on mouse-down.

That felt really off, since the moving is down with mouse-down and move,
so I think giving the user feedback about the mouse-down event makes
more sense.

I know there's a subjectivity to this change, so I'm ready to hear other
opinions, but for now I want to go with this.

Release Notes:

- N/A
2024-09-30 12:39:11 +02:00
Thorsten Ball
533416c5a9 terminal: Make CursorShape configurable (#18530)
This builds on top of @Yevgen's #15840 and combines it with the settings
names introduced in #17572.

Closes #4731.

Release Notes:

- Added a setting for the terminal's default cursor shape. The setting
is `{"terminal": {"cursor_shape": "block"}}``. Possible values: `block`,
`bar`, `hollow`, `underline`.

Demo:


https://github.com/user-attachments/assets/96ed28c2-c222-436b-80cb-7cd63eeb47dd
2024-09-30 12:38:57 +02:00
0hDEADBEAF
57ad5778fa Add a way to explicitly specify RC toolkit path (#18402)
Closes #18393 

Release Notes:

- Added a `ZED_RC_TOOLKIT_PATH` env variable so `winresource` crate can fetch the RC executable path correctly on some configurations
2024-09-30 11:34:44 +03:00
Patrick MARIE
707ccb04d2 Restore paste on middle-click on linux (#18503)
This is a partial revert of e6c1c51b37, which removed the middle-click
pasting on linux (both x11 & wayland). It also restores the
`middle_click_paste` option behavior which became unexistent.

Release Notes:

- Restore Linux middle-click pasting.
2024-09-30 10:27:47 +02:00
VacheDesNeiges
1f72069b42 Improve C++ Tree-sitter queries (#18016)
I made a few tree-sitter queries for improving the highlighting of C++. 

There is one query that I'm not totally certain about and would
appreciate some feedback on it, the one that concerns attributes.

Many editor only highlight the identifier as a keyword (This is the
behavior implemented in this commit), while others, for example the
tree-sitter plugin for neovim, tags the entire attribute for
highlighting (double brackets included). I don't know which one is
preferable. Here are screenshots of the two versions:


![image](https://github.com/user-attachments/assets/4e1b92c8-adc7-4900-a5b1-dc43c98f4c67)


![image](https://github.com/user-attachments/assets/290a13e3-5cb3-45cb-b6d9-3dc3e6a8af2d)


Release Notes:


- Fixed C++ attributes identifiers being wrongly highlighed through the
tag "variable"
- C++ attribute identifiers (nodiscard,deprecated, noreturn, etc.. ) are
now highlighted through the tag "keyword"
- Changed C++ primitives types (void, bool, int, size_t, etc.. ) to no
longer be highlighted with the tag "keyword", they can now be
highlighted by the tag "type.primitive".
- Added a tag "concept" for highlighting C++ concept identifiers. (This
tag name has been chosen to be the same than the one returned by
clangd's semantic tokens)
2024-09-30 10:27:30 +02:00
Kirill Bulatov
ed5eb725f9 Improve language server log view split ergonomics (#18527)
Allows to split log view, and opens it split on the right, same as the
syntax tree view.

Release Notes:

- Improved language server log panel split ergonomics
2024-09-30 11:25:11 +03:00
jansol
3fafdeb1a8 gpui: Fix blur region on Plasma/Wayland (#18465)
Once again aping after what winit does - since we always want to have
the whole window blurred there is apparently no need to specify a blur
region at all. Rounded corners would be the exception, but that is not
possible with the current protocol (it is planned for the vendor-neutral
version though!)

This eliminates the problem where only a fixed region of the window
would get blurred if the window was resized to be larger than at launch.
Also a drive-by comment grammar fix 😉

Release Notes:

- Fixed blur region handling on Plasma/Wayland
2024-09-30 10:09:13 +03:00
Sylvain Brunerie
898d48a574 php: Add syntax highlighting inside heredoc strings (#18368)
PHP heredoc strings make it easy to define string literals over multiple
lines:

```php
    $someString = <<<EOT
        multiline
        text
        EOT;
```

That `EOT` identifier can be anything else, and it is actually being
used in Sublime Text and VS Code to inject syntax highlighting for
another language in said string, depending on the identifier. For
instance, if the identifier is SQL, SQL syntax highlighting will be
applied to the contents of the string. Likewise if the identifier is CSS
or JS.

```php
    $someString = <<<SQL
        SELECT *
        FROM my_table
        SQL;
```

This PR changes the PHP extension so that it supports that feature too.

Release Notes:

- php: Added syntax highlighting inside heredoc strings
2024-09-30 10:02:12 +03:00
Stanislav Alekseev
5b40debb5f Don't stop loading the env if direnv call fails (#18473)
Before this we we would stop loading the environment if the call to
direnv failed, which is not necessary in any way
cc @mrnugget

Release Notes:

- Fixed the environment not loading if `direnv` mode is set to `direct`
and `.envrc` is not allowed
2024-09-30 09:54:22 +03:00
Maksim Bondarenkov
e39695bf1c docs: Update msys2 section in development/windows (#18385)
merge after
https://packages.msys2.org/packages/mingw-w64-clang-x86_64-zed is
available. alternatively you can check the
[queue](https://packages.msys2.org/queue) for build status

Zed now compiles and runs under msys2/CLANG64 environment, so change the
docs to give the users a choice of their environment

Release Notes:

- N/A
2024-09-30 09:38:49 +03:00
Tom Wieczorek
77df7e56f7 settings: Make external formatter arguments optional (#18340)
If specifying a formatter in the settings like this:

    "languages": {
      "foo": {
        "formatter": {
          "external": {
            "command": "/path/to/foo-formatter"
          }
        }
      }
    }

Zed will show an error like this:

    Invalid user settings file
    data did not match any variant of untagged enum SingleOrVec

This is because the arguments are not optional. The error is hard to
understand, so let's make the arguments actually optional, which makes
the above settings snippet valid.

Release Notes:

- Make external formatter arguments optional
2024-09-30 09:34:41 +03:00
Piotr Osiewicz
250f2e76eb tasks: Display runnables at the start of folds (#18526)
Release Notes:

- Fixed task indicators not showing up at the starts of folds.
2024-09-30 08:05:51 +02:00
Thorben Kröger
5f35fa5d92 Associate uv.lock files with TOML (#18426)
The `uv` python package manager uses the TOML for it's `uv.lock` file,
see https://docs.astral.sh/uv/guides/projects/#uvlock.

Ref #7808

Release Notes:

- associate `uv.lock` files with the TOML language
2024-09-29 13:54:09 -04:00
Antonio Scandurra
84ce81caf1 Pass Summary::Context to Item::summarize (#18510)
We are going to use this in the multi-buffer to produce a summary for an
`Excerpt` that contains a `Range<Anchor>`.

Release Notes:

- N/A

Co-authored-by: Nathan <nathan@zed.dev>
2024-09-29 10:30:48 -06:00
Joseph T. Lyons
8aeab4800c Continue to redirect to GitHub commits for nightly and dev release notes (#18487)
We are now using the `view release notes locally` action when clicking
on the update toast - the endpoint for this action does not currently
return anything for valid for these channels, as we don't have support
yet for diffing between these builds, so for now, [continue to do what
the `view release notes` action did and just send the user to the commit
view on
GitHub](caffb2733f/crates/auto_update/src/auto_update.rs (L255-L260)).
It is a bit counterintuitive to send the user to the browser when using
the "local" action, but this is just a patch in the interim.

If we make adjustments to our channels to keep the nightly tag stable
and add some sort of unique suffix, like a timestamp, we can then adjust
things to return these in the request body and show them in the editor.

Release Notes:

- N/A
2024-09-28 15:20:32 -04:00
Joseph T. Lyons
1021f0e288 Show release notes locally when showing update notification (#18486)
Closes https://github.com/zed-industries/zed/issues/17527

I think we are ok to switch to using the local action now. There are a
few things we don't support, like media, but we don't include media
directly too often, and I think this might help push the community to
maybe add support for it. That being said, I updated the markdown coming
back from the endpoint to include links to the web version of the
release notes, so they can always hop over to that version, if they
would like.


https://github.com/user-attachments/assets/b4d207a7-1640-48f1-91d0-94537f74116c

All forming of the Markdown happens in the endpoint, so if someone with
a better eye wants to update this, you can do that here:


0e5923e3e7/src/pages/api/release_notes/v2/%5Bchannel_type%5D/%5Bversion%5D.ts (L50-L62)

Release Notes:

- Changed the `view the release notes` button in the update toast to
trigger the local release notes action.
2024-09-28 14:21:13 -04:00
Danilo Leal
675673ed54 Fine-tune hunk control spacing (#18463)
<img width="900" alt="Screenshot 2024-09-28 at 1 09 35 AM"
src="https://github.com/user-attachments/assets/0b9d744f-3b92-488a-bc74-987f5a9d8c6c">

---

Release Notes:

- N/A
2024-09-28 01:45:40 +02:00
Danilo Leal
3737d4eb4f Add tooltip for code actions icon button (#18461)
I have just recently discovered this keybinding myself out of talking to
folks, ha. The tooltip here might ease the discovery for other folks in
the future.

<img width="700" alt="Screenshot 2024-09-27 at 11 04 28 PM"
src="https://github.com/user-attachments/assets/844d3b55-15af-47f7-a8db-5c8832ceba29">

---

Release Notes:

- N/A
2024-09-27 18:25:02 -03:00
Max Brunsfeld
0daa070448 More git hunk highlighting fixes (#18459)
Follow-up to https://github.com/zed-industries/zed/pull/18454

Release Notes:

- N/A
2024-09-27 13:48:37 -07:00
Max Brunsfeld
689da9d0b1 Move git hunk controls to the left side (#18460)
![Screenshot 2024-09-27 at 1 05
14 PM](https://github.com/user-attachments/assets/260a7d05-daa8-4a22-92bc-3b956035227f)

Release Notes:

- N/A
2024-09-27 13:13:55 -07:00
Danilo Leal
1c5be9de4e Capitalize tooltip labels on buffer search (#18458)
For consistency, as this seems to be the pattern we're using overall for
labels and buttons.

---

Release Notes:

- N/A
2024-09-27 17:02:32 -03:00
Kirill Bulatov
d5f67406b0 Install cargo-edito without extra features (#18457)
https://github.com/killercup/cargo-edit/pull/907 removed the feature
from the crate

Release Notes:

- N/A
2024-09-27 22:42:04 +03:00
Max Brunsfeld
c3075dfe9a Fix bugs in diff hunk highlighting (#18454)
Fixes https://github.com/zed-industries/zed/issues/18405

In https://github.com/zed-industries/zed/pull/18313, we introduced a
problem where git addition highlights might spuriously return when
undoing certain changes. It turned out, there were already some cases
where git hunk highlighting was incorrect when editing at the boundaries
of expanded diff hunks.

In this PR, I've introduced a test helper method for more rigorously
(and readably) testing the editor's git state. You can assert about the
entire state of an editor's diff decorations using a formatted diff:

```rust
    cx.assert_diff_hunks(
        r#"
        - use some::mod1;
          use some::mod2;
          const A: u32 = 42;
        - const B: u32 = 42;
          const C: u32 = 42;
          fn main() {
        -     println!("hello");
        +     //println!("hello");
              println!("world");
        +     //
        +     //
          }
          fn another() {
              println!("another");
        +     println!("another");
          }
        - fn another2() {
              println!("another2");
          }
        "#
        .unindent(),
    );
```

This will assert about the editor's actual row highlights, not just the
editor's internal hunk-tracking state.

I rewrote all of our editor diff tests to use these more high-level
assertions, and it caught the new bug, as well as some pre-existing bugs
in the highlighting of added content.

The problem was how we *remove* highlighted rows. Previously, it relied
on supplying exactly the same range as one that we had previously
highlighted. I've added a `remove_highlighted_rows(ranges)` APIs which
is much simpler - it clears out any row ranges that intersect the given
ranges (which is all that we need for the Git diff use case).

Release Notes:

- N/A
2024-09-27 11:14:28 -07:00
Richard Feldman
caaa9a00a9 Remove Qwen2 model (#18444)
Removed deprecated Qwen2 7B Instruct model from zed.dev provider (staff
only).

Release Notes:

- N/A
2024-09-27 13:30:25 -04:00
Conrad Irwin
ffd1083cc1 vim: Command selection fixes (#18424)
Release Notes:

- vim: Fixed cursor position after `:{range}yank`.
- vim: Added `:fo[ld]`, `:foldo[pen]` and `:foldc[lose]`
2024-09-27 10:06:19 -06:00
Joseph T. Lyons
6d4ecac610 Add a get-release-notes-since script (#18445)
Release Notes:

- N/A
2024-09-27 10:59:19 -04:00
Ömer Sinan Ağacan
dc5ffe6994 Fix GoToDefinition changing the viewport unnecessarily (#18441)
Closes #10738.

Release Notes:

- Fixed `GoToDefinition` changing the viewport (scrolling up/down) even when the definition is already within the viewport. ([#10738](https://github.com/zed-industries/zed/issues/10738))
2024-09-27 17:55:03 +03:00
Peter Tripp
03c7f08581 docs: Ollama api_url improvements (#18440) 2024-09-27 10:29:49 -04:00
Bennet Bo Fenner
73ff8c0f1f Fix missing tooltips for selected buttons (#18435)
Reverts #13857. Hiding tooltips for selected buttons prevents tooltips
like "Close x dock" from showing up, see #14938 for an example.
The intention of the original PR was to hide the "Show application menu"
tooltip, while the context menu is open.
In order to fix this without breaking other UI elements, we track the
state of the context menu using `PopoverMenuHandle` now, which allows us
to prevent the tooltip from showing up while the context menu is open.

Closes #14938

Release Notes:

- Fixed an issue where some tooltips would not show up
2024-09-27 14:16:14 +02:00
Bennet Bo Fenner
1c5d9c221a Add missing shortcuts in tooltips (#18282)
Fixes some missing shortcuts from Tooltips like the project search,
buffer search, quick action bar, ....


https://github.com/user-attachments/assets/d3a0160a-8d6e-4ddc-bf82-1fabeca42d59

This should hopefully help new users learn and discover some nice
keyboard shortcuts

Release Notes:

- Display keyboard shortcuts inside tooltips in the project search,
buffer search etc.
2024-09-27 11:06:48 +02:00
Bennet Bo Fenner
a1d2e1106e assistant: Fix copy/cut not working when selection is empty (#18403)
Release Notes:

- Fixed copy/cut/paste not working in the assistant panel when selection
was empty
2024-09-27 10:51:49 +02:00
Kirill Bulatov
568a21a700 Fix the numeration in line wrap docs (#18428)
Follow-up of https://github.com/zed-industries/zed/pull/18412

Release Notes:

- N/A

Co-authored-by: Thorsten Ball <thorsten@zed.dev>
2024-09-27 10:48:34 +03:00
Thorsten Ball
5199135b54 ssh remoting: Show error if opening connection timed out (#18401)
This shows an error if opening a connection to a remote host didn't work
in the timeout of 10s (maybe we'll need to make that configurable in the
future? for now it seems fine.)

![screenshot-2024-09-26-18 01
07@2x](https://github.com/user-attachments/assets/cbfa0e9f-9c29-4b6c-bade-07fdd7393c9d)


Release Notes:

- N/A

---------

Co-authored-by: Bennet <bennet@zed.dev>
Co-authored-by: Conrad <conrad@zed.dev>
2024-09-27 09:31:45 +02:00
CharlesChen0823
8559731e0d project: Fix worktree store event missing in remote projects (#18376)
Release Notes:

- N/A
2024-09-27 08:55:35 +02:00
Conrad Irwin
02d0561586 Fix read timeout for ollama (#18417)
Supercedes: #18310

Release Notes:

- Fixed `low_speed_timeout_in_seconds` for Ollama
2024-09-27 00:36:17 -06:00
Conrad Irwin
1be3c44550 vim: Support za (#18421)
Closes #6822
Updates #5142 

Release Notes:

- Added new fold actions to toggle folds (`cmd-k cmd-l`), fold every
fold (`cmd-k cmd-0`) unfold every fold (`cmd-k cmd-j`) to fold
recursively (`cmd-k cmd-[`) and unfold recursively (`cmd-k cmd-]`).
- vim: Added `za` to toggle fold under cursor.
- vim: Added `zO`/`zC`/`zA` to open, close and toggle folds recursively
(and fixed `zc` to not recurse into selections).
- vim: Added `zR`/`zM` to open/close all folds in the buffer.
2024-09-26 23:52:07 -06:00
Conrad Irwin
32605e9ea4 Fix register selection in visual mode (#18418)
Related to #12895

Release Notes:

- vim: Fix register selection in visual yank
2024-09-26 20:27:49 -06:00
Kirill Bulatov
c83d007138 Remove non-wrapping settings from the language configuration (#18412)
Closes https://github.com/zed-industries/zed/issues/17736

Those are limited with 1024 symbols before wrapping still, and were
introduced for git diff deleted hunks display.
Instead of confusing people with actually wrapping, restores behavior
that was before https://github.com/zed-industries/zed/pull/11080

Release Notes:

- Removed confusing soft wrap option behavior
([#17736]https://github.com/zed-industries/zed/issues/17736)
2024-09-26 23:43:58 +03:00
Peter Tripp
48c6eb9ac7 Add script to generate license dependencies as csv (#18411)
Co-authored-by: Joseph T. Lyons <JosephTLyons@gmail.com>
2024-09-26 16:21:20 -04:00
Conrad Irwin
e28496d4e2 Stop leaking isahc assumption (#18408)
Users of our http_client crate knew they were interacting with isahc as
they set its extensions on the request. This change adds our own
equivalents for their APIs in preparation for changing the default http
client.

Release Notes:

- N/A
2024-09-26 14:01:05 -06:00
Max Brunsfeld
c1a039a5d7 Remove old project search code path, bump min-supported zed version for collaboration (#18404)
Release Notes:

- N/A
2024-09-26 12:10:39 -07:00
Mikayla Maki
71da81c743 SSH Remoting: Fix bugs in worktree syncing (#18406)
Release Notes:

- N/A

---------

Co-authored-by: conrad <conrad@zed.dev>
2024-09-26 12:03:57 -07:00
thataboy
11058765be Add ability to separately set background color for highlighted brackets (#17566)
Closes https://github.com/zed-industries/zed/issues/16380

Currently brackets are highlighted with
`editor.document_highlight.read_background`. This commit adds a separate
`editor.document_highlight.bracket_background` theme setting so bracket
highlights can be made more prominent without doing the same to other
highlights, making the display too busy.

(My own theme)


https://github.com/user-attachments/assets/29a8c05e-2f1a-4c16-9be8-a4b4cb143548

I set defaults for light and dark theme that I hope are sensible and not
too obnoxious, but noticeable so people can change it if they don't like
it.

Release Notes:

- Added `editor.document_highlight.bracket_background` field to the
theme to set background color of highlighted brackets.
- This will fall back to `editor.document_highlight.read_background`, if
not set.

<img width="355" alt="Screenshot 2024-09-08 at 8 46 57 AM"
src="https://github.com/user-attachments/assets/3270bb4d-19f5-4b34-8003-982377b2ceb6">
<img width="444" alt="Screenshot 2024-09-08 at 9 03 27 AM"
src="https://github.com/user-attachments/assets/3b12d84d-913c-4bde-9132-9b10f4a8d49b">

---------

Co-authored-by: Marshall Bowers <elliott.codes@gmail.com>
2024-09-26 12:48:23 -04:00
renovate[bot]
c7a79cfc02 Update Rust crate libc to v0.2.159 (#18370)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [libc](https://redirect.github.com/rust-lang/libc) |
workspace.dependencies | patch | `0.2.158` -> `0.2.159` |

---

### Release Notes

<details>
<summary>rust-lang/libc (libc)</summary>

###
[`v0.2.159`](https://redirect.github.com/rust-lang/libc/releases/tag/0.2.159)

[Compare
Source](https://redirect.github.com/rust-lang/libc/compare/0.2.158...0.2.159)

##### Added

- Android: add more `AT_*` constants in
[#&#8203;3779](https://redirect.github.com/rust-lang/libc/pull/3779)
- Apple: add missing `NOTE_*` constants in
[#&#8203;3883](https://redirect.github.com/rust-lang/libc/pull/3883)
- Hermit: add missing error numbers in
[#&#8203;3858](https://redirect.github.com/rust-lang/libc/pull/3858)
- Hurd: add `__timeval` for 64-bit support in
[#&#8203;3786](https://redirect.github.com/rust-lang/libc/pull/3786)
- Linux: add `epoll_pwait2` in
[#&#8203;3868](https://redirect.github.com/rust-lang/libc/pull/3868)
- Linux: add `mq_notify` in
[#&#8203;3849](https://redirect.github.com/rust-lang/libc/pull/3849)
- Linux: add missing `NFT_CT_*` constants in
[#&#8203;3844](https://redirect.github.com/rust-lang/libc/pull/3844)
- Linux: add the `fchmodat2` syscall in
[#&#8203;3588](https://redirect.github.com/rust-lang/libc/pull/3588)
- Linux: add the `mseal` syscall in
[#&#8203;3798](https://redirect.github.com/rust-lang/libc/pull/3798)
- OpenBSD: add `sendmmsg` and `recvmmsg` in
[#&#8203;3831](https://redirect.github.com/rust-lang/libc/pull/3831)
- Unix: add `IN6ADDR_ANY_INIT` and `IN6ADDR_LOOPBACK_INIT` in
[#&#8203;3693](https://redirect.github.com/rust-lang/libc/pull/3693)
- VxWorks: add `S_ISVTX` in
[#&#8203;3768](https://redirect.github.com/rust-lang/libc/pull/3768)
- VxWorks: add `vxCpuLib` and `taskLib` functions
[#&#8203;3861](https://redirect.github.com/rust-lang/libc/pull/3861)
- WASIp2: add definitions for `std::net` support in
[#&#8203;3892](https://redirect.github.com/rust-lang/libc/pull/3892)

##### Fixed

- Correctly handle version checks when `clippy-driver` is used
[#&#8203;3893](https://redirect.github.com/rust-lang/libc/pull/3893)

##### Changed

- EspIdf: change signal constants to c_int in
[#&#8203;3895](https://redirect.github.com/rust-lang/libc/pull/3895)
- HorizonOS: update network definitions in
[#&#8203;3863](https://redirect.github.com/rust-lang/libc/pull/3863)
- Linux: combine `ioctl` APIs in
[#&#8203;3722](https://redirect.github.com/rust-lang/libc/pull/3722)
- WASI: enable CI testing in
[#&#8203;3869](https://redirect.github.com/rust-lang/libc/pull/3869)
- WASIp2: enable CI testing in
[#&#8203;3870](https://redirect.github.com/rust-lang/libc/pull/3870)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "after 3pm on Wednesday" in timezone
America/New_York, Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOC44MC4wIiwidXBkYXRlZEluVmVyIjoiMzguODAuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-26 12:16:49 -04:00
renovate[bot]
84a6ded657 Update Rust crate clap to v4.5.18 (#18369)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [clap](https://redirect.github.com/clap-rs/clap) |
workspace.dependencies | patch | `4.5.17` -> `4.5.18` |

---

### Release Notes

<details>
<summary>clap-rs/clap (clap)</summary>

###
[`v4.5.18`](https://redirect.github.com/clap-rs/clap/blob/HEAD/CHANGELOG.md#4518---2024-09-20)

[Compare
Source](https://redirect.github.com/clap-rs/clap/compare/v4.5.17...v4.5.18)

##### Features

- *(builder)* Expose `Arg::get_display_order` and
`Command::get_display_order`

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "after 3pm on Wednesday" in timezone
America/New_York, Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOC44MC4wIiwidXBkYXRlZEluVmVyIjoiMzguODAuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-26 11:52:12 -04:00
renovate[bot]
e5bbd378a6 Update Rust crate cargo_toml to v0.20.5 (#18365)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [cargo_toml](https://lib.rs/cargo_toml)
([source](https://gitlab.com/lib.rs/cargo_toml)) |
workspace.dependencies | patch | `0.20.4` -> `0.20.5` |

---

### Release Notes

<details>
<summary>lib.rs/cargo_toml (cargo_toml)</summary>

###
[`v0.20.5`](https://gitlab.com/lib.rs/cargo_toml/compare/v0.20.4...v0.20.5)

[Compare
Source](https://gitlab.com/lib.rs/cargo_toml/compare/v0.20.4...v0.20.5)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "after 3pm on Wednesday" in timezone
America/New_York, Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOC44MC4wIiwidXBkYXRlZEluVmVyIjoiMzguODAuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-26 11:44:38 -04:00
renovate[bot]
82eb753b31 Update actions/setup-node digest to 0a44ba7 (#18357)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [actions/setup-node](https://redirect.github.com/actions/setup-node) |
action | digest | `1e60f62` -> `0a44ba7` |

---

### Configuration

📅 **Schedule**: Branch creation - "after 3pm on Wednesday" in timezone
America/New_York, Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOC44MC4wIiwidXBkYXRlZEluVmVyIjoiMzguODAuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-26 11:24:01 -04:00
renovate[bot]
de1889d6a8 Update Rust crate async-trait to v0.1.83 (#18364)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [async-trait](https://redirect.github.com/dtolnay/async-trait) |
workspace.dependencies | patch | `0.1.82` -> `0.1.83` |

---

### Release Notes

<details>
<summary>dtolnay/async-trait (async-trait)</summary>

###
[`v0.1.83`](https://redirect.github.com/dtolnay/async-trait/releases/tag/0.1.83)

[Compare
Source](https://redirect.github.com/dtolnay/async-trait/compare/0.1.82...0.1.83)

- Prevent needless_arbitrary_self_type lint being produced in generated
code
([#&#8203;278](https://redirect.github.com/dtolnay/async-trait/issues/278))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "after 3pm on Wednesday" in timezone
America/New_York, Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOC44MC4wIiwidXBkYXRlZEluVmVyIjoiMzguODAuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-26 08:49:50 -06:00
Piotr Osiewicz
f143396825 ssh: Do not require user to be signed in to use ssh remoting (#18396)
Fixes #18392

Closes #18392

Release Notes:

- N/A
2024-09-26 16:24:11 +02:00
Thorsten Ball
7eea1a6f51 git blame gutter: Use smallest possible space (#18145)
Before:
![screenshot-2024-09-26-15 00
20@2x](https://github.com/user-attachments/assets/f6706325-5bef-404e-a0b4-63a5121969fa)

After:

![screenshot-2024-09-26-15 02
24@2x](https://github.com/user-attachments/assets/739d0831-0b4a-457f-917e-10f3a662e74d)


Release Notes:

- Improved the git blame gutter to take up only the space required to
display the longest git author name in the current file.

---------

Co-authored-by: Bennet Bo Fenner <bennet@zed.dev>
2024-09-26 15:47:14 +02:00
Galen Elias
1a4f9b2891 Fix minimum gutter line number spacing (#18021)
I was inspecting how Zed did the layout in the editor, specifically for
the gutter, and noticed that `em_width * X` is being used as the 'width
of X consecutive characters'. Howevever, that math didn't work for me,
because em_width doesn't account for the space between characters, so
you can't just multiply it by a character count.

One place this is actually noticeable is in the logic for
`min_width_for_number_on_gutter`, where we try to reserve 4 characters
of line number space. However, once you actually hit 4 characters, the
actual width is bigger, causing things to resize. This seems clearly
counter to the intent of the code.

It seems the more correct logic is to use `em_advance` which accounts
for the space between the characters. I am leaving the rest of the uses
of `em_width` for generic padding. It is also possible that
`column_pixels()` would be the more correct fix here, but it wasn't
straightforward to use that due to it residing EditorElement source
file.

On my MacBook this increases the width of the gutter by 6 pixels when
there are <999 lines in the file, otherwise it's identical.

It might be worth doing some more general audit of some of the other
uses of em_width as a concept. (e.g. `git_blame_entries_width`)


https://github.com/user-attachments/assets/f2a28cd5-9bb6-4109-bf41-1838e56a75f9

Release Notes:

- Fix a slight gutter flicker when going over 999 lines
2024-09-26 16:30:06 +03:00
Taras Martyniuk
1deed247eb terraform: Bump to v0.1.1 (#18382)
This PR bumps the Terraform extension to v0.1.1

- https://github.com/zed-industries/zed/pull/17200

Release Notes:

- N/A
2024-09-26 08:36:58 -04:00
Piotr Osiewicz
db92a31067 lsp: Do not notify all language servers on file save (#17756)
This is not an ideal solution to
https://github.com/fasterthanlime/zed-diags-readme, but current status
quo is not great either; we were just going through all of the language
servers and notifying them, whereas we should ideally do it based on a
glob.
/cc @fasterthanlime

Release Notes:

- N/A
2024-09-26 13:18:50 +02:00
Bennet Bo Fenner
31902a1b73 Remove leftover println statements (#18389)
Remove some leftover println statements from #17644

Release Notes:

- N/A
2024-09-26 12:52:56 +02:00
Thorsten Ball
3f415f3587 Fix use_on_type_format setting being unused per language (#18387)
Before this change, `use_on_type_format` would only have an effect when
defined on a global level in our settings.

But our default.json settings would also document that it's used in
language settings, i.e.:

```json
{
  "languages": {
    "C": {
      "use_on_type_format": false
    },
    "C++": {
      "use_on_type_format": false
    }
  }
}
```

But this did **not** work.

With the change, it now works globally and per-language.

Release Notes:

- Fixed `use_on_type_format` setting not working when defined inside
`"languages"` in the settings. This change will now change the default
behavior for C, C++, and Markdown, by turning language server's
`OnTypeFormatting` completions off by default.

Co-authored-by: Bennet <bennet@zed.dev>
2024-09-26 12:27:08 +02:00
Thorsten Ball
140d70289e Avoid panic by only restoring workspace if UI has launched (#18386)
This should fix the `unregistered setting type
workspace::workspace_settings::WorkspaceSettings` panic that came from
inside `restorable_workspace_locations`.

We tracked it down to a possible scenario (we can't recreate it though)
in which `app.on_reopen` is called before the app has finished
launching.

In any case, this check makes sense, because we only want to restore a
workspace in case the whole app has launched with a UI.

Release Notes:

- N/A

Co-authored-by: Bennet <bennet@zed.dev>
2024-09-26 12:26:58 +02:00
Hyunmin Woo (Hanul)
b9b689d322 Fix Typo in rust language guide (#18383)
Release Notes:

- N/A
2024-09-26 12:24:29 +02:00
Thorsten Ball
2d2e20f9d4 editor: Fix cursor shape not restoring when setting removed (#18379)
Closes #18119

Release Notes:

- Fixed the cursor shape in the editor not changing back to default when
`{"cursor_shape": "..."}` setting is removed. (Does not apply to Vim
mode.)
2024-09-26 11:07:07 +02:00
Conrad Irwin
b701eab44f Avoid unwrap in file finder (#18374)
Release Notes:

- Fixed a (rare) panic in file finder

---------

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
2024-09-26 10:31:17 +03:00
Max Brunsfeld
6167688a63 Proposed changes editor features (#18373)
This PR adds some more functionality to the Proposed Changes Editor
view, which we'll be using in
https://github.com/zed-industries/zed/pull/18240 for allowing the
assistant to propose changes to a set of buffers.

* Add an `Apply All` button, and fully implement applying of changes to
the base buffer
* Make the proposed changes editor searchable
* Fix a bug in branch buffers' diff state management

Release Notes:

- N/A
2024-09-25 16:33:00 -07:00
Mikayla Maki
3161aedcb0 Fix broken collaboration UI from #18308 (#18372)
Fixes a bug introduced by #18308, that caused the call controls to
render incorrectly.

Release Notes:

- N/A
2024-09-25 16:03:08 -07:00
Conrad Irwin
64532e94e4 Move adapters to remote (#18359)
Release Notes:

- ssh remoting: run LSP Adapters on host

---------

Co-authored-by: Mikayla <mikayla@zed.dev>
2024-09-25 15:29:04 -07:00
Peter Tripp
40408e731e Fix sending alt-enter in terminal (#18363) 2024-09-25 18:01:33 -04:00
Peter Tripp
7398f795e3 Ollama llama3.2 default context size (#18366)
Release Notes:

- Ollama: Added llama3.2 support
2024-09-25 18:01:12 -04:00
Piotr Osiewicz
4b4565fb7a assistant: Enable assistant panel/inline assists in ssh remote projects (#18367)
Release Notes:

- ssh remoting: Enable assistant panel and inline assists (running on
client)
2024-09-25 22:55:36 +02:00
425 changed files with 11085 additions and 7869 deletions

View File

@@ -10,7 +10,7 @@ runs:
cargo install cargo-nextest
- name: Install Node
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4
with:
node-version: "18"

View File

@@ -41,7 +41,7 @@ jobs:
exit 1
;;
esac
which cargo-set-version > /dev/null || cargo install cargo-edit --features vendored-openssl
which cargo-set-version > /dev/null || cargo install cargo-edit
output=$(cargo set-version -p zed --bump patch 2>&1 | sed 's/.* //')
git commit -am "Bump to $output for @$GITHUB_ACTOR" --author "Zed Bot <hi@zed.dev>"
git tag v${output}${tag_suffix}

View File

@@ -7,9 +7,13 @@ on:
- "v[0-9]+.[0-9]+.x"
tags:
- "v*"
paths-ignore:
- "docs/**"
pull_request:
branches:
- "**"
paths-ignore:
- "docs/**"
concurrency:
# Allow only one workflow per any non-`main` branch.
@@ -172,7 +176,7 @@ jobs:
DIGITALOCEAN_SPACES_SECRET_KEY: ${{ secrets.DIGITALOCEAN_SPACES_SECRET_KEY }}
steps:
- name: Install Node
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4
with:
node-version: "18"
@@ -192,29 +196,12 @@ jobs:
- name: Determine version and release channel
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
run: |
set -eu
# This exports RELEASE_CHANNEL into env (GITHUB_ENV)
script/determine-release-channel
version=$(script/get-crate-version zed)
channel=$(cat crates/zed/RELEASE_CHANNEL)
echo "Publishing version: ${version} on release channel ${channel}"
echo "RELEASE_CHANNEL=${channel}" >> $GITHUB_ENV
expected_tag_name=""
case ${channel} in
stable)
expected_tag_name="v${version}";;
preview)
expected_tag_name="v${version}-pre";;
nightly)
expected_tag_name="v${version}-nightly";;
*)
echo "can't publish a release on channel ${channel}"
exit 1;;
esac
if [[ $GITHUB_REF_NAME != $expected_tag_name ]]; then
echo "invalid release tag ${GITHUB_REF_NAME}. expected ${expected_tag_name}"
exit 1
fi
- name: Draft release notes
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
run: |
mkdir -p target/
# 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
@@ -271,7 +258,7 @@ jobs:
timeout-minutes: 60
name: Create a Linux bundle
runs-on:
- buildjet-16vcpu-ubuntu-2204
- buildjet-16vcpu-ubuntu-2004
if: ${{ startsWith(github.ref, 'refs/tags/v') || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
needs: [linux_tests]
env:
@@ -284,34 +271,13 @@ jobs:
clean: false
- name: Install Linux dependencies
run: ./script/linux
run: ./script/linux && ./script/install-mold 2.34.0
- name: Determine version and release channel
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
run: |
set -eu
version=$(script/get-crate-version zed)
channel=$(cat crates/zed/RELEASE_CHANNEL)
echo "Publishing version: ${version} on release channel ${channel}"
echo "RELEASE_CHANNEL=${channel}" >> $GITHUB_ENV
expected_tag_name=""
case ${channel} in
stable)
expected_tag_name="v${version}";;
preview)
expected_tag_name="v${version}-pre";;
nightly)
expected_tag_name="v${version}-nightly";;
*)
echo "can't publish a release on channel ${channel}"
exit 1;;
esac
if [[ $GITHUB_REF_NAME != $expected_tag_name ]]; then
echo "invalid release tag ${GITHUB_REF_NAME}. expected ${expected_tag_name}"
exit 1
fi
# This exports RELEASE_CHANNEL into env (GITHUB_ENV)
script/determine-release-channel
- name: Create Linux .tar.gz bundle
run: script/bundle-linux
@@ -357,29 +323,8 @@ jobs:
- name: Determine version and release channel
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
run: |
set -eu
version=$(script/get-crate-version zed)
channel=$(cat crates/zed/RELEASE_CHANNEL)
echo "Publishing version: ${version} on release channel ${channel}"
echo "RELEASE_CHANNEL=${channel}" >> $GITHUB_ENV
expected_tag_name=""
case ${channel} in
stable)
expected_tag_name="v${version}";;
preview)
expected_tag_name="v${version}-pre";;
nightly)
expected_tag_name="v${version}-nightly";;
*)
echo "can't publish a release on channel ${channel}"
exit 1;;
esac
if [[ $GITHUB_REF_NAME != $expected_tag_name ]]; then
echo "invalid release tag ${GITHUB_REF_NAME}. expected ${expected_tag_name}"
exit 1
fi
# This exports RELEASE_CHANNEL into env (GITHUB_ENV)
script/determine-release-channel
- name: Create and upload Linux .tar.gz bundle
run: script/bundle-linux

View File

@@ -14,7 +14,7 @@ jobs:
stale-issue-message: >
Hi there! 👋
We're working to clean up our issue tracker by closing older issues that might not be relevant anymore. Are you able to reproduce this issue in the latest version of Zed? If so, please let us know by commenting on this issue and we will keep it open; otherwise, we'll close it in 10 days. Feel free to open a new issue if you're seeing this message after the issue has been closed.
We're working to clean up our issue tracker by closing older issues that might not be relevant anymore. Are you able to reproduce this issue in the latest version of Zed? If so, please let us know by commenting on this issue and we will keep it open; otherwise, we'll close it in 7 days. Feel free to open a new issue if you're seeing this message after the issue has been closed.
Thanks for your help!
close-issue-message: "This issue was closed due to inactivity; feel free to open a new issue if you're still experiencing this problem!"
@@ -23,7 +23,7 @@ jobs:
# 'community' to 'zed' repository. The migration added activity to all
# issues, preventing 365 days from working until then.
days-before-stale: 180
days-before-close: 10
days-before-close: 7
any-of-issue-labels: "defect,panic / crash"
operations-per-run: 1000
ascending: true

View File

@@ -21,7 +21,7 @@ jobs:
version: 9
- name: Setup Node
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4
with:
node-version: "20"
cache: "pnpm"

View File

@@ -36,28 +36,28 @@ jobs:
mdbook build ./docs --dest-dir=../target/deploy/docs/
- name: Deploy Docs
uses: cloudflare/wrangler-action@f84a562284fc78278ff9052435d9526f9c718361 # v3
uses: cloudflare/wrangler-action@168bc28b7078db16f6f1ecc26477fc2248592143 # v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy target/deploy --project-name=docs
- name: Deploy Install
uses: cloudflare/wrangler-action@f84a562284fc78278ff9052435d9526f9c718361 # v3
uses: cloudflare/wrangler-action@168bc28b7078db16f6f1ecc26477fc2248592143 # v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: r2 object put -f script/install.sh zed-open-source-website-assets/install.sh
- name: Deploy Docs Workers
uses: cloudflare/wrangler-action@f84a562284fc78278ff9052435d9526f9c718361 # v3
uses: cloudflare/wrangler-action@168bc28b7078db16f6f1ecc26477fc2248592143 # v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: deploy .cloudflare/docs-proxy/src/worker.js
- name: Deploy Install Workers
uses: cloudflare/wrangler-action@f84a562284fc78278ff9052435d9526f9c718361 # v3
uses: cloudflare/wrangler-action@168bc28b7078db16f6f1ecc26477fc2248592143 # v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}

View File

@@ -3,7 +3,8 @@ name: Publish Collab Server Image
on:
push:
tags:
- collab-production
# Pause production deploys while we investigate an issue.
# - collab-production
- collab-staging
env:
@@ -76,7 +77,11 @@ jobs:
clean: false
- name: Build docker image
run: docker build . --build-arg GITHUB_SHA=$GITHUB_SHA --tag registry.digitalocean.com/zed/collab:$GITHUB_SHA
run: |
docker build -f Dockerfile-collab \
--build-arg GITHUB_SHA=$GITHUB_SHA \
--tag registry.digitalocean.com/zed/collab:$GITHUB_SHA \
.
- name: Publish docker image
run: docker push registry.digitalocean.com/zed/collab:${GITHUB_SHA}

View File

@@ -20,11 +20,14 @@ jobs:
with:
version: 9
- run: |
- name: Prettier Check on /docs
working-directory: ./docs
run: |
pnpm dlx prettier . --check || {
echo "To fix, run from the root of the zed repo:"
echo " cd docs && pnpm dlx prettier . --write && cd .."
false
}
working-directory: ./docs
- name: Check spelling
run: script/check-spelling docs/

View File

@@ -22,7 +22,7 @@ jobs:
- buildjet-16vcpu-ubuntu-2204
steps:
- name: Install Node
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4
with:
node-version: "18"

View File

@@ -70,7 +70,7 @@ jobs:
ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON: ${{ secrets.ZED_CLOUD_PROVIDER_ADDITIONAL_MODELS_JSON }}
steps:
- name: Install Node
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4
with:
node-version: "18"
@@ -100,7 +100,7 @@ jobs:
name: Create a Linux *.tar.gz bundle for x86
if: github.repository_owner == 'zed-industries'
runs-on:
- buildjet-16vcpu-ubuntu-2204
- buildjet-16vcpu-ubuntu-2004
needs: tests
env:
DIGITALOCEAN_SPACES_ACCESS_KEY: ${{ secrets.DIGITALOCEAN_SPACES_ACCESS_KEY }}
@@ -117,7 +117,7 @@ jobs:
run: echo "$HOME/.cargo/bin" >> $GITHUB_PATH
- name: Install Linux dependencies
run: ./script/linux
run: ./script/linux && ./script/install-mold 2.34.0
- name: Limit target directory size
run: script/clear-target-dir-if-larger-than 100

2
.gitignore vendored
View File

@@ -10,7 +10,7 @@
/crates/collab/seed.json
/crates/zed/resources/flatpak/flatpak-cargo-sources.json
/dev.zed.Zed*.json
/assets/*licenses.md
/assets/*licenses.*
**/venv
.build
*.wasm

View File

@@ -38,6 +38,10 @@
}
}
},
"file_types": {
"Dockerfile": ["Dockerfile*[!dockerignore]"],
"Git Ignore": ["dockerignore"]
},
"hard_tabs": false,
"formatter": "auto",
"remove_trailing_whitespace_on_save": true,

684
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -52,7 +52,6 @@ members = [
"crates/indexed_docs",
"crates/inline_completion_button",
"crates/install_cli",
"crates/isahc_http_client",
"crates/journal",
"crates/language",
"crates/language_model",
@@ -88,6 +87,7 @@ members = [
"crates/remote",
"crates/remote_server",
"crates/repl",
"crates/reqwest_client",
"crates/rich_text",
"crates/rope",
"crates/rpc",
@@ -99,6 +99,7 @@ members = [
"crates/settings_ui",
"crates/snippet",
"crates/snippet_provider",
"crates/snippets_ui",
"crates/sqlez",
"crates/sqlez_macros",
"crates/story",
@@ -121,6 +122,7 @@ members = [
"crates/ui",
"crates/ui_input",
"crates/ui_macros",
"crates/ureq_client",
"crates/util",
"crates/vcs_menu",
"crates/vim",
@@ -129,7 +131,6 @@ members = [
"crates/worktree",
"crates/zed",
"crates/zed_actions",
"crates/hyper_client",
#
# Extensions
@@ -153,6 +154,7 @@ members = [
"extensions/php",
"extensions/perplexity",
"extensions/prisma",
"extensions/proto",
"extensions/purescript",
"extensions/ruff",
"extensions/ruby",
@@ -175,6 +177,7 @@ members = [
default-members = ["crates/zed"]
[workspace.dependencies]
#
# Workspace member crates
#
@@ -220,7 +223,6 @@ go_to_line = { path = "crates/go_to_line" }
google_ai = { path = "crates/google_ai" }
gpui = { path = "crates/gpui" }
gpui_macros = { path = "crates/gpui_macros" }
handlebars = "4.3"
headless = { path = "crates/headless" }
html_to_markdown = { path = "crates/html_to_markdown" }
http_client = { path = "crates/http_client" }
@@ -228,7 +230,6 @@ image_viewer = { path = "crates/image_viewer" }
indexed_docs = { path = "crates/indexed_docs" }
inline_completion_button = { path = "crates/inline_completion_button" }
install_cli = { path = "crates/install_cli" }
isahc_http_client = { path = "crates/isahc_http_client" }
journal = { path = "crates/journal" }
language = { path = "crates/language" }
language_model = { path = "crates/language_model" }
@@ -265,6 +266,7 @@ release_channel = { path = "crates/release_channel" }
remote = { path = "crates/remote" }
remote_server = { path = "crates/remote_server" }
repl = { path = "crates/repl" }
reqwest_client = { path = "crates/reqwest_client" }
rich_text = { path = "crates/rich_text" }
rope = { path = "crates/rope" }
rpc = { path = "crates/rpc" }
@@ -276,6 +278,7 @@ settings = { path = "crates/settings" }
settings_ui = { path = "crates/settings_ui" }
snippet = { path = "crates/snippet" }
snippet_provider = { path = "crates/snippet_provider" }
snippets_ui = { path = "crates/snippets_ui" }
sqlez = { path = "crates/sqlez" }
sqlez_macros = { path = "crates/sqlez_macros" }
story = { path = "crates/story" }
@@ -298,6 +301,7 @@ title_bar = { path = "crates/title_bar" }
ui = { path = "crates/ui" }
ui_input = { path = "crates/ui_input" }
ui_macros = { path = "crates/ui_macros" }
ureq_client = { path = "crates/ureq_client" }
util = { path = "crates/util" }
vcs_menu = { path = "crates/vcs_menu" }
vim = { path = "crates/vim" }
@@ -317,6 +321,7 @@ any_vec = "0.14"
anyhow = "1.0.86"
arrayvec = { version = "0.7.4", features = ["serde"] }
ashpd = "0.9.1"
async-compat = "0.2.1"
async-compression = { version = "0.4", features = ["gzip", "futures-io"] }
async-dispatcher = "0.1"
async-fs = "1.6"
@@ -324,7 +329,7 @@ async-pipe = { git = "https://github.com/zed-industries/async-pipe-rs", rev = "8
async-recursion = "1.0.0"
async-tar = "0.5.0"
async-trait = "0.1"
async-tungstenite = "0.23"
async-tungstenite = "0.28"
async-watch = "0.3.1"
async_zip = { version = "0.0.17", features = ["deflate", "deflate64"] }
base64 = "0.22"
@@ -355,20 +360,15 @@ futures-batch = "0.6.1"
futures-lite = "1.13"
git2 = { version = "0.19", default-features = false }
globset = "0.4"
handlebars = "4.3"
heed = { version = "0.20.1", features = ["read-txn-no-tls"] }
hex = "0.4.3"
hyper = "1.4.1"
hyper-util = "0.1.9"
hyper-rustls = "0.27.3"
html5ever = "0.27.0"
hyper = "0.14"
ignore = "0.4.22"
image = "0.25.1"
indexmap = { version = "1.6.2", features = ["serde"] }
indoc = "2"
# We explicitly disable http2 support in isahc.
isahc = { version = "1.7.2", default-features = false, features = [
"text-decoding",
] }
itertools = "0.13.0"
jsonwebtoken = "9.3"
libc = "0.2"
@@ -383,9 +383,9 @@ ordered-float = "2.1.1"
palette = { version = "0.7.5", default-features = false, features = ["std"] }
parking_lot = "0.12.1"
pathdiff = "0.2"
profiling = "1"
postage = { version = "0.5", features = ["futures-traits"] }
pretty_assertions = "1.3.0"
profiling = "1"
prost = "0.9"
prost-build = "0.9"
prost-types = "0.9"
@@ -393,13 +393,14 @@ pulldown-cmark = { version = "0.12.0", default-features = false }
rand = "0.8.5"
regex = "1.5"
repair_json = "0.1.0"
reqwest = { git = "https://github.com/zed-industries/reqwest.git", rev = "fd110f6998da16bbca97b6dddda9be7827c50e29" }
rsa = "0.9.6"
runtimelib = { version = "0.15", default-features = false, features = [
"async-dispatcher-runtime",
] }
rustc-demangle = "0.1.23"
rust-embed = { version = "8.4", features = ["include-exclude"] }
rustls = "0.20.3"
rustls = "0.21.12"
rustls-native-certs = "0.8.0"
schemars = { version = "0.8", features = ["impl_json_schema"] }
semver = "1.0"
@@ -419,6 +420,7 @@ similar = "1.3"
simplelog = "0.12.2"
smallvec = { version = "1.6", features = ["union"] }
smol = "1.2"
sqlformat = "0.2"
strsim = "0.11"
strum = { version = "0.25.0", features = ["derive"] }
subtle = "2.5.0"
@@ -453,15 +455,14 @@ tree-sitter-html = "0.20"
tree-sitter-jsdoc = "0.23"
tree-sitter-json = "0.23"
tree-sitter-md = { git = "https://github.com/zed-industries/tree-sitter-markdown", rev = "4cfa6aad6b75052a5077c80fd934757d9267d81b" }
protols-tree-sitter-proto = { git = "https://github.com/zed-industries/tree-sitter-proto", rev = "0848bd30a64be48772e15fbb9d5ba8c0cc5772ad" }
tree-sitter-python = "0.23"
tree-sitter-regex = "0.23"
tree-sitter-ruby = "0.23"
tree-sitter-rust = "0.23"
tree-sitter-typescript = "0.23"
tree-sitter-yaml = { git = "https://github.com/zed-industries/tree-sitter-yaml", rev = "baff0b51c64ef6a1fb1f8390f3ad6015b83ec13a" }
unindent = "0.1.7"
tree-sitter-yaml = { git = "https://github.com/zed-industries/tree-sitter-yaml", rev = "baff0b51c64ef6a1fb1f8390f3ad6015b83ec13a" }
unicase = "2.6"
unindent = "0.1.7"
unicode-segmentation = "1.10"
url = "2.2"
uuid = { version = "1.1.2", features = ["v4", "v5", "serde"] }

26
Dockerfile-distros Normal file
View File

@@ -0,0 +1,26 @@
# syntax=docker/dockerfile:1
ARG BASE_IMAGE
FROM ${BASE_IMAGE}
WORKDIR /app
ARG TZ=Etc/UTC \
LANG=C.UTF-8 \
LC_ALL=C.UTF-8 \
DEBIAN_FRONTEND=noninteractive
ENV CARGO_TERM_COLOR=always
COPY script/linux script/
RUN ./script/linux
COPY script/install-mold script/install-cmake script/
RUN ./script/install-mold "2.34.0"
RUN ./script/install-cmake "3.30.4"
COPY . .
# When debugging, make these into individual RUN statements.
# Cleanup to avoid saving big layers we aren't going to use.
RUN . "$HOME/.cargo/env" \
&& cargo fetch \
&& cargo build \
&& cargo run -- --help \
&& cargo clean --quiet

View File

@@ -0,0 +1,2 @@
**/target
**/node_modules

View 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-trash"><path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/></svg>

After

Width:  |  Height:  |  Size: 330 B

View File

@@ -196,7 +196,7 @@
}
},
{
"context": "BufferSearchBar && in_replace",
"context": "BufferSearchBar && in_replace > Editor",
"bindings": {
"enter": "search::ReplaceNext",
"ctrl-enter": "search::ReplaceAll"
@@ -310,6 +310,11 @@
"ctrl-shift-\\": "editor::MoveToEnclosingBracket",
"ctrl-shift-[": "editor::Fold",
"ctrl-shift-]": "editor::UnfoldLines",
"ctrl-k ctrl-l": "editor::ToggleFold",
"ctrl-k ctrl-[": "editor::FoldRecursive",
"ctrl-k ctrl-]": "editor::UnfoldRecursive",
"ctrl-k ctrl-0": "editor::FoldAll",
"ctrl-k ctrl-j": "editor::UnfoldAll",
"ctrl-space": "editor::ShowCompletions",
"ctrl-.": "editor::ToggleCodeActions",
"alt-ctrl-r": "editor::RevealInFileManager",

View File

@@ -232,7 +232,7 @@
}
},
{
"context": "BufferSearchBar && in_replace",
"context": "BufferSearchBar && in_replace > Editor",
"bindings": {
"enter": "search::ReplaceNext",
"cmd-enter": "search::ReplaceAll"
@@ -347,6 +347,11 @@
"cmd-shift-\\": "editor::MoveToEnclosingBracket",
"alt-cmd-[": "editor::Fold",
"alt-cmd-]": "editor::UnfoldLines",
"cmd-k cmd-l": "editor::ToggleFold",
"cmd-k cmd-[": "editor::FoldRecursive",
"cmd-k cmd-]": "editor::UnfoldRecursive",
"cmd-k cmd-0": "editor::FoldAll",
"cmd-k cmd-j": "editor::UnfoldAll",
"ctrl-space": "editor::ShowCompletions",
"cmd-.": "editor::ToggleCodeActions",
"alt-cmd-r": "editor::RevealInFileManager",
@@ -435,7 +440,12 @@
"cmd-k shift-right": ["workspace::SwapPaneInDirection", "Right"],
"cmd-k shift-up": ["workspace::SwapPaneInDirection", "Up"],
"cmd-k shift-down": ["workspace::SwapPaneInDirection", "Down"],
"cmd-shift-x": "zed::Extensions",
"cmd-shift-x": "zed::Extensions"
}
},
{
"context": "Workspace && !Terminal",
"bindings": {
"alt-t": "task::Rerun",
"alt-shift-t": "task::Spawn"
}

View File

@@ -132,9 +132,15 @@
"z z": "editor::ScrollCursorCenter",
"z .": ["workspace::SendKeystrokes", "z z ^"],
"z b": "editor::ScrollCursorBottom",
"z a": "editor::ToggleFold",
"z A": "editor::ToggleFoldRecursive",
"z c": "editor::Fold",
"z C": "editor::FoldRecursive",
"z o": "editor::UnfoldLines",
"z O": "editor::UnfoldRecursive",
"z f": "editor::FoldSelectedRanges",
"z M": "editor::FoldAll",
"z R": "editor::UnfoldAll",
"shift-z shift-q": ["pane::CloseActiveItem", { "saveIntent": "skip" }],
"shift-z shift-z": ["pane::CloseActiveItem", { "saveIntent": "saveAll" }],
// Count support

View File

@@ -50,6 +50,9 @@ And here's the section to rewrite based on that prompt again for reference:
{{#if diagnostic_errors}}
{{#each diagnostic_errors}}
Below are the diagnostic errors visible to the user. If the user requests problems to be fixed, use this information, but do not try to fix these errors if the user hasn't asked you to.
<diagnostic_error>
<line_number>{{line_number}}</line_number>
<error_message>{{error_message}}</error_message>

View File

@@ -356,9 +356,19 @@
/// Scrollbar-related settings
"scrollbar": {
/// When to show the scrollbar in the project panel.
/// This setting can take four values:
///
/// Default: always
"show": "always"
/// 1. null (default): Inherit editor settings
/// 2. Show the scrollbar if there's important information or
/// follow the system's configured behavior (default):
/// "auto"
/// 3. Match the system's configured behavior:
/// "system"
/// 4. Always show the scrollbar:
/// "always"
/// 5. Never show the scrollbar:
/// "never"
"show": null
}
},
"outline_panel": {
@@ -535,17 +545,16 @@
// How to soft-wrap long lines of text.
// Possible values:
//
// 1. Do not soft wrap.
// 1. Prefer a single line generally, unless an overly long line is encountered.
// "soft_wrap": "none",
// 2. Prefer a single line generally, unless an overly long line is encountered.
// "soft_wrap": "prefer_line",
// 3. Soft wrap lines that overflow the editor.
// "soft_wrap": "prefer_line", // (deprecated, same as "none")
// 2. Soft wrap lines that overflow the editor.
// "soft_wrap": "editor_width",
// 4. Soft wrap lines at the preferred line length.
// 3. Soft wrap lines at the preferred line length.
// "soft_wrap": "preferred_line_length",
// 5. Soft wrap lines at the preferred line length or the editor width (whichever is smaller).
// 4. Soft wrap lines at the preferred line length or the editor width (whichever is smaller).
// "soft_wrap": "bounded",
"soft_wrap": "prefer_line",
"soft_wrap": "none",
// The column at which to soft-wrap lines, for buffers where soft-wrap
// is enabled.
"preferred_line_length": 80,
@@ -600,13 +609,11 @@
}
},
// Configuration for how direnv configuration should be loaded. May take 2 values:
// 1. Load direnv configuration through the shell hook, works for POSIX shells and fish.
// "load_direnv": "shell_hook"
// 2. Load direnv configuration using `direnv export json` directly.
// This can help with some shells that otherwise would not detect
// the direnv environment, such as nushell or elvish.
// 1. Load direnv configuration using `direnv export json` directly.
// "load_direnv": "direct"
"load_direnv": "shell_hook",
// 2. Load direnv configuration through the shell hook, works for POSIX shells and fish.
// "load_direnv": "shell_hook"
"load_direnv": "direct",
"inline_completions": {
// A list of globs representing files that inline completions should be disabled for.
"disabled_globs": [".env"]
@@ -672,6 +679,18 @@
// 3. Always blink the cursor, ignoring the terminal mode
// "blinking": "on",
"blinking": "terminal_controlled",
// Default cursor shape for the terminal.
// 1. A block that surrounds the following character
// "block"
// 2. A vertical bar
// "bar"
// 3. An underline that runs along the following character
// "underscore"
// 4. A box drawn around the following character
// "hollow"
//
// Default: not set, defaults to "block"
"cursor_shape": null,
// Set whether Alternate Scroll mode (code: ?1007) is active by default.
// Alternate Scroll mode converts mouse scroll events into up / down key
// presses when in the alternate screen (e.g. when running applications
@@ -770,7 +789,8 @@
"**/Zed/**/*.json",
"tsconfig.json",
"pyrightconfig.json"
]
],
"TOML": ["uv.lock"]
},
/// By default use a recent system version of node, or install our own.
/// You can override this to use a version of node that is not in $PATH with:

View File

@@ -1 +1,2 @@
allow-private-module-inception = true
avoid-breaking-exported-api = false

View File

@@ -20,7 +20,6 @@ anyhow.workspace = true
chrono.workspace = true
futures.workspace = true
http_client.workspace = true
isahc.workspace = true
schemars = { workspace = true, optional = true }
serde.workspace = true
serde_json.workspace = true

View File

@@ -6,8 +6,8 @@ use std::{pin::Pin, str::FromStr};
use anyhow::{anyhow, Context, Result};
use chrono::{DateTime, Utc};
use futures::{io::BufReader, stream::BoxStream, AsyncBufReadExt, AsyncReadExt, Stream, StreamExt};
use http_client::{AsyncBody, HttpClient, Method, Request as HttpRequest};
use isahc::http::{HeaderMap, HeaderValue};
use http_client::http::{HeaderMap, HeaderValue};
use http_client::{AsyncBody, HttpClient, HttpRequestExt, Method, Request as HttpRequest};
use serde::{Deserialize, Serialize};
use strum::{EnumIter, EnumString};
use thiserror::Error;
@@ -288,7 +288,7 @@ pub async fn stream_completion_with_rate_limit_info(
.header("X-Api-Key", api_key)
.header("Content-Type", "application/json");
if let Some(low_speed_timeout) = low_speed_timeout {
request_builder = request_builder.low_speed_timeout(100, low_speed_timeout);
request_builder = request_builder.read_timeout(low_speed_timeout);
}
let serialized_request =
serde_json::to_string(&request).context("failed to serialize request")?;

View File

@@ -72,11 +72,12 @@ use std::{
time::Duration,
};
use terminal_view::{terminal_panel::TerminalPanel, TerminalView};
use text::SelectionGoal;
use ui::TintColor;
use ui::{
prelude::*,
utils::{format_distance_from_now, DateTimeType},
Avatar, AvatarShape, ButtonLike, ContextMenu, Disclosure, ElevationIndex, KeyBinding, ListItem,
Avatar, ButtonLike, ContextMenu, Disclosure, ElevationIndex, KeyBinding, ListItem,
ListItemSpacing, PopoverMenu, PopoverMenuHandle, Tooltip,
};
use util::{maybe, ResultExt};
@@ -261,9 +262,7 @@ impl PickerDelegate for SavedContextPickerDelegate {
.gap_2()
.children(if let Some(host_user) = host_user {
vec![
Avatar::new(host_user.avatar_uri.clone())
.shape(AvatarShape::Circle)
.into_any_element(),
Avatar::new(host_user.avatar_uri.clone()).into_any_element(),
Label::new(format!("Shared by @{}", host_user.github_login))
.color(Color::Muted)
.size(LabelSize::Small)
@@ -960,7 +959,8 @@ impl AssistantPanel {
}
fn new_context(&mut self, cx: &mut ViewContext<Self>) -> Option<View<ContextEditor>> {
if self.project.read(cx).is_via_collab() {
let project = self.project.read(cx);
if project.is_via_collab() && project.dev_server_project_id().is_none() {
let task = self
.context_store
.update(cx, |store, cx| store.create_remote_context(cx));
@@ -3437,7 +3437,7 @@ impl ContextEditor {
fn copy(&mut self, _: &editor::actions::Copy, cx: &mut ViewContext<Self>) {
if self.editor.read(cx).selections.count() == 1 {
let (copied_text, metadata) = self.get_clipboard_contents(cx);
let (copied_text, metadata, _) = self.get_clipboard_contents(cx);
cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
copied_text,
metadata,
@@ -3451,11 +3451,9 @@ impl ContextEditor {
fn cut(&mut self, _: &editor::actions::Cut, cx: &mut ViewContext<Self>) {
if self.editor.read(cx).selections.count() == 1 {
let (copied_text, metadata) = self.get_clipboard_contents(cx);
let (copied_text, metadata, selections) = self.get_clipboard_contents(cx);
self.editor.update(cx, |editor, cx| {
let selections = editor.selections.all::<Point>(cx);
editor.transact(cx, |this, cx| {
this.change_selections(Some(Autoscroll::fit()), cx, |s| {
s.select(selections);
@@ -3475,52 +3473,71 @@ impl ContextEditor {
cx.propagate();
}
fn get_clipboard_contents(&mut self, cx: &mut ViewContext<Self>) -> (String, CopyMetadata) {
let creases = self.editor.update(cx, |editor, cx| {
let selection = editor.selections.newest::<Point>(cx);
let selection_start = editor.selections.newest::<usize>(cx).start;
fn get_clipboard_contents(
&mut self,
cx: &mut ViewContext<Self>,
) -> (String, CopyMetadata, Vec<text::Selection<usize>>) {
let (snapshot, selection, creases) = self.editor.update(cx, |editor, cx| {
let mut selection = editor.selections.newest::<Point>(cx);
let snapshot = editor.buffer().read(cx).snapshot(cx);
editor.display_map.update(cx, |display_map, cx| {
display_map
.snapshot(cx)
.crease_snapshot
.creases_in_range(
MultiBufferRow(selection.start.row)..MultiBufferRow(selection.end.row + 1),
&snapshot,
)
.filter_map(|crease| {
if let Some(metadata) = &crease.metadata {
let start = crease
.range
.start
.to_offset(&snapshot)
.saturating_sub(selection_start);
let end = crease
.range
.end
.to_offset(&snapshot)
.saturating_sub(selection_start);
let range_relative_to_selection = start..end;
let is_entire_line = selection.is_empty() || editor.selections.line_mode;
if is_entire_line {
selection.start = Point::new(selection.start.row, 0);
selection.end =
cmp::min(snapshot.max_point(), Point::new(selection.start.row + 1, 0));
selection.goal = SelectionGoal::None;
}
if range_relative_to_selection.is_empty() {
None
let selection_start = snapshot.point_to_offset(selection.start);
(
snapshot.clone(),
selection.clone(),
editor.display_map.update(cx, |display_map, cx| {
display_map
.snapshot(cx)
.crease_snapshot
.creases_in_range(
MultiBufferRow(selection.start.row)
..MultiBufferRow(selection.end.row + 1),
&snapshot,
)
.filter_map(|crease| {
if let Some(metadata) = &crease.metadata {
let start = crease
.range
.start
.to_offset(&snapshot)
.saturating_sub(selection_start);
let end = crease
.range
.end
.to_offset(&snapshot)
.saturating_sub(selection_start);
let range_relative_to_selection = start..end;
if range_relative_to_selection.is_empty() {
None
} else {
Some(SelectedCreaseMetadata {
range_relative_to_selection,
crease: metadata.clone(),
})
}
} else {
Some(SelectedCreaseMetadata {
range_relative_to_selection,
crease: metadata.clone(),
})
None
}
} else {
None
}
})
.collect::<Vec<_>>()
})
})
.collect::<Vec<_>>()
}),
)
});
let selection = selection.map(|point| snapshot.point_to_offset(point));
let context = self.context.read(cx);
let selection = self.editor.read(cx).selections.newest::<usize>(cx);
let mut text = String::new();
for message in context.messages(cx) {
if message.offset_range.start >= selection.range().end {
@@ -3539,7 +3556,7 @@ impl ContextEditor {
}
}
(text, CopyMetadata { creases })
(text, CopyMetadata { creases }, vec![selection])
}
fn paste(&mut self, action: &editor::actions::Paste, cx: &mut ViewContext<Self>) {

View File

@@ -46,7 +46,7 @@ use std::{
sync::Arc,
time::{Duration, Instant},
};
use telemetry_events::{AssistantKind, AssistantPhase};
use telemetry_events::{AssistantEvent, AssistantKind, AssistantPhase};
use text::BufferSnapshot;
use util::{post_inc, ResultExt, TryFutureExt};
use uuid::Uuid;
@@ -549,7 +549,7 @@ impl Context {
cx: &mut ModelContext<Self>,
) -> Self {
let buffer = cx.new_model(|_cx| {
let mut buffer = Buffer::remote(
let buffer = Buffer::remote(
language::BufferId::new(1).unwrap(),
replica_id,
capability,
@@ -2133,14 +2133,21 @@ impl Context {
});
if let Some(telemetry) = this.telemetry.as_ref() {
telemetry.report_assistant_event(
Some(this.id.0.clone()),
AssistantKind::Panel,
AssistantPhase::Response,
model.telemetry_id(),
let language_name = this
.buffer
.read(cx)
.language()
.map(|language| language.name());
telemetry.report_assistant_event(AssistantEvent {
conversation_id: Some(this.id.0.clone()),
kind: AssistantKind::Panel,
phase: AssistantPhase::Response,
model: model.telemetry_id(),
model_provider: model.provider_id().to_string(),
response_latency,
error_message,
);
language_name,
});
}
if let Ok(stop_reason) = result {

View File

@@ -50,6 +50,7 @@ use std::{
task::{self, Poll},
time::{Duration, Instant},
};
use telemetry_events::{AssistantEvent, AssistantKind, AssistantPhase};
use terminal_view::terminal_panel::TerminalPanel;
use text::{OffsetRangeExt, ToPoint as _};
use theme::ThemeSettings;
@@ -209,18 +210,6 @@ impl InlineAssistant {
initial_prompt: Option<String>,
cx: &mut WindowContext,
) {
if let Some(telemetry) = self.telemetry.as_ref() {
if let Some(model) = LanguageModelRegistry::read_global(cx).active_model() {
telemetry.report_assistant_event(
None,
telemetry_events::AssistantKind::Inline,
telemetry_events::AssistantPhase::Invoked,
model.telemetry_id(),
None,
None,
);
}
}
let snapshot = editor.read(cx).buffer().read(cx).snapshot(cx);
let mut selections = Vec::<Selection<Point>>::new();
@@ -267,6 +256,21 @@ impl InlineAssistant {
text_anchor: buffer.anchor_after(buffer_range.end),
};
codegen_ranges.push(start..end);
if let Some(telemetry) = self.telemetry.as_ref() {
if let Some(model) = LanguageModelRegistry::read_global(cx).active_model() {
telemetry.report_assistant_event(AssistantEvent {
conversation_id: None,
kind: AssistantKind::Inline,
phase: AssistantPhase::Invoked,
model: model.telemetry_id(),
model_provider: model.provider_id().to_string(),
response_latency: None,
error_message: None,
language_name: buffer.language().map(|language| language.name()),
});
}
}
}
let assist_group_id = self.next_assist_group_id.post_inc();
@@ -761,23 +765,34 @@ impl InlineAssistant {
}
pub fn finish_assist(&mut self, assist_id: InlineAssistId, undo: bool, cx: &mut WindowContext) {
if let Some(telemetry) = self.telemetry.as_ref() {
if let Some(model) = LanguageModelRegistry::read_global(cx).active_model() {
telemetry.report_assistant_event(
None,
telemetry_events::AssistantKind::Inline,
if undo {
telemetry_events::AssistantPhase::Rejected
} else {
telemetry_events::AssistantPhase::Accepted
},
model.telemetry_id(),
None,
None,
);
}
}
if let Some(assist) = self.assists.get(&assist_id) {
if let Some(telemetry) = self.telemetry.as_ref() {
if let Some(model) = LanguageModelRegistry::read_global(cx).active_model() {
let language_name = assist.editor.upgrade().and_then(|editor| {
let multibuffer = editor.read(cx).buffer().read(cx);
let ranges = multibuffer.range_to_buffer_ranges(assist.range.clone(), cx);
ranges
.first()
.and_then(|(buffer, _, _)| buffer.read(cx).language())
.map(|language| language.name())
});
telemetry.report_assistant_event(AssistantEvent {
conversation_id: None,
kind: AssistantKind::Inline,
phase: if undo {
AssistantPhase::Rejected
} else {
AssistantPhase::Accepted
},
model: model.telemetry_id(),
model_provider: model.provider_id().to_string(),
response_latency: None,
error_message: None,
language_name,
});
}
}
let assist_group_id = assist.group_id;
if self.assist_groups[&assist_group_id].linked {
for assist_id in self.unlink_assist_group(assist_group_id, cx) {
@@ -1142,7 +1157,7 @@ impl InlineAssistant {
for row_range in inserted_row_ranges {
editor.highlight_rows::<InlineAssist>(
row_range,
Some(cx.theme().status().info_background),
cx.theme().status().info_background,
false,
cx,
);
@@ -1208,8 +1223,8 @@ impl InlineAssistant {
editor.set_read_only(true);
editor.set_show_inline_completions(Some(false), cx);
editor.highlight_rows::<DeletedLines>(
Anchor::min()..=Anchor::max(),
Some(cx.theme().status().deleted_background),
Anchor::min()..Anchor::max(),
cx.theme().status().deleted_background,
false,
cx,
);
@@ -2557,7 +2572,7 @@ enum CodegenStatus {
#[derive(Default)]
struct Diff {
deleted_row_ranges: Vec<(Anchor, RangeInclusive<u32>)>,
inserted_row_ranges: Vec<RangeInclusive<Anchor>>,
inserted_row_ranges: Vec<Range<Anchor>>,
}
impl Diff {
@@ -2706,6 +2721,7 @@ impl CodegenAlternative {
self.edit_position = Some(self.range.start.bias_right(&self.snapshot));
let telemetry_id = model.telemetry_id();
let provider_id = model.provider_id();
let chunks: LocalBoxFuture<Result<BoxStream<Result<String>>>> =
if user_prompt.trim().to_lowercase() == "delete" {
async { Ok(stream::empty().boxed()) }.boxed_local()
@@ -2716,7 +2732,7 @@ impl CodegenAlternative {
.spawn(|_, cx| async move { model.stream_completion_text(request, &cx).await });
async move { Ok(chunks.await?.boxed()) }.boxed_local()
};
self.handle_stream(telemetry_id, chunks, cx);
self.handle_stream(telemetry_id, provider_id.to_string(), chunks, cx);
Ok(())
}
@@ -2780,6 +2796,7 @@ impl CodegenAlternative {
pub fn handle_stream(
&mut self,
model_telemetry_id: String,
model_provider_id: String,
stream: impl 'static + Future<Output = Result<BoxStream<'static, Result<String>>>>,
cx: &mut ModelContext<Self>,
) {
@@ -2810,6 +2827,15 @@ impl CodegenAlternative {
}
let telemetry = self.telemetry.clone();
let language_name = {
let multibuffer = self.buffer.read(cx);
let ranges = multibuffer.range_to_buffer_ranges(self.range.clone(), cx);
ranges
.first()
.and_then(|(buffer, _, _)| buffer.read(cx).language())
.map(|language| language.name())
};
self.diff = Diff::default();
self.status = CodegenStatus::Pending;
let mut edit_start = self.range.start.to_offset(&snapshot);
@@ -2920,14 +2946,16 @@ impl CodegenAlternative {
let error_message =
result.as_ref().err().map(|error| error.to_string());
if let Some(telemetry) = telemetry {
telemetry.report_assistant_event(
None,
telemetry_events::AssistantKind::Inline,
telemetry_events::AssistantPhase::Response,
model_telemetry_id,
telemetry.report_assistant_event(AssistantEvent {
conversation_id: None,
kind: AssistantKind::Inline,
phase: AssistantPhase::Response,
model: model_telemetry_id,
model_provider: model_provider_id.to_string(),
response_latency,
error_message,
);
language_name,
});
}
result?;
@@ -3103,7 +3131,7 @@ impl CodegenAlternative {
new_end_row,
new_snapshot.line_len(MultiBufferRow(new_end_row)),
));
self.diff.inserted_row_ranges.push(start..=end);
self.diff.inserted_row_ranges.push(start..end);
new_row += lines;
}
}
@@ -3181,7 +3209,7 @@ impl CodegenAlternative {
new_end_row,
new_snapshot.line_len(MultiBufferRow(new_end_row)),
));
inserted_row_ranges.push(start..=end);
inserted_row_ranges.push(start..end);
new_row += line_count;
}
}
@@ -3539,6 +3567,7 @@ mod tests {
let (chunks_tx, chunks_rx) = mpsc::unbounded();
codegen.update(cx, |codegen, cx| {
codegen.handle_stream(
String::new(),
String::new(),
future::ready(Ok(chunks_rx.map(Ok).boxed())),
cx,
@@ -3610,6 +3639,7 @@ mod tests {
let (chunks_tx, chunks_rx) = mpsc::unbounded();
codegen.update(cx, |codegen, cx| {
codegen.handle_stream(
String::new(),
String::new(),
future::ready(Ok(chunks_rx.map(Ok).boxed())),
cx,
@@ -3684,6 +3714,7 @@ mod tests {
let (chunks_tx, chunks_rx) = mpsc::unbounded();
codegen.update(cx, |codegen, cx| {
codegen.handle_stream(
String::new(),
String::new(),
future::ready(Ok(chunks_rx.map(Ok).boxed())),
cx,
@@ -3757,6 +3788,7 @@ mod tests {
let (chunks_tx, chunks_rx) = mpsc::unbounded();
codegen.update(cx, |codegen, cx| {
codegen.handle_stream(
String::new(),
String::new(),
future::ready(Ok(chunks_rx.map(Ok).boxed())),
cx,
@@ -3820,6 +3852,7 @@ mod tests {
let (chunks_tx, chunks_rx) = mpsc::unbounded();
codegen.update(cx, |codegen, cx| {
codegen.handle_stream(
String::new(),
String::new(),
future::ready(Ok(chunks_rx.map(Ok).boxed())),
cx,

View File

@@ -910,7 +910,7 @@ impl PromptLibrary {
.features
.clone(),
font_size: HeadlineSize::Large
.size()
.rems()
.into(),
font_weight: settings.ui_font.weight,
line_height: relative(

View File

@@ -31,11 +31,11 @@ impl SlashCommand for AutoCommand {
}
fn description(&self) -> String {
"Automatically infer what context to add, based on your prompt".into()
"Automatically infer what context to add".into()
}
fn menu_text(&self) -> String {
"Automatically Infer Context".into()
self.description()
}
fn label(&self, cx: &AppContext) -> CodeLabel {

View File

@@ -19,11 +19,11 @@ impl SlashCommand for DeltaSlashCommand {
}
fn description(&self) -> String {
"re-insert changed files".into()
"Re-insert changed files".into()
}
fn menu_text(&self) -> String {
"Re-insert Changed Files".into()
self.description()
}
fn requires_argument(&self) -> bool {

View File

@@ -95,7 +95,7 @@ impl SlashCommand for DiagnosticsSlashCommand {
}
fn menu_text(&self) -> String {
"Insert Diagnostics".into()
self.description()
}
fn requires_argument(&self) -> bool {

View File

@@ -104,11 +104,11 @@ impl SlashCommand for FetchSlashCommand {
}
fn description(&self) -> String {
"insert URL contents".into()
"Insert fetched URL contents".into()
}
fn menu_text(&self) -> String {
"Insert fetched URL contents".into()
self.description()
}
fn requires_argument(&self) -> bool {

View File

@@ -110,11 +110,11 @@ impl SlashCommand for FileSlashCommand {
}
fn description(&self) -> String {
"insert file".into()
"Insert file".into()
}
fn menu_text(&self) -> String {
"Insert File".into()
self.description()
}
fn requires_argument(&self) -> bool {

View File

@@ -19,11 +19,11 @@ impl SlashCommand for NowSlashCommand {
}
fn description(&self) -> String {
"insert the current date and time".into()
"Insert current date and time".into()
}
fn menu_text(&self) -> String {
"Insert Current Date and Time".into()
self.description()
}
fn requires_argument(&self) -> bool {

View File

@@ -47,11 +47,11 @@ impl SlashCommand for ProjectSlashCommand {
}
fn description(&self) -> String {
"Generate semantic searches based on the current context".into()
"Generate a semantic search based on context".into()
}
fn menu_text(&self) -> String {
"Project Context".into()
self.description()
}
fn requires_argument(&self) -> bool {

View File

@@ -16,11 +16,11 @@ impl SlashCommand for PromptSlashCommand {
}
fn description(&self) -> String {
"insert prompt from library".into()
"Insert prompt from library".into()
}
fn menu_text(&self) -> String {
"Insert Prompt from Library".into()
self.description()
}
fn requires_argument(&self) -> bool {

View File

@@ -34,11 +34,11 @@ impl SlashCommand for SearchSlashCommand {
}
fn description(&self) -> String {
"semantic search".into()
"Search your project semantically".into()
}
fn menu_text(&self) -> String {
"Semantic Search".into()
self.description()
}
fn requires_argument(&self) -> bool {

View File

@@ -17,11 +17,11 @@ impl SlashCommand for OutlineSlashCommand {
}
fn description(&self) -> String {
"insert symbols for active tab".into()
"Insert symbols for active tab".into()
}
fn menu_text(&self) -> String {
"Insert Symbols for Active Tab".into()
self.description()
}
fn complete_argument(

View File

@@ -24,11 +24,11 @@ impl SlashCommand for TabSlashCommand {
}
fn description(&self) -> String {
"insert open tabs (active tab by default)".to_owned()
"Insert open tabs (active tab by default)".to_owned()
}
fn menu_text(&self) -> String {
"Insert Open Tabs".to_owned()
self.description()
}
fn requires_argument(&self) -> bool {

View File

@@ -29,11 +29,11 @@ impl SlashCommand for TerminalSlashCommand {
}
fn description(&self) -> String {
"insert terminal output".into()
"Insert terminal output".into()
}
fn menu_text(&self) -> String {
"Insert Terminal Output".into()
self.description()
}
fn requires_argument(&self) -> bool {

View File

@@ -29,11 +29,11 @@ impl SlashCommand for WorkflowSlashCommand {
}
fn description(&self) -> String {
"insert a prompt that opts into the edit workflow".into()
"Insert prompt to opt into the edit workflow".into()
}
fn menu_text(&self) -> String {
"Insert Workflow Prompt".into()
self.description()
}
fn requires_argument(&self) -> bool {

View File

@@ -184,7 +184,7 @@ impl PickerDelegate for SlashCommandDelegate {
h_flex()
.group(format!("command-entry-label-{ix}"))
.w_full()
.min_w(px(220.))
.min_w(px(250.))
.child(
v_flex()
.child(
@@ -203,7 +203,9 @@ impl PickerDelegate for SlashCommandDelegate {
div()
.font_buffer(cx)
.child(
Label::new(args).size(LabelSize::Small),
Label::new(args)
.size(LabelSize::Small)
.color(Color::Muted),
)
.visible_on_hover(format!(
"command-entry-label-{ix}"

View File

@@ -25,6 +25,7 @@ use std::{
sync::Arc,
time::{Duration, Instant},
};
use telemetry_events::{AssistantEvent, AssistantKind, AssistantPhase};
use terminal::Terminal;
use terminal_view::TerminalView;
use theme::ThemeSettings;
@@ -1039,6 +1040,7 @@ impl Codegen {
self.transaction = Some(TerminalTransaction::start(self.terminal.clone()));
self.generation = cx.spawn(|this, mut cx| async move {
let model_telemetry_id = model.telemetry_id();
let model_provider_id = model.provider_id();
let response = model.stream_completion_text(prompt, &cx).await;
let generate = async {
let (mut hunks_tx, mut hunks_rx) = mpsc::channel(1);
@@ -1063,14 +1065,16 @@ impl Codegen {
let error_message = result.as_ref().err().map(|error| error.to_string());
if let Some(telemetry) = telemetry {
telemetry.report_assistant_event(
None,
telemetry_events::AssistantKind::Inline,
telemetry_events::AssistantPhase::Response,
model_telemetry_id,
telemetry.report_assistant_event(AssistantEvent {
conversation_id: None,
kind: AssistantKind::Inline,
phase: AssistantPhase::Response,
model: model_telemetry_id,
model_provider: model_provider_id.to_string(),
response_latency,
error_message,
);
language_name: None,
});
}
result?;

View File

@@ -264,6 +264,18 @@ pub fn view_release_notes(_: &ViewReleaseNotes, cx: &mut AppContext) -> Option<(
fn view_release_notes_locally(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) {
let release_channel = ReleaseChannel::global(cx);
let url = match release_channel {
ReleaseChannel::Nightly => Some("https://github.com/zed-industries/zed/commits/nightly/"),
ReleaseChannel::Dev => Some("https://github.com/zed-industries/zed/commits/main/"),
_ => None,
};
if let Some(url) = url {
cx.open_url(url);
return;
}
let version = AppVersion::global(cx).to_string();
let client = client::Client::global(cx).http_client();
@@ -345,15 +357,17 @@ pub fn notify_of_any_new_update(cx: &mut ViewContext<Workspace>) -> Option<()> {
let should_show_notification = should_show_notification.await?;
if should_show_notification {
workspace.update(&mut cx, |workspace, cx| {
let workspace_handle = workspace.weak_handle();
workspace.show_notification(
NotificationId::unique::<UpdateNotification>(),
cx,
|cx| cx.new_view(|_| UpdateNotification::new(version)),
|cx| cx.new_view(|_| UpdateNotification::new(version, workspace_handle)),
);
updater
.read(cx)
.set_should_show_update_notification(false, cx)
.detach_and_log_err(cx);
updater.update(cx, |updater, cx| {
updater
.set_should_show_update_notification(false, cx)
.detach_and_log_err(cx);
});
})?;
}
anyhow::Ok(())

View File

@@ -1,13 +1,18 @@
use gpui::{
div, DismissEvent, EventEmitter, InteractiveElement, IntoElement, ParentElement, Render,
SemanticVersion, StatefulInteractiveElement, Styled, ViewContext,
SemanticVersion, StatefulInteractiveElement, Styled, ViewContext, WeakView,
};
use menu::Cancel;
use release_channel::ReleaseChannel;
use workspace::ui::{h_flex, v_flex, Icon, IconName, Label, StyledExt};
use util::ResultExt;
use workspace::{
ui::{h_flex, v_flex, Icon, IconName, Label, StyledExt},
Workspace,
};
pub struct UpdateNotification {
version: SemanticVersion,
workspace: WeakView<Workspace>,
}
impl EventEmitter<DismissEvent> for UpdateNotification {}
@@ -41,7 +46,11 @@ impl Render for UpdateNotification {
.child(Label::new("View the release notes"))
.cursor_pointer()
.on_click(cx.listener(|this, _, cx| {
crate::view_release_notes(&Default::default(), cx);
this.workspace
.update(cx, |workspace, cx| {
crate::view_release_notes_locally(workspace, cx);
})
.log_err();
this.dismiss(&menu::Cancel, cx)
})),
)
@@ -49,8 +58,8 @@ impl Render for UpdateNotification {
}
impl UpdateNotification {
pub fn new(version: SemanticVersion) -> Self {
Self { version }
pub fn new(version: SemanticVersion, workspace: WeakView<Workspace>) -> Self {
Self { version, workspace }
}
pub fn dismiss(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {

View File

@@ -1,7 +1,7 @@
use editor::Editor;
use gpui::{
Element, EventEmitter, IntoElement, ParentElement, Render, StyledText, Subscription,
ViewContext,
Element, EventEmitter, FocusableView, IntoElement, ParentElement, Render, StyledText,
Subscription, ViewContext,
};
use itertools::Itertools;
use std::cmp;
@@ -90,17 +90,30 @@ impl Render for Breadcrumbs {
ButtonLike::new("toggle outline view")
.child(breadcrumbs_stack)
.style(ButtonStyle::Transparent)
.on_click(move |_, cx| {
if let Some(editor) = editor.upgrade() {
outline::toggle(editor, &editor::actions::ToggleOutline, cx)
.on_click({
let editor = editor.clone();
move |_, cx| {
if let Some(editor) = editor.upgrade() {
outline::toggle(editor, &editor::actions::ToggleOutline, cx)
}
}
})
.tooltip(|cx| {
Tooltip::for_action(
"Show symbol outline",
&editor::actions::ToggleOutline,
cx,
)
.tooltip(move |cx| {
if let Some(editor) = editor.upgrade() {
let focus_handle = editor.read(cx).focus_handle(cx);
Tooltip::for_action_in(
"Show symbol outline",
&editor::actions::ToggleOutline,
&focus_handle,
cx,
)
} else {
Tooltip::for_action(
"Show symbol outline",
&editor::actions::ToggleOutline,
cx,
)
}
}),
),
None => element

View File

@@ -808,7 +808,7 @@ pub fn mentions_to_proto(mentions: &[(Range<usize>, UserId)]) -> Vec<proto::Chat
impl sum_tree::Item for ChannelMessage {
type Summary = ChannelMessageSummary;
fn summary(&self) -> Self::Summary {
fn summary(&self, _cx: &()) -> Self::Summary {
ChannelMessageSummary {
max_id: self.id,
count: 1,

View File

@@ -18,6 +18,7 @@ test-support = ["clock/test-support", "collections/test-support", "gpui/test-sup
[dependencies]
anyhow.workspace = true
async-recursion = "0.3"
async-tls = "0.13"
async-tungstenite = { workspace = true, features = ["async-std", "async-tls"] }
chrono = { workspace = true, features = ["serde"] }
clock.workspace = true
@@ -34,8 +35,6 @@ postage.workspace = true
rand.workspace = true
release_channel.workspace = true
rpc = { workspace = true, features = ["gpui"] }
rustls.workspace = true
rustls-native-certs.workspace = true
schemars.workspace = true
serde.workspace = true
serde_json.workspace = true

View File

@@ -394,7 +394,7 @@ pub struct PendingEntitySubscription<T: 'static> {
}
impl<T: 'static> PendingEntitySubscription<T> {
pub fn set_model(mut self, model: &Model<T>, cx: &mut AsyncAppContext) -> Subscription {
pub fn set_model(mut self, model: &Model<T>, cx: &AsyncAppContext) -> Subscription {
self.consumed = true;
let mut handlers = self.client.handler_set.lock();
let id = (TypeId::of::<T>(), self.remote_id);
@@ -1023,7 +1023,7 @@ impl Client {
&self,
http: Arc<HttpClientWithUrl>,
release_channel: Option<ReleaseChannel>,
) -> impl Future<Output = Result<Url>> {
) -> impl Future<Output = Result<url::Url>> {
#[cfg(any(test, feature = "test-support"))]
let url_override = self.rpc_url.read().clone();
@@ -1117,7 +1117,7 @@ impl Client {
// for us from the RPC URL.
//
// Among other things, it will generate and set a `Sec-WebSocket-Key` header for us.
let mut request = rpc_url.into_client_request()?;
let mut request = IntoClientRequest::into_client_request(rpc_url.as_str())?;
// We then modify the request to add our desired headers.
let request_headers = request.headers_mut();
@@ -1137,30 +1137,13 @@ impl Client {
match url_scheme {
Https => {
let client_config = {
let mut root_store = rustls::RootCertStore::empty();
let root_certs = rustls_native_certs::load_native_certs();
for error in root_certs.errors {
log::warn!("error loading native certs: {:?}", error);
}
root_store.add_parsable_certificates(
&root_certs
.certs
.into_iter()
.map(|cert| cert.as_ref().to_owned())
.collect::<Vec<_>>(),
);
rustls::ClientConfig::builder()
.with_safe_defaults()
.with_root_certificates(root_store)
.with_no_client_auth()
};
let (stream, _) =
async_tungstenite::async_tls::client_async_tls_with_connector(
request,
stream,
Some(client_config.into()),
Some(async_tls::TlsConnector::from(
http_client::TLS_CONFIG.clone(),
)),
)
.await?;
Ok(Connection::new(
@@ -1752,7 +1735,7 @@ impl CredentialsProvider for KeychainCredentialsProvider {
}
/// prefix for the zed:// url scheme
pub static ZED_URL_SCHEME: &str = "zed";
pub const ZED_URL_SCHEME: &str = "zed";
/// Parses the given link into a Zed link.
///

View File

@@ -16,9 +16,9 @@ use std::io::Write;
use std::{env, mem, path::PathBuf, sync::Arc, time::Duration};
use sysinfo::{CpuRefreshKind, Pid, ProcessRefreshKind, RefreshKind, System};
use telemetry_events::{
ActionEvent, AppEvent, AssistantEvent, AssistantKind, AssistantPhase, CallEvent, CpuEvent,
EditEvent, EditorEvent, Event, EventRequestBody, EventWrapper, ExtensionEvent,
InlineCompletionEvent, MemoryEvent, ReplEvent, SettingEvent,
ActionEvent, AppEvent, AssistantEvent, CallEvent, CpuEvent, EditEvent, EditorEvent, Event,
EventRequestBody, EventWrapper, ExtensionEvent, InlineCompletionEvent, MemoryEvent, ReplEvent,
SettingEvent,
};
use tempfile::NamedTempFile;
#[cfg(not(debug_assertions))]
@@ -288,7 +288,7 @@ impl Telemetry {
system_id: Option<String>,
installation_id: Option<String>,
session_id: String,
cx: &mut AppContext,
cx: &AppContext,
) {
let mut state = self.state.lock();
state.system_id = system_id.map(|id| id.into());
@@ -391,25 +391,8 @@ impl Telemetry {
self.report_event(event)
}
pub fn report_assistant_event(
self: &Arc<Self>,
conversation_id: Option<String>,
kind: AssistantKind,
phase: AssistantPhase,
model: String,
response_latency: Option<Duration>,
error_message: Option<String>,
) {
let event = Event::Assistant(AssistantEvent {
conversation_id,
kind,
phase,
model: model.to_string(),
response_latency,
error_message,
});
self.report_event(event)
pub fn report_assistant_event(self: &Arc<Self>, event: AssistantEvent) {
self.report_event(Event::Assistant(event));
}
pub fn report_call_event(

View File

@@ -138,7 +138,7 @@ enum UpdateContacts {
}
impl UserStore {
pub fn new(client: Arc<Client>, cx: &mut ModelContext<Self>) -> Self {
pub fn new(client: Arc<Client>, cx: &ModelContext<Self>) -> Self {
let (mut current_user_tx, current_user_rx) = watch::channel();
let (update_contacts_tx, mut update_contacts_rx) = mpsc::unbounded();
let rpc_subscriptions = vec![
@@ -310,7 +310,7 @@ impl UserStore {
fn update_contacts(
&mut self,
message: UpdateContacts,
cx: &mut ModelContext<Self>,
cx: &ModelContext<Self>,
) -> Task<Result<()>> {
match message {
UpdateContacts::Wait(barrier) => {
@@ -525,9 +525,9 @@ impl UserStore {
}
pub fn dismiss_contact_request(
&mut self,
&self,
requester_id: u64,
cx: &mut ModelContext<Self>,
cx: &ModelContext<Self>,
) -> Task<Result<()>> {
let client = self.client.upgrade();
cx.spawn(move |_, _| async move {
@@ -573,7 +573,7 @@ impl UserStore {
})
}
pub fn clear_contacts(&mut self) -> impl Future<Output = ()> {
pub fn clear_contacts(&self) -> impl Future<Output = ()> {
let (tx, mut rx) = postage::barrier::channel();
self.update_contacts_tx
.unbounded_send(UpdateContacts::Clear(tx))
@@ -583,7 +583,7 @@ impl UserStore {
}
}
pub fn contact_updates_done(&mut self) -> impl Future<Output = ()> {
pub fn contact_updates_done(&self) -> impl Future<Output = ()> {
let (tx, mut rx) = postage::barrier::channel();
self.update_contacts_tx
.unbounded_send(UpdateContacts::Wait(tx))
@@ -594,9 +594,9 @@ impl UserStore {
}
pub fn get_users(
&mut self,
&self,
user_ids: Vec<u64>,
cx: &mut ModelContext<Self>,
cx: &ModelContext<Self>,
) -> Task<Result<Vec<Arc<User>>>> {
let mut user_ids_to_fetch = user_ids.clone();
user_ids_to_fetch.retain(|id| !self.users.contains_key(id));
@@ -629,9 +629,9 @@ impl UserStore {
}
pub fn fuzzy_search_users(
&mut self,
&self,
query: String,
cx: &mut ModelContext<Self>,
cx: &ModelContext<Self>,
) -> Task<Result<Vec<Arc<User>>>> {
self.load_users(proto::FuzzySearchUsers { query }, cx)
}
@@ -640,11 +640,7 @@ impl UserStore {
self.users.get(&user_id).cloned()
}
pub fn get_user_optimistic(
&mut self,
user_id: u64,
cx: &mut ModelContext<Self>,
) -> Option<Arc<User>> {
pub fn get_user_optimistic(&self, user_id: u64, cx: &ModelContext<Self>) -> Option<Arc<User>> {
if let Some(user) = self.users.get(&user_id).cloned() {
return Some(user);
}
@@ -653,11 +649,7 @@ impl UserStore {
None
}
pub fn get_user(
&mut self,
user_id: u64,
cx: &mut ModelContext<Self>,
) -> Task<Result<Arc<User>>> {
pub fn get_user(&self, user_id: u64, cx: &ModelContext<Self>) -> Task<Result<Arc<User>>> {
if let Some(user) = self.users.get(&user_id).cloned() {
return Task::ready(Ok(user));
}
@@ -697,7 +689,7 @@ impl UserStore {
.map(|accepted_tos_at| accepted_tos_at.is_some())
}
pub fn accept_terms_of_service(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
pub fn accept_terms_of_service(&self, cx: &ModelContext<Self>) -> Task<Result<()>> {
if self.current_user().is_none() {
return Task::ready(Err(anyhow!("no current user")));
};
@@ -726,9 +718,9 @@ impl UserStore {
}
fn load_users(
&mut self,
&self,
request: impl RequestMessage<Response = UsersResponse>,
cx: &mut ModelContext<Self>,
cx: &ModelContext<Self>,
) -> Task<Result<Vec<Arc<User>>>> {
let client = self.client.clone();
cx.spawn(|this, mut cx| async move {

View File

@@ -28,8 +28,8 @@ axum = { version = "0.6", features = ["json", "headers", "ws"] }
axum-extra = { version = "0.4", features = ["erased-json"] }
base64.workspace = true
chrono.workspace = true
clock.workspace = true
clickhouse.workspace = true
clock.workspace = true
collections.workspace = true
dashmap.workspace = true
envy = "0.4.2"
@@ -37,19 +37,19 @@ futures.workspace = true
google_ai.workspace = true
hex.workspace = true
http_client.workspace = true
isahc_http_client.workspace = true
jsonwebtoken.workspace = true
live_kit_server.workspace = true
log.workspace = true
nanoid.workspace = true
open_ai.workspace = true
supermaven_api.workspace = true
parking_lot.workspace = true
prometheus = "0.13"
prost.workspace = true
rand.workspace = true
reqwest = { version = "0.11", features = ["json"] }
reqwest_client.workspace = true
rpc.workspace = true
rustc-demangle.workspace = true
scrypt = "0.11"
sea-orm = { version = "1.1.0-rc.1", features = ["sqlx-postgres", "postgres-array", "runtime-tokio-rustls", "with-uuid"] }
semantic_version.workspace = true
@@ -61,7 +61,7 @@ sha2.workspace = true
sqlx = { version = "0.8", features = ["runtime-tokio-rustls", "postgres", "json", "time", "uuid", "any"] }
strum.workspace = true
subtle.workspace = true
rustc-demangle.workspace = true
supermaven_api.workspace = true
telemetry_events.workspace = true
text.workspace = true
thiserror.workspace = true
@@ -85,6 +85,7 @@ client = { workspace = true, features = ["test-support"] }
collab_ui = { workspace = true, features = ["test-support"] }
collections = { workspace = true, features = ["test-support"] }
ctor.workspace = true
dev_server_projects.workspace = true
editor = { workspace = true, features = ["test-support"] }
env_logger.workspace = true
file_finder.workspace = true
@@ -92,6 +93,7 @@ fs = { workspace = true, features = ["test-support"] }
git = { workspace = true, features = ["test-support"] }
git_hosting_providers.workspace = true
gpui = { workspace = true, features = ["test-support"] }
headless.workspace = true
hyper.workspace = true
indoc.workspace = true
language = { workspace = true, features = ["test-support"] }
@@ -108,7 +110,6 @@ recent_projects = { workspace = true }
release_channel.workspace = true
remote = { workspace = true, features = ["test-support"] }
remote_server.workspace = true
dev_server_projects.workspace = true
rpc = { workspace = true, features = ["test-support"] }
sea-orm = { version = "1.1.0-rc.1", features = ["sqlx-sqlite"] }
serde_json.workspace = true
@@ -120,7 +121,6 @@ unindent.workspace = true
util.workspace = true
workspace = { workspace = true, features = ["test-support"] }
worktree = { workspace = true, features = ["test-support"] }
headless.workspace = true
[package.metadata.cargo-machete]
ignored = ["async-stripe"]

View File

@@ -149,18 +149,6 @@ spec:
secretKeyRef:
name: google-ai
key: api_key
- name: RUNPOD_API_KEY
valueFrom:
secretKeyRef:
name: runpod
key: api_key
optional: true
- name: RUNPOD_API_SUMMARY_URL
valueFrom:
secretKeyRef:
name: runpod
key: summary
optional: true
- name: BLOB_STORE_ACCESS_KEY
valueFrom:
secretKeyRef:

View File

@@ -112,6 +112,7 @@ CREATE TABLE "worktree_settings_files" (
"worktree_id" INTEGER NOT NULL,
"path" VARCHAR NOT NULL,
"content" TEXT,
"kind" VARCHAR,
PRIMARY KEY(project_id, worktree_id, path),
FOREIGN KEY(project_id, worktree_id) REFERENCES worktrees (project_id, id) ON DELETE CASCADE
);

View File

@@ -0,0 +1 @@
ALTER TABLE "worktree_settings_files" ADD COLUMN "kind" VARCHAR;

View File

@@ -23,7 +23,7 @@ use telemetry_events::{
};
use uuid::Uuid;
static CRASH_REPORTS_BUCKET: &str = "zed-crash-reports";
const CRASH_REPORTS_BUCKET: &str = "zed-crash-reports";
pub fn router() -> Router {
Router::new()

View File

@@ -35,6 +35,7 @@ use std::{
};
use time::PrimitiveDateTime;
use tokio::sync::{Mutex, OwnedMutexGuard};
use worktree_settings_file::LocalSettingsKind;
#[cfg(test)]
pub use tests::TestDb;
@@ -766,6 +767,7 @@ pub struct Worktree {
pub struct WorktreeSettingsFile {
pub path: String,
pub content: String,
pub kind: LocalSettingsKind,
}
pub struct NewExtensionVersion {
@@ -783,3 +785,21 @@ pub struct ExtensionVersionConstraints {
pub schema_versions: RangeInclusive<i32>,
pub wasm_api_versions: RangeInclusive<SemanticVersion>,
}
impl LocalSettingsKind {
pub fn from_proto(proto_kind: proto::LocalSettingsKind) -> Self {
match proto_kind {
proto::LocalSettingsKind::Settings => Self::Settings,
proto::LocalSettingsKind::Tasks => Self::Tasks,
proto::LocalSettingsKind::Editorconfig => Self::Editorconfig,
}
}
pub fn to_proto(&self) -> proto::LocalSettingsKind {
match self {
Self::Settings => proto::LocalSettingsKind::Settings,
Self::Tasks => proto::LocalSettingsKind::Tasks,
Self::Editorconfig => proto::LocalSettingsKind::Editorconfig,
}
}
}

View File

@@ -32,6 +32,7 @@ macro_rules! id_type {
#[allow(unused)]
#[allow(missing_docs)]
pub fn from_proto(value: u64) -> Self {
debug_assert!(value != 0);
Self(value as i32)
}

View File

@@ -1,3 +1,4 @@
use anyhow::Context as _;
use util::ResultExt;
use super::*;
@@ -285,7 +286,7 @@ impl Database {
)
.one(&*tx)
.await?
.ok_or_else(|| anyhow!("no such project"))?;
.ok_or_else(|| anyhow!("no such project: {project_id}"))?;
// Update metadata.
worktree::Entity::update(worktree::ActiveModel {
@@ -527,6 +528,12 @@ impl Database {
connection: ConnectionId,
) -> Result<TransactionGuard<Vec<ConnectionId>>> {
let project_id = ProjectId::from_proto(update.project_id);
let kind = match update.kind {
Some(kind) => proto::LocalSettingsKind::from_i32(kind)
.with_context(|| format!("unknown worktree settings kind: {kind}"))?,
None => proto::LocalSettingsKind::Settings,
};
let kind = LocalSettingsKind::from_proto(kind);
self.project_transaction(project_id, |tx| async move {
// Ensure the update comes from the host.
let project = project::Entity::find_by_id(project_id)
@@ -543,6 +550,7 @@ impl Database {
worktree_id: ActiveValue::Set(update.worktree_id as i64),
path: ActiveValue::Set(update.path.clone()),
content: ActiveValue::Set(content.clone()),
kind: ActiveValue::Set(kind),
})
.on_conflict(
OnConflict::columns([
@@ -800,6 +808,7 @@ impl Database {
worktree.settings_files.push(WorktreeSettingsFile {
path: db_settings_file.path,
content: db_settings_file.content,
kind: db_settings_file.kind,
});
}
}

View File

@@ -735,6 +735,7 @@ impl Database {
worktree.settings_files.push(WorktreeSettingsFile {
path: db_settings_file.path,
content: db_settings_file.content,
kind: db_settings_file.kind,
});
}
}

View File

@@ -11,9 +11,25 @@ pub struct Model {
#[sea_orm(primary_key)]
pub path: String,
pub content: String,
pub kind: LocalSettingsKind,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {}
#[derive(
Copy, Clone, Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum, Default, Hash, serde::Serialize,
)]
#[sea_orm(rs_type = "String", db_type = "String(StringLen::None)")]
#[serde(rename_all = "snake_case")]
pub enum LocalSettingsKind {
#[default]
#[sea_orm(string_value = "settings")]
Settings,
#[sea_orm(string_value = "tasks")]
Tasks,
#[sea_orm(string_value = "editorconfig")]
Editorconfig,
}

View File

@@ -170,8 +170,6 @@ pub struct Config {
pub anthropic_api_key: Option<Arc<str>>,
pub anthropic_staff_api_key: Option<Arc<str>>,
pub llm_closed_beta_model_name: Option<Arc<str>>,
pub runpod_api_key: Option<Arc<str>>,
pub runpod_api_summary_url: Option<Arc<str>>,
pub zed_client_checksum_seed: Option<String>,
pub slack_panics_webhook: Option<String>,
pub auto_join_channel_id: Option<ChannelId>,
@@ -235,8 +233,6 @@ impl Config {
stripe_api_key: None,
stripe_price_id: None,
supermaven_admin_api_key: None,
runpod_api_key: None,
runpod_api_summary_url: None,
user_backfiller_github_access_token: None,
}
}

View File

@@ -22,7 +22,8 @@ use chrono::{DateTime, Duration, Utc};
use collections::HashMap;
use db::{usage_measure::UsageMeasure, ActiveUserCount, LlmDatabase};
use futures::{Stream, StreamExt as _};
use isahc_http_client::IsahcHttpClient;
use reqwest_client::ReqwestClient;
use rpc::ListModelsResponse;
use rpc::{
proto::Plan, LanguageModelProvider, PerformCompletionParams, EXPIRED_LLM_TOKEN_HEADER_NAME,
@@ -43,7 +44,7 @@ pub struct LlmState {
pub config: Config,
pub executor: Executor,
pub db: Arc<LlmDatabase>,
pub http_client: IsahcHttpClient,
pub http_client: ReqwestClient,
pub clickhouse_client: Option<clickhouse::Client>,
active_user_count_by_model:
RwLock<HashMap<(LanguageModelProvider, String), (DateTime<Utc>, ActiveUserCount)>>,
@@ -69,11 +70,8 @@ impl LlmState {
let db = Arc::new(db);
let user_agent = format!("Zed Server/{}", env!("CARGO_PKG_VERSION"));
let http_client = IsahcHttpClient::builder()
.default_header("User-Agent", user_agent)
.build()
.map(IsahcHttpClient::from)
.context("failed to construct http client")?;
let http_client =
ReqwestClient::user_agent(&user_agent).context("failed to construct http client")?;
let this = Self {
executor,
@@ -400,42 +398,6 @@ async fn perform_completion(
})
.boxed()
}
LanguageModelProvider::Zed => {
let api_key = state
.config
.runpod_api_key
.as_ref()
.context("no Qwen2-7B API key configured on the server")?;
let api_url = state
.config
.runpod_api_summary_url
.as_ref()
.context("no Qwen2-7B URL configured on the server")?;
let chunks = open_ai::stream_completion(
&state.http_client,
api_url,
api_key,
serde_json::from_str(params.provider_request.get())?,
None,
)
.await?;
chunks
.map(|event| {
event.map(|chunk| {
let input_tokens =
chunk.usage.as_ref().map_or(0, |u| u.prompt_tokens) as usize;
let output_tokens =
chunk.usage.as_ref().map_or(0, |u| u.completion_tokens) as usize;
(
serde_json::to_vec(&chunk).unwrap(),
input_tokens,
output_tokens,
)
})
})
.boxed()
}
};
Ok(Response::new(Body::wrap_stream(TokenCountingStream {

View File

@@ -77,7 +77,6 @@ fn authorize_access_for_country(
LanguageModelProvider::Anthropic => anthropic::is_supported_country(country_code),
LanguageModelProvider::OpenAi => open_ai::is_supported_country(country_code),
LanguageModelProvider::Google => google_ai::is_supported_country(country_code),
LanguageModelProvider::Zed => true,
};
if !is_country_supported_by_provider {
Err(Error::http(
@@ -213,7 +212,6 @@ mod tests {
(LanguageModelProvider::Anthropic, "T1"), // Tor
(LanguageModelProvider::OpenAi, "T1"), // Tor
(LanguageModelProvider::Google, "T1"), // Tor
(LanguageModelProvider::Zed, "T1"), // Tor
];
for (provider, country_code) in cases {

View File

@@ -40,15 +40,6 @@ pub async fn seed_database(_config: &Config, db: &mut LlmDatabase, _force: bool)
price_per_million_input_tokens: 25, // $0.25/MTok
price_per_million_output_tokens: 125, // $1.25/MTok
},
ModelParams {
provider: LanguageModelProvider::Zed,
name: "Qwen/Qwen2-7B-Instruct".into(),
max_requests_per_minute: 5,
max_tokens_per_minute: 25_000, // These are arbitrary limits we've set to cap costs; we control this number
max_tokens_per_day: 300_000,
price_per_million_input_tokens: 25,
price_per_million_output_tokens: 125,
},
])
.await
}

View File

@@ -26,7 +26,6 @@ async fn test_initialize_providers(db: &mut LlmDatabase) {
LanguageModelProvider::Anthropic,
LanguageModelProvider::Google,
LanguageModelProvider::OpenAi,
LanguageModelProvider::Zed
]
)
}

View File

@@ -36,8 +36,8 @@ use collections::{HashMap, HashSet};
pub use connection_pool::{ConnectionPool, ZedVersion};
use core::fmt::{self, Debug, Formatter};
use http_client::HttpClient;
use isahc_http_client::IsahcHttpClient;
use open_ai::{OpenAiEmbeddingModel, OPEN_AI_API_URL};
use reqwest_client::ReqwestClient;
use sha2::Digest;
use supermaven_api::{CreateExternalUserRequest, SupermavenAdminApi};
@@ -474,9 +474,6 @@ impl Server {
.add_request_handler(user_handler(
forward_read_only_project_request::<proto::GetReferences>,
))
.add_request_handler(user_handler(
forward_read_only_project_request::<proto::SearchProject>,
))
.add_request_handler(user_handler(forward_find_search_candidates_request))
.add_request_handler(user_handler(
forward_read_only_project_request::<proto::GetDocumentHighlights>,
@@ -957,8 +954,8 @@ impl Server {
tracing::info!("connection opened");
let user_agent = format!("Zed Server/{}", env!("CARGO_PKG_VERSION"));
let http_client = match IsahcHttpClient::builder().default_header("User-Agent", user_agent).build() {
Ok(http_client) => Arc::new(IsahcHttpClient::from(http_client)),
let http_client = match ReqwestClient::user_agent(&user_agent) {
Ok(http_client) => Arc::new(http_client),
Err(error) => {
tracing::error!(?error, "failed to create HTTP client");
return;
@@ -1742,6 +1739,7 @@ fn notify_rejoined_projects(
worktree_id: worktree.id,
path: settings_file.path,
content: Some(settings_file.content),
kind: Some(settings_file.kind.to_proto().into()),
},
)?;
}
@@ -2223,6 +2221,7 @@ fn join_project_internal(
worktree_id: worktree.id,
path: settings_file.path,
content: Some(settings_file.content),
kind: Some(proto::update_user_settings::Kind::Settings.into()),
},
)?;
}
@@ -2298,7 +2297,7 @@ async fn list_remote_directory(
let dev_server_connection_id = session
.connection_pool()
.await
.dev_server_connection_id_supporting(dev_server_id, ZedVersion::with_list_directory())?;
.online_dev_server_connection_id(dev_server_id)?;
session
.db()
@@ -2337,10 +2336,7 @@ async fn update_dev_server_project(
let dev_server_connection_id = session
.connection_pool()
.await
.dev_server_connection_id_supporting(
dev_server_project.dev_server_id,
ZedVersion::with_list_directory(),
)?;
.online_dev_server_connection_id(dev_server_project.dev_server_id)?;
session.peer.send(
dev_server_connection_id,
@@ -2950,40 +2946,6 @@ async fn forward_find_search_candidates_request(
.await
.host_for_read_only_project_request(project_id, session.connection_id, session.user_id())
.await?;
let host_version = session
.connection_pool()
.await
.connection(host_connection_id)
.map(|c| c.zed_version);
if host_version.is_some_and(|host_version| host_version < ZedVersion::with_search_candidates())
{
let query = request.query.ok_or_else(|| anyhow!("missing query"))?;
let search = proto::SearchProject {
project_id: project_id.to_proto(),
query: query.query,
regex: query.regex,
whole_word: query.whole_word,
case_sensitive: query.case_sensitive,
files_to_include: query.files_to_include,
files_to_exclude: query.files_to_exclude,
include_ignored: query.include_ignored,
};
let payload = session
.peer
.forward_request(session.connection_id, host_connection_id, search)
.await?;
return response.send(proto::FindSearchCandidatesResponse {
buffer_ids: payload
.locations
.into_iter()
.map(|loc| loc.buffer_id)
.collect(),
});
}
let payload = session
.peer
.forward_request(session.connection_id, host_connection_id, request)

View File

@@ -32,15 +32,7 @@ impl fmt::Display for ZedVersion {
impl ZedVersion {
pub fn can_collaborate(&self) -> bool {
self.0 >= SemanticVersion::new(0, 134, 0)
}
pub fn with_list_directory() -> ZedVersion {
ZedVersion(SemanticVersion::new(0, 145, 0))
}
pub fn with_search_candidates() -> ZedVersion {
ZedVersion(SemanticVersion::new(0, 151, 0))
self.0 >= SemanticVersion::new(0, 151, 0)
}
}
@@ -169,6 +161,16 @@ impl ConnectionPool {
self.connected_dev_servers.get(&dev_server_id).copied()
}
pub fn online_dev_server_connection_id(
&self,
dev_server_id: DevServerId,
) -> Result<ConnectionId> {
match self.connected_dev_servers.get(&dev_server_id) {
Some(cid) => Ok(*cid),
None => Err(anyhow!(proto::ErrorCode::DevServerOffline)),
}
}
pub fn dev_server_connection_id_supporting(
&self,
dev_server_id: DevServerId,

View File

@@ -246,7 +246,7 @@ async fn test_channel_notes_participant_indices(
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
let (workspace_b, cx_b) = client_b.build_workspace(&project_b, cx_b);
// Clients A and B open the same file.

View File

@@ -76,7 +76,7 @@ async fn test_host_disconnect(
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
cx_a.background_executor.run_until_parked();
assert!(worktree_a.read_with(cx_a, |tree, _| tree.has_update_observer()));
@@ -192,7 +192,7 @@ async fn test_newline_above_or_below_does_not_move_guest_cursor(
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
// Open a buffer as client A
let buffer_a = project_a
@@ -308,7 +308,7 @@ async fn test_collaborating_with_completion(cx_a: &mut TestAppContext, cx_b: &mu
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
// Open a file in an editor as the guest.
let buffer_b = project_b
@@ -565,7 +565,7 @@ async fn test_collaborating_with_code_actions(
.unwrap();
// Join the project as client B.
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
let (workspace_b, cx_b) = client_b.build_workspace(&project_b, cx_b);
let editor_b = workspace_b
.update(cx_b, |workspace, cx| {
@@ -780,7 +780,7 @@ async fn test_collaborating_with_renames(cx_a: &mut TestAppContext, cx_b: &mut T
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
let (workspace_b, cx_b) = client_b.build_workspace(&project_b, cx_b);
let editor_b = workspace_b
@@ -1030,7 +1030,7 @@ async fn test_language_server_statuses(cx_a: &mut TestAppContext, cx_b: &mut Tes
.await
.unwrap();
executor.run_until_parked();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
project_b.read_with(cx_b, |project, cx| {
let status = project.language_server_statuses(cx).next().unwrap().1;
@@ -1126,9 +1126,7 @@ async fn test_share_project(
.await
.unwrap();
let client_b_peer_id = client_b.peer_id().unwrap();
let project_b = client_b
.build_dev_server_project(initial_project.id, cx_b)
.await;
let project_b = client_b.join_remote_project(initial_project.id, cx_b).await;
let replica_id_b = project_b.read_with(cx_b, |project, _| project.replica_id());
@@ -1230,9 +1228,7 @@ async fn test_share_project(
.update(cx_c, |call, cx| call.accept_incoming(cx))
.await
.unwrap();
let _project_c = client_c
.build_dev_server_project(initial_project.id, cx_c)
.await;
let _project_c = client_c.join_remote_project(initial_project.id, cx_c).await;
// Client B closes the editor, and client A sees client B's selections removed.
cx_b.update(move |_| drop(editor_b));
@@ -1291,7 +1287,7 @@ async fn test_on_input_format_from_host_to_guest(
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
// Open a file in an editor as the host.
let buffer_a = project_a
@@ -1411,7 +1407,7 @@ async fn test_on_input_format_from_guest_to_host(
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
// Open a file in an editor as the guest.
let buffer_b = project_b
@@ -1574,7 +1570,7 @@ async fn test_mutual_editor_inlay_hint_cache_update(
.unwrap();
// Client B joins the project
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
active_call_b
.update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
.await
@@ -1836,7 +1832,7 @@ async fn test_inlay_hint_refresh_is_forwarded(
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
active_call_b
.update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
.await
@@ -2050,7 +2046,7 @@ async fn test_git_blame_is_forwarded(cx_a: &mut TestAppContext, cx_b: &mut TestA
.unwrap();
// Join the project as client B.
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
let (workspace_b, cx_b) = client_b.build_workspace(&project_b, cx_b);
let editor_b = workspace_b
.update(cx_b, |workspace, cx| {

View File

@@ -74,7 +74,7 @@ async fn test_basic_following(
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
active_call_b
.update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
.await
@@ -162,7 +162,7 @@ async fn test_basic_following(
executor.run_until_parked();
let active_call_c = cx_c.read(ActiveCall::global);
let project_c = client_c.build_dev_server_project(project_id, cx_c).await;
let project_c = client_c.join_remote_project(project_id, cx_c).await;
let (workspace_c, cx_c) = client_c.build_workspace(&project_c, cx_c);
active_call_c
.update(cx_c, |call, cx| call.set_location(Some(&project_c), cx))
@@ -175,7 +175,7 @@ async fn test_basic_following(
cx_d.executor().run_until_parked();
let active_call_d = cx_d.read(ActiveCall::global);
let project_d = client_d.build_dev_server_project(project_id, cx_d).await;
let project_d = client_d.join_remote_project(project_id, cx_d).await;
let (workspace_d, cx_d) = client_d.build_workspace(&project_d, cx_d);
active_call_d
.update(cx_d, |call, cx| call.set_location(Some(&project_d), cx))
@@ -569,7 +569,7 @@ async fn test_following_tab_order(
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
active_call_b
.update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
.await
@@ -686,7 +686,7 @@ async fn test_peers_following_each_other(cx_a: &mut TestAppContext, cx_b: &mut T
.unwrap();
// Client B joins the project.
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
active_call_b
.update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
.await
@@ -1199,7 +1199,7 @@ async fn test_auto_unfollowing(cx_a: &mut TestAppContext, cx_b: &mut TestAppCont
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
active_call_b
.update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
.await
@@ -1335,7 +1335,7 @@ async fn test_peers_simultaneously_following_each_other(
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
let (workspace_b, cx_b) = client_b.build_workspace(&project_b, cx_b);
executor.run_until_parked();
@@ -1685,7 +1685,7 @@ async fn test_following_into_excluded_file(
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
active_call_b
.update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
.await

View File

@@ -33,7 +33,7 @@ use project::{
};
use rand::prelude::*;
use serde_json::json;
use settings::SettingsStore;
use settings::{LocalSettingsKind, SettingsStore};
use std::{
cell::{Cell, RefCell},
env, future, mem,
@@ -1372,7 +1372,7 @@ async fn test_unshare_project(
.unwrap();
let worktree_a = project_a.read_with(cx_a, |project, cx| project.worktrees(cx).next().unwrap());
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
executor.run_until_parked();
assert!(worktree_a.read_with(cx_a, |tree, _| tree.has_update_observer()));
@@ -1392,7 +1392,7 @@ async fn test_unshare_project(
assert!(project_b.read_with(cx_b, |project, _| project.is_disconnected()));
// Client C opens the project.
let project_c = client_c.build_dev_server_project(project_id, cx_c).await;
let project_c = client_c.join_remote_project(project_id, cx_c).await;
// When client A unshares the project, client C's project becomes read-only.
project_a
@@ -1409,7 +1409,7 @@ async fn test_unshare_project(
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
let project_c2 = client_c.build_dev_server_project(project_id, cx_c).await;
let project_c2 = client_c.join_remote_project(project_id, cx_c).await;
executor.run_until_parked();
assert!(worktree_a.read_with(cx_a, |tree, _| tree.has_update_observer()));
@@ -1514,9 +1514,9 @@ async fn test_project_reconnect(
.await
.unwrap();
let project_b1 = client_b.build_dev_server_project(project1_id, cx_b).await;
let project_b2 = client_b.build_dev_server_project(project2_id, cx_b).await;
let project_b3 = client_b.build_dev_server_project(project3_id, cx_b).await;
let project_b1 = client_b.join_remote_project(project1_id, cx_b).await;
let project_b2 = client_b.join_remote_project(project2_id, cx_b).await;
let project_b3 = client_b.join_remote_project(project3_id, cx_b).await;
executor.run_until_parked();
let worktree1_id = worktree_a1.read_with(cx_a, |worktree, _| {
@@ -2310,8 +2310,8 @@ async fn test_propagate_saves_and_fs_changes(
.unwrap();
// Join that worktree as clients B and C.
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_c = client_c.build_dev_server_project(project_id, cx_c).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
let project_c = client_c.join_remote_project(project_id, cx_c).await;
let worktree_b = project_b.read_with(cx_b, |p, cx| p.worktrees(cx).next().unwrap());
@@ -2535,7 +2535,7 @@ async fn test_git_diff_base_change(
.await
.unwrap();
let project_remote = client_b.build_dev_server_project(project_id, cx_b).await;
let project_remote = client_b.join_remote_project(project_id, cx_b).await;
let diff_base = "
one
@@ -2791,7 +2791,7 @@ async fn test_git_branch_name(
.await
.unwrap();
let project_remote = client_b.build_dev_server_project(project_id, cx_b).await;
let project_remote = client_b.join_remote_project(project_id, cx_b).await;
client_a
.fs()
.set_branch_name(Path::new("/dir/.git"), Some("branch-1"));
@@ -2836,7 +2836,7 @@ async fn test_git_branch_name(
assert_branch(Some("branch-2"), project, cx)
});
let project_remote_c = client_c.build_dev_server_project(project_id, cx_c).await;
let project_remote_c = client_c.join_remote_project(project_id, cx_c).await;
executor.run_until_parked();
project_remote_c.read_with(cx_c, |project, cx| {
@@ -2891,7 +2891,7 @@ async fn test_git_status_sync(
.await
.unwrap();
let project_remote = client_b.build_dev_server_project(project_id, cx_b).await;
let project_remote = client_b.join_remote_project(project_id, cx_b).await;
// Wait for it to catch up to the new status
executor.run_until_parked();
@@ -2967,7 +2967,7 @@ async fn test_git_status_sync(
});
// And synchronization while joining
let project_remote_c = client_c.build_dev_server_project(project_id, cx_c).await;
let project_remote_c = client_c.join_remote_project(project_id, cx_c).await;
executor.run_until_parked();
project_remote_c.read_with(cx_c, |project, cx| {
@@ -3015,7 +3015,7 @@ async fn test_fs_operations(
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
let worktree_a = project_a.read_with(cx_a, |project, cx| project.worktrees(cx).next().unwrap());
let worktree_b = project_b.read_with(cx_b, |project, cx| project.worktrees(cx).next().unwrap());
@@ -3316,7 +3316,7 @@ async fn test_local_settings(
executor.run_until_parked();
// As client B, join that project and observe the local settings.
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
let worktree_b = project_b.read_with(cx_b, |project, cx| project.worktrees(cx).next().unwrap());
executor.run_until_parked();
@@ -3327,8 +3327,16 @@ async fn test_local_settings(
.local_settings(worktree_b.read(cx).id())
.collect::<Vec<_>>(),
&[
(Path::new("").into(), r#"{"tab_size":2}"#.to_string()),
(Path::new("a").into(), r#"{"tab_size":8}"#.to_string()),
(
Path::new("").into(),
LocalSettingsKind::Settings,
r#"{"tab_size":2}"#.to_string()
),
(
Path::new("a").into(),
LocalSettingsKind::Settings,
r#"{"tab_size":8}"#.to_string()
),
]
)
});
@@ -3346,8 +3354,16 @@ async fn test_local_settings(
.local_settings(worktree_b.read(cx).id())
.collect::<Vec<_>>(),
&[
(Path::new("").into(), r#"{}"#.to_string()),
(Path::new("a").into(), r#"{"tab_size":8}"#.to_string()),
(
Path::new("").into(),
LocalSettingsKind::Settings,
r#"{}"#.to_string()
),
(
Path::new("a").into(),
LocalSettingsKind::Settings,
r#"{"tab_size":8}"#.to_string()
),
]
)
});
@@ -3375,8 +3391,16 @@ async fn test_local_settings(
.local_settings(worktree_b.read(cx).id())
.collect::<Vec<_>>(),
&[
(Path::new("a").into(), r#"{"tab_size":8}"#.to_string()),
(Path::new("b").into(), r#"{"tab_size":4}"#.to_string()),
(
Path::new("a").into(),
LocalSettingsKind::Settings,
r#"{"tab_size":8}"#.to_string()
),
(
Path::new("b").into(),
LocalSettingsKind::Settings,
r#"{"tab_size":4}"#.to_string()
),
]
)
});
@@ -3406,7 +3430,11 @@ async fn test_local_settings(
store
.local_settings(worktree_b.read(cx).id())
.collect::<Vec<_>>(),
&[(Path::new("a").into(), r#"{"hard_tabs":true}"#.to_string()),]
&[(
Path::new("a").into(),
LocalSettingsKind::Settings,
r#"{"hard_tabs":true}"#.to_string()
),]
)
});
}
@@ -3439,7 +3467,7 @@ async fn test_buffer_conflict_after_save(
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
// Open a buffer as client B
let buffer_b = project_b
@@ -3503,7 +3531,7 @@ async fn test_buffer_reloading(
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
// Open a buffer as client B
let buffer_b = project_b
@@ -3557,7 +3585,7 @@ async fn test_editing_while_guest_opens_buffer(
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
// Open a buffer as client A
let buffer_a = project_a
@@ -3605,7 +3633,7 @@ async fn test_leaving_worktree_while_opening_buffer(
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
// See that a guest has joined as client A.
executor.run_until_parked();
@@ -3652,7 +3680,7 @@ async fn test_canceling_buffer_opening(
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
let buffer_a = project_a
.update(cx_a, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
@@ -3709,8 +3737,8 @@ async fn test_leaving_project(
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
let project_b1 = client_b.build_dev_server_project(project_id, cx_b).await;
let project_c = client_c.build_dev_server_project(project_id, cx_c).await;
let project_b1 = client_b.join_remote_project(project_id, cx_b).await;
let project_c = client_c.join_remote_project(project_id, cx_c).await;
// Client A sees that a guest has joined.
executor.run_until_parked();
@@ -3751,7 +3779,7 @@ async fn test_leaving_project(
});
// Client B re-joins the project and can open buffers as before.
let project_b2 = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b2 = client_b.join_remote_project(project_id, cx_b).await;
executor.run_until_parked();
project_a.read_with(cx_a, |project, _| {
@@ -3927,7 +3955,7 @@ async fn test_collaborating_with_diagnostics(
);
// Join the worktree as client B.
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
// Wait for server to see the diagnostics update.
executor.run_until_parked();
@@ -3952,7 +3980,7 @@ async fn test_collaborating_with_diagnostics(
});
// Join project as client C and observe the diagnostics.
let project_c = client_c.build_dev_server_project(project_id, cx_c).await;
let project_c = client_c.join_remote_project(project_id, cx_c).await;
executor.run_until_parked();
let project_c_diagnostic_summaries =
Rc::new(RefCell::new(project_c.read_with(cx_c, |project, cx| {
@@ -4160,7 +4188,7 @@ async fn test_collaborating_with_lsp_progress_updates_and_diagnostics_ordering(
.unwrap();
// Join the project as client B and open all three files.
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
let guest_buffers = futures::future::try_join_all(file_names.iter().map(|file_name| {
project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, file_name), cx))
}))
@@ -4266,7 +4294,7 @@ async fn test_reloading_buffer_manually(
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
let open_buffer = project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx));
let buffer_b = cx_b.executor().spawn(open_buffer).await.unwrap();
@@ -4364,7 +4392,7 @@ async fn test_formatting_buffer(
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
let open_buffer = project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx));
let buffer_b = cx_b.executor().spawn(open_buffer).await.unwrap();
@@ -4409,7 +4437,7 @@ async fn test_formatting_buffer(
file.defaults.formatter = Some(SelectedFormatter::List(FormatterList(
vec![Formatter::External {
command: "awk".into(),
arguments: vec!["{sub(/two/,\"{buffer_path}\")}1".to_string()].into(),
arguments: Some(vec!["{sub(/two/,\"{buffer_path}\")}1".to_string()].into()),
}]
.into(),
)));
@@ -4486,7 +4514,7 @@ async fn test_prettier_formatting_buffer(
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
let open_buffer = project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.ts"), cx));
let buffer_b = cx_b.executor().spawn(open_buffer).await.unwrap();
@@ -4599,7 +4627,7 @@ async fn test_definition(
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
// Open the file on client B.
let open_buffer = project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx));
@@ -4744,7 +4772,7 @@ async fn test_references(
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
// Open the file on client B.
let open_buffer = project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "one.rs"), cx));
@@ -4901,7 +4929,7 @@ async fn test_project_search(
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
// Perform a search as the guest.
let mut results = HashMap::default();
@@ -4991,7 +5019,7 @@ async fn test_document_highlights(
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
// Open the file on client B.
let open_b = project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx));
@@ -5109,7 +5137,7 @@ async fn test_lsp_hover(
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
// Open the file as the guest
let open_buffer = project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx));
@@ -5286,7 +5314,7 @@ async fn test_project_symbols(
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
// Cause the language server to start.
let open_buffer_task =
@@ -5381,7 +5409,7 @@ async fn test_open_buffer_while_getting_definition_pointing_to_it(
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
let open_buffer_task = project_b.update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.rs"), cx));
let buffer_b1 = cx_b.executor().spawn(open_buffer_task).await.unwrap();
@@ -6470,7 +6498,7 @@ async fn test_context_collaboration_with_reconnect(
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
// Client A sees that a guest has joined.
executor.run_until_parked();

View File

@@ -4,12 +4,12 @@ use fs::{FakeFs, Fs as _};
use gpui::{Context as _, TestAppContext};
use language::language_settings::all_language_settings;
use project::ProjectPath;
use remote::SshSession;
use remote::SshRemoteClient;
use remote_server::HeadlessProject;
use serde_json::json;
use std::{path::Path, sync::Arc};
#[gpui::test]
#[gpui::test(iterations = 10)]
async fn test_sharing_an_ssh_remote_project(
cx_a: &mut TestAppContext,
cx_b: &mut TestAppContext,
@@ -24,7 +24,7 @@ async fn test_sharing_an_ssh_remote_project(
.await;
// Set up project on remote FS
let (client_ssh, server_ssh) = SshSession::fake(cx_a, server_cx);
let (client_ssh, server_ssh) = SshRemoteClient::fake(cx_a, server_cx);
let remote_fs = FakeFs::new(server_cx.executor());
remote_fs
.insert_tree(
@@ -54,9 +54,8 @@ async fn test_sharing_an_ssh_remote_project(
let (project_a, worktree_id) = client_a
.build_ssh_project("/code/project1", client_ssh, cx_a)
.await;
executor.run_until_parked();
// User A shares the remote project.
// While the SSH worktree is being scanned, user A shares the remote project.
let active_call_a = cx_a.read(ActiveCall::global);
let project_id = active_call_a
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
@@ -64,12 +63,30 @@ async fn test_sharing_an_ssh_remote_project(
.unwrap();
// User B joins the project.
let project_b = client_b.build_dev_server_project(project_id, cx_b).await;
let project_b = client_b.join_remote_project(project_id, cx_b).await;
let worktree_b = project_b
.update(cx_b, |project, cx| project.worktree_for_id(worktree_id, cx))
.unwrap();
let worktree_a = project_a
.update(cx_a, |project, cx| project.worktree_for_id(worktree_id, cx))
.unwrap();
executor.run_until_parked();
worktree_a.update(cx_a, |worktree, _cx| {
assert_eq!(
worktree.paths().map(Arc::as_ref).collect::<Vec<_>>(),
vec![
Path::new(".zed"),
Path::new(".zed/settings.json"),
Path::new("README.md"),
Path::new("src"),
Path::new("src/lib.rs"),
]
);
});
worktree_b.update(cx_b, |worktree, _cx| {
assert_eq!(
worktree.paths().map(Arc::as_ref).collect::<Vec<_>>(),

View File

@@ -25,7 +25,7 @@ use node_runtime::NodeRuntime;
use notifications::NotificationStore;
use parking_lot::Mutex;
use project::{Project, WorktreeId};
use remote::SshSession;
use remote::SshRemoteClient;
use rpc::{
proto::{self, ChannelRole},
RECEIVE_TIMEOUT,
@@ -679,8 +679,6 @@ impl TestServer {
stripe_api_key: None,
stripe_price_id: None,
supermaven_admin_api_key: None,
runpod_api_key: None,
runpod_api_summary_url: None,
user_backfiller_github_access_token: None,
},
})
@@ -837,7 +835,7 @@ impl TestClient {
pub async fn build_ssh_project(
&self,
root_path: impl AsRef<Path>,
ssh: Arc<SshSession>,
ssh: Model<SshRemoteClient>,
cx: &mut TestAppContext,
) -> (Model<Project>, WorktreeId) {
let project = cx.update(|cx| {
@@ -921,7 +919,7 @@ impl TestClient {
})
}
pub async fn build_dev_server_project(
pub async fn join_remote_project(
&self,
host_project_id: u64,
guest_cx: &mut TestAppContext,

View File

@@ -37,7 +37,6 @@ fs.workspace = true
futures.workspace = true
gpui.workspace = true
http_client.workspace = true
isahc.workspace = true
language.workspace = true
lsp.workspace = true
menu.workspace = true

View File

@@ -7,8 +7,7 @@ use chrono::DateTime;
use fs::Fs;
use futures::{io::BufReader, stream::BoxStream, AsyncBufReadExt, AsyncReadExt, StreamExt};
use gpui::{AppContext, AsyncAppContext, Global};
use http_client::{AsyncBody, HttpClient, Method, Request as HttpRequest};
use isahc::config::Configurable;
use http_client::{AsyncBody, HttpClient, HttpRequestExt, Method, Request as HttpRequest};
use paths::home_dir;
use serde::{Deserialize, Serialize};
use settings::watch_config_file;
@@ -275,7 +274,7 @@ async fn request_api_token(
.header("Accept", "application/json");
if let Some(low_speed_timeout) = low_speed_timeout {
request_builder = request_builder.low_speed_timeout(100, low_speed_timeout);
request_builder = request_builder.read_timeout(low_speed_timeout);
}
let request = request_builder.body(AsyncBody::empty())?;
@@ -332,7 +331,7 @@ async fn stream_completion(
.header("Copilot-Integration-Id", "vscode-chat");
if let Some(low_speed_timeout) = low_speed_timeout {
request_builder = request_builder.low_speed_timeout(100, low_speed_timeout);
request_builder = request_builder.read_timeout(low_speed_timeout);
}
let request = request_builder.body(AsyncBody::from(serde_json::to_string(&request)?))?;
let mut response = client.send(request).await?;

View File

@@ -188,7 +188,7 @@ macro_rules! define_connection {
};
}
pub fn write_and_log<F>(cx: &mut AppContext, db_write: impl FnOnce() -> F + Send + 'static)
pub fn write_and_log<F>(cx: &AppContext, db_write: impl FnOnce() -> F + Send + 'static)
where
F: Future<Output = anyhow::Result<()>> + Send,
{

View File

@@ -1,7 +1,7 @@
use crate::ProjectDiagnosticsEditor;
use gpui::{EventEmitter, ParentElement, Render, View, ViewContext, WeakView};
use ui::prelude::*;
use ui::{IconButton, IconName, Tooltip};
use ui::{IconButton, IconButtonShape, IconName, Tooltip};
use workspace::{item::ItemHandle, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView};
pub struct ToolbarControls {
@@ -33,11 +33,19 @@ impl Render for ToolbarControls {
"Include Warnings"
};
let warning_color = if include_warnings {
Color::Warning
} else {
Color::Muted
};
h_flex()
.gap_1()
.when(has_stale_excerpts, |div| {
div.child(
IconButton::new("update-excerpts", IconName::Update)
.icon_color(Color::Info)
.shape(IconButtonShape::Square)
.disabled(is_updating)
.tooltip(move |cx| Tooltip::text("Update excerpts", cx))
.on_click(cx.listener(|this, _, cx| {
@@ -51,6 +59,8 @@ impl Render for ToolbarControls {
})
.child(
IconButton::new("toggle-warnings", IconName::Warning)
.icon_color(warning_color)
.shape(IconButtonShape::Square)
.tooltip(move |cx| Tooltip::text(tooltip, cx))
.on_click(cx.listener(|this, _, cx| {
if let Some(editor) = this.editor() {

View File

@@ -24,7 +24,8 @@ test-support = [
"workspace/test-support",
"tree-sitter-rust",
"tree-sitter-typescript",
"tree-sitter-html"
"tree-sitter-html",
"unindent",
]
[dependencies]
@@ -54,6 +55,7 @@ markdown.workspace = true
multi_buffer.workspace = true
ordered-float.workspace = true
parking_lot.workspace = true
pretty_assertions.workspace = true
project.workspace = true
rand.workspace = true
rpc.workspace = true
@@ -74,6 +76,7 @@ theme.workspace = true
tree-sitter-html = { workspace = true, optional = true }
tree-sitter-rust = { workspace = true, optional = true }
tree-sitter-typescript = { workspace = true, optional = true }
unindent = { workspace = true, optional = true }
ui.workspace = true
url.workspace = true
util.workspace = true

View File

@@ -193,6 +193,7 @@ gpui::actions!(
AcceptPartialInlineCompletion,
AddSelectionAbove,
AddSelectionBelow,
ApplyDiffHunk,
Backspace,
Cancel,
CancelLanguageServerWork,
@@ -230,7 +231,11 @@ gpui::actions!(
ExpandMacroRecursively,
FindAllReferences,
Fold,
FoldAll,
FoldRecursive,
FoldSelectedRanges,
ToggleFold,
ToggleFoldRecursive,
Format,
GoToDeclaration,
GoToDeclarationSplit,
@@ -340,7 +345,9 @@ gpui::actions!(
Transpose,
Undo,
UndoSelection,
UnfoldAll,
UnfoldLines,
UnfoldRecursive,
UniqueLinesCaseInsensitive,
UniqueLinesCaseSensitive,
]

View File

@@ -9,7 +9,7 @@ use crate::lsp_ext::find_specific_language_server_in_selection;
use crate::{element::register_action, Editor, SwitchSourceHeader};
static CLANGD_SERVER_NAME: &str = "clangd";
const CLANGD_SERVER_NAME: &str = "clangd";
fn is_c_language(language: &Language) -> bool {
return language.name() == "C++".into() || language.name() == "C".into();

View File

@@ -1360,7 +1360,7 @@ impl<'a> Iterator for BlockBufferRows<'a> {
impl sum_tree::Item for Transform {
type Summary = TransformSummary;
fn summary(&self) -> Self::Summary {
fn summary(&self, _cx: &()) -> Self::Summary {
self.summary.clone()
}
}

View File

@@ -291,7 +291,7 @@ impl sum_tree::Summary for ItemSummary {
impl sum_tree::Item for CreaseItem {
type Summary = ItemSummary;
fn summary(&self) -> Self::Summary {
fn summary(&self, _cx: &MultiBufferSnapshot) -> Self::Summary {
ItemSummary {
range: self.crease.range.clone(),
}

View File

@@ -944,7 +944,7 @@ struct TransformSummary {
impl sum_tree::Item for Transform {
type Summary = TransformSummary;
fn summary(&self) -> Self::Summary {
fn summary(&self, _cx: &()) -> Self::Summary {
self.summary.clone()
}
}
@@ -1004,7 +1004,7 @@ impl Default for FoldRange {
impl sum_tree::Item for Fold {
type Summary = FoldSummary;
fn summary(&self) -> Self::Summary {
fn summary(&self, _cx: &MultiBufferSnapshot) -> Self::Summary {
FoldSummary {
start: self.range.start,
end: self.range.end,

View File

@@ -74,7 +74,7 @@ impl Inlay {
impl sum_tree::Item for Transform {
type Summary = TransformSummary;
fn summary(&self) -> Self::Summary {
fn summary(&self, _cx: &()) -> Self::Summary {
match self {
Transform::Isomorphic(summary) => TransformSummary {
input: summary.clone(),

View File

@@ -917,7 +917,7 @@ impl Transform {
impl sum_tree::Item for Transform {
type Summary = TransformSummary;
fn summary(&self) -> Self::Summary {
fn summary(&self, _cx: &()) -> Self::Summary {
self.summary.clone()
}
}

View File

@@ -61,7 +61,7 @@ use debounced_delay::DebouncedDelay;
use display_map::*;
pub use display_map::{DisplayPoint, FoldPlaceholder};
pub use editor_settings::{
CurrentLineHighlight, EditorSettings, ScrollBeyondLastLine, SearchSettings,
CurrentLineHighlight, EditorSettings, ScrollBeyondLastLine, SearchSettings, ShowScrollbar,
};
pub use editor_settings_controls::*;
use element::LineWithInvisibles;
@@ -98,7 +98,9 @@ use language::{
};
use language::{point_to_lsp, BufferRow, CharClassifier, Runnable, RunnableRange};
use linked_editing_ranges::refresh_linked_ranges;
use proposed_changes_editor::{ProposedChangesBuffer, ProposedChangesEditor};
pub use proposed_changes_editor::{
ProposedChangesBuffer, ProposedChangesEditor, ProposedChangesEditorToolbar,
};
use similar::{ChangeTag, TextDiff};
use task::{ResolvedTask, TaskTemplate, TaskVariables};
@@ -374,12 +376,20 @@ pub enum EditorMode {
Full,
}
#[derive(Clone, Debug)]
#[derive(Copy, Clone, Debug)]
pub enum SoftWrap {
/// Prefer not to wrap at all.
///
/// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
/// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
GitDiff,
/// Prefer a single line generally, unless an overly long line is encountered.
None,
PreferLine,
/// Soft wrap lines that exceed the editor width.
EditorWidth,
/// Soft wrap lines at the preferred line length.
Column(u32),
/// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
Bounded(u32),
}
@@ -661,7 +671,7 @@ pub struct EditorSnapshot {
show_git_diff_gutter: Option<bool>,
show_code_actions: Option<bool>,
show_runnables: Option<bool>,
render_git_blame_gutter: bool,
git_blame_gutter_max_author_length: Option<usize>,
pub display_snapshot: DisplaySnapshot,
pub placeholder_text: Option<Arc<str>>,
is_focused: bool,
@@ -671,7 +681,7 @@ pub struct EditorSnapshot {
gutter_hovered: bool,
}
const GIT_BLAME_GUTTER_WIDTH_CHARS: f32 = 53.;
const GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED: usize = 20;
#[derive(Default, Debug, Clone, Copy)]
pub struct GutterDimensions {
@@ -811,8 +821,8 @@ impl SelectionHistory {
struct RowHighlight {
index: usize,
range: RangeInclusive<Anchor>,
color: Option<Hsla>,
range: Range<Anchor>,
color: Hsla,
should_autoscroll: bool,
}
@@ -1218,6 +1228,10 @@ impl CompletionsMenu {
None
};
let color_swatch = completion
.color()
.map(|color| div().size_4().bg(color).rounded_sm());
div().min_w(px(220.)).max_w(px(540.)).child(
ListItem::new(mat.candidate_id)
.inset(true)
@@ -1233,6 +1247,7 @@ impl CompletionsMenu {
task.detach_and_log_err(cx)
}
}))
.start_slot::<Div>(color_swatch)
.child(h_flex().overflow_hidden().child(completion_label))
.end_slot::<Label>(documentation_label),
)
@@ -1835,7 +1850,7 @@ impl Editor {
let blink_manager = cx.new_model(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
.then(|| language_settings::SoftWrap::PreferLine);
.then(|| language_settings::SoftWrap::None);
let mut project_subscriptions = Vec::new();
if mode == EditorMode::Full {
@@ -2209,6 +2224,19 @@ impl Editor {
}
pub fn snapshot(&mut self, cx: &mut WindowContext) -> EditorSnapshot {
let git_blame_gutter_max_author_length = self
.render_git_blame_gutter(cx)
.then(|| {
if let Some(blame) = self.blame.as_ref() {
let max_author_length =
blame.update(cx, |blame, cx| blame.max_author_length(cx));
Some(max_author_length)
} else {
None
}
})
.flatten();
EditorSnapshot {
mode: self.mode,
show_gutter: self.show_gutter,
@@ -2216,7 +2244,7 @@ impl Editor {
show_git_diff_gutter: self.show_git_diff_gutter,
show_code_actions: self.show_code_actions,
show_runnables: self.show_runnables,
render_git_blame_gutter: self.render_git_blame_gutter(cx),
git_blame_gutter_max_author_length,
display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
scroll_anchor: self.scroll_manager.anchor(),
ongoing_scroll: self.scroll_manager.ongoing_scroll(),
@@ -3036,7 +3064,7 @@ impl Editor {
}
pub fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
if self.clear_clicked_diff_hunks(cx) {
if self.clear_expanded_diff_hunks(cx) {
cx.notify();
return;
}
@@ -3440,7 +3468,7 @@ impl Editor {
s.select(new_selections)
});
if !bracket_inserted && EditorSettings::get_global(cx).use_on_type_format {
if !bracket_inserted {
if let Some(on_type_format_task) =
this.trigger_on_type_formatting(text.to_string(), cx)
{
@@ -4189,6 +4217,15 @@ impl Editor {
.read(cx)
.text_anchor_for_position(position, cx)?;
let settings = language_settings::language_settings(
buffer.read(cx).language_at(buffer_position).as_ref(),
buffer.read(cx).file(),
cx,
);
if !settings.use_on_type_format {
return None;
}
// OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
// hence we do LSP request & edit on host side only — add formats to host's history.
let push_to_lsp_host_history = true;
@@ -5336,6 +5373,19 @@ impl Editor {
.icon_size(IconSize::XSmall)
.icon_color(Color::Muted)
.selected(is_active)
.tooltip({
let focus_handle = self.focus_handle.clone();
move |cx| {
Tooltip::for_action_in(
"Toggle Code Actions",
&ToggleCodeActions {
deployed_from_indicator: None,
},
&focus_handle,
cx,
)
}
})
.on_click(cx.listener(move |editor, _e, cx| {
editor.focus(cx);
editor.toggle_code_actions(
@@ -6160,6 +6210,20 @@ impl Editor {
}
}
fn apply_selected_diff_hunks(&mut self, _: &ApplyDiffHunk, cx: &mut ViewContext<Self>) {
let snapshot = self.buffer.read(cx).snapshot(cx);
let hunks = hunks_for_selections(&snapshot, &self.selections.disjoint_anchors());
self.transact(cx, |editor, cx| {
for hunk in hunks {
if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
buffer.update(cx, |buffer, cx| {
buffer.merge_into_base(Some(hunk.buffer_range.to_offset(buffer)), cx);
});
}
}
});
}
pub fn open_active_item_in_terminal(&mut self, _: &OpenInTerminal, cx: &mut ViewContext<Self>) {
if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
let project_path = buffer.read(cx).project_path(cx)?;
@@ -9665,7 +9729,7 @@ impl Editor {
if Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
let buffer = target.buffer.read(cx);
let range = check_multiline_range(buffer, range);
editor.change_selections(Some(Autoscroll::focused()), cx, |s| {
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
s.select_ranges([range]);
});
} else {
@@ -10519,17 +10583,79 @@ impl Editor {
}
}
pub fn fold(&mut self, _: &actions::Fold, cx: &mut ViewContext<Self>) {
let mut fold_ranges = Vec::new();
pub fn toggle_fold(&mut self, _: &actions::ToggleFold, cx: &mut ViewContext<Self>) {
let selection = self.selections.newest::<Point>(cx);
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let range = if selection.is_empty() {
let point = selection.head().to_display_point(&display_map);
let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
.to_point(&display_map);
start..end
} else {
selection.range()
};
if display_map.folds_in_range(range).next().is_some() {
self.unfold_lines(&Default::default(), cx)
} else {
self.fold(&Default::default(), cx)
}
}
pub fn toggle_fold_recursive(
&mut self,
_: &actions::ToggleFoldRecursive,
cx: &mut ViewContext<Self>,
) {
let selection = self.selections.newest::<Point>(cx);
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let range = if selection.is_empty() {
let point = selection.head().to_display_point(&display_map);
let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
.to_point(&display_map);
start..end
} else {
selection.range()
};
if display_map.folds_in_range(range).next().is_some() {
self.unfold_recursive(&Default::default(), cx)
} else {
self.fold_recursive(&Default::default(), cx)
}
}
pub fn fold(&mut self, _: &actions::Fold, cx: &mut ViewContext<Self>) {
let mut fold_ranges = Vec::new();
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let selections = self.selections.all_adjusted(cx);
for selection in selections {
let range = selection.range().sorted();
let buffer_start_row = range.start.row;
for row in (0..=range.end.row).rev() {
if range.start.row != range.end.row {
let mut found = false;
let mut row = range.start.row;
while row <= range.end.row {
if let Some((foldable_range, fold_text)) =
{ display_map.foldable_range(MultiBufferRow(row)) }
{
found = true;
row = foldable_range.end.row + 1;
fold_ranges.push((foldable_range, fold_text));
} else {
row += 1
}
}
if found {
continue;
}
}
for row in (0..=range.start.row).rev() {
if let Some((foldable_range, fold_text)) =
display_map.foldable_range(MultiBufferRow(row))
{
@@ -10546,6 +10672,61 @@ impl Editor {
self.fold_ranges(fold_ranges, true, cx);
}
pub fn fold_all(&mut self, _: &actions::FoldAll, cx: &mut ViewContext<Self>) {
let mut fold_ranges = Vec::new();
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
for row in 0..display_map.max_buffer_row().0 {
if let Some((foldable_range, fold_text)) =
display_map.foldable_range(MultiBufferRow(row))
{
fold_ranges.push((foldable_range, fold_text));
}
}
self.fold_ranges(fold_ranges, true, cx);
}
pub fn fold_recursive(&mut self, _: &actions::FoldRecursive, cx: &mut ViewContext<Self>) {
let mut fold_ranges = Vec::new();
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let selections = self.selections.all_adjusted(cx);
for selection in selections {
let range = selection.range().sorted();
let buffer_start_row = range.start.row;
if range.start.row != range.end.row {
let mut found = false;
for row in range.start.row..=range.end.row {
if let Some((foldable_range, fold_text)) =
{ display_map.foldable_range(MultiBufferRow(row)) }
{
found = true;
fold_ranges.push((foldable_range, fold_text));
}
}
if found {
continue;
}
}
for row in (0..=range.start.row).rev() {
if let Some((foldable_range, fold_text)) =
display_map.foldable_range(MultiBufferRow(row))
{
if foldable_range.end.row >= buffer_start_row {
fold_ranges.push((foldable_range, fold_text));
} else {
break;
}
}
}
}
self.fold_ranges(fold_ranges, true, cx);
}
pub fn fold_at(&mut self, fold_at: &FoldAt, cx: &mut ViewContext<Self>) {
let buffer_row = fold_at.buffer_row;
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
@@ -10580,6 +10761,24 @@ impl Editor {
self.unfold_ranges(ranges, true, true, cx);
}
pub fn unfold_recursive(&mut self, _: &UnfoldRecursive, cx: &mut ViewContext<Self>) {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let selections = self.selections.all::<Point>(cx);
let ranges = selections
.iter()
.map(|s| {
let mut range = s.display_range(&display_map).sorted();
*range.start.column_mut() = 0;
*range.end.column_mut() = display_map.line_len(range.end.row());
let start = range.start.to_point(&display_map);
let end = range.end.to_point(&display_map);
start..end
})
.collect::<Vec<_>>();
self.unfold_ranges(ranges, true, true, cx);
}
pub fn unfold_at(&mut self, unfold_at: &UnfoldAt, cx: &mut ViewContext<Self>) {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
@@ -10593,11 +10792,21 @@ impl Editor {
.selections
.all::<Point>(cx)
.iter()
.any(|selection| selection.range().overlaps(&intersection_range));
.any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
self.unfold_ranges(std::iter::once(intersection_range), true, autoscroll, cx)
}
pub fn unfold_all(&mut self, _: &actions::UnfoldAll, cx: &mut ViewContext<Self>) {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
self.unfold_ranges(
[Point::zero()..display_map.max_point().to_point(&display_map)],
true,
true,
cx,
);
}
pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
let selections = self.selections.all::<Point>(cx);
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
@@ -10874,8 +11083,9 @@ impl Editor {
let settings = self.buffer.read(cx).settings_at(0, cx);
let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
match mode {
language_settings::SoftWrap::None => SoftWrap::None,
language_settings::SoftWrap::PreferLine => SoftWrap::PreferLine,
language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
SoftWrap::None
}
language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
language_settings::SoftWrap::PreferredLineLength => {
SoftWrap::Column(settings.preferred_line_length)
@@ -10923,9 +11133,10 @@ impl Editor {
self.soft_wrap_mode_override.take();
} else {
let soft_wrap = match self.soft_wrap_mode(cx) {
SoftWrap::None | SoftWrap::PreferLine => language_settings::SoftWrap::EditorWidth,
SoftWrap::GitDiff => return,
SoftWrap::None => language_settings::SoftWrap::EditorWidth,
SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
language_settings::SoftWrap::PreferLine
language_settings::SoftWrap::None
}
};
self.soft_wrap_mode_override = Some(soft_wrap);
@@ -11051,30 +11262,32 @@ impl Editor {
None
}
fn target_file<'a>(&self, cx: &'a AppContext) -> Option<&'a dyn language::LocalFile> {
self.active_excerpt(cx)?
.1
.read(cx)
.file()
.and_then(|f| f.as_local())
}
pub fn reveal_in_finder(&mut self, _: &RevealInFileManager, cx: &mut ViewContext<Self>) {
if let Some(buffer) = self.buffer().read(cx).as_singleton() {
if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
cx.reveal_path(&file.abs_path(cx));
}
if let Some(target) = self.target_file(cx) {
cx.reveal_path(&target.abs_path(cx));
}
}
pub fn copy_path(&mut self, _: &CopyPath, cx: &mut ViewContext<Self>) {
if let Some(buffer) = self.buffer().read(cx).as_singleton() {
if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
if let Some(path) = file.abs_path(cx).to_str() {
cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
}
if let Some(file) = self.target_file(cx) {
if let Some(path) = file.abs_path(cx).to_str() {
cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
}
}
}
pub fn copy_relative_path(&mut self, _: &CopyRelativePath, cx: &mut ViewContext<Self>) {
if let Some(buffer) = self.buffer().read(cx).as_singleton() {
if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
if let Some(path) = file.path().to_str() {
cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
}
if let Some(file) = self.target_file(cx) {
if let Some(path) = file.path().to_str() {
cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
}
}
}
@@ -11285,12 +11498,10 @@ impl Editor {
}
pub fn copy_file_location(&mut self, _: &CopyFileLocation, cx: &mut ViewContext<Self>) {
if let Some(buffer) = self.buffer().read(cx).as_singleton() {
if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
if let Some(path) = file.path().to_str() {
let selection = self.selections.newest::<Point>(cx).start.row + 1;
cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
}
if let Some(file) = self.target_file(cx) {
if let Some(path) = file.path().to_str() {
let selection = self.selections.newest::<Point>(cx).start.row + 1;
cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
}
}
}
@@ -11321,56 +11532,130 @@ impl Editor {
}
}
/// Adds or removes (on `None` color) a highlight for the rows corresponding to the anchor range given.
/// On matching anchor range, replaces the old highlight; does not clear the other existing highlights.
/// If multiple anchor ranges will produce highlights for the same row, the last range added will be used.
/// Adds a row highlight for the given range. If a row has multiple highlights, the
/// last highlight added will be used.
///
/// If the range ends at the beginning of a line, then that line will not be highlighted.
pub fn highlight_rows<T: 'static>(
&mut self,
rows: RangeInclusive<Anchor>,
color: Option<Hsla>,
range: Range<Anchor>,
color: Hsla,
should_autoscroll: bool,
cx: &mut ViewContext<Self>,
) {
let snapshot = self.buffer().read(cx).snapshot(cx);
let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
let existing_highlight_index = row_highlights.binary_search_by(|highlight| {
highlight
.range
.start()
.cmp(rows.start(), &snapshot)
.then(highlight.range.end().cmp(rows.end(), &snapshot))
let ix = row_highlights.binary_search_by(|highlight| {
Ordering::Equal
.then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
.then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
});
match (color, existing_highlight_index) {
(Some(_), Ok(ix)) | (_, Err(ix)) => row_highlights.insert(
ix,
RowHighlight {
index: post_inc(&mut self.highlight_order),
range: rows,
should_autoscroll,
color,
},
),
(None, Ok(i)) => {
row_highlights.remove(i);
if let Err(mut ix) = ix {
let index = post_inc(&mut self.highlight_order);
// If this range intersects with the preceding highlight, then merge it with
// the preceding highlight. Otherwise insert a new highlight.
let mut merged = false;
if ix > 0 {
let prev_highlight = &mut row_highlights[ix - 1];
if prev_highlight
.range
.end
.cmp(&range.start, &snapshot)
.is_ge()
{
ix -= 1;
if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
prev_highlight.range.end = range.end;
}
merged = true;
prev_highlight.index = index;
prev_highlight.color = color;
prev_highlight.should_autoscroll = should_autoscroll;
}
}
if !merged {
row_highlights.insert(
ix,
RowHighlight {
range: range.clone(),
index,
color,
should_autoscroll,
},
);
}
// If any of the following highlights intersect with this one, merge them.
while let Some(next_highlight) = row_highlights.get(ix + 1) {
let highlight = &row_highlights[ix];
if next_highlight
.range
.start
.cmp(&highlight.range.end, &snapshot)
.is_le()
{
if next_highlight
.range
.end
.cmp(&highlight.range.end, &snapshot)
.is_gt()
{
row_highlights[ix].range.end = next_highlight.range.end;
}
row_highlights.remove(ix + 1);
} else {
break;
}
}
}
}
/// Remove any highlighted row ranges of the given type that intersect the
/// given ranges.
pub fn remove_highlighted_rows<T: 'static>(
&mut self,
ranges_to_remove: Vec<Range<Anchor>>,
cx: &mut ViewContext<Self>,
) {
let snapshot = self.buffer().read(cx).snapshot(cx);
let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
let mut ranges_to_remove = ranges_to_remove.iter().peekable();
row_highlights.retain(|highlight| {
while let Some(range_to_remove) = ranges_to_remove.peek() {
match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
Ordering::Less | Ordering::Equal => {
ranges_to_remove.next();
}
Ordering::Greater => {
match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
Ordering::Less | Ordering::Equal => {
return false;
}
Ordering::Greater => break,
}
}
}
}
true
})
}
/// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
pub fn clear_row_highlights<T: 'static>(&mut self) {
self.highlighted_rows.remove(&TypeId::of::<T>());
}
/// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
pub fn highlighted_rows<T: 'static>(
&self,
) -> Option<impl Iterator<Item = (&RangeInclusive<Anchor>, Option<&Hsla>)>> {
Some(
self.highlighted_rows
.get(&TypeId::of::<T>())?
.iter()
.map(|highlight| (&highlight.range, highlight.color.as_ref())),
)
pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
self.highlighted_rows
.get(&TypeId::of::<T>())
.map_or(&[] as &[_], |vec| vec.as_slice())
.iter()
.map(|highlight| (highlight.range.clone(), highlight.color))
}
/// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
@@ -11388,17 +11673,22 @@ impl Editor {
.fold(
BTreeMap::<DisplayRow, Hsla>::new(),
|mut unique_rows, highlight| {
let start_row = highlight.range.start().to_display_point(&snapshot).row();
let end_row = highlight.range.end().to_display_point(&snapshot).row();
for row in start_row.0..=end_row.0 {
let start = highlight.range.start.to_display_point(&snapshot);
let end = highlight.range.end.to_display_point(&snapshot);
let start_row = start.row().0;
let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
&& end.column() == 0
{
end.row().0.saturating_sub(1)
} else {
end.row().0
};
for row in start_row..=end_row {
let used_index =
used_highlight_orders.entry(row).or_insert(highlight.index);
if highlight.index >= *used_index {
*used_index = highlight.index;
match highlight.color {
Some(hsla) => unique_rows.insert(DisplayRow(row), hsla),
None => unique_rows.remove(&DisplayRow(row)),
};
unique_rows.insert(DisplayRow(row), highlight.color);
}
}
unique_rows
@@ -11414,10 +11704,11 @@ impl Editor {
.values()
.flat_map(|highlighted_rows| highlighted_rows.iter())
.filter_map(|highlight| {
if highlight.color.is_none() || !highlight.should_autoscroll {
return None;
if highlight.should_autoscroll {
Some(highlight.range.start.to_display_point(snapshot).row())
} else {
None
}
Some(highlight.range.start().to_display_point(snapshot).row())
})
.min()
}
@@ -11923,12 +12214,19 @@ impl Editor {
)),
cx,
);
let editor_settings = EditorSettings::get_global(cx);
if let Some(cursor_shape) = editor_settings.cursor_shape {
self.cursor_shape = cursor_shape;
let old_cursor_shape = self.cursor_shape;
{
let editor_settings = EditorSettings::get_global(cx);
self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
}
if old_cursor_shape != self.cursor_shape {
cx.emit(EditorEvent::CursorShapeChanged);
}
self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
let project_settings = ProjectSettings::get_global(cx);
self.serialize_dirty_buffers = project_settings.session.restore_unsaved_buffers;
@@ -11964,12 +12262,9 @@ impl Editor {
let buffer = self.buffer.read(cx);
let mut new_selections_by_buffer = HashMap::default();
for selection in self.selections.all::<usize>(cx) {
for (buffer, mut range, _) in
for (buffer, range, _) in
buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
{
if selection.reversed {
mem::swap(&mut range.start, &mut range.end);
}
let mut range = range.to_point(buffer.read(cx));
range.start.column = 0;
range.end.column = buffer.read(cx).line_len(range.end.row);
@@ -12938,6 +13233,7 @@ impl EditorSnapshot {
font_id: FontId,
font_size: Pixels,
em_width: Pixels,
em_advance: Pixels,
max_line_number_width: Pixels,
cx: &AppContext,
) -> GutterDimensions {
@@ -12958,7 +13254,7 @@ impl EditorSnapshot {
.unwrap_or(gutter_settings.line_numbers);
let line_gutter_width = if show_line_numbers {
// Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
let min_width_for_number_on_gutter = em_width * 4.0;
let min_width_for_number_on_gutter = em_advance * 4.0;
max_line_number_width.max(min_width_for_number_on_gutter)
} else {
0.0.into()
@@ -12970,9 +13266,19 @@ impl EditorSnapshot {
let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
let git_blame_entries_width = self
.render_git_blame_gutter
.then_some(em_width * GIT_BLAME_GUTTER_WIDTH_CHARS);
let git_blame_entries_width =
self.git_blame_gutter_max_author_length
.map(|max_author_length| {
// Length of the author name, but also space for the commit hash,
// the spacing and the timestamp.
let max_char_count = max_author_length
.min(GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED)
+ 7 // length of commit sha
+ 14 // length of max relative timestamp ("60 minutes ago")
+ 4; // gaps and margins
em_advance * max_char_count
});
let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
left_padding += if show_code_actions || show_runnables {
@@ -13125,6 +13431,7 @@ pub enum EditorEvent {
TransactionBegun {
transaction_id: clock::Lamport,
},
CursorShapeChanged,
}
impl EventEmitter<EditorEvent> for Editor {}

View File

@@ -13,7 +13,6 @@ pub struct EditorSettings {
pub show_completions_on_input: bool,
pub show_completion_documentation: bool,
pub completion_documentation_secondary_query_debounce: u64,
pub use_on_type_format: bool,
pub toolbar: Toolbar,
pub scrollbar: Scrollbar,
pub gutter: Gutter,
@@ -209,11 +208,6 @@ pub struct EditorSettingsContent {
///
/// Default: 300 ms
pub completion_documentation_secondary_query_debounce: Option<u64>,
/// Whether to use additional LSP queries to format (and amend) the code after
/// every "trigger" symbol input, defined by LSP server capabilities.
///
/// Default: true
pub use_on_type_format: Option<bool>,
/// Toolbar related settings
pub toolbar: Option<ToolbarContent>,
/// Scrollbar related settings

File diff suppressed because it is too large Load Diff

View File

@@ -21,7 +21,7 @@ use crate::{
EditorSnapshot, EditorStyle, ExpandExcerpts, FocusedBlock, GutterDimensions, HalfPageDown,
HalfPageUp, HandleInput, HoveredCursor, HoveredHunk, LineDown, LineUp, OpenExcerpts, PageDown,
PageUp, Point, RowExt, RowRangeExt, SelectPhase, Selection, SoftWrap, ToPoint,
CURSORS_VISIBLE_FOR, MAX_LINE_LEN,
CURSORS_VISIBLE_FOR, GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED, MAX_LINE_LEN,
};
use client::ParticipantIndex;
use collections::{BTreeMap, HashMap};
@@ -335,8 +335,14 @@ impl EditorElement {
register_action(view, cx, Editor::open_url);
register_action(view, cx, Editor::open_file);
register_action(view, cx, Editor::fold);
register_action(view, cx, Editor::fold_all);
register_action(view, cx, Editor::fold_at);
register_action(view, cx, Editor::fold_recursive);
register_action(view, cx, Editor::toggle_fold);
register_action(view, cx, Editor::toggle_fold_recursive);
register_action(view, cx, Editor::unfold_lines);
register_action(view, cx, Editor::unfold_recursive);
register_action(view, cx, Editor::unfold_all);
register_action(view, cx, Editor::unfold_at);
register_action(view, cx, Editor::fold_selected_ranges);
register_action(view, cx, Editor::show_completions);
@@ -430,6 +436,7 @@ impl EditorElement {
register_action(view, cx, Editor::accept_inline_completion);
register_action(view, cx, Editor::revert_file);
register_action(view, cx, Editor::revert_selected_hunks);
register_action(view, cx, Editor::apply_selected_diff_hunks);
register_action(view, cx, Editor::open_active_item_in_terminal)
}
@@ -630,11 +637,30 @@ impl EditorElement {
cx.stop_propagation();
} else if end_selection && pending_nonempty_selections {
cx.stop_propagation();
} else if cfg!(target_os = "linux")
&& event.button == MouseButton::Middle
&& (!text_hitbox.is_hovered(cx) || editor.read_only(cx))
{
return;
} else if cfg!(target_os = "linux") && event.button == MouseButton::Middle {
if !text_hitbox.is_hovered(cx) || editor.read_only(cx) {
return;
}
#[cfg(target_os = "linux")]
if EditorSettings::get_global(cx).middle_click_paste {
if let Some(text) = cx.read_from_primary().and_then(|item| item.text()) {
let point_for_position =
position_map.point_for_position(text_hitbox.bounds, event.position);
let position = point_for_position.previous_valid;
editor.select(
SelectPhase::Begin {
position,
add: false,
click_count: 1,
},
cx,
);
editor.insert(&text, cx);
}
cx.stop_propagation()
}
}
}
@@ -1445,7 +1471,7 @@ impl EditorElement {
AvailableSpace::MaxContent
};
let scroll_top = scroll_position.y * line_height;
let start_x = em_width * 1;
let start_x = em_width;
let mut last_used_color: Option<(PlayerColor, Oid)> = None;
@@ -1640,7 +1666,16 @@ impl EditorElement {
return None;
}
if snapshot.is_line_folded(multibuffer_row) {
return None;
// Skip folded indicators, unless it's the starting line of a fold.
if multibuffer_row
.0
.checked_sub(1)
.map_or(false, |previous_row| {
snapshot.is_line_folded(MultiBufferRow(previous_row))
})
{
return None;
}
}
let button = editor.render_run_indicator(
&self.style,
@@ -4228,7 +4263,7 @@ fn render_blame_entry(
let short_commit_id = blame_entry.sha.display_short();
let author_name = blame_entry.author.as_deref().unwrap_or("<no name>");
let name = util::truncate_and_trailoff(author_name, 20);
let name = util::truncate_and_trailoff(author_name, GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED);
let details = blame.read(cx).details_for_entry(&blame_entry);
@@ -4240,22 +4275,21 @@ fn render_blame_entry(
h_flex()
.w_full()
.justify_between()
.font_family(style.text.font().family)
.line_height(style.text.line_height)
.id(("blame", ix))
.children([
div()
.text_color(sha_color.cursor)
.child(short_commit_id)
.mr_2(),
div()
.w_full()
.h_flex()
.justify_between()
.text_color(cx.theme().status().hint)
.child(name)
.child(relative_timestamp),
])
.text_color(cx.theme().status().hint)
.pr_2()
.gap_2()
.child(
h_flex()
.items_center()
.gap_2()
.child(div().text_color(sha_color.cursor).child(short_commit_id))
.child(name),
)
.child(relative_timestamp)
.on_mouse_down(MouseButton::Right, {
let blame_entry = blame_entry.clone();
let details = details.clone();
@@ -4970,6 +5004,7 @@ impl Element for EditorElement {
font_id,
font_size,
em_width,
em_advance,
self.max_line_number_width(&snapshot, cx),
cx,
);
@@ -4994,10 +5029,8 @@ impl Element for EditorElement {
snapshot
} else {
let wrap_width = match editor.soft_wrap_mode(cx) {
SoftWrap::None => None,
SoftWrap::PreferLine => {
Some((MAX_LINE_LEN / 2) as f32 * em_advance)
}
SoftWrap::GitDiff => None,
SoftWrap::None => Some((MAX_LINE_LEN / 2) as f32 * em_advance),
SoftWrap::EditorWidth => Some(editor_width),
SoftWrap::Column(column) => Some(column as f32 * em_advance),
SoftWrap::Bounded(column) => {
@@ -6283,10 +6316,21 @@ fn compute_auto_height_layout(
.unwrap()
.size
.width;
let em_advance = cx
.text_system()
.advance(font_id, font_size, 'm')
.unwrap()
.width;
let mut snapshot = editor.snapshot(cx);
let gutter_dimensions =
snapshot.gutter_dimensions(font_id, font_size, em_width, max_line_number_width, cx);
let gutter_dimensions = snapshot.gutter_dimensions(
font_id,
font_size,
em_width,
em_advance,
max_line_number_width,
cx,
);
editor.gutter_dimensions = gutter_dimensions;
let text_width = width - gutter_dimensions.width;

View File

@@ -29,7 +29,7 @@ pub struct GitBlameEntrySummary {
impl sum_tree::Item for GitBlameEntry {
type Summary = GitBlameEntrySummary;
fn summary(&self) -> Self::Summary {
fn summary(&self, _cx: &()) -> Self::Summary {
GitBlameEntrySummary { rows: self.rows }
}
}
@@ -207,6 +207,27 @@ impl GitBlame {
})
}
pub fn max_author_length(&mut self, cx: &mut ModelContext<Self>) -> usize {
self.sync(cx);
let mut max_author_length = 0;
for entry in self.entries.iter() {
let author_len = entry
.blame
.as_ref()
.and_then(|entry| entry.author.as_ref())
.map(|author| author.len());
if let Some(author_len) = author_len {
if author_len > max_author_length {
max_author_length = author_len;
}
}
}
max_author_length
}
pub fn blur(&mut self, _: &mut ModelContext<Self>) {
self.focused = false;
}

View File

@@ -32,7 +32,7 @@ pub fn refresh_matching_bracket_highlights(editor: &mut Editor, cx: &mut ViewCon
opening_range.to_anchors(&snapshot.buffer_snapshot),
closing_range.to_anchors(&snapshot.buffer_snapshot),
],
|theme| theme.editor_document_highlight_read_background,
|theme| theme.editor_document_highlight_bracket_background,
cx,
)
}

View File

@@ -6,10 +6,7 @@ use multi_buffer::{
Anchor, AnchorRangeExt, ExcerptRange, MultiBuffer, MultiBufferDiffHunk, MultiBufferRow,
MultiBufferSnapshot, ToPoint,
};
use std::{
ops::{Range, RangeInclusive},
sync::Arc,
};
use std::{ops::Range, sync::Arc};
use ui::{
prelude::*, ActiveTheme, ContextMenu, IconButtonShape, InteractiveElement, IntoElement,
ParentElement, PopoverMenu, Styled, Tooltip, ViewContext, VisualContext,
@@ -17,10 +14,10 @@ use ui::{
use util::RangeExt;
use crate::{
editor_settings::CurrentLineHighlight, hunk_status, hunks_for_selections, BlockDisposition,
BlockProperties, BlockStyle, CustomBlockId, DiffRowHighlight, DisplayRow, DisplaySnapshot,
Editor, EditorElement, EditorSnapshot, ExpandAllHunkDiffs, GoToHunk, GoToPrevHunk,
RangeToAnchorExt, RevertFile, RevertSelectedHunks, ToDisplayPoint, ToggleHunkDiff,
editor_settings::CurrentLineHighlight, hunk_status, hunks_for_selections, ApplyDiffHunk,
BlockDisposition, BlockProperties, BlockStyle, CustomBlockId, DiffRowHighlight, DisplayRow,
DisplaySnapshot, Editor, EditorElement, ExpandAllHunkDiffs, GoToHunk, GoToPrevHunk, RevertFile,
RevertSelectedHunks, ToDisplayPoint, ToggleHunkDiff,
};
#[derive(Debug, Clone)]
@@ -35,6 +32,7 @@ pub(super) struct ExpandedHunks {
pub(crate) hunks: Vec<ExpandedHunk>,
diff_base: HashMap<BufferId, DiffBaseBuffer>,
hunk_update_tasks: HashMap<Option<BufferId>, Task<()>>,
expand_all: bool,
}
#[derive(Debug, Clone)]
@@ -75,6 +73,10 @@ impl ExpandedHunks {
}
impl Editor {
pub fn set_expand_all_diff_hunks(&mut self) {
self.expanded_hunks.expand_all = true;
}
pub(super) fn toggle_hovered_hunk(
&mut self,
hovered_hunk: &HoveredHunk,
@@ -136,6 +138,10 @@ impl Editor {
hunks_to_toggle: Vec<MultiBufferDiffHunk>,
cx: &mut ViewContext<Self>,
) {
if self.expanded_hunks.expand_all {
return;
}
let previous_toggle_task = self.expanded_hunks.hunk_update_tasks.remove(&None);
let new_toggle_task = cx.spawn(move |editor, mut cx| async move {
if let Some(task) = previous_toggle_task {
@@ -219,14 +225,7 @@ impl Editor {
});
}
for removed_rows in highlights_to_remove {
editor.highlight_rows::<DiffRowHighlight>(
to_inclusive_row_range(removed_rows, &snapshot),
None,
false,
cx,
);
}
editor.remove_highlighted_rows::<DiffRowHighlight>(highlights_to_remove, cx);
editor.remove_blocks(blocks_to_remove, None, cx);
for hunk in hunks_to_expand {
editor.expand_diff_hunk(None, &hunk, cx);
@@ -248,19 +247,14 @@ impl Editor {
cx: &mut ViewContext<'_, Editor>,
) -> Option<()> {
let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
let multi_buffer_row_range = hunk
.multi_buffer_range
.start
.to_point(&multi_buffer_snapshot)
..hunk.multi_buffer_range.end.to_point(&multi_buffer_snapshot);
let hunk_start = hunk.multi_buffer_range.start;
let hunk_end = hunk.multi_buffer_range.end;
let hunk_range = hunk.multi_buffer_range.clone();
let hunk_point_range = hunk_range.to_point(&multi_buffer_snapshot);
let buffer = self.buffer().clone();
let snapshot = self.snapshot(cx);
let (diff_base_buffer, deleted_text_lines) = buffer.update(cx, |buffer, cx| {
let hunk = buffer_diff_hunk(&snapshot.buffer_snapshot, multi_buffer_row_range.clone())?;
let mut buffer_ranges = buffer.range_to_buffer_ranges(multi_buffer_row_range, cx);
let hunk = buffer_diff_hunk(&snapshot.buffer_snapshot, hunk_point_range.clone())?;
let mut buffer_ranges = buffer.range_to_buffer_ranges(hunk_point_range, cx);
if buffer_ranges.len() == 1 {
let (buffer, _, _) = buffer_ranges.pop()?;
let diff_base_buffer = diff_base_buffer
@@ -285,7 +279,7 @@ impl Editor {
probe
.hunk_range
.start
.cmp(&hunk_start, &multi_buffer_snapshot)
.cmp(&hunk_range.start, &multi_buffer_snapshot)
}) {
Ok(_already_present) => return None,
Err(ix) => ix,
@@ -305,8 +299,8 @@ impl Editor {
}
DiffHunkStatus::Added => {
self.highlight_rows::<DiffRowHighlight>(
to_inclusive_row_range(hunk_start..hunk_end, &snapshot),
Some(added_hunk_color(cx)),
hunk_range.clone(),
added_hunk_color(cx),
false,
cx,
);
@@ -314,8 +308,8 @@ impl Editor {
}
DiffHunkStatus::Modified => {
self.highlight_rows::<DiffRowHighlight>(
to_inclusive_row_range(hunk_start..hunk_end, &snapshot),
Some(added_hunk_color(cx)),
hunk_range.clone(),
added_hunk_color(cx),
false,
cx,
);
@@ -333,7 +327,7 @@ impl Editor {
block_insert_index,
ExpandedHunk {
blocks,
hunk_range: hunk_start..hunk_end,
hunk_range,
status: hunk.status,
folded: false,
diff_base_byte_range: hunk.diff_base_byte_range.clone(),
@@ -343,12 +337,49 @@ impl Editor {
Some(())
}
fn apply_changes_in_range(
&mut self,
range: Range<Anchor>,
cx: &mut ViewContext<'_, Editor>,
) -> Option<()> {
let (buffer, range, _) = self
.buffer
.read(cx)
.range_to_buffer_ranges(range, cx)
.into_iter()
.next()?;
buffer.update(cx, |branch_buffer, cx| {
branch_buffer.merge_into_base(Some(range), cx);
});
None
}
pub(crate) fn apply_all_changes(&self, cx: &mut ViewContext<Self>) {
let buffers = self.buffer.read(cx).all_buffers();
for branch_buffer in buffers {
branch_buffer.update(cx, |branch_buffer, cx| {
branch_buffer.merge_into_base(None, cx);
});
}
}
fn hunk_header_block(
&self,
hunk: &HoveredHunk,
cx: &mut ViewContext<'_, Editor>,
) -> BlockProperties<Anchor> {
let border_color = cx.theme().colors().border_disabled;
let is_branch_buffer = self
.buffer
.read(cx)
.point_to_buffer_offset(hunk.multi_buffer_range.start, cx)
.map_or(false, |(buffer, _, _)| {
buffer.read(cx).diff_base_buffer().is_some()
});
let border_color = cx.theme().colors().border_variant;
let bg_color = cx.theme().colors().editor_background;
let gutter_color = match hunk.status {
DiffHunkStatus::Added => cx.theme().status().created,
DiffHunkStatus::Modified => cx.theme().status().modified,
@@ -364,14 +395,18 @@ impl Editor {
render: Box::new({
let editor = cx.view().clone();
let hunk = hunk.clone();
move |cx| {
let hunk_controls_menu_handle =
editor.read(cx).hunk_controls_menu_handle.clone();
h_flex()
.id(cx.block_id)
.w_full()
.h(cx.line_height())
.w_full()
.border_t_1()
.border_color(border_color)
.bg(bg_color)
.child(
div()
.id("gutter-strip")
@@ -391,180 +426,72 @@ impl Editor {
)
.child(
h_flex()
.px_6()
.size_full()
.justify_between()
.border_t_1()
.border_color(border_color)
.child(
h_flex()
.gap_2()
.pl_6()
.child(
IconButton::new("next-hunk", IconName::ArrowDown)
.shape(IconButtonShape::Square)
.icon_size(IconSize::Small)
.tooltip({
let focus_handle = editor.focus_handle(cx);
move |cx| {
Tooltip::for_action_in(
"Next Hunk",
&GoToHunk,
&focus_handle,
cx,
)
}
})
.on_click({
let editor = editor.clone();
let hunk = hunk.clone();
move |_event, cx| {
editor.update(cx, |editor, cx| {
let snapshot = editor.snapshot(cx);
let position = hunk
.multi_buffer_range
.end
.to_point(
&snapshot.buffer_snapshot,
);
if let Some(hunk) = editor
.go_to_hunk_after_position(
&snapshot, position, cx,
)
{
let multi_buffer_start = snapshot
.buffer_snapshot
.anchor_before(Point::new(
hunk.row_range.start.0,
0,
));
let multi_buffer_end = snapshot
.buffer_snapshot
.anchor_after(Point::new(
hunk.row_range.end.0,
0,
));
editor.expand_diff_hunk(
None,
&HoveredHunk {
multi_buffer_range:
multi_buffer_start
..multi_buffer_end,
status: hunk_status(&hunk),
diff_base_byte_range: hunk
.diff_base_byte_range,
},
cx,
);
}
});
}
}),
)
.child(
IconButton::new("prev-hunk", IconName::ArrowUp)
.shape(IconButtonShape::Square)
.icon_size(IconSize::Small)
.tooltip({
let focus_handle = editor.focus_handle(cx);
move |cx| {
Tooltip::for_action_in(
"Previous Hunk",
&GoToPrevHunk,
&focus_handle,
cx,
)
}
})
.on_click({
let editor = editor.clone();
let hunk = hunk.clone();
move |_event, cx| {
editor.update(cx, |editor, cx| {
let snapshot = editor.snapshot(cx);
let position = hunk
.multi_buffer_range
.start
.to_point(
&snapshot.buffer_snapshot,
);
let hunk = editor
.go_to_hunk_before_position(
&snapshot, position, cx,
);
if let Some(hunk) = hunk {
let multi_buffer_start = snapshot
.buffer_snapshot
.anchor_before(Point::new(
hunk.row_range.start.0,
0,
));
let multi_buffer_end = snapshot
.buffer_snapshot
.anchor_after(Point::new(
hunk.row_range.end.0,
0,
));
editor.expand_diff_hunk(
None,
&HoveredHunk {
multi_buffer_range:
multi_buffer_start
..multi_buffer_end,
status: hunk_status(&hunk),
diff_base_byte_range: hunk
.diff_base_byte_range,
},
cx,
);
}
});
}
}),
),
)
.child(
h_flex()
.gap_2()
.pr_6()
.child({
let focus = editor.focus_handle(cx);
PopoverMenu::new("hunk-controls-dropdown")
.trigger(
IconButton::new(
"toggle_editor_selections_icon",
IconName::EllipsisVertical,
)
.gap_1()
.when(!is_branch_buffer, |row| {
row.child(
IconButton::new("next-hunk", IconName::ArrowDown)
.shape(IconButtonShape::Square)
.icon_size(IconSize::Small)
.style(ButtonStyle::Subtle)
.selected(
hunk_controls_menu_handle.is_deployed(),
)
.when(
!hunk_controls_menu_handle.is_deployed(),
|this| {
this.tooltip(|cx| {
Tooltip::text("Hunk Controls", cx)
})
},
),
)
.anchor(AnchorCorner::TopRight)
.with_handle(hunk_controls_menu_handle)
.menu(move |cx| {
let focus = focus.clone();
let menu =
ContextMenu::build(cx, move |menu, _| {
menu.context(focus.clone()).action(
"Discard All",
RevertFile.boxed_clone(),
.tooltip({
let focus_handle = editor.focus_handle(cx);
move |cx| {
Tooltip::for_action_in(
"Next Hunk",
&GoToHunk,
&focus_handle,
cx,
)
});
Some(menu)
})
}
})
.on_click({
let editor = editor.clone();
let hunk = hunk.clone();
move |_event, cx| {
editor.update(cx, |editor, cx| {
editor.go_to_subsequent_hunk(
hunk.multi_buffer_range.end,
cx,
);
});
}
}),
)
.child(
IconButton::new("prev-hunk", IconName::ArrowUp)
.shape(IconButtonShape::Square)
.icon_size(IconSize::Small)
.tooltip({
let focus_handle = editor.focus_handle(cx);
move |cx| {
Tooltip::for_action_in(
"Previous Hunk",
&GoToPrevHunk,
&focus_handle,
cx,
)
}
})
.on_click({
let editor = editor.clone();
let hunk = hunk.clone();
move |_event, cx| {
editor.update(cx, |editor, cx| {
editor.go_to_preceding_hunk(
hunk.multi_buffer_range.start,
cx,
);
});
}
}),
)
})
.child(
IconButton::new("discard", IconName::RotateCcw)
IconButton::new("discard", IconName::Undo)
.shape(IconButtonShape::Square)
.icon_size(IconSize::Small)
.tooltip({
@@ -608,32 +535,115 @@ impl Editor {
}
}),
)
.child(
IconButton::new("collapse", IconName::Close)
.shape(IconButtonShape::Square)
.icon_size(IconSize::Small)
.tooltip({
let focus_handle = editor.focus_handle(cx);
move |cx| {
Tooltip::for_action_in(
"Collapse Hunk",
&ToggleHunkDiff,
&focus_handle,
cx,
.map(|this| {
if is_branch_buffer {
this.child(
IconButton::new("apply", IconName::Check)
.shape(IconButtonShape::Square)
.icon_size(IconSize::Small)
.tooltip({
let focus_handle =
editor.focus_handle(cx);
move |cx| {
Tooltip::for_action_in(
"Apply Hunk",
&ApplyDiffHunk,
&focus_handle,
cx,
)
}
})
.on_click({
let editor = editor.clone();
let hunk = hunk.clone();
move |_event, cx| {
editor.update(cx, |editor, cx| {
editor.apply_changes_in_range(
hunk.multi_buffer_range
.clone(),
cx,
);
});
}
}),
)
} else {
this.child({
let focus = editor.focus_handle(cx);
PopoverMenu::new("hunk-controls-dropdown")
.trigger(
IconButton::new(
"toggle_editor_selections_icon",
IconName::EllipsisVertical,
)
.shape(IconButtonShape::Square)
.icon_size(IconSize::Small)
.style(ButtonStyle::Subtle)
.selected(
hunk_controls_menu_handle
.is_deployed(),
)
.when(
!hunk_controls_menu_handle
.is_deployed(),
|this| {
this.tooltip(|cx| {
Tooltip::text(
"Hunk Controls",
cx,
)
})
},
),
)
}
.anchor(AnchorCorner::TopRight)
.with_handle(hunk_controls_menu_handle)
.menu(move |cx| {
let focus = focus.clone();
let menu = ContextMenu::build(
cx,
move |menu, _| {
menu.context(focus.clone())
.action(
"Discard All Hunks",
RevertFile
.boxed_clone(),
)
},
);
Some(menu)
})
})
.on_click({
let editor = editor.clone();
let hunk = hunk.clone();
move |_event, cx| {
editor.update(cx, |editor, cx| {
editor.toggle_hovered_hunk(&hunk, cx);
});
}
}),
),
),
}
}),
)
.when(!is_branch_buffer, |div| {
div.child(
IconButton::new("collapse", IconName::Close)
.shape(IconButtonShape::Square)
.icon_size(IconSize::Small)
.tooltip({
let focus_handle = editor.focus_handle(cx);
move |cx| {
Tooltip::for_action_in(
"Collapse Hunk",
&ToggleHunkDiff,
&focus_handle,
cx,
)
}
})
.on_click({
let editor = editor.clone();
let hunk = hunk.clone();
move |_event, cx| {
editor.update(cx, |editor, cx| {
editor.toggle_hovered_hunk(&hunk, cx);
});
}
}),
)
}),
)
.into_any_element()
}
@@ -708,7 +718,10 @@ impl Editor {
}
}
pub(super) fn clear_clicked_diff_hunks(&mut self, cx: &mut ViewContext<'_, Editor>) -> bool {
pub(super) fn clear_expanded_diff_hunks(&mut self, cx: &mut ViewContext<'_, Editor>) -> bool {
if self.expanded_hunks.expand_all {
return false;
}
self.expanded_hunks.hunk_update_tasks.clear();
self.clear_row_highlights::<DiffRowHighlight>();
let to_remove = self
@@ -812,33 +825,43 @@ impl Editor {
status,
} => {
let hunk_display_range = display_row_range;
if expanded_hunk_display_range.start
> hunk_display_range.end
{
recalculated_hunks.next();
continue;
} else if expanded_hunk_display_range.end
< hunk_display_range.start
{
break;
} else {
if !expanded_hunk.folded
&& expanded_hunk_display_range == hunk_display_range
&& expanded_hunk.status == hunk_status(buffer_hunk)
&& expanded_hunk.diff_base_byte_range
== buffer_hunk.diff_base_byte_range
{
recalculated_hunks.next();
retain = true;
} else {
if editor.expanded_hunks.expand_all {
hunks_to_reexpand.push(HoveredHunk {
status,
multi_buffer_range,
diff_base_byte_range,
});
}
continue;
}
if expanded_hunk_display_range.end
< hunk_display_range.start
{
break;
}
if !expanded_hunk.folded
&& expanded_hunk_display_range == hunk_display_range
&& expanded_hunk.status == hunk_status(buffer_hunk)
&& expanded_hunk.diff_base_byte_range
== buffer_hunk.diff_base_byte_range
{
recalculated_hunks.next();
retain = true;
} else {
hunks_to_reexpand.push(HoveredHunk {
status,
multi_buffer_range,
diff_base_byte_range,
});
}
break;
}
}
}
@@ -850,14 +873,27 @@ impl Editor {
retain
});
for removed_rows in highlights_to_remove {
editor.highlight_rows::<DiffRowHighlight>(
to_inclusive_row_range(removed_rows, &snapshot),
None,
false,
cx,
);
if editor.expanded_hunks.expand_all {
for hunk in recalculated_hunks {
match diff_hunk_to_display(&hunk, &snapshot) {
DisplayDiffHunk::Folded { .. } => {}
DisplayDiffHunk::Unfolded {
diff_base_byte_range,
multi_buffer_range,
status,
..
} => {
hunks_to_reexpand.push(HoveredHunk {
status,
multi_buffer_range,
diff_base_byte_range,
});
}
}
}
}
editor.remove_highlighted_rows::<DiffRowHighlight>(highlights_to_remove, cx);
editor.remove_blocks(blocks_to_remove, None, cx);
if let Some(diff_base_buffer) = &diff_base_buffer {
@@ -894,6 +930,51 @@ impl Editor {
}
})
}
fn go_to_subsequent_hunk(&mut self, position: Anchor, cx: &mut ViewContext<Self>) {
let snapshot = self.snapshot(cx);
let position = position.to_point(&snapshot.buffer_snapshot);
if let Some(hunk) = self.go_to_hunk_after_position(&snapshot, position, cx) {
let multi_buffer_start = snapshot
.buffer_snapshot
.anchor_before(Point::new(hunk.row_range.start.0, 0));
let multi_buffer_end = snapshot
.buffer_snapshot
.anchor_after(Point::new(hunk.row_range.end.0, 0));
self.expand_diff_hunk(
None,
&HoveredHunk {
multi_buffer_range: multi_buffer_start..multi_buffer_end,
status: hunk_status(&hunk),
diff_base_byte_range: hunk.diff_base_byte_range,
},
cx,
);
}
}
fn go_to_preceding_hunk(&mut self, position: Anchor, cx: &mut ViewContext<Self>) {
let snapshot = self.snapshot(cx);
let position = position.to_point(&snapshot.buffer_snapshot);
let hunk = self.go_to_hunk_before_position(&snapshot, position, cx);
if let Some(hunk) = hunk {
let multi_buffer_start = snapshot
.buffer_snapshot
.anchor_before(Point::new(hunk.row_range.start.0, 0));
let multi_buffer_end = snapshot
.buffer_snapshot
.anchor_after(Point::new(hunk.row_range.end.0, 0));
self.expand_diff_hunk(
None,
&HoveredHunk {
multi_buffer_range: multi_buffer_start..multi_buffer_end,
status: hunk_status(&hunk),
diff_base_byte_range: hunk.diff_base_byte_range,
},
cx,
);
}
}
}
fn to_diff_hunk(
@@ -976,13 +1057,15 @@ fn editor_with_deleted_text(
editor.scroll_manager.set_forbid_vertical_scroll(true);
editor.set_read_only(true);
editor.set_show_inline_completions(Some(false), cx);
editor.highlight_rows::<DiffRowHighlight>(
Anchor::min()..=Anchor::max(),
Some(deleted_color),
enum DeletedBlockRowHighlight {}
editor.highlight_rows::<DeletedBlockRowHighlight>(
Anchor::min()..Anchor::max(),
deleted_color,
false,
cx,
);
editor.set_current_line_highlight(Some(CurrentLineHighlight::None));
editor.set_current_line_highlight(Some(CurrentLineHighlight::None)); //
editor
._subscriptions
.extend([cx.on_blur(&editor.focus_handle, |editor, cx| {
@@ -991,37 +1074,41 @@ fn editor_with_deleted_text(
});
})]);
let parent_editor_for_reverts = parent_editor.clone();
let original_multi_buffer_range = hunk.multi_buffer_range.clone();
let diff_base_range = hunk.diff_base_byte_range.clone();
editor
.register_action::<RevertSelectedHunks>(move |_, cx| {
parent_editor_for_reverts
.update(cx, |editor, cx| {
let Some((buffer, original_text)) =
editor.buffer().update(cx, |buffer, cx| {
let (_, buffer, _) = buffer
.excerpt_containing(original_multi_buffer_range.start, cx)?;
let original_text =
buffer.read(cx).diff_base()?.slice(diff_base_range.clone());
Some((buffer, Arc::from(original_text.to_string())))
})
else {
return;
};
buffer.update(cx, |buffer, cx| {
buffer.edit(
Some((
original_multi_buffer_range.start.text_anchor
..original_multi_buffer_range.end.text_anchor,
original_text,
)),
None,
cx,
)
});
})
.ok();
.register_action::<RevertSelectedHunks>({
let parent_editor = parent_editor.clone();
move |_, cx| {
parent_editor
.update(cx, |editor, cx| {
let Some((buffer, original_text)) =
editor.buffer().update(cx, |buffer, cx| {
let (_, buffer, _) = buffer.excerpt_containing(
original_multi_buffer_range.start,
cx,
)?;
let original_text =
buffer.read(cx).diff_base()?.slice(diff_base_range.clone());
Some((buffer, Arc::from(original_text.to_string())))
})
else {
return;
};
buffer.update(cx, |buffer, cx| {
buffer.edit(
Some((
original_multi_buffer_range.start.text_anchor
..original_multi_buffer_range.end.text_anchor,
original_text,
)),
None,
cx,
)
});
})
.ok();
}
})
.detach();
let hunk = hunk.clone();
@@ -1056,21 +1143,6 @@ fn buffer_diff_hunk(
None
}
fn to_inclusive_row_range(
row_range: Range<Anchor>,
snapshot: &EditorSnapshot,
) -> RangeInclusive<Anchor> {
let mut display_row_range =
row_range.start.to_display_point(snapshot)..row_range.end.to_display_point(snapshot);
if display_row_range.end.row() > display_row_range.start.row() {
*display_row_range.end.row_mut() -= 1;
}
let point_range = display_row_range.start.to_point(&snapshot.display_snapshot)
..display_row_range.end.to_point(&snapshot.display_snapshot);
let new_range = point_range.to_anchors(&snapshot.buffer_snapshot);
new_range.start..=new_range.end
}
impl DisplayDiffHunk {
pub fn start_display_row(&self) -> DisplayRow {
match self {

View File

@@ -158,6 +158,12 @@ pub fn deploy_context_menu(
}
let focus = cx.focused();
let has_reveal_target = editor.target_file(cx).is_some();
let reveal_in_finder_label = if cfg!(target_os = "macos") {
"Reveal in Finder"
} else {
"Reveal in File Manager"
};
ui::ContextMenu::build(cx, |menu, _cx| {
let builder = menu
.on_blur_subscription(Subscription::new(|| {}))
@@ -180,11 +186,13 @@ pub fn deploy_context_menu(
.action("Copy", Box::new(Copy))
.action("Paste", Box::new(Paste))
.separator()
.when(cfg!(target_os = "macos"), |builder| {
builder.action("Reveal in Finder", Box::new(RevealInFileManager))
})
.when(cfg!(not(target_os = "macos")), |builder| {
builder.action("Reveal in File Manager", Box::new(RevealInFileManager))
.map(|builder| {
if has_reveal_target {
builder.action(reveal_in_finder_label, Box::new(RevealInFileManager))
} else {
builder
.disabled_action(reveal_in_finder_label, Box::new(RevealInFileManager))
}
})
.action("Open in Terminal", Box::new(OpenInTerminal))
.action("Copy Permalink", Box::new(CopyPermalinkToLine));

View File

@@ -6,16 +6,19 @@ use language::{Buffer, BufferEvent, Capability};
use multi_buffer::{ExcerptRange, MultiBuffer};
use project::Project;
use smol::stream::StreamExt;
use std::{ops::Range, time::Duration};
use std::{any::TypeId, ops::Range, time::Duration};
use text::ToOffset;
use ui::prelude::*;
use workspace::Item;
use workspace::{
searchable::SearchableItemHandle, Item, ItemHandle as _, ToolbarItemEvent, ToolbarItemLocation,
ToolbarItemView, Workspace,
};
pub struct ProposedChangesEditor {
editor: View<Editor>,
_subscriptions: Vec<Subscription>,
_recalculate_diffs_task: Task<Option<()>>,
recalculate_diffs_tx: mpsc::UnboundedSender<Model<Buffer>>,
recalculate_diffs_tx: mpsc::UnboundedSender<RecalculateDiff>,
}
pub struct ProposedChangesBuffer<T> {
@@ -23,6 +26,15 @@ pub struct ProposedChangesBuffer<T> {
pub ranges: Vec<Range<T>>,
}
pub struct ProposedChangesEditorToolbar {
current_editor: Option<View<ProposedChangesEditor>>,
}
struct RecalculateDiff {
buffer: Model<Buffer>,
debounce: bool,
}
impl ProposedChangesEditor {
pub fn new<T: ToOffset>(
buffers: Vec<ProposedChangesBuffer<T>>,
@@ -51,21 +63,26 @@ impl ProposedChangesEditor {
let (recalculate_diffs_tx, mut recalculate_diffs_rx) = mpsc::unbounded();
Self {
editor: cx
.new_view(|cx| Editor::for_multibuffer(multibuffer.clone(), project, true, cx)),
editor: cx.new_view(|cx| {
let mut editor = Editor::for_multibuffer(multibuffer.clone(), project, true, cx);
editor.set_expand_all_diff_hunks();
editor
}),
recalculate_diffs_tx,
_recalculate_diffs_task: cx.spawn(|_, mut cx| async move {
let mut buffers_to_diff = HashSet::default();
while let Some(buffer) = recalculate_diffs_rx.next().await {
buffers_to_diff.insert(buffer);
while let Some(mut recalculate_diff) = recalculate_diffs_rx.next().await {
buffers_to_diff.insert(recalculate_diff.buffer);
loop {
while recalculate_diff.debounce {
cx.background_executor()
.timer(Duration::from_millis(250))
.await;
let mut had_further_changes = false;
while let Ok(next_buffer) = recalculate_diffs_rx.try_next() {
buffers_to_diff.insert(next_buffer?);
while let Ok(next_recalculate_diff) = recalculate_diffs_rx.try_next() {
let next_recalculate_diff = next_recalculate_diff?;
recalculate_diff.debounce &= next_recalculate_diff.debounce;
buffers_to_diff.insert(next_recalculate_diff.buffer);
had_further_changes = true;
}
if !had_further_changes {
@@ -92,8 +109,24 @@ impl ProposedChangesEditor {
event: &BufferEvent,
_cx: &mut ViewContext<Self>,
) {
if let BufferEvent::Edited = event {
self.recalculate_diffs_tx.unbounded_send(buffer).ok();
match event {
BufferEvent::Operation { .. } => {
self.recalculate_diffs_tx
.unbounded_send(RecalculateDiff {
buffer,
debounce: true,
})
.ok();
}
BufferEvent::DiffBaseChanged => {
self.recalculate_diffs_tx
.unbounded_send(RecalculateDiff {
buffer,
debounce: false,
})
.ok();
}
_ => (),
}
}
}
@@ -122,4 +155,93 @@ impl Item for ProposedChangesEditor {
fn tab_content_text(&self, _cx: &WindowContext) -> Option<SharedString> {
Some("Proposed changes".into())
}
fn as_searchable(&self, _: &View<Self>) -> Option<Box<dyn SearchableItemHandle>> {
Some(Box::new(self.editor.clone()))
}
fn act_as_type<'a>(
&'a self,
type_id: TypeId,
self_handle: &'a View<Self>,
_: &'a AppContext,
) -> Option<gpui::AnyView> {
if type_id == TypeId::of::<Self>() {
Some(self_handle.to_any())
} else if type_id == TypeId::of::<Editor>() {
Some(self.editor.to_any())
} else {
None
}
}
fn added_to_workspace(&mut self, workspace: &mut Workspace, cx: &mut ViewContext<Self>) {
self.editor.update(cx, |editor, cx| {
Item::added_to_workspace(editor, workspace, cx)
});
}
fn deactivated(&mut self, cx: &mut ViewContext<Self>) {
self.editor.update(cx, Item::deactivated);
}
fn navigate(&mut self, data: Box<dyn std::any::Any>, cx: &mut ViewContext<Self>) -> bool {
self.editor
.update(cx, |editor, cx| Item::navigate(editor, data, cx))
}
fn set_nav_history(
&mut self,
nav_history: workspace::ItemNavHistory,
cx: &mut ViewContext<Self>,
) {
self.editor.update(cx, |editor, cx| {
Item::set_nav_history(editor, nav_history, cx)
});
}
}
impl ProposedChangesEditorToolbar {
pub fn new() -> Self {
Self {
current_editor: None,
}
}
fn get_toolbar_item_location(&self) -> ToolbarItemLocation {
if self.current_editor.is_some() {
ToolbarItemLocation::PrimaryRight
} else {
ToolbarItemLocation::Hidden
}
}
}
impl Render for ProposedChangesEditorToolbar {
fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
let editor = self.current_editor.clone();
Button::new("apply-changes", "Apply All").on_click(move |_, cx| {
if let Some(editor) = &editor {
editor.update(cx, |editor, cx| {
editor.editor.update(cx, |editor, cx| {
editor.apply_all_changes(cx);
})
});
}
})
}
}
impl EventEmitter<ToolbarItemEvent> for ProposedChangesEditorToolbar {}
impl ToolbarItemView for ProposedChangesEditorToolbar {
fn set_active_pane_item(
&mut self,
active_pane_item: Option<&dyn workspace::ItemHandle>,
_cx: &mut ViewContext<Self>,
) -> workspace::ToolbarItemLocation {
self.current_editor =
active_pane_item.and_then(|item| item.downcast::<ProposedChangesEditor>());
self.get_toolbar_item_location()
}
}

View File

@@ -10,7 +10,7 @@ use crate::{
ExpandMacroRecursively,
};
static RUST_ANALYZER_NAME: &str = "rust-analyzer";
const RUST_ANALYZER_NAME: &str = "rust-analyzer";
fn is_rust_language(language: &Language) -> bool {
language.name() == "Rust".into()

View File

@@ -88,116 +88,3 @@ pub(crate) fn build_editor_with_project(
) -> Editor {
Editor::new(EditorMode::Full, buffer, Some(project), true, cx)
}
#[cfg(any(test, feature = "test-support"))]
pub fn editor_hunks(
editor: &Editor,
snapshot: &DisplaySnapshot,
cx: &mut ViewContext<'_, Editor>,
) -> Vec<(
String,
git::diff::DiffHunkStatus,
std::ops::Range<crate::DisplayRow>,
)> {
use multi_buffer::MultiBufferRow;
use text::Point;
use crate::hunk_status;
snapshot
.buffer_snapshot
.git_diff_hunks_in_range(MultiBufferRow::MIN..MultiBufferRow::MAX)
.map(|hunk| {
let display_range = Point::new(hunk.row_range.start.0, 0)
.to_display_point(snapshot)
.row()
..Point::new(hunk.row_range.end.0, 0)
.to_display_point(snapshot)
.row();
let (_, buffer, _) = editor
.buffer()
.read(cx)
.excerpt_containing(Point::new(hunk.row_range.start.0, 0), cx)
.expect("no excerpt for expanded buffer's hunk start");
let diff_base = buffer
.read(cx)
.diff_base()
.expect("should have a diff base for expanded hunk")
.slice(hunk.diff_base_byte_range.clone())
.to_string();
(diff_base, hunk_status(&hunk), display_range)
})
.collect()
}
#[cfg(any(test, feature = "test-support"))]
pub fn expanded_hunks(
editor: &Editor,
snapshot: &DisplaySnapshot,
cx: &mut ViewContext<'_, Editor>,
) -> Vec<(
String,
git::diff::DiffHunkStatus,
std::ops::Range<crate::DisplayRow>,
)> {
editor
.expanded_hunks
.hunks(false)
.map(|expanded_hunk| {
let hunk_display_range = expanded_hunk
.hunk_range
.start
.to_display_point(snapshot)
.row()
..expanded_hunk
.hunk_range
.end
.to_display_point(snapshot)
.row();
let (_, buffer, _) = editor
.buffer()
.read(cx)
.excerpt_containing(expanded_hunk.hunk_range.start, cx)
.expect("no excerpt for expanded buffer's hunk start");
let diff_base = buffer
.read(cx)
.diff_base()
.expect("should have a diff base for expanded hunk")
.slice(expanded_hunk.diff_base_byte_range.clone())
.to_string();
(diff_base, expanded_hunk.status, hunk_display_range)
})
.collect()
}
#[cfg(any(test, feature = "test-support"))]
pub fn expanded_hunks_background_highlights(
editor: &mut Editor,
cx: &mut gpui::WindowContext,
) -> Vec<std::ops::RangeInclusive<crate::DisplayRow>> {
use crate::DisplayRow;
let mut highlights = Vec::new();
let mut range_start = 0;
let mut previous_highlighted_row = None;
for (highlighted_row, _) in editor.highlighted_display_rows(cx) {
match previous_highlighted_row {
Some(previous_row) => {
if previous_row + 1 != highlighted_row.0 {
highlights.push(DisplayRow(range_start)..=DisplayRow(previous_row));
range_start = highlighted_row.0;
}
}
None => {
range_start = highlighted_row.0;
}
}
previous_highlighted_row = Some(highlighted_row.0);
}
if let Some(previous_row) = previous_highlighted_row {
highlights.push(DisplayRow(range_start)..=DisplayRow(previous_row));
}
highlights
}

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