Compare commits

...

203 Commits

Author SHA1 Message Date
Joseph T. Lyons
2182449e56 zed 0.177.11 2025-03-18 13:56:09 -04:00
Cole Miller
33d0340729 worktree: Fix tracking of git status scans and re-enable tests (#26926)
Closes #ISSUE

Release Notes:

- N/A
2025-03-18 13:48:02 -04:00
Cole Miller
157b78dc92 Disable flaky file status test again (#26925)
Failure on an unrelated commit:
https://github.com/zed-industries/zed/actions/runs/13903012863/job/38899239052

Release Notes:

- N/A
2025-03-18 13:47:08 -04:00
Cole Miller
88f5cdb4e8 Reinstate failing worktree tests (#26733)
Just debugging for now

Release Notes:

- N/A
2025-03-18 13:46:47 -04:00
Cole Miller
e8dab9c9af Fold git merge messages into commit editor placeholder text (#26992)
This PR changes the git commit message editors to surface git's
suggested merge message, if any, as placeholder text, as opposed to
"real" buffer text as was previously the case.

Release Notes:

- Changed git commit message editors to use placeholder text for git's
suggested merge messages
2025-03-18 13:42:06 -04:00
Cole Miller
af6da2d641 Add missing commit event reporting (#26990)
cc @morgankrey 

Release Notes:

- N/A
2025-03-18 13:39:39 -04:00
Cole Miller
8185c47594 git: Always zero panel's entry counts when clearing entries (#26924)
Keep the panel's state consistent even when we transition to having no
active repository.

Release Notes:

- N/A
2025-03-18 13:39:03 -04:00
Joseph T. Lyons
a829e03648 Send stable release notes email (#26964)
Release Notes:

- N/A
2025-03-17 23:26:11 -04:00
Joseph T. Lyons
f64820a1e1 zed 0.177.10 2025-03-17 14:08:44 -04:00
gcp-cherry-pick-bot[bot]
32b9ca125d Fix the feedback modal (cherry-pick #26793) (#26807)
Cherry-picked Fix the feedback modal (#26793)

Closes #26787

Release Notes:

- Fixed a bug that prevented typing in the in-app feedback form

Co-authored-by: Cole Miller <cole@zed.dev>
2025-03-14 18:17:55 -04:00
Joseph T. Lyons
4da6dfa89a zed 0.177.9 2025-03-14 10:43:11 -04:00
gcp-cherry-pick-bot[bot]
d6e24d3fe9 Allow parsing commits when we can't resolve the permalink (cherry-pick #26709) (#26735)
Cherry-picked Allow parsing commits when we can't resolve the permalink
(#26709)

Closes #26577

Release Notes:

- git: Fix showing commit messages for all repos

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-13 18:33:43 -04:00
Cole Miller
3f9c2bf81a worktree: Disable flaky test_file_status test (#26729)
See also:
- https://github.com/zed-industries/zed/pull/26684
- https://github.com/zed-industries/zed/pull/26710

Release Notes:

- N/A
2025-03-13 17:33:26 -04:00
gcp-cherry-pick-bot[bot]
140856c6f8 Fixes to excerpt movement actions and bindings + add multibuffer and singleton_buffer key contexts (cherry-pick #26264) (#26730)
Cherry-picked Fixes to excerpt movement actions and bindings + add
`multibuffer` and `singleton_buffer` key contexts (#26264)

Closes #26002 

Release Notes:

- Added `multibuffer` key context.
- `cmd-down` and `cmd-shift-down` on Mac now moves to the end of the
last line of a singleton buffer instead of the beginning. In
multibuffers, these now move to the start of the next excerpt.
- Fixed `vim::PreviousSectionEnd` (bound to `[ ]`) to move to the
beginning of the line, matching the behavior of `vim::NextSectionEnd`.
- Added `editor::MoveToStartOfNextExcerpt` and
`editor::MoveToEndOfPreviousExcerpt`.

Co-authored-by: Michael Sloan <michael@zed.dev>
2025-03-13 23:11:38 +02:00
gcp-cherry-pick-bot[bot]
7039018de1 Fix flicker when reverting last hunk from the project diff view (cherry-pick #26706) (#26711)
Cherry-picked Fix flicker when reverting last hunk from the project diff
view (#26706)

Closes #26696

Closes #ISSUE

Release Notes:

- git: Fix flicker when reverting last hunk in project diff view

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-13 16:55:28 -04:00
gcp-cherry-pick-bot[bot]
7634056f9a Don't render "Initialize Repository" button when no worktrees (cherry-pick #26713) (#26727)
Cherry-picked Don't render "Initialize Repository" button when no
worktrees (#26713)

Closes #26676  

Release Notes:

- Fixed the git panel to not show an "Initialize Repositories" button in
empty projects

Co-authored-by: Cole Miller <cole@zed.dev>
2025-03-13 16:49:38 -04:00
gcp-cherry-pick-bot[bot]
e3487e7829 Use system git for committing (cherry-pick #26705) (#26725)
Cherry-picked Use system git for committing (#26705)

Closes #26472

Release Notes:

- On macOS, switched to using the system's git binary to create commits.
This fixes issues that some users were seeing with pre-commit hooks.
Compatibility note: after this change, it is no longer possible to
commit from Zed unless git is installed.

Co-authored-by: Cole Miller <cole@zed.dev>
2025-03-13 16:49:10 -04:00
gcp-cherry-pick-bot[bot]
9df953dd1b git: Fix race condition when [un]staging hunks in quick succession (cherry-pick #26422) (#26718)
Cherry-picked git: Fix race condition when [un]staging hunks in quick
succession (#26422)

- [x] Fix `[un]stage` hunk operations cancelling pending ones
  - [x] Add test
- [ ] bugs I stumbled upon (try to repro again before merging)
  - [x] holding `git::StageAndNext` skips hunks randomly 
    - [x] Add test
  - [x] restoring a file keeps it in the git panel
- [x] Double clicking on `toggle staged` fast makes Zed disagree with
`git` CLI
- [x] checkbox shows ✔️ (fully staged) after a single
stage

Release Notes:

- N/A

---------

Co-authored-by: João Marcos <marcospb19@hotmail.com>
Co-authored-by: Cole <cole@zed.dev>
Co-authored-by: Max <max@zed.dev>
2025-03-13 17:18:49 -03:00
Peter Tripp
2bd2ad89df worktree: Disable flaky tests (test_write_file, test_git_status_postprocessing) (#26710)
Comment out flaky tests:
- `worktree_tests::test_write_file`
- `worktree_tests::test_git_status_postprocessing`

Job links:
- windows fail:
https://github.com/zed-industries/zed/actions/runs/13841766606/job/38730766252
- macos fail:
https://github.com/zed-industries/zed/actions/runs/13841766606/job/38730764118

That
[commit](85384fb9c6)
was a non-op script change, but in the [prior
commit](00359271d1)
[windows/macos
pass](https://github.com/zed-industries/zed/actions/runs/13841135221).

Similar experience with `worktree_tests::test_write_file` on both macOS
windows too.

- See also: https://github.com/zed-industries/zed/pull/26684

Release Notes:

- N/A
2025-03-13 15:17:25 -04:00
Peter Tripp
fe79166931 ci: Fix 'Run Tests' not always running (#26685)
Follow up to:
- https://github.com/zed-industries/zed/pull/26551

We need the "Tests Pass" step to run `if: always()`. 
Turns out when it's 'skipped', it counts as 'passing' with respect to
required status checks.


Release Notes:

- N/A
2025-03-13 15:04:25 -04:00
Peter Tripp
99d1bcbe78 ci: Use smaller windows runners (#26674)
Let's see if the speed of `windows-2025-32` for `windows_tests` is
fast-enough for PRs and everywhere else use `windows-2025-16`. Leaving
`windows_clippy` unchanged with `windows-2025-16`.

Release Notes:

- N/A
2025-03-13 14:02:14 -04:00
gcp-cherry-pick-bot[bot]
da7da16723 Fix being unable to put a cursor after trailing deletion hunks (cherry-pick #26621) (#26694)
Cherry-picked Fix being unable to put a cursor after trailing deletion
hunks (#26621)

Closes #26541

Release Notes:

- Fixed a bug that prevented putting the cursor after a deletion hunk at
the end of a file, in the absence of trailing newlines

---------

Co-authored-by: Max <max@zed.dev>

Co-authored-by: Cole Miller <cole@zed.dev>
Co-authored-by: Max <max@zed.dev>
2025-03-13 13:35:51 -04:00
Marshall Bowers
17aa999693 worktree: Disable flaky test_git_repository_status test (#26684)
This PR disables the flaky `test_git_repository_status` test.

Release Notes:

- N/A
2025-03-13 12:17:32 -04:00
Joseph T. Lyons
e37aa89984 zed 0.177.8 2025-03-13 10:17:08 -04:00
gcp-cherry-pick-bot[bot]
81e0367d31 theme: Fix incorrect version control keys in One themes (cherry-pick #26606) (#26623)
Cherry-picked theme: Fix incorrect version control keys in One themes
(#26606)

While the `.{variants}` of the theme keys _were_ incorrect, they are
actually more consistent with our current theme keys (thanks AI!) So we
will keep theme, and fix the incorrect usages in the one themes and
elsewhere.

Old description:
> 
> This PR fixes an issue where we specified the incorrect theme keys
(thanks AI!) > in the theme schema. The following keys have been changed
to their correct > versions:
> 
> | Before                        | After                   |
> |-------------------------------|-------------------------|
> | version_control.added         | version_control_added   |
> | version_control.deleted       | version_control_deleted |
> | version_control.modified      | version_control_modified|
> | version_control.renamed       | version_control_renamed |
> | version_control.conflict      | version_control_conflict|
> | version_control.ignored       | version_control_ignored |
> 
> Please use the after versions in your themes, as they are correct! 
> 
> We won't be adding secondary keys to fix this automatically as git
only > officially launched today.
> 
> Due to this change, we've also updated the version control keys in the
One > themes to keep the default diff hunks looks from changing.

Closes #26572

Release Notes:

- theme: Fixed an issue where version control colors weren't applying
correctly.

Co-authored-by: Nate Butler <iamnbutler@gmail.com>
2025-03-13 09:55:44 -04:00
Nate Butler
8979aa8440 gruvbox: version_control_ -> version_control. (#26665)
Missed this in PR #26606 

Before:

![CleanShot 2025-03-13 at 08 58
59@2x](https://github.com/user-attachments/assets/021df4b1-5a70-4fae-a109-9b8bb35949e3)

After:

![CleanShot 2025-03-13 at 08 59
22@2x](https://github.com/user-attachments/assets/01dca26d-77ec-4a54-8b7c-aa2fb160ff7d)

Release Notes:

- theme: Fixed an issue where version control colors weren't applying
correctly. (again)
2025-03-13 09:54:13 -04:00
Mikayla Maki
3f5bee3e23 Rename the editor::ToggleGitBlame action to git::Blame (#26565)
Release Notes:

- Git Beta: Renamed `editor::ToggleGitBlame` to `git::Blame`

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
Co-authored-by: Cole Miller <m@cole-miller.net>
Co-authored-by: Nathan Sobo <nathan@zed.dev>
Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
2025-03-12 22:35:11 -04:00
Conrad Irwin
ab6b368698 Fix overflow in create branch label (#26591)
Closes #ISSUE

Release Notes:

- N/A
2025-03-12 22:33:45 -04:00
Conrad Irwin
6d6998f0c8 git: Hard wrap in editor (#26507)
This adds the ability for the editor to implement hard wrap (similar to
"textwidth" in vim).

If you are typing and your line extends beyond the limit, a newline is
inserted before the most recent space on the line. If you are otherwise
editing the line, pasting, etc. then you will need to manually rewrap.

Release Notes:

- git: Commit messages are now wrapped "as you type" to 72 characters.
2025-03-12 22:27:55 -04:00
Alex Ozer
f0bc0bf007 Fix soft_wrap setting not applying to buffers starting with a different language (#25880)
Closes #22999 
# Problem

Currently, the default soft wrap mode of an editor is determined by
reading the language-specific settings of the language _at offset zero_
in the editor's (multi)buffer. While this provides a way to pick a
single soft wrap mode for a multi-language multibuffer, it's a bad
choice for a single-buffer multibuffer that begins with a different
embedded language. For example, Markdown with frontmatter:

```markdown
---
my_front_matter
---

# Hello World
```

Setting this in config:

```json
  "languages": {
    "Markdown": { "soft_wrap": "bounded" }
  },
```

Will not soft wrap the Markdown file as the language at offset zero is
YAML.

# Solution

Instead of using the language at offset zero, use the language of the
first buffer in the multibuffer (the buffer at offset zero). This gives
better behavior for single-buffer editors, and a similar default for
multi-language multibuffers as before.

# Testing

All existing `editor` crate tests pass, but I would appreciate any
guidance for where best to add additional testing.

Release Notes:

- Fixed soft_wrap setting not applying to buffers starting with a
different language

---------

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
2025-03-12 22:27:30 -04:00
Max Brunsfeld
3a681ecb5c Fix auto-indent when pasting multi-line content that was copied start… (#26246)
Closes https://github.com/zed-industries/zed/issues/24914 (again)

Release Notes:

- Fixed an issue where multi-line pasted content was auto-indented
incorrectly if copied from the middle of an existing line.
2025-03-12 22:02:48 -04:00
Peter Tripp
d0bd74be78 ci: Fix tests not-running on main (#26613)
Follow-up to #26551 

Fix for tests being skipped on main.
Also fetch less history: [example
run](https://github.com/zed-industries/zed/actions/runs/13822318758/job/38670334893)

Release Notes:

- N/A
2025-03-12 19:53:34 -04:00
Mikayla Maki
645d8ac58c Fix a bug where the modal layer could not be dismissed by the mouse 2025-03-12 16:46:17 -07:00
Peter Tripp
7f1ec5c221 ci: GitHub actions refactor (#26551)
Refactor GitHub actions CI workflow.
- Single combined 'tests_pass' action so we only need one mandatory
check for merge queue
- Add new `job_spec` job which determines what needs to be run (+5secs)
  - Do not run full CI for docs only changes (~30secs vs 10+mins)
- Only run `script/generate-licenses` if Cargo.lock changed (saves
~23secs on mac_test)
- Move prettier /docs check to ci.yml and remove docs.yml
- Run Windows tests on every PR commit
- Added new Windows runners named to reflect their OS/capacity
(windows-2025-64, windows-2025-32, windows-2025-16)

Release Notes:

- N/A
2025-03-12 17:57:34 -04:00
gcp-cherry-pick-bot[bot]
38cd1b853a Fix message on push (cherry-pick #26588) (#26594)
Cherry-picked Fix message on push (#26588)

Instead of saying "Successfully pushed new branch" we say "Pushed x to y"

Release Notes:

- N/A

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-12 17:47:25 -04:00
gcp-cherry-pick-bot[bot]
438d4c7979 Fix unstage/stage in project diff not working when git panel isn't open (cherry-pick #26575) (#26580)
Cherry-picked Fix unstage/stage in project diff not working when git
panel isn't open (#26575)

Closes #ISSUE

Release Notes:

- Fix Bug where unstage/stage all in project diff wouldn't work while
git panel was closed

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>

Co-authored-by: Anthony Eid <56899983+Anthony-Eid@users.noreply.github.com>
Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-12 13:51:47 -06:00
gcp-cherry-pick-bot[bot]
b56b4723d4 Git on main thread (cherry-pick #26573) (#26585)
Cherry-picked Git on main thread (#26573)

This moves spawning of the git subprocess to the main thread. We're not
yet
sure why, but when we spawn a process using GCD's background queues,
sub-processes like git-credential-manager fail to open windows.

This seems to be fixable either by using the main thread, or by using a
standard background thread,
but for now we use the main thread.


Release Notes:

- Git: Fix git-credential-manager

---------

Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
Co-authored-by: Kirill Bulatov <mail4score@gmail.com>

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
Co-authored-by: Kirill Bulatov <mail4score@gmail.com>
2025-03-12 13:51:25 -06:00
Joseph T. Lyons
ab9b3f1ba3 v0.177.x stable 2025-03-12 12:52:45 -04:00
Julia Ryan
c20682336b Disable uncommit button for parentless commits (#25983)
Closes #25976

There's a couple states that this covers:
- upon `git init`, no footer is shown at all
- after 1 commit (or when on any parentless commit), the uncommit button
is ~disabled~ hidden
- otherwise commit button is shown

Also updated the button with "meta" tooltip showing human readable
description and git command.

Release Notes:

- N/A

---------

Co-authored-by: Nate Butler <iamnbutler@gmail.com>
2025-03-12 09:39:55 -07:00
Nate Butler
ca1ec68399 git_ui: Update Project Diff empty state design (#26554)
Title

Release Notes:

- N/A

---------

Co-authored-by: Cole Miller <m@cole-miller.net>
2025-03-12 12:24:07 -04:00
Danilo Leal
cf2a11ccde docs: Update the Git page (#26530)
So it reflects the new set of features supported starting from v0.177.

Release Notes:

- N/A
2025-03-12 12:23:59 -04:00
Mikayla Maki
06d9fbe675 git: Add an onboarding and banner flow (#26518)
TODO:

- [ ] Hide the reset onboarding action (only useful for development,
uncomment:
https://github.com/zed-industries/zed/pull/26518/files#diff-f0ce01d9a3df30f60c64b6f9906c54aa0191246a58dbf5297ee321575a180879R96)
- [x] Get a designer to replace the modal background (@danilo-leal)

Release Notes:

- Added a small onboarding banner for the git launch

---------

Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
Co-authored-by: Danilo Leal <67129314+danilo-leal@users.noreply.github.com>
2025-03-12 12:21:13 -04:00
Nils Koch
f143d1b86e Check if additional git provider is not the original git provider (#26533)
Release Notes:

- N/A

Yesterday I worked on https://github.com/zed-industries/zed/pull/26482
and noticed afterwards that we have duplicated hosting providers if the
git remote host is "gitlab.com" and after the PR also for "github.com".
This is not a big problem, since the original providers are registered
first and therefore we first find a match with the original providers,
but I think we should address this nevertheless.

We initialize every hosting provider with the defaults here:

b008b2863e/crates/git_hosting_providers/src/git_hosting_providers.rs (L15-L24)

After that, we also register additional hosting providers:

b008b2863e/crates/git_hosting_providers/src/git_hosting_providers.rs (L30-L43)

If we do not check if the additional provider is not the original
provider, we will register the same provider twice.

---------

Co-authored-by: Marshall Bowers <git@maxdeviant.com>
2025-03-12 10:51:37 -04:00
Cole Miller
7728a8bffb git: Fix placeholder dots in untracked files (#26537)
This regressed at some point.

Release Notes:

- N/A
2025-03-12 10:18:54 -04:00
Nils Koch
d8bc10ec58 Add detection of self hosted GitHub enterprise instances (#26482)
This PR does not close an issue, but it is an issue and and fix in one.
I hope this is ok, but please let me know if you prefer me to open an
issue before.

Release Notes:

- Add "copy permalink" action for self-hosted GitHub enterprise
instances

# Issue
### Related issues:
* https://github.com/zed-industries/zed/issues/26393
* https://github.com/zed-industries/zed/issues/11043

When you try to copy a permalink from a self-hosted GitHub enterprise
instance, you get the following error:

<img width="383" alt="permalink"
src="https://github.com/user-attachments/assets/b32338a7-a2d7-48fc-86bf-ade1d32ed1f7"
/>

You also cannot open a PR or commit when you hover over a git blame:


https://github.com/user-attachments/assets/a5491ce7-270b-412f-b9ac-027ec020b028


### Reproduce
If you do not have access to a self-hosted GitHub instance, you can
change the remote url of any git repo:
```
git remote set-url origin git@github.mycorp.com:nilskch/zed.git
```

With the fix, permalinks still won't bring you to a valid website, but
you can verify that they are correctly created.

# Solution

Currently, we only support detecting self-hosted GitLab instances, but
not self-hosted GitHub instances. We detect GitLab instances by checking
if "gitlab" is part of the git URL.

This PR adds the same logic to detect self-hosted GitHub enterprise
instances (by checking if "github" is in the URL).

This solution is not ideal, since self-hosted GitHub or GitLab instances
might not contain the word "github" or "gitlab". #26393 proposes adding
a setting that would allow users to map specific domains to their
corresponding git provider types. This mapping would help Zed correctly
identify the appropriate git instance, even if "gitlab" or "github" are
not part of the URL.

This PR does not implement the offered solution, but I added a TODO
where the fix for #26393 has to make changes.
2025-03-12 09:47:38 -04:00
gcp-cherry-pick-bot[bot]
896276fc4a Don't clobber the user's upstream settings (cherry-pick #26486) (#26528)
Cherry-picked Don't clobber the user's upstream settings (#26486)

It's not clobbering time :(

Release Notes:

- Git Beta: Fixed a bug where our push button would always overwrite the
current branch's upstream

Co-authored-by: Mikayla Maki <mikayla@zed.dev>
2025-03-12 00:53:46 -07:00
Mikayla Maki
828dd3cf39 Add git init button (#26522)
Because why not

Release Notes:

- N/A
2025-03-12 00:42:09 -07:00
Julia Ryan
0bea86d065 Rework git toasts (#26420)
The notifications from git output could take up variable amounts of
screen space, and they were quite obnoxious when a git command printed
lots of output, such as fetching many new branches or verbose push
hooks.

This change makes the push/pull/fetch buttons trigger a small
notification toast, based on the output of the command that was ran. For
errors or commands with more output the user may want to see, there's an
"Open Log" button which opens a new buffer with the output of that
command.

It also uses this behavior for long error notifications for other git
commands like `commit` and `checkout`. The output of those commands can
be quite long due to arbitrary githooks running.

Release Notes:

- N/A

---------

Co-authored-by: Mikayla Maki <mikayla.c.maki@gmail.com>
2025-03-12 00:35:46 -07:00
gcp-cherry-pick-bot[bot]
6a3204cf1d Hide generate commit message button when assistant is disabled (cherry-pick #26519) (#26521)
Cherry-picked Hide generate commit message button when assistant is
disabled (#26519)

Release Notes:

- Git Beta: Fixed the generate commit message button still showing when
the assistant is disabled.

Co-authored-by: Mikayla Maki <mikayla@zed.dev>
2025-03-11 23:11:04 -07:00
gcp-cherry-pick-bot[bot]
6247405396 git: Remove hunk style setting (cherry-pick #26504) (#26517)
Cherry-picked git: Remove hunk style setting (#26504)

Co-authored-by: Cole Miller <cole@zed.dev>
2025-03-11 21:58:49 -07:00
gcp-cherry-pick-bot[bot]
4d521a6f71 git: Prevent up and down motions leaking out of the commit editor (cherry-pick #26501) (#26509) 2025-03-12 00:15:08 -04:00
gcp-cherry-pick-bot[bot]
a34e00e511 Fix git panel entries getting cut off (cherry-pick #26499) (#26500)
Cherry-picked Fix git panel entries getting cut off (#26499)

Closes #26497 

Release Notes:

- N/A

Co-authored-by: Cole Miller <cole@zed.dev>
2025-03-11 20:01:37 -04:00
gcp-cherry-pick-bot[bot]
6ef3870d5f git_ui: Truncate long repository and branch names for respective selectors in panel (cherry-pick #26483) (#26488)
Cherry-picked git_ui: Truncate long repository and branch names for
respective selectors in panel (#26483)

This PR fixes a long repo name pushing the branch selector off the
screen, as well as just generally truncating them down in a way smarter
than a fixed character limit when long.

| Before | After |
|---------|-----------|
| ![CleanShot 2025-03-11 at 17 21

31@2x](https://github.com/user-attachments/assets/8762b5a7-883c-4080-a6cf-e8007c4737e7)
| ![CleanShot 2025-03-11 at 17 21

44@2x](https://github.com/user-attachments/assets/c3904c29-d939-445f-b700-5bf73f257256)
|


Release Notes:

- Git Panel: Smart truncate long branch and repository names in their
respective selectors

Co-authored-by: Nate Butler <iamnbutler@gmail.com>
2025-03-11 16:14:30 -07:00
gcp-cherry-pick-bot[bot]
70247843db Fix conflict marker in project diff view (cherry-pick #26466) (#26492)
Cherry-picked Fix conflict marker in project diff view (#26466)

Closes #ISSUE

Release Notes:

- N/A

Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
2025-03-11 16:14:19 -07:00
gcp-cherry-pick-bot[bot]
c5c3c79a70 git_ui: Panel Horizontal Scroll (cherry-pick #26402) (#26496)
Cherry-picked git_ui: Panel Horizontal Scroll (#26402)

Known Issues:
- When items can horizontal scroll, the right selected border is hidden

TODO:
- [ ] Width calculation is off
- [ ] When scrollbars should autohide they don't until hovering the
panel
- [ ] When switching to and from scrollbar track being visible we are
missing a notify somewhere.

Release Notes:

- Git Panel: Added horizontal scrolling in the git panel

---------

Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
Co-authored-by: Cole Miller <m@cole-miller.net>
Co-authored-by: Cole Miller <cole@zed.dev>

Co-authored-by: Nate Butler <iamnbutler@gmail.com>
Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
Co-authored-by: Cole Miller <m@cole-miller.net>
Co-authored-by: Cole Miller <cole@zed.dev>
2025-03-11 16:14:08 -07:00
gcp-cherry-pick-bot[bot]
bbea043d42 Git panel editor scroll (cherry-pick #26465) (#26493)
Cherry-picked Git panel editor scroll (#26465)

Release Notes:

- N/A

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-11 16:14:00 -07:00
gcp-cherry-pick-bot[bot]
b7a242b22e Tweak stage/unstage-and-next to start a commit instead of wrapping in the project diff editor (cherry-pick #26434) (#26490)
Cherry-picked Tweak stage/unstage-and-next to start a commit instead of
wrapping in the project diff editor (#26434)

Release Notes:

- Git Beta: improved the stage-and-next and unstage-and-next actions in
the project diff editor to start a commit after acting on the last hunk

Co-authored-by: Cole Miller <cole@zed.dev>
2025-03-11 18:29:22 -04:00
Joseph T. Lyons
ac209f11f6 zed 0.177.7 2025-03-11 13:02:24 -04:00
gcp-cherry-pick-bot[bot]
44a43c72d0 Address out-of-bounds panic in inline completion button (cherry-pick #26394) (#26440)
Cherry-picked Address out-of-bounds panic in inline completion button
(#26394)

Closes #26350

Release Notes:

- Git Beta: Fixed a panic that could occur when using the project diff

Co-authored-by: Cole Miller <cole@zed.dev>
2025-03-11 11:54:25 -04:00
gcp-cherry-pick-bot[bot]
74c1ec5bac Show a disabled stage all button for no entries (cherry-pick #26436) (#26437)
Cherry-picked Show a disabled stage all button for no entries (#26436)

Closes #ISSUE

Release Notes:

- N/A

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-11 01:11:14 -04:00
gcp-cherry-pick-bot[bot]
61187a974e Fix enter binding in git panel's commit editor on Linux (cherry-pick #26427) (#26438)
Cherry-picked Fix enter binding in git panel's commit editor on Linux
(#26427)

Closes #26110 

Release Notes:

- Git Beta: fixed being unable to enter newline in the git panel's
commit editor on Linux

Co-authored-by: Cole Miller <cole@zed.dev>
2025-03-11 00:38:18 -04:00
Conrad Irwin
2da767d545 Go back to "create branch" in the list (#26433)
Closes #ISSUE

Release Notes:

- N/A
2025-03-10 22:26:51 -06:00
gcp-cherry-pick-bot[bot]
58bb9f344f Git commit modal branch list (cherry-pick #26417) (#26435)
Cherry-picked Git commit modal branch list (#26417)

Closes #26273

Release Notes:

- git: Fixes opening the branch selector in the commit modal with
cmd-option-b
- git: Truncates the branch selector in the commit modal

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-10 22:25:57 -06:00
gcp-cherry-pick-bot[bot]
8c3585d9b6 git_ui: Show more information in the branch picker (cherry-pick #25359) (#26432)
Cherry-picked git_ui: Show more information in the branch picker
(#25359)

Final product:

![CleanShot 2025-02-26 at 9  08

17@2x](https://github.com/user-attachments/assets/e5db1932-b2c6-4b32-ab67-ef0a0d19f022)

Release Notes:

- Added more information about Git branches to the branch picker.

---------

Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
Co-authored-by: Marshall Bowers <git@maxdeviant.com>
Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>

Co-authored-by: Angelk90 <20476002+Angelk90@users.noreply.github.com>
Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
Co-authored-by: Marshall Bowers <git@maxdeviant.com>
Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-10 21:58:52 -06:00
gcp-cherry-pick-bot[bot]
1365247ff6 Use current upstream for permalink to line (cherry-pick #26398) (#26429)
Cherry-picked Use current upstream for permalink to line (#26398)

Release Notes:

- git: Copy permalink to line now uses the upstream of the current
branch instead of "origin"

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-10 21:49:34 -06:00
gcp-cherry-pick-bot[bot]
f4028ef9ad Unwind deprecated permalinks code (cherry-pick #26395) (#26426)
Cherry-picked Unwind deprecated permalinks code (#26395)

Release Notes:

- N/A

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-10 20:54:06 -06:00
Max Brunsfeld
7fa916a488 Fix race conditions in updating buffer diffs on git changes (#26409)
Release Notes:

- N/A

---------

Co-authored-by: Cole Miller <m@cole-miller.net>
2025-03-10 16:53:05 -07:00
gcp-cherry-pick-bot[bot]
198ecff6ad Fix panic opening branch picker in commit modal (cherry-pick #26407) (#26413)
Cherry-picked Fix panic opening branch picker in commit modal (#26407)

Closes #ISSUE

Release Notes:

- N/A

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-10 16:58:07 -06:00
gcp-cherry-pick-bot[bot]
a4b9b5df8b Git commit modal command (cherry-pick #26405) (#26411)
Cherry-picked Git commit modal command (#26405)

Fix KeyBinding::for_action() to use the active focus handle instead of
what was
rendered last.

This makes the UI consistently chose the cmd-escape binding for close
(because escape in the editor is editor::Cancel?),
so force it to be "escape"

Release Notes:

- git: Fixed escape tooltip in commit modal

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-10 16:36:31 -06:00
gcp-cherry-pick-bot[bot]
633df53388 Add a missing notify when updating the project diff (cherry-pick #26396) (#26400)
Cherry-picked Add a missing notify when updating the project diff
(#26396)

Closes #ISSUE

Release Notes:

- Git Beta: Fixed a bug that caused the project diff not to update in
response to git-related events

Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>

Co-authored-by: Cole Miller <cole@zed.dev>
Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
2025-03-10 17:31:21 -04:00
Nate Butler
790fb9e5cb git_ui: Design Polish (#26361)
Polish PR

- [ ] Horizontal scrollbar for git panel
- [ ] Allow shift clicking a checkbox in any section to stage the whole
section
- [ ] Clean up design of no changes/pending push state in panel
- [x] Ensure checkbox placeholder dot is centered in the checkbox
- [x] Improve spacing between elements in git panel entries
- [x] Update git branch icon to match branch selector text when disabled
- [x] Truncate last commit message less aggressively in panel
- [x] Clean up new panel header design
- [x] Remove `_background` version control keys (backgrounds are derived
from the foreground colors)

Before:

![CleanShot 2025-03-10 at 11 54
32@2x](https://github.com/user-attachments/assets/46b18f66-bb5c-435e-a0da-6cc931bd8a15)

After:

![CleanShot 2025-03-10 at 11 55
24@2x](https://github.com/user-attachments/assets/fcf688c7-b949-41a2-a7b8-1a198eb7fa4a)

Before:

![CleanShot 2025-03-10 at 12 02
14@2x](https://github.com/user-attachments/assets/1990f4b3-c2f0-4e02-89ad-211aaebb3821)

After:

![CleanShot 2025-03-10 at 12 02
53@2x](https://github.com/user-attachments/assets/9b1caf65-c48f-44c9-924b-484892fb543f)

Release Notes:

- N/A *or* Added/Fixed/Improved ...

---------

Co-authored-by: Cole Miller <cole@zed.dev>
Co-authored-by: Cole Miller <m@cole-miller.net>
Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
2025-03-10 17:27:51 -04:00
gcp-cherry-pick-bot[bot]
17c0113390 Remove GitUiFeatureFlag and enable panel unconditionally (cherry-pick #26386) (#26392)
Cherry-picked Remove GitUiFeatureFlag and enable panel unconditionally
(#26386)

Release Notes:

- git: Enable for everyone

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-10 14:50:16 -06:00
gcp-cherry-pick-bot[bot]
cb8d667cdb Scroll project diff into view always (cherry-pick #26379) (#26387)
Cherry-picked Scroll project diff into view always (#26379)

Closes #ISSUE

Release Notes:

- N/A

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-10 12:40:32 -06:00
Conrad Irwin
6d7943419b Git keyboard shortcuts (#26374)
Closes #26040

Release Notes:

- git: Add keyboard shortcuts (when the panel is open) for fetch `ctrl-g
ctrl-g`, pull `ctrl-g down`, push `ctrl-g up`, force-push `ctrl-g
shift-up`, open diff `ctrl-g d`
2025-03-10 12:28:45 -06:00
gcp-cherry-pick-bot[bot]
d474438c9d Restore git panel header (cherry-pick #26354) (#26380)
Cherry-picked Restore git panel header (#26354)

Let's play around with it. This should not be added to tomorrow's
preview.

Release Notes:

- Git Beta: Added a panel header with an open diff and stage/unstage all
buttons.

Co-authored-by: Mikayla Maki <mikayla@zed.dev>
2025-03-10 12:27:59 -06:00
gcp-cherry-pick-bot[bot]
c21ab404e5 git: Pass project environment to git binary invocations (cherry-pick #26301) (#26373)
Cherry-picked git: Pass project environment to git binary invocations
(#26301)

Closes #26213 

Release Notes:

- Git Beta: pass down environment variables from project to git
operations

Co-authored-by: Cole Miller <cole@zed.dev>
2025-03-10 12:31:30 -04:00
Joseph T. Lyons
4b24ef3d7e zed 0.177.6 2025-03-10 12:31:01 -04:00
João Marcos
1d7ffff974 Remove redundant checks in do_stage_or_unstage_and_next (#26364)
Release Notes:

- N/A
2025-03-10 12:26:47 -04:00
gcp-cherry-pick-bot[bot]
44c93b087f git_ui: Branch picker improvements (cherry-pick #26287) (#26371)
Cherry-picked git_ui: Branch picker improvements (#26287)

- Truncate branch names based on the width of the picker
- Use a footer for "Create branch" instead of a picker entry

Still to do:

- [x] Select the footer button when no matches and run the create logic
on `enter`
- [x] Make it possible to quickly select the footer button from the
keyboard when there are matches

Release Notes:

- Git Beta: Removed limitation that made it impossible to create a
branch from the branch picker when it too closely resembled an existing
branch name

Co-authored-by: Cole Miller <cole@zed.dev>
2025-03-10 12:12:36 -04:00
Richard Hao
4144a2e37c git: Disable commit message generation when commit not possible (#26329)
## Issue:

- `Generate Commit Message` will generate a random message if there are
no changes.
<img width="614" alt="image"
src="https://github.com/user-attachments/assets/c16cadac-01af-47c0-a2db-a5bbf62f84bb"
/>


## After Fixed:

- `Generate Commit Message` will be disabled if commit is not possible
<img width="610" alt="image"
src="https://github.com/user-attachments/assets/5ea9ca70-6fa3-4144-ab4e-be7a986d5496"
/>


## Release Notes:

- Fixed: Disable commit message generation when commit is not possible
2025-03-10 02:49:24 -04:00
Max Brunsfeld
1eff87c2f6 Follow-up fixes for recent multi buffer optimizations (#26345)
I realized that the optimization broke multi buffer syncing after buffer
reparses.

Release Notes:

- N/A
2025-03-09 22:16:28 -07:00
Danilo Leal
25997137fc git: Refine diff hunk controls visuals (#26317)
You may need to zoom in hard to see this 😅 but the main addition of this
PR is just ensuring there's also horizontal border instead of just on
the bottom. Also added some box-shadow here to make it pop out of the
diff a bit more.

| Before | After |
|--------|--------|
| ![CleanShot 2025-03-08 at 12  37
40@2x](https://github.com/user-attachments/assets/98e0329e-646f-4455-89fa-3f6ec1211361)
| ![CleanShot 2025-03-08 at 12  36
40@2x](https://github.com/user-attachments/assets/7f667e65-5b72-4156-b0ec-2b162eb76f2f)
|

Release Notes:

- N/A
2025-03-10 00:15:58 -04:00
Max Brunsfeld
ea2df99770 Fix performance bottlenecks when multi buffers have huge numbers of buffers (#26308)
This is motivated by trying to make the Project Diff view usable with
huge Git change sets.

Release Notes:

- Improved performance of rendering multibuffers with very large numbers
of buffers
2025-03-10 00:15:58 -04:00
Mikayla Maki
6c574fa94c Git UI papercuts (#26316)
Release Notes:

- Git Beta: added `git:Add` as an alias for the existing `git::Diff`
- Git Beta: Fixed a bug where the 'generate commit message' keybinding
wasn't working.
- Git Beta: Made the empty project diff state a little more helpful with
a button to push, and a button to close the item.
2025-03-10 00:15:58 -04:00
Mikayla Maki
783e239d52 Add git branch switching aliases (#26315)
This gives us _very_ rudimentary support for `git switch` and `git
checkout` now, by making them aliases for our existing `git::branch`
call.

Release Notes:

- Git Beta: Added `git::Switch` and `git::CheckoutBranch` as aliases for
the existing `git::Branch`
2025-03-10 00:09:38 -04:00
Mikayla Maki
4c455ca96e Improve when the commit suggestions would show (#26313)
Release Notes:

- Git Beta: Fixed a few bugs where the suggested commit text wouldn't
show in certain cases, or would update slowly.
2025-03-10 00:08:59 -04:00
Kiran_Peraka
270e47cc79 git: Fix errors not showing in the toast notification (#26303)
Release Notes:

- Resolved an issue where error messages from Git were not being
displayed in toast notifications.
<img width="1702" alt="Screenshot 2025-03-08 at 1 11 30 AM"
src="https://github.com/user-attachments/assets/a46517db-4e64-4c5e-a64e-96e820ca9aec"
/>
2025-03-10 00:08:50 -04:00
Mikayla Maki
c075dd5bd6 Change the default staging and unstaging state display (#26299)
This adds a setting for the "border" hunk display mode, as discussed,
and makes it the default.

Here's how it looks in light mode:

<img width="1512" alt="Screenshot 2025-03-07 at 11 39 25 AM"
src="https://github.com/user-attachments/assets/a934faa3-ec69-47e1-ad46-535e48b98e9f"
/>

And dark mode:

<img width="1511" alt="Screenshot 2025-03-07 at 11 39 56 AM"
src="https://github.com/user-attachments/assets/43c9afd1-22bb-4bd8-96ce-82702a6cbc80"
/>

Release Notes:

- Git Beta: Adjusted the default hunk styling for staged and unstaged
changes

Co-authored-by: Conrad <conrad@zed.dev>
Co-authored-by: Nate <nate@zed.dev>
2025-03-10 00:08:27 -04:00
Conrad Irwin
3129e3dcf5 Remove worktree and project notifies (#26244)
This reduces the number of multibuffer syncs from 100,000 to 20,000.
Before this change each editor individually observed the project, so
literally any project change was amplified by the number of editors you
had open.

Now editors listen to their buffers instead of the project, and other
users of `cx.observe` on the project have been updated to use specific
events to reduce churn.

Follow up to #26237

Release Notes:

- Improved performance of Zed in large repos with lots of file system
events.

---------

Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
(cherry picked from commit 80fb88520f)
2025-03-10 00:06:01 -04:00
Conrad Irwin
dfbfcdfa2c Track dirtyness per item (#26237)
This reduces the number of multibuffer syncs when starting the editor
with 80
files open in the Zed repo from 10,000,000 to 100,000 by avoiding
O(n**2)
dirtyness checks.

Release Notes:

- Fixed a beachball when restarting in a large repo with a large number
open files
2025-03-10 00:06:01 -04:00
gcp-cherry-pick-bot[bot]
53ff7ca27d worktree: Add some info-level logging about added and removed repository entries (cherry-pick #26291) (#26292)
Cherry-picked worktree: Add some info-level logging about added and
removed repository entries (#26291)

Trying to track down a user's reported issue with parent repositories
not getting picked up.

Release Notes:

- N/A

Co-authored-by: Cole Miller <cole@zed.dev>
2025-03-07 14:02:36 -05:00
Joseph T. Lyons
0a391abaa4 zed 0.177.5 2025-03-07 13:55:22 -05:00
Marshall Bowers
e29fb616ed git_ui: Try to prompt the model out of including the diff output (#26281)
This PR updates the prompt for generating commit messages to tell the
model not to include the raw diff output in the message.

Release Notes:

- N/A
2025-03-07 13:50:30 -05:00
Kirill Bulatov
9db97b887c Fix inline diagnostics in the project diff (#26275)
205f9a9f03/crates/editor/src/element.rs (L1643)

Due to the snippet above, Zed is supposed to have `row` larger or equal
to `start_row` here:


205f9a9f03/crates/editor/src/element.rs (L1694)

yet the panic were reported when clicking in the project diff.

That project diff has a lot of highlighting happening already, so the PR
disables inline diagnostics within a git diff view.


Release Notes:

- N/A
2025-03-07 13:50:30 -05:00
loczek
871bca5b4d git: Fix git panel not using default width (#26220)
Closes #26062

Removing the width here causes zed to use the default value (inside
default settings) after restart like other panels.

Release Notes:

- Fixed issue where git panel wasn't using default width after restart

Co-authored-by: Mikayla Maki <mikayla@zed.dev>
2025-03-07 13:50:30 -05:00
Mikayla Maki
6dde040b97 Add staged variants of the hunk_style controls (#26259)
This PR adds a few more hunk style settings that flips the emphasis.
Normally, the concept at Zed has been that the project diff should
emphasize what's going into the commit. However, this leads to a problem
where the default state of all diff hunks are in the non-emphasized
state, making them hard to see and interact with. Especially on light
themes. This PR is an experiment in flipping the emphasis states. Now
the project diff is more like a queue of work, with the next "job" (hunk
to be evaluated) emphasized, and the "completed" (staged) hunks
deemphasized. This fixes the default state issue but is a big jump from
how we've been thinking about it. So here we can try it out and see how
it feels :)

Release Notes:

- Git Beta: Added hunk style settings to emphasize the unstaged state,
rather than the staged state.
2025-03-07 13:49:32 -05:00
Mikayla Maki
d6190dbe4f Restore co-author hiding (#26257)
Release Notes:

- N/A
2025-03-07 13:49:32 -05:00
Marshall Bowers
7365cac495 Improve the generate commit message design (#26233)
[WIP]

Release Notes:

- N/A

---------

Co-authored-by: Mikayla Maki <mikayla.c.maki@gmail.com>
Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
2025-03-07 13:49:32 -05:00
Cole Miller
84f8b86fb9 Fix paths on Windows in new test (#26255)
Closes #ISSUE

Release Notes:

- N/A *or* Added/Fixed/Improved ...
2025-03-07 13:49:32 -05:00
Cole Miller
e53389fd53 Disable restore hunk control for created files (#25841)
Release Notes:

- Git Beta: disable hunk restore action and button for created files
2025-03-07 13:49:32 -05:00
Nate Butler
12fb23bf62 Add StatusToast & the ToastLayer (#26232)
https://github.com/user-attachments/assets/b16e32e6-46c6-41dc-ab68-1824d288c8c2

This PR adds the first part of our planned extended notification system:
StatusToasts.

It also makes various updates to ComponentPreview and adds a `Styled`
extension in `ui::style::animation` to make it easier to animate styled
elements.

_**Note**: We will be very, very selective with what elements are
allowed to be animated in Zed. Assume PRs adding animation to elements
will all need to be manually signed off on by a designer._

## Status Toast

![CleanShot 2025-03-06 at 14 15
52@2x](https://github.com/user-attachments/assets/b65d4661-f8d1-4e98-b9be-2c05cba1409f)

These are designed to be used for notifying about things that don't
require an action to be taken or don't need to be triaged. They are
designed to be ignorable, and dismiss themselves automatically after a
set time.

They can optionally include a single action. 

Example: When the user enables Vim Mode, that action might let them undo
enabling it.

![CleanShot 2025-03-06 at 14 18
34@2x](https://github.com/user-attachments/assets/eb6cb20e-c968-4f03-88a5-ecb6a8809150)

Status Toasts should _not_ be used when an action is required, or for
any binary choice.

If the user must provide some input, this isn't the right component!

### Out of scope

- Toasts should fade over a short time (like AnimationDuration::Fast or
Instant) when dismissed
- We should visually show when the toast will dismiss. We'll need to
pipe the `duration_remaining` from the toast layer -> ActiveToast to do
this.
- Dismiss any active toast if another notification kind is created, like
a Notification or Alert.

Release Notes:

- N/A

---------

Co-authored-by: Cole Miller <m@cole-miller.net>
2025-03-07 13:14:44 -05:00
Joseph T. Lyons
75f7def31c Add event to track LLM-generated commit messages (#26245)
Release Notes:

- N/A
2025-03-07 13:13:51 -05:00
Marshall Bowers
9195cd5233 git_ui: Add support for generating commit messages with an LLM (#26227)
This PR finishes up the support for generating commit messages using an
LLM.

We're shelling out to `git diff` to get the diff text, as it seemed more
efficient than attempting to reconstruct the diff ourselves from our
internal Git state.


https://github.com/user-attachments/assets/9bcf30a7-7a08-4f49-a753-72a5d954bddd

Release Notes:

- Git Beta: Added support for generating commit messages using a
language model.

---------

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-07 13:13:17 -05:00
Marshall Bowers
f0be14277a git_ui: Scaffold out support for generating commit messages with an LLM (#26161)
This PR adds the rough structure needed to support generating commit
messages using an LLM.

This functionality is not yet surfaced to the user.

This is the current state, if you tweak the source to show the button:

https://github.com/user-attachments/assets/66d1fbc4-09f3-4277-84f4-e9c9ebab274c

Release Notes:

- N/A
2025-03-07 13:12:46 -05:00
Cole Miller
0dec6fbfab Cherry-pick: Worktree paths in git panel, take 2 (#26047) (#26252)
Release Notes:

- Git Beta: updated the git panel to use worktree-relative paths and
support opening files outside the active repository's worktree
2025-03-06 19:26:27 -05:00
Max Brunsfeld
4f8a094c11 Fix early return when reaching end excerpt in lift_buffer_metadata (#26253)
Release Notes:

- Fixed a bug causing slowness when viewing multi buffers with lots of
excerpts
2025-03-06 16:26:15 -08:00
gcp-cherry-pick-bot[bot]
43c81067c7 Disable restore hunk control for created files (cherry-pick #25841) (#26251)
Cherry-picked Disable restore hunk control for created files (#25841)

Release Notes:

- Git Beta: disable hunk restore action and button for created files

Co-authored-by: Cole Miller <cole@zed.dev>
2025-03-06 18:51:36 -05:00
gcp-cherry-pick-bot[bot]
b7b700e4f7 language_models: Remove .unwraps in Bedrock provider (cherry-pick #26238) (#26241)
Cherry-picked language_models: Remove `.unwrap`s in Bedrock provider
(#26238)

This PR removes a number of `.unwrap`s in the Bedrock provider.

We must not `.unwrap` in situations where it is not provably safe to do
so, which it was not in any of these cases.

Release Notes:

- Fixed some potential panics in the AWS Bedrock model provider.

Co-authored-by: Marshall Bowers <git@maxdeviant.com>
2025-03-06 16:18:28 -05:00
gcp-cherry-pick-bot[bot]
f3fb7b776d Git telemetry (cherry-pick #26222) (#26229)
Cherry-picked Git telemetry (#26222)

Release Notes:

- git: Adds telemetry to git actions

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-06 11:40:53 -07:00
Conrad Irwin
decfd9877a Git askpass (#25953)
Supersedes #25848

Release Notes:

- git: Supporting push/pull/fetch when remote requires auth

---------

Co-authored-by: Mikayla Maki <mikayla.c.maki@gmail.com>
2025-03-06 10:46:00 -07:00
Max Brunsfeld
661e36f736 Clear pending staged/unstaged diff hunks hunks when writing to the git index fails (#26173)
Release Notes:

- Git Beta: Fixed a bug where discarding a hunk in the project diff view
performed two concurrent saves of the buffer.
- Git Beta: Fixed an issue where diff hunks appeared in the wrong state
after failing to write to the git index.
2025-03-06 10:45:52 -07:00
Julia Ryan
c80d25174f Git uncommit warning (#25977)
Adds a prompt when clicking the uncommit button when the current commit
is already present on a remote branch:

![screenshot showing
prompt](https://github.com/user-attachments/assets/d6421875-588e-4db0-aee0-a92f36bce94b)

Release Notes:

- N/A

---------

Co-authored-by: Conrad <conrad@zed.dev>
2025-03-06 10:44:54 -07:00
Peter Tripp
420bb84152 ci: Less Windows CI for PRs (#26155)
Split Windows GHA CI job into `windows_clippy` and `windows_tests`
(`cargo test` and `cargo build`). `windows_clippy` will continue to run
on every PR commit, but `windows_tests` will only be run on main. Tag a
PR `windows` if you would like to run windows tests.

Added a call to the Azure metadata service to detect the Azure hardware
used by the GitHub hosted Windows runners. This is temporary and I'll
remove once I've gathered some data (adds 5-15secs to Windows CI times)

Release Notes:

- N/A

---------

Co-authored-by: Mikayla Maki <mikayla@zed.dev>
2025-03-06 10:43:14 -07:00
Conrad Irwin
b8d1c3c866 git: Make repo selector wider (#26149)
…m_item()

Closes #ISSUE

Release Notes:

- git: Fixed repository selector being too narrow
2025-03-06 10:41:36 -07:00
Mikayla Maki
090c38d872 Fix git branches in non-active repository (#26148)
Release Notes:

- Git Beta: Fixed a bug where the branch selector would only show for
the first repository opened.

---------

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
Co-authored-by: Richard Feldman <oss@rtfeldman.com>
2025-03-06 10:41:15 -07:00
Joseph T. Lyons
8a0fb9100e zed 0.177.4 2025-03-06 11:06:23 -05:00
0x2CA
664ccc48c8 git: Fix git commit font fallbacks (#26184)
Closes #ISSUE

Release Notes:

- Fixed git commit font_fallbacks
2025-03-06 10:49:57 -05:00
gcp-cherry-pick-bot[bot]
b575bc9a9d Fix panic in commit editor selections syncing (cherry-pick #26186) (#26188)
Cherry-picked Fix panic in commit editor selections syncing (#26186)

Closes #26183 

Release Notes:

- Git Beta: Fixed a panic when selecting text in one of the commit
message editors

Co-authored-by: Cole Miller <cole@zed.dev>
2025-03-05 22:43:13 -05:00
gcp-cherry-pick-bot[bot]
da895a6fd8 git: Add CHERRY_PICK_HEAD to the list of merge heads (cherry-pick #26145) (#26168)
Cherry-picked git: Add CHERRY_PICK_HEAD to the list of merge heads
(#26145)

Attempt to fix an issue where conflicts from a cherry-pick don't get
cleared out of the git panel after being resolved.

Release Notes:

- Git Beta: Fixed resolution of conflicts from cherry-picks not being
reflected in the git panel

Co-authored-by: Cole Miller <cole@zed.dev>
2025-03-05 21:26:21 -05:00
gcp-cherry-pick-bot[bot]
2309721274 Fix panic when expanding a deletion hunk with blame open (cherry-pick #26130) (#26142)
Cherry-picked Fix panic when expanding a deletion hunk with blame open
(#26130)

Closes #26118

Release Notes:

- Fixed a panic when expanding diff hunks while git blame is open

Co-authored-by: Cole Miller <cole@zed.dev>
2025-03-05 13:17:32 -05:00
Marshall Bowers
fa2f982848 Fix language model selector (#26138)
This PR fixes the language model selector.

I tried to piece together the state prior to #25697 (the state it was in
at 11838cf89e) while retaining unrelated
changes that happened since then.

Release Notes:

- Fixed an issue where language models would not be authenticated until
after the model selector was opened (Preview only).
2025-03-05 12:49:42 -05:00
Marshall Bowers
78b460f701 Clean up language model selector (#26134)
This PR does some cleanup for the language model selector after
https://github.com/zed-industries/zed/pull/26090.

Release Notes:

- N/A
2025-03-05 12:49:34 -05:00
Cole Miller
2d5063b5f5 zed 0.177.3 2025-03-05 12:47:49 -05:00
Max Brunsfeld
a87929c5fd Bump Tree-sitter to 0.25.3 for error recovery fixes (#26092)
For https://github.com/tree-sitter/tree-sitter/pull/4257

Release Notes:

- Fixed a hang that could occur when editing certain Zig files.
2025-03-05 09:44:59 -08:00
gcp-cherry-pick-bot[bot]
535c949a1a Fix performance regression in multibuffer diff syncing (cherry-pick #26137) (#26139)
Cherry-picked Fix performance regression in multibuffer diff syncing
(#26137)

This fixes a performance problem introduced in #25906 and caused by
calling `BufferDiff::snapshot` too frequently.

Release Notes:

- Fixed a performance regression related to buffer diffs

Co-authored-by: Conrad <conrad@zed.dev>

Co-authored-by: Cole Miller <cole@zed.dev>
Co-authored-by: Conrad <conrad@zed.dev>
2025-03-05 12:41:37 -05:00
Joseph T. Lyons
4b6fcef379 zed 0.177.2 2025-03-05 08:51:18 -05:00
gcp-cherry-pick-bot[bot]
dc374713d8 Fix diff_hunk_before in a multibuffer (cherry-pick #26059) (#26102)
Cherry-picked Fix diff_hunk_before in a multibuffer (#26059)

Also simplify it to avoid doing a bunch of unnecessary work.

Co-Authored-By: Cole <cole@zed.dev>

Closes #ISSUE

Release Notes:

- git: Fix jumping to the previous diff hunk

---------

Co-authored-by: Cole <cole@zed.dev>

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
Co-authored-by: Cole <cole@zed.dev>
2025-03-04 21:45:57 -07:00
gcp-cherry-pick-bot[bot]
c084706377 git: Improvements to fetch/push/pull (cherry-pick #26041) (#26051)
Cherry-picked git: Improvements to fetch/push/pull (#26041)

- Add global handlers so these actions can be invoked from the command
palette, etc.
- Tweak spinner to not show itself until a remote has been selected

Release Notes:

- N/A

Co-authored-by: Cole Miller <cole@zed.dev>
2025-03-04 20:09:43 -07:00
gcp-cherry-pick-bot[bot]
578c9f826b Synchronize modal commit editor with panel editor (cherry-pick #26068) (#26093)
Cherry-picked Synchronize modal commit editor with panel editor (#26068)

Release Notes:

- Git Beta: Synchronized selections between the modal editor and the
panel editor
- Git Beta: Allow opening the commit modal even if we're unable to
commit.

Co-authored-by: Mikayla Maki <mikayla@zed.dev>
2025-03-04 20:07:06 -07:00
gcp-cherry-pick-bot[bot]
f06cee40df Fix focus handle leak (cherry-pick #26090) (#26094)
Cherry-picked Fix focus handle leak (#26090)

This fixes a major performance issue in the current git beta.
This PR also removes the PopoverButton component, which was easy to
misuse.

Release Notes:

- Git Beta: Fix frame drops caused by opening the git panel

---------

Co-authored-by: Mikayla Maki <mikayla.c.maki@gmail.com>

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
Co-authored-by: Mikayla Maki <mikayla.c.maki@gmail.com>
2025-03-04 20:06:55 -07:00
Max Brunsfeld
1f936eccc7 Fix lag when large diff hunk intersects the viewport (#26088)
We were iterating over the row range of a hunk, and inserting into a
hash map for every row.

Release Notes:

- Fixed a performance problem when a large diff hunk was displayed in an
editor.
2025-03-04 16:28:56 -08:00
Joseph T. Lyons
1516ee3e46 zed 0.177.1 2025-03-04 13:04:11 -05:00
gcp-cherry-pick-bot[bot]
53af68aa82 git: Fix project diff shortcuts (cherry-pick #26045) (#26049)
Cherry-picked git: Fix project diff shortcuts (#26045)

Release Notes:

- git: Fix keyboard shortcut display in project diff view
- vim: add git keyboard shortcuts: `d u/d U` for staging/unstaging in
the project diff view. `d o/d O` to show hide/toggle staged in the
editor and `d p` for restoring the hunk.

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-04 13:01:18 -05:00
gcp-cherry-pick-bot[bot]
e897f191f6 Git Beta: Fix a few cases of empty toasts showing up (cherry-pick #25985) (#25987)
Cherry-picked Git Beta: Fix a few cases of empty toasts showing up
(#25985)

Improve parsing of git remote outputs

Release Notes:

- N/A

Co-authored-by: Mikayla Maki <mikayla@zed.dev>
2025-03-04 10:36:06 -07:00
gcp-cherry-pick-bot[bot]
aba10b73d2 Git fix repo selection (cherry-pick #25996) (#25998)
Cherry-picked Git fix repo selection (#25996)

Release Notes:

- git: Fixed a bug where staging/unstaging of hunks could use the wrong
git repository if you had many open

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-04 10:35:53 -07:00
gcp-cherry-pick-bot[bot]
46190bd087 git: Fix race condition loading project diff (cherry-pick #25992) (#25999)
Cherry-picked git: Fix race condition loading project diff (#25992)

Release Notes:

- git: Fixed a race condition where some files would be missing from
project diff

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-04 10:35:42 -07:00
Nate Butler
0b360febad git: Add hunk_style setting (#26038)
This PR adds the `git.hunk_style` setting, allowing setting an alternate
style for hunks – specifically the rendering of unstaged hunks.

It has 2 options:

- `transparent` (unstaged hunks are more transparent/less opaque than
staged hunks)
- `pattern (unstaged hunks are indicated by a visual pattern)

We'll possibly explore a VSCode-style "don't show staged hunks", but the
complexity it adds is a bit out of scope for now.

Transparent:

![CleanShot 2025-03-04 at 09 07
09@2x](https://github.com/user-attachments/assets/a74c4286-8264-48a2-bd58-0c582efb4e22)

Pattern:

![CleanShot 2025-03-04 at 09 10
12@2x](https://github.com/user-attachments/assets/4dd3040e-fb36-4670-9279-fcc7a4f12ced)

Release Notes:

- Git Beta: Added `git.hunk_style` setting to allow toggling between git
hunk visual styles.
2025-03-04 11:12:36 -05:00
gcp-cherry-pick-bot[bot]
11d75c42f1 Disable diff hunks for untracked files, even w/ no newline at eof (cherry-pick #25980) (#26004)
Cherry-picked Disable diff hunks for untracked files, even w/ no newline
at eof (#25980)

This fixes an issue where diff hunks were shown for untracked files, but
only if the files did not end with a newline.

Release Notes:

- N/A

Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
2025-03-04 07:56:49 -08:00
Joseph T. Lyons
b3de2bf740 Reuse existing logic used to generate commit messages to disable commit buttons (#26034)
Also
- Recomputes `suggested_commit_message` and no longer stores it, to
ensure things are always up to date
- Reduces indentation in `render_footer`

Release Notes:

- N/A
2025-03-04 09:06:17 -05:00
Cole Miller
b2f174a622 Revert "git: Use worktree paths in the panel (#25950)" (#25995)
This reverts commit e7b3b8bf03.

Release Notes:

- N/A
2025-03-04 09:06:10 -05:00
gcp-cherry-pick-bot[bot]
a3b7c1d9e3 Fix a panic on Linux theme appearance change (cherry-pick #26019) (#26028)
Cherry-picked Fix a panic on Linux theme appearance change (#26019)

Closes https://github.com/zed-industries/zed/issues/26009



21484a2e9d/crates/gpui/src/platform/linux/platform.rs (L517-L519)

`with_common` panicked at `borrow_mut` which is the way it's implemented
for X11, Wayland and Headless Linux counterparts.



21484a2e9d/crates/gpui/src/platform/linux/wayland/client.rs (L722-L724)

By accessing the appearance global instead of a `RefCell` with it, the
panic goes away with one notable side-effect, on Linux only: the first
global's value on `Dark` appearance would be `Light`: it becomes normal
instantly, thanks to



21484a2e9d/crates/workspace/src/workspace.rs (L1083-L1090)

Things work without flickering:



[linux_theme_toggle.webm](https://github.com/user-attachments/assets/0e39ddc0-b4ff-4475-93ff-7b2bd7233628)


Release Notes:

- Fixed a panic on Linux theme appearance change

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
2025-03-04 15:02:10 +02:00
Joseph T. Lyons
f4b83d1fba Make suggested commits placeholders and allow them to be committed (#26006)
This does not fix the bug where, when the commit editor modal is open,
changing the staged file does not update the suggested message in the
commit editor. Conrad mentioned he thought we shouldn't be allowed to
change those when the modal is open, so I'm not attempting to fix that.

Release Notes:

- Made suggested commits placeholders and allow them to be committed.
2025-03-04 02:02:50 -05:00
gcp-cherry-pick-bot[bot]
5de7f1bcd5 Skip .git/lfs FS events (cherry-pick #25927) (#26005)
Cherry-picked Skip .git/lfs FS events (#25927)

Closes https://github.com/zed-industries/zed/issues/25865
Closes https://github.com/zed-industries/zed/pull/25915

In the issue, Zed had caused `.git/lfs/tmp/466102258`-like files to
appear in the directory, which lead to background FS event listener to
handle this as an update, incrementing snapshot's `scan_id`, which lead
to git status rescan, which caused another increment to `status_scan_id`
— incrementing either of the IDs causes the related repo data to be
considered "changed:



41b45eaba7/crates/worktree/src/worktree.rs (L1590-L1605)

hence propagating events to the other parts of the system (e.g. git
blame, which was also active in the issue's case)

```
[2025-03-01T20:01:08+01:00 DEBUG worktree] ignoring event ".git/lfs/tmp/466102258" within unloaded directory
[2025-03-01T20:01:08+01:00 DEBUG worktree] received fs events []
[2025-03-01T20:01:08+01:00 DEBUG worktree] reloading repositories: ["/Users/alex/dev/monorepo/.git"]
[2025-03-01T20:01:08+01:00 DEBUG editor::git::blame] Status of git repositories updated. Regenerating blame data...
[2025-03-01T20:01:08+01:00 DEBUG editor::git::blame] Status of git repositories updated. Regenerating blame data...
[2025-03-01T20:01:08+01:00 DEBUG editor::git::blame] Status of git repositories updated. Regenerating blame data...
```

Due to repo update events sent, another `.git/lfs/tmp/` entry is
created, things start over...

The PR fixes this by ignoring any `.git/lfs/` directory-related FS
events, as needed for the current git status update heuristics.

https://github.com/zed-industries/zed/pull/25915 tried to follow further
and `scan_id` and `status_scan_id` but we do not store all git state in
memory, e.g. head


e0060b92cc/crates/editor/src/editor_tests.rs (L13686)
as

[tests](https://github.com/zed-industries/zed/actions/runs/13631960559/job/38101504549?pr=25915)
show.

Release Notes:

- Improved `.git` scan heuristics

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
2025-03-04 08:38:18 +02:00
gcp-cherry-pick-bot[bot]
375885e6ec Disable Git panel button to open commit editor in certain cases (cherry-pick #26000) (#26001)
Cherry-picked Disable Git panel button to open commit editor in certain
cases (#26000)

Also:

- Internally renames a bit of code to make it easy to identify between
when we are disabling the buttons that open and close the modal editor
(in Git Panel and Project Diff) vs when we are disabling the commit
buttons (in Git Panel and Git commit editor modal).
- Deletes some unused code.

Release Notes:

- Unified disabling / enabling the button to open the Git commit editor
modal in the Git panel with the Project Diff commit button.
- Unified disabling / enabling the commit buttons, for the same cases,
between the Git panel and Git commit editor modal.

Co-authored-by: Joseph T. Lyons <JosephTLyons@gmail.com>
2025-03-04 01:03:07 -05:00
gcp-cherry-pick-bot[bot]
7ab9ec904e git: New enter behaviour (cherry-pick #25986) (#25993)
Cherry-picked git: New enter behaviour (#25986)

Closes #25951

Release Notes:

- git: Update "enter" in the list of changed files to preserve focus. If
you want the old behaviour, hit enter twice.
- git: Follow the cursor, not the scroll anchor, in the list. Although
the scroll anchor was nice for passive scrolling, it broke if you had
changed the overflow scroll settings.

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-03 21:40:46 -07:00
gcp-cherry-pick-bot[bot]
94425051a1 Improve consistency with commit button tooltip between Git panel and modal (cherry-pick #25990) (#25991)
Cherry-picked Refactor more code around commit button text (#25990)

Missed this when doing https://github.com/zed-industries/zed/pull/25988

Release Notes:

- N/A

Co-authored-by: Joseph T. Lyons <JosephTLyons@gmail.com>
2025-03-03 22:55:26 -05:00
gcp-cherry-pick-bot[bot]
7bd4a85a29 Use same commit button text in panel and modal (cherry-pick #25988) (#25989)
Cherry-picked Use same commit button text in panel and modal (#25988)

Release Notes:

- Fixed inconsistencies in commit button text between Git panel and
modal.

Co-authored-by: Joseph T. Lyons <JosephTLyons@gmail.com>
2025-03-03 22:32:57 -05:00
gcp-cherry-pick-bot[bot]
7d1b50ea85 vim: Fix key navigation on folded buffer headers (cherry-pick #25944) (#25972)
Cherry-picked vim: Fix key navigation on folded buffer headers (#25944)

Closes #24243

Release Notes:

- vim: Fix j/k on folded multibuffer headers

---------

Co-authored-by: João Marcos <marcospb19@hotmail.com>

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
Co-authored-by: João Marcos <marcospb19@hotmail.com>
2025-03-03 19:40:24 -07:00
gcp-cherry-pick-bot[bot]
96ce87d2dd Fix toggle fold in deleted hunk (cherry-pick #25967) (#25982)
Cherry-picked Fix toggle fold in deleted hunk (#25967)

Updates #25835
Updates #25951

Closes #ISSUE

Release Notes:

- Fixed toggling folds from within deleted hunks

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-03 19:39:52 -07:00
Max Brunsfeld
1c6bf1f9b1 Show git panel footer even when on a detached HEAD (#25968)
Previously, the git panel footer would accidentally hide when not on a
branch.

Release Notes:

- N/A

Co-authored-by: Ben Kunkle <ben.kunkle@gmail.com>
2025-03-03 16:46:14 -08:00
Cole Miller
8d9d14c2b9 git: Use worktree paths in the panel (#25950)
This PR changes the git panel to use worktree-relative paths for its
entries, instead of repository-relative paths as before. Paths that lie
outside the active repository's worktree are no longer shown in the
panel. Note that in both respects this is how the project diff editor
already works, so this PR brings those two pieces of UI into harmony.

Release Notes:

- N/A
2025-03-03 19:16:25 -05:00
Nate Butler
46944b679f git_ui: horizontal is not vertical (#25961)
Fixes an issue where I was missing some brain cells and changed the git
panel's `render_entries` to a `v_flex` instead of an `h_flex`.

But actually, fixes the git panel entries from disappearing when a
scrollbar is rendered.

**Before**

![CleanShot 2025-03-03 at 16 36
52@2x](https://github.com/user-attachments/assets/9dca7b9c-318d-4b3f-ab3e-e7242fa7f73a)

**After**

![CleanShot 2025-03-03 at 16 35
59@2x](https://github.com/user-attachments/assets/c1fe5fb1-ad57-4bca-ace4-365e70a74066)


Closes #25955

Release Notes:

- Git Beta: Fixed an issue where when the git panel would need to scroll
all the items are pushed off the screen.
2025-03-03 19:15:20 -05:00
Nate Butler
b1386bff7b git_ui: Prevent button overflow due to long names (#25940)
- Fix component preview widths for git panel
- Fix buttons getting pushed off the screen in git  panel

Release Notes:

- N/A

---------

Co-authored-by: Mikayla Maki <mikayla.c.maki@gmail.com>
2025-03-03 19:14:37 -05:00
gcp-cherry-pick-bot[bot]
02204dee06 git: Don't consider $HOME as containing git repository unless it's opened directly (cherry-pick #25948) (#25952)
Cherry-picked git: Don't consider $HOME as containing git repository
unless it's opened directly (#25948)

When a worktree is created, we walk up the ancestors of the root path
trying to find a git repository. In particular, if your `$HOME` is a git
repository and you open some subdirectory of `$HOME` that's *not* a git
repository, we end up scanning `$HOME` and everything under it looking
for changed and untracked files, which is often pretty slow. Consistency
here is not very useful and leads to a bad experience.

This PR adds a special case to not consider `$HOME` as a containing git
repository, unless you ask for it by doing the equivalent of `zed ~`.

Release Notes:

- Changed the behavior of git features to not treat `$HOME` as a git
repository unless opened directly

Co-authored-by: Cole Miller <cole@zed.dev>
2025-03-03 17:38:11 -05:00
gcp-cherry-pick-bot[bot]
a1e613805a Add some logging to debug missing parent git repositories (cherry-pick #25943) (#25946)
Cherry-picked Add some logging to debug missing parent git repositories
(#25943)

We've had some issues reported with git repositories not getting
detected when they're a strict parent of the worktree root. Add a bit
more logging to understand what's going on here.

Release Notes:

- N/A

Co-authored-by: Cole Miller <cole@zed.dev>
2025-03-03 14:25:18 -05:00
gcp-cherry-pick-bot[bot]
5852f2e0a4 Fix missing hunks in project diff after revert (cherry-pick #25906) (#25947)
Cherry-picked Fix missing hunks in project diff after revert (#25906)

Release Notes:

- N/A

Co-authored-by: Cole Miller <cole@zed.dev>
2025-03-03 14:25:05 -05:00
Joseph T. Lyons
3130b46515 v0.177.x preview 2025-03-03 12:42:43 -05:00
Bennet Bo Fenner
669082dbe0 assistant2: Fix keyboard navigation issues when a picker is open (#25928)
This fixes:
- Bug: Using "up" in model selector triggers assistant2::FocusUp not
menu::SelectPrev
- Bug: Pressing arrow up/down in the model selector opened in the inline
assistant doesn't work
- Bug: Dismissing the model selector with Esc is not working
- Bug: Dismissing context pickers with Esc no longer working

Release Notes:

- N/A
2025-03-03 17:02:25 +01:00
Marshall Bowers
d5bc7b9a79 extension_cli: Make use of scrollbar_thumb.background a hard error (#25932)
This PR updates the extension CLI to make the use of
`scrollbar_thumb.background` in a theme a hard error.

We're working to eradicate usage of this theme property, so this will
prevent new extensions from being published that use it.

Release Notes:

- N/A
2025-03-03 15:55:15 +00:00
smit
8bb2739e28 keymap: Update Prev to Previous follow-up (#25931)
Follow-up for https://github.com/zed-industries/zed/pull/25909

Add three more action replacements:

```
1. "pane::ActivatePrevItem" -> "pane::ActivatePreviousItem"
2. "vim::MoveToPrev" -> "vim::MoveToPrevious"
3. "vim:MoveToPrevMatch" -> "vim:MoveToPreviousMatch" 
```

Release Notes:

- N/A
2025-03-03 21:19:25 +05:30
Peter Tripp
466be14b56 Revert "Use multi-line regex for '\s'" (#25926)
Reverts zed-industries/zed#19241
Closes: https://github.com/zed-industries/zed/issues/25901

Although `\s` contains `\n` it is widely used in non-multiline regexes (unlike `\n`).
2025-03-03 10:32:49 -05:00
Kirill Bulatov
95446195af Skip .git/lfs FS events (#25927)
Closes https://github.com/zed-industries/zed/issues/25865
Closes https://github.com/zed-industries/zed/pull/25915

In the issue, Zed had caused `.git/lfs/tmp/466102258`-like files to
appear in the directory, which lead to background FS event listener to
handle this as an update, incrementing snapshot's `scan_id`, which lead
to git status rescan, which caused another increment to `status_scan_id`
— incrementing either of the IDs causes the related repo data to be
considered "changed:


41b45eaba7/crates/worktree/src/worktree.rs (L1590-L1605)

hence propagating events to the other parts of the system (e.g. git
blame, which was also active in the issue's case)

```
[2025-03-01T20:01:08+01:00 DEBUG worktree] ignoring event ".git/lfs/tmp/466102258" within unloaded directory
[2025-03-01T20:01:08+01:00 DEBUG worktree] received fs events []
[2025-03-01T20:01:08+01:00 DEBUG worktree] reloading repositories: ["/Users/alex/dev/monorepo/.git"]
[2025-03-01T20:01:08+01:00 DEBUG editor::git::blame] Status of git repositories updated. Regenerating blame data...
[2025-03-01T20:01:08+01:00 DEBUG editor::git::blame] Status of git repositories updated. Regenerating blame data...
[2025-03-01T20:01:08+01:00 DEBUG editor::git::blame] Status of git repositories updated. Regenerating blame data...
```

Due to repo update events sent, another `.git/lfs/tmp/` entry is
created, things start over...

The PR fixes this by ignoring any `.git/lfs/` directory-related FS
events, as needed for the current git status update heuristics.

https://github.com/zed-industries/zed/pull/25915 tried to follow further
and `scan_id` and `status_scan_id` but we do not store all git state in
memory, e.g. head

e0060b92cc/crates/editor/src/editor_tests.rs (L13686)
as
[tests](https://github.com/zed-industries/zed/actions/runs/13631960559/job/38101504549?pr=25915)
show.

Release Notes:

- Improved `.git` scan heuristics
2025-03-03 15:04:46 +00:00
Max Brunsfeld
b34c0fd71b git_ui: Fix item heights in git panel (#25833)
- Fixes items slightly overlapping in the git panel
- Fixes commit button in the project diff not opening modal

Release Notes:

- N/A

---------

Co-authored-by: Nate Butler <iamnbutler@gmail.com>
Co-authored-by: Cole Miller <m@cole-miller.net>
2025-03-03 09:39:24 -05:00
Danilo Leal
e0060b92cc assistant: Adjust slash command picker (#25920)
Mostly just fine-tuning its positioning. Other changes are mainly using
the Label's `buffer_font` method instead of using a div for that.

Release Notes:

- N/A
2025-03-03 11:09:49 -03:00
Danilo Leal
06bcc42652 Revert "assistant_context_editor: Close menus on send (#25440)" (#25916)
Reverting https://github.com/zed-industries/zed/pull/25440

This is a good change, but given the PR was open for a while, I guess it
didn't catch conflicts with main, and so it broke it. Will revert it for
now, to keep main fresh, but will look into adding this behavior back
again.

Release Notes:

- N/A
2025-03-03 12:40:01 +00:00
brian tan
f24c226af8 assistant_context_editor: Close menus on send (#25440)
Closes #ISSUE

Before:


https://github.com/user-attachments/assets/e63b6207-0c80-4fd6-99c0-febe3d639ba1

After:


https://github.com/user-attachments/assets/870f2c6d-9b7f-456d-a1e3-26e1c31b129d

Release Notes:

- N/A
2025-03-03 09:22:23 -03:00
smit
593f3dc1d5 keymap: Update Prev to Previous for consistency (#25909)
Closes #10167

This is take 2 on https://github.com/zed-industries/zed/pull/2341 which
was closed due to lack of migrator.

This PR contains rename of following keymap actions: 
```sh
1. ["editor::GoToPrevHunk", { "center_cursor": true }] -> ["editor::GoToPreviousHunk", { "center_cursor": true }]
2. "editor::GoToPrevDiagnostic" -> "editor::GoToPreviousDiagnostic"
3. "editor::ContextMenuPrev" -> "editor::ContextMenuPrevious"
4. "search::SelectPrevMatch" -> "search::SelectPreviousMatch"
5. "file_finder::SelectPrev" -> "file_finder::SelectPrevious"
6. "menu::SelectPrev" -> "menu::SelectPrevious"
7. "editor::TabPrev" -> "editor::Backtab"
```

Release Notes:

- Renamed several keymap actions for consistency (e.g., `GoToPrevHunk` →
`GoToPreviousHunk`, `TabPrev` → `Backtab`). Your existing configured
keybindings will still work. You can click **"Backup and Update"** at
the top of your keymap file to easily update to the new actions.


Co-authored-by: Joseph T. Lyons <JosephTLyons@gmail.com>
2025-03-03 17:44:49 +05:30
Danilo Leal
61d584db45 context menu: Adjust item disabled state when there is docs aside (#25860)
When a context menu item has a documentation aside element attached to
it, we're now hiding the keybinding (which wouldn't trigger anything
anyway) to make room for displaying an info icon, with the purpose of
indicating the existence of the docs aside, which will typically explain
the reason why the item’s disabled in the first place.

Also, changed the label color to use the `Disabled` token; more
appropriate for this, and just slightly darker, which is great!

<img
src="https://github.com/user-attachments/assets/a7f9f022-16d1-41d5-b1b5-3cbcc9630cc8"
width="500px"/>

Release Notes:

- N/A
2025-03-03 08:59:42 -03:00
Jason Lee
c37f616c3b gpui: Maintain img aspect ratio when max_width is set (#25632)
Release Notes:

- Fixed Markdown preview to display image with max width 100%.

## Before

<img width="1202" alt="image"
src="https://github.com/user-attachments/assets/359628df-8746-456f-a768-b3428923c937"
/>
<img width="750" alt="SCR-20250226-napv"
src="https://github.com/user-attachments/assets/f6154516-470e-41b2-84f5-ef0612c447ad"
/>


## After

<img width="1149" alt="image"
src="https://github.com/user-attachments/assets/2279347d-9c69-4a47-bb62-ccc8e55a98f6"
/>
<img width="520" alt="SCR-20250226-ngyz"
src="https://github.com/user-attachments/assets/03af5f14-1935-472e-822f-4c7f62630780"
/>
2025-03-03 12:36:27 +01:00
Mikayla Maki
73ac19958a Add user-visible output for remote operations (#25849)
This PR adds toasts for reporting success and errors from remote git
operations. This PR also adds a focus handle to notifications, in
anticipation of making them keyboard accessible.

Release Notes:

- N/A

---------

Co-authored-by: julia <julia@zed.dev>
2025-03-03 09:20:15 +00:00
Mikayla Maki
508b9d3b5d Add an informative tooltip to commit button when unable to commit (#25912)
Release Notes:

- N/A
2025-03-03 08:44:46 +00:00
Morgan Metz
0a4ff2f475 tab: Add setting to hide the close button entirely (#23880)
Closes #23744

Release Notes:

- Changed the `always_show_close_button` key to `show_close_button` and
introduced a new `hidden` value, that allows never displaying the close
button.

---------

Co-authored-by: Peter Tripp <peter@zed.dev>
Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
Co-authored-by: smit <0xtimsb@gmail.com>
2025-03-03 08:31:48 +05:30
Max Brunsfeld
ae6d350334 Use system-installed git binary for push/pull/fetch (#25900)
### Problem

When using HTTPS remotes, users are getting errors when trying to push
or pull via the git panel.

On macOS, Zed bundles a `git` binary that's part of
[`dugite-native`](https://github.com/desktop/dugite-native). But we
don't include the entire package. Additional binaries from
`dugite-native` are needed for pulling and pushing over HTTPS.

### Solution

Rather than bundling those additional binaries, I've changed the `push`,
`pull`, and `fetch` actions to rely on the *system-installed* `git`
binary. The downside of this is that, if the user does not have Git
installed, they wont' be able to push, pull, or fetch from within Zed.
But we believe that the vast majority of users will have Git installed.
Also, unlike `diff` and `status`, which Zed needs to call in the
background without any user interaction, `push`/`pull` and `fetch` are
explicit actions that the user takes in Zed, so there is an opportunity
to prompt them to install Git if they haven't.

### Background

There are three ways (that I know of) that users might authenticate when
pushing, pulling, or fetching over HTTPS.

1. Via a built-in [Git
`credential.helper`](https://git-scm.com/docs/gitcredentials). On macOS,
Git ships with a helper called `credential-osxkeychain` that stores
internet passwords in the OS Keychain. You can opt into this globally
with the command `git config --global credential.helper osxkeychain`,
which writes to your `~/.gitconfig`.
2. Via [`Git Credential Manager`
(GCM)](https://github.com/git-ecosystem/git-credential-manager), which
is a different `credential.helper`, [built by
GitHub](https://github.blog/security/application-security/git-credential-manager-authentication-for-everyone/),
which must be installed manually, and integrates with specific Git
hosting providers like GitHub and Azure.
3. By typing their Username and Password/Access-token interactively when
pushing/pulling/fetching.

### Testing Status

* [ ] 🚫 Interactive password auth - not yet supported, requires
https://github.com/zed-industries/zed/pull/25848
* [x] **credential-osxkeychain** - when using the built-in credential
helper, and the credentials are already stored in the keychain,
push/pull/fetch now work fine .
* [ ] **GCM**  - still testing.
* Right now, I'm seeing `git-credential-manager` just hang indefinitely
when pushing from Zed, even though it works when pushing from a
terminal.



Release Notes:

- N/A
2025-03-02 17:31:47 -08:00
Piotr Osiewicz
0e44f93178 lsp: Do not add trailing slash to workspace folders (#25903)
Closes #25390

Release Notes:

- Fixed issues with ansible-language-server sending phantom diagnostic
updates
2025-03-02 22:09:13 +00:00
Joseph T. Lyons
65d92d7278 Make more log files read only (#25887)
Closes https://github.com/zed-industries/zed/issues/5105

Makes the following logs read only

- Zed error / warning log
- Zed telemetry log

Release Notes:

- N/A
2025-03-02 08:05:55 +00:00
Devzeth
8b5ef2558b docs: Add documentation for Seed search query from cursor (#25875)
Missing documentation added for `seed_search_query_from_cursor`. 

Release Notes:

- N/A
2025-03-02 08:46:22 +02:00
Ben Kunkle
fec228bb23 Fix issue with cmd-w closing window in preview tabs on MacOS (#25878)
Closes #25810

Reorders default macOS keymap so that `cmd-w` in `"context":
"PromptLibrary"` bindings is not the last binding for
`workspace::CloseWindow` and therefore does not get rendered in the app
menu or intercepted by MacOS

Release Notes:

- N/A
2025-03-01 19:33:01 -06:00
Devzeth
e00d737196 Add constructor highlighting for JS/TS/TSX (#25207)
Closes #19267

Adds highlight field specifically for `constructor` in JS/TS/TSX so that
it can be highlighted as a different color than regular methods

Release Notes:

- N/A

---------

Co-authored-by: Ben Kunkle <ben@zed.dev>
2025-03-02 00:43:51 +00:00
Egor Krugletsov
b0dee94126 pane: Hide "Copy Relative Path" and "Reveal In Project Panel" actions for files outside of the projects (#25386)
"Copy Relative Path" action had a check for existence of relative path
but it always passed because
[`WorktreeStore::find_worktree()`](1d5499bee7/crates/project/src/worktree_store.rs (L148))
function returned empty path for these kinds of files. It feels correct
to make changes there, but I don't know what else could be impacted.

"Reveal In Project Panel" had no check whatsoever and so I made one.

Release Notes:

- N/A
2025-03-01 23:31:18 +02:00
greathongtu
e65471c7a1 Optimize JSON merging by removing redundant key clones in serde_json operations (#25866)
Hi Zed team! 👋
As a fan of Zed Editor who's excited to contribute, I noticed a small
optimization opportunity in the JSON merging utilities.

<b>Changes:</b>
Removed redundant key.clone() calls in insert() operations within 2
functions:
1. merge_json_value_into
2. merge_non_null_json_value_into

<b>Why:</b>
Since we're already moving ownership of `source_object` 's contents and
key is no longer used further, we could directly pass `key` to `insert`
without cloning.
Eliminates redundant allocations, improving performance slightly for
JSON-heavy operations.

<b>Testing:</b>
I have tested this locally and all existing tests passed. The change
preserves behavior while removing redundancy.

Love using Zed and happy to contribute! Let me know if any adjustments
are needed!

Release Notes:

- N/A
2025-03-01 14:13:38 -05:00
张小白
6713ec8cdf windows: Bring back restoration of tabs (#25870)
Closes #25022

Release Notes:

- N/A
2025-03-01 17:18:34 +00:00
Joseph T. Lyons
48e09c0026 Tweak the Git beta issue template (#25869)
Release Notes:

- N/A
2025-03-01 11:33:42 -05:00
Joseph T. Lyons
3f03d7b023 Add a temporary issue template for Git beta bugs (#25867)
Release Notes:

- N/A
2025-03-01 11:31:25 -05:00
Devzeth
fa96e2259b paths: Add support for clickable file paths in the Odin language format (#25842)
This PR adds support for clickable file paths in the Odin language format.

The odin compiler errors use the format `/path/to/file.odin(1:1)`. We
didn't recognize this format, making these paths non-clickable in the
terminal.

Also added tests for this. 


Release Notes:

- Added support for clickable file paths in the Odin language format.

---------

Co-authored-by: Peter Tripp <peter@zed.dev>
2025-03-01 16:22:12 +00:00
Maksim Bondarenkov
a8a05f208b cli: Add extra paths in detect() on Windows (#25765)
I'm already integrating CLI into MSYS2 package, and this patche helped
me to make it work like in Arch:
https://github.com/msys2/MINGW-packages/pull/23537. used the same way as
in [Linux
implementation](6856e869fc/crates/cli/src/main.rs (L314))

Closes #ISSUE

Release Notes:

- N/A
2025-03-02 00:17:55 +08:00
Peter Tripp
aa1ab50656 Add stop_at_indent for Editor::DeleteToBeginningOfLine (#25688)
Added test_beginning_of_line_stop_at_indent editor test

- Follow-up to: https://github.com/zed-industries/zed/pull/25428
- Replaces: https://github.com/zed-industries/zed/pull/25346

This is all authored by @felixpackard in #25346
I just updated it to use `stop_at_indent` instead of
`stop_at_first_char`.

Release Notes:

- Added support for `stop_at_indent` to
`Editor::DeleteToBeginningOfLine` (thanks
[@felixpackard](https://github.com/felixpackard))

Co-authored-by: Felix Packard <felix@rigr.gg>
2025-03-01 11:03:47 -05:00
张小白
d115cb1944 windows: Use dev drive instead of ReFS (#25858)
Closes #ISSUE

Release Notes:

- N/A *or* Added/Fixed/Improved ...
2025-03-01 22:43:10 +08:00
Kirill Bulatov
42571e405f Ensure inlay hint toggling with modifiers happens fast (#25852)
Follow-up of https://github.com/zed-industries/zed/pull/25766 
Fixes the bugs found:

* modifier toggle not happening instantly due to `edit_debounce_ms`
considered
* hint update race that ignored the cache clear

Release Notes:

- N/A
2025-03-01 08:15:57 +00:00
João Marcos
2d61a51ded Diff View: Scroll to center of hunks when reviewing (#25846)
When reviewing hunks, scroll to put them at the center of the screen
so you can better see the context around that hunk.

The field `center_cursor` was added to the actions `editor::GoToHunk`
and `editor::GoToPrevHunk`, this was set to `false` by default in
keymaps, as it wouldn't help with in-editor navigation.

The field is set to `true` for when you trigger `git::StageAndNext`
and `git::UnstageAndNext`, this is also `true` for the buttons in the
Diff View toolbar.

Release Notes:

- N/A
2025-03-01 03:20:26 +00:00
João Marcos
a2876f5d3e Support hunk-wise StageAndNext and UnstageAndNext (#25845)
This PR adds the `whole_excerpt` field to the actions:

- `git::StageAndNext`
- `git::UnstageAndNext`

Which is set by false by default, effectively, now staging and unstaging
with these actions is done hunk-by-hunk, this also affects the `Stage`
and
`Unstage` buttons in the Diff View toolbar.

A caveat: with this PR, there is no way to configure the buttons in the
Diff
View toolbar to restore the previous behavior, if we want, I think we
can make
it a setting, but let's see if anyone really wants that.

Release Notes:

- N/A
2025-03-01 02:39:08 +00:00
Cole Miller
13deaa3f69 Fix new git panel buttons (#25844)
Release Notes:

- N/A
2025-02-28 21:19:20 -05:00
Ben Kunkle
694afd15c9 Fix buffer search options not resetting when dismissed after Vim mode search then reopened with buffer: deploy search (#25838)
Closes #25315

Release Notes:

- Fixes an issue where the buffer search options would not be reset when
using `buffer: deploy search` after using Vim search (`*` & `#`) which
enable all search options
2025-02-28 18:59:22 -06:00
Cole Miller
eb648dd096 Follow-up tweaks to new git panel footer (#25832)
- Use a popover for the branch picker
- Don't deploy a repository selector if there's only one repo

Release Notes:

- N/A
2025-02-28 19:05:43 -05:00
Max Brunsfeld
1c4c568068 Allow unfolding deleted buffers in project diff w/ keyboard (#25835)
Release Notes:

- N/A
2025-02-28 16:02:35 -08:00
Ben Kunkle
ec88a6886f Fix active pane modifiers applying to parent pane axis if child pane is active (#25836)
Closes #25304

Release Notes:

- Fixed an issue where `active_pane_modifiers` settings would be applied
to a parent pane if one of it's child panes was active
2025-02-28 23:47:15 +00:00
Piotr Osiewicz
7fb16977ce chore: Extract PromptStore out of prompt_library (#25837)
One step closer to removing long pole with assistant/assistant2 builds

Release Notes:

- N/A
2025-03-01 00:34:28 +01:00
Peter Tripp
53b2792844 Improve script/mitm-proxy.sh to support podman (#25834) 2025-02-28 22:37:03 +00:00
Peter Tripp
760d08711c Update bundled JSON schemas (2025-02-28) (#25826)
Updated JSON schemas to
[SchemaStore/schemastore@b107b83](b107b83a50)
(2025-02-28)

-
[tsconfig.json](https://github.com/SchemaStore/schemastore/commits/master/src/schemas/json/tsconfig.json)
@
[b107b83](https://raw.githubusercontent.com/SchemaStore/schemastore/b107b83a50bad9ac06dd171201dc870901f92ca8/src/schemas/json/tsconfig.json)
-
[package.json](https://github.com/SchemaStore/schemastore/commits/master/src/schemas/json/package.json)
@
[b107b83](https://raw.githubusercontent.com/SchemaStore/schemastore/b107b83a50bad9ac06dd171201dc870901f92ca8/src/schemas/json/package.json)

Previously:
- https://github.com/zed-industries/zed/pull/20910

Release Notes:

- Updated bundled JSON schemas for package.json and tsconfig.json
2025-02-28 16:32:16 -05:00
Marshall Bowers
71866d6314 assistant2: Include some text in the tool result messages (#25825)
This PR makes it so we include some textual content in the user messages
that as used to send up tool results.

I observed that when sending up the tool results with no text, it would
lead the model to start replying with no text, which would then result
in an error when attaching later tool results.

I think there's a deeper issue at play here, but for now we just include
some text to keep the model on track.

Release Notes:

- N/A
2025-02-28 21:02:03 +00:00
Max Brunsfeld
0c2bbb3aa9 Optimistically update hunk states when staging and unstaging hunks (#25687)
This PR adds an optimistic update when staging or unstaging diff hunks.
In the process, I've also refactored the logic for staging and unstaging
hunks, to consolidate more of it in the `buffer_diff` crate.

I've also changed the way that we treat untracked files. Previously, we
maintained an empty diff for them, so as not to show unwanted
entire-file diff hunks in a regular editor. But then in the project diff
view, we had to account for this, and replace these empty diffs with
entire-file diffs. This form of state management made it more difficult
to store the pending hunks, so now we always use the same
`BufferDiff`/`BufferDiffSnapshot` for untracked files (with a single
hunk spanning the entire buffer), but we just have a special case in
regular buffers, that avoids showing that entire-file hunk.

* [x] Avoid creating a long queue of `set_index` operations when
staging/unstaging rapidly
* [x] Keep pending hunks when diff is recalculated without base text
changes
* [x] Be optimistic even when staging the single hunk in added/deleted
files
* Testing

Release Notes:

- N/A

---------

Co-authored-by: Cole Miller <m@cole-miller.net>
2025-02-28 20:55:29 +00:00
Nate Butler
9d8a163f5b git_ui: New panel design (#25821)
This PR updates the ui of the git panel. It removes the header from the
panel and unifies the repository, branch and commit controls in the
bottom section.

It also adds a secondary menu to the primary button giving access to a
variety of actions for managing local and remote changes:

![CleanShot 2025-02-28 at 12 18
15@2x](https://github.com/user-attachments/assets/0260c122-405f-46fc-8cc8-d6beac782b9d)

Known issues (will be fixed in a later pr)
- Spinner showing git operation progress was removed, will be re-added
- Clicking expand with the panel editor focused will commit (due to
shared action name. Already tracked)

Before | After

![CleanShot 2025-02-28 at 12 22
18@2x](https://github.com/user-attachments/assets/4c1e4ac9-b975-487f-bf4e-8815a8da4f4f)

(Also adds `component`, `linkme` to cargo-machete ignore as they are
used in the `IntoComponent` proc-macro and will always be incorrectly
flagged as unused)

Release Notes:

- N/A

---------

Co-authored-by: Cole Miller <m@cole-miller.net>
Co-authored-by: Cole Miller <53574922+cole-miller@users.noreply.github.com>
Co-authored-by: Cole Miller <cole@zed.dev>
2025-02-28 20:00:39 +00:00
Nate Butler
8a22a07d14 git: Adjust rendering of git hunks (#25824)
- Light themes get their own values (creating better contrast and a
better distinction between staged and unstaged hunks in light themes.)
- Scrollbar git hunks indicators now use the correct colors

Before:

![CleanShot 2025-02-28 at 14 31
29@2x](https://github.com/user-attachments/assets/038fe11c-7163-4f1b-92b8-56b24c8e9443)

After:

![CleanShot 2025-02-28 at 14 32
04@2x](https://github.com/user-attachments/assets/869d33d9-d925-4cbe-84bd-e54caf971431)


Release Notes:

- Fixed an issue where git hunk indicators in editor scrollbars used the
incorrect colors.
2025-02-28 19:54:12 +00:00
smit
fad4df5e70 editor: Add Organize Imports Action (#25793)
Closes #10004

This PR adds support for the organize imports action. Previously, you
had to manually configure it in the settings and then use format to run
it.

Note: Default key binding will be `alt-shift-o` which is similar to
VSCode's organize import. Also, because `cmd-shift-o` is taken by
outline picker.

Todo:

- [x] Initial working
- [x] Handle remote
- [x] Handle multi buffer
- [x] Can we make it generic for executing any code action?

Release Notes:

- Added `editor:OrganizeImports` action to organize imports (sort,
remove unused, etc) for supported LSPs. You can trigger it by using the
`alt-shift-o` key binding.
2025-03-01 00:59:09 +05:30
277 changed files with 15830 additions and 5540 deletions

View File

@@ -0,0 +1,51 @@
name: Git Beta
description: There is a bug related to new Git features in Zed
type: "Bug"
labels: [git]
title: "Git Beta: <a short description of the Git bug>"
body:
- type: textarea
attributes:
label: Summary
description: Describe the bug with a one line summary, and provide detailed reproduction steps
value: |
<!-- Please insert a one line summary of the issue below -->
<!-- Include all steps necessary to reproduce from a clean Zed installation. Be verbose -->
Steps to trigger the problem:
1.
2.
3.
Actual Behavior:
Expected Behavior:
validations:
required: true
- type: textarea
id: environment
attributes:
label: Zed Version and System Specs
description: 'Open Zed, and in the command palette select "zed: Copy System Specs Into Clipboard"'
placeholder: |
Output of "zed: Copy System Specs Into Clipboard"
validations:
required: true
- type: textarea
attributes:
label: If applicable, attach your `~/Library/Logs/Zed/Zed.log` file to this issue.
description: |
macOS: `~/Library/Logs/Zed/Zed.log`
Linux: `~/.local/share/zed/logs/Zed.log` or $XDG_DATA_HOME
If you only need the most recent lines, you can run the `zed: open log` command palette action to see the last 1000.
value: |
<details><summary>Zed.log</summary>
<!-- Click below this line and paste or drag-and-drop your log-->
```
```
<!-- Click above this line and paste or drag-and-drop your log--></details>
validations:
required: false

View File

@@ -23,9 +23,47 @@ env:
RUST_BACKTRACE: 1
jobs:
job_spec:
name: Decide which jobs to run
if: github.repository_owner == 'zed-industries'
outputs:
run_tests: ${{ steps.filter.outputs.run_tests }}
runs-on:
- ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
# 350 is arbitrary; ~10days of history on main (5secs); full history is ~25secs
fetch-depth: ${{ github.ref == 'refs/heads/main' && 2 || 350 }}
- name: Fetch git history and generate output filters
id: filter
run: |
if [ -z "$GITHUB_BASE_REF" ]; then
echo "Not in a PR context (i.e., push to main/stable/preview)"
COMPARE_REV=$(git rev-parse HEAD~1)
else
echo "In a PR context comparing to pull_request.base.ref"
git fetch origin "$GITHUB_BASE_REF" --depth=350
COMPARE_REV=$(git merge-base "origin/${GITHUB_BASE_REF}" HEAD)
fi
if [[ $(git diff --name-only $COMPARE_REV ${{ github.sha }} | grep -v "^docs/") ]]; then
echo "run_tests=true" >> $GITHUB_OUTPUT
else
echo "run_tests=false" >> $GITHUB_OUTPUT
fi
if [[ $(git diff --name-only $COMPARE_REV ${{ github.sha }} | grep '^Cargo.lock') ]]; then
echo "run_license=true" >> $GITHUB_OUTPUT
else
echo "run_license=false" >> $GITHUB_OUTPUT
fi
migration_checks:
name: Check Postgres and Protobuf migrations, mergability
if: github.repository_owner == 'zed-industries'
needs: [job_spec]
if: |
github.repository_owner == 'zed-industries' &&
needs.job_spec.outputs.run_tests == 'true'
timeout-minutes: 60
runs-on:
- self-hosted
@@ -69,6 +107,7 @@ jobs:
style:
timeout-minutes: 60
name: Check formatting and spelling
needs: [job_spec]
if: github.repository_owner == 'zed-industries'
runs-on:
- buildjet-8vcpu-ubuntu-2204
@@ -76,6 +115,21 @@ jobs:
- name: Checkout repo
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
with:
version: 9
- name: Prettier Check on /docs
working-directory: ./docs
run: |
pnpm dlx prettier@${PRETTIER_VERSION} . --check || {
echo "To fix, run from the root of the zed repo:"
echo " cd docs && pnpm dlx prettier@${PRETTIER_VERSION} . --write && cd .."
false
}
env:
PRETTIER_VERSION: 3.5.0
# To support writing comments that they will certainly be revisited.
- name: Check for todo! and FIXME comments
run: script/check-todos
@@ -91,7 +145,10 @@ jobs:
macos_tests:
timeout-minutes: 60
name: (macOS) Run Clippy and tests
if: github.repository_owner == 'zed-industries'
needs: [job_spec]
if: |
github.repository_owner == 'zed-industries' &&
needs.job_spec.outputs.run_tests == 'true'
runs-on:
- self-hosted
- test
@@ -123,7 +180,9 @@ jobs:
- name: Check licenses
run: |
script/check-licenses
script/generate-licenses /tmp/zed_licenses_output
if [[ "${{ needs.job_spec.outputs.run_license }}" == "true" ]]; then
script/generate-licenses /tmp/zed_licenses_output
fi
- name: Check for new vulnerable dependencies
if: github.event_name == 'pull_request'
@@ -154,7 +213,10 @@ jobs:
linux_tests:
timeout-minutes: 60
name: (Linux) Run Clippy and tests
if: github.repository_owner == 'zed-industries'
needs: [job_spec]
if: |
github.repository_owner == 'zed-industries' &&
needs.job_spec.outputs.run_tests == 'true'
runs-on:
- buildjet-16vcpu-ubuntu-2204
steps:
@@ -203,9 +265,12 @@ jobs:
build_remote_server:
timeout-minutes: 60
name: (Linux) Build Remote Server
if: github.repository_owner == 'zed-industries'
needs: [job_spec]
if: |
github.repository_owner == 'zed-industries' &&
needs.job_spec.outputs.run_tests == 'true'
runs-on:
- buildjet-16vcpu-ubuntu-2204
- buildjet-8vcpu-ubuntu-2204
steps:
- name: Add Rust to the PATH
run: echo "$HOME/.cargo/bin" >> $GITHUB_PATH
@@ -236,11 +301,14 @@ jobs:
if: always()
run: rm -rf ./../.cargo
windows_tests:
windows_clippy:
timeout-minutes: 60
name: (Windows) Run Clippy and tests
if: github.repository_owner == 'zed-industries'
runs-on: hosted-windows-2
name: (Windows) Run Clippy
needs: [job_spec]
if: |
github.repository_owner == 'zed-industries' &&
needs.job_spec.outputs.run_tests == 'true'
runs-on: windows-2025-16
steps:
# more info here:- https://github.com/rust-lang/cargo/issues/13020
- name: Enable longer pathnames for git
@@ -275,6 +343,61 @@ jobs:
working-directory: ${{ env.ZED_WORKSPACE }}
run: ./script/clippy.ps1
- name: Check dev drive space
working-directory: ${{ env.ZED_WORKSPACE }}
# `setup-dev-driver.ps1` creates a 100GB drive, with CI taking up ~45GB of the drive.
run: ./script/exit-ci-if-dev-drive-is-full.ps1 95
# Since the Windows runners are stateful, so we need to remove the config file to prevent potential bug.
- name: Clean CI config file
if: always()
run: |
if (Test-Path "${{ env.CARGO_HOME }}/config.toml") {
Remove-Item -Path "${{ env.CARGO_HOME }}/config.toml" -Force
}
# Windows CI takes twice as long as our other platforms and fast github hosted runners are expensive.
# But we still want to do CI, so let's only run tests on main and come back to this when we're
# ready to self host our Windows CI (e.g. during the push for full Windows support)
windows_tests:
timeout-minutes: 60
name: (Windows) Run Tests
needs: [job_spec]
if: |
github.repository_owner == 'zed-industries' &&
needs.job_spec.outputs.run_tests == 'true'
# Use bigger runners for PRs (speed); smaller for async (cost)
runs-on: ${{ github.event_name == 'pull_request' && 'windows-2025-32' || 'windows-2025-16' }}
steps:
# more info here:- https://github.com/rust-lang/cargo/issues/13020
- name: Enable longer pathnames for git
run: git config --system core.longpaths true
- name: Checkout repo
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
clean: false
- name: Create Dev Drive using ReFS
run: ./script/setup-dev-driver.ps1
# actions/checkout does not let us clone into anywhere outside ${{ github.workspace }}, so we have to copy the clone...
- name: Copy Git Repo to Dev Drive
run: |
Copy-Item -Path "${{ github.workspace }}" -Destination "${{ env.ZED_WORKSPACE }}" -Recurse
- name: Cache dependencies
uses: swatinem/rust-cache@f0deed1e0edfc6a9be95417288c0e1099b1eeec3 # v2
with:
save-if: ${{ github.ref == 'refs/heads/main' }}
workspaces: ${{ env.ZED_WORKSPACE }}
cache-provider: "github"
- name: Configure CI
run: |
mkdir -p ${{ env.CARGO_HOME }} -ErrorAction Ignore
cp ./.cargo/ci-config.toml ${{ env.CARGO_HOME }}/config.toml
- name: Run tests
uses: ./.github/actions/run_tests_windows
with:
@@ -292,7 +415,45 @@ jobs:
# Since the Windows runners are stateful, so we need to remove the config file to prevent potential bug.
- name: Clean CI config file
if: always()
run: Remove-Item -Path "${{ env.CARGO_HOME }}/config.toml" -Force
run: |
if (Test-Path "${{ env.CARGO_HOME }}/config.toml") {
Remove-Item -Path "${{ env.CARGO_HOME }}/config.toml" -Force
}
tests_pass:
name: Tests Pass
runs-on: ubuntu-latest
needs:
- job_spec
- style
- migration_checks
- linux_tests
- build_remote_server
- macos_tests
- windows_clippy
- windows_tests
if: always()
steps:
- name: Check all tests passed
run: |
# Check dependent jobs...
RET_CODE=0
# Always check style
[[ "${{ needs.style.result }}" != 'success' ]] && { RET_CODE=1; echo "style tests failed"; }
# Only check test jobs if they were supposed to run
if [[ "${{ needs.job_spec.outputs.run_tests }}" == "true" ]]; then
[[ "${{ needs.macos_tests.result }}" != 'success' ]] && { RET_CODE=1; echo "macOS tests failed"; }
[[ "${{ needs.linux_tests.result }}" != 'success' ]] && { RET_CODE=1; echo "Linux tests failed"; }
[[ "${{ needs.windows_tests.result }}" != 'success' ]] && { RET_CODE=1; echo "Windows tests failed"; }
[[ "${{ needs.windows_clippy.result }}" != 'success' ]] && { RET_CODE=1; echo "Windows clippy failed"; }
[[ "${{ needs.migration_checks.result }}" != 'success' ]] && { RET_CODE=1; echo "Migration checks failed"; }
[[ "${{ needs.build_remote_server.result }}" != 'success' ]] && { RET_CODE=1; echo "Remote server build failed"; }
fi
if [[ "$RET_CODE" -eq 0 ]]; then
echo "All tests passed successfully!"
fi
exit $RET_CODE
bundle-mac:
timeout-minutes: 120
@@ -300,7 +461,9 @@ jobs:
runs-on:
- self-hosted
- bundle
if: ${{ startsWith(github.ref, 'refs/tags/v') || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
if: |
startsWith(github.ref, 'refs/tags/v')
|| contains(github.event.pull_request.labels.*.name, 'run-bundling')
needs: [macos_tests]
env:
MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
@@ -390,7 +553,9 @@ jobs:
name: Linux x86_x64 release bundle
runs-on:
- buildjet-16vcpu-ubuntu-2004
if: ${{ startsWith(github.ref, 'refs/tags/v') || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
if: |
startsWith(github.ref, 'refs/tags/v')
|| contains(github.event.pull_request.labels.*.name, 'run-bundling')
needs: [linux_tests]
env:
ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
@@ -407,7 +572,7 @@ jobs:
run: ./script/linux && ./script/install-mold 2.34.0
- name: Determine version and release channel
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
if: startsWith(github.ref, 'refs/tags/v')
run: |
# This exports RELEASE_CHANNEL into env (GITHUB_ENV)
script/determine-release-channel
@@ -417,11 +582,22 @@ jobs:
- name: Upload Linux bundle to workflow run if main branch or specific label
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4
if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
if: |
github.ref == 'refs/heads/main'
|| contains(github.event.pull_request.labels.*.name, 'run-bundling')
with:
name: zed-${{ github.event.pull_request.head.sha || github.sha }}-x86_64-unknown-linux-gnu.tar.gz
path: target/release/zed-*.tar.gz
- name: Upload Linux remote server to workflow run if main branch or specific label
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4
if: |
github.ref == 'refs/heads/main'
|| contains(github.event.pull_request.labels.*.name, 'run-bundling')
with:
name: zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-x86_64-unknown-linux-gnu.gz
path: target/zed-remote-server-linux-x86_64.gz
- name: Upload app bundle to release
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
with:
@@ -438,7 +614,9 @@ jobs:
name: Linux arm64 release bundle
runs-on:
- buildjet-16vcpu-ubuntu-2204-arm
if: ${{ startsWith(github.ref, 'refs/tags/v') || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
if: |
startsWith(github.ref, 'refs/tags/v')
|| contains(github.event.pull_request.labels.*.name, 'run-bundling')
needs: [linux_tests]
env:
ZED_CLIENT_CHECKSUM_SEED: ${{ secrets.ZED_CLIENT_CHECKSUM_SEED }}
@@ -455,7 +633,7 @@ jobs:
run: ./script/linux
- name: Determine version and release channel
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
if: startsWith(github.ref, 'refs/tags/v')
run: |
# This exports RELEASE_CHANNEL into env (GITHUB_ENV)
script/determine-release-channel
@@ -465,11 +643,22 @@ jobs:
- name: Upload Linux bundle to workflow run if main branch or specific label
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4
if: ${{ github.ref == 'refs/heads/main' }} || contains(github.event.pull_request.labels.*.name, 'run-bundling') }}
if: |
github.ref == 'refs/heads/main'
|| contains(github.event.pull_request.labels.*.name, 'run-bundling')
with:
name: zed-${{ github.event.pull_request.head.sha || github.sha }}-aarch64-unknown-linux-gnu.tar.gz
path: target/release/zed-*.tar.gz
- name: Upload Linux remote server to workflow run if main branch or specific label
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4
if: |
github.ref == 'refs/heads/main'
|| contains(github.event.pull_request.labels.*.name, 'run-bundling')
with:
name: zed-remote-server-${{ github.event.pull_request.head.sha || github.sha }}-aarch64-unknown-linux-gnu.gz
path: target/zed-remote-server-linux-aarch64.gz
- name: Upload app bundle to release
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
with:
@@ -483,7 +672,9 @@ jobs:
auto-release-preview:
name: Auto release preview
if: ${{ startsWith(github.ref, 'refs/tags/v') && endsWith(github.ref, '-pre') && !endsWith(github.ref, '.0-pre') }}
if: |
startsWith(github.ref, 'refs/tags/v')
&& endsWith(github.ref, '-pre') && !endsWith(github.ref, '.0-pre')
needs: [bundle-mac, bundle-linux-x86_x64, bundle-linux-aarch64]
runs-on:
- self-hosted

View File

@@ -17,7 +17,7 @@ jobs:
else
URL="https://zed.dev/releases/stable/latest"
fi
echo "::set-output name=URL::$URL"
echo "URL=$URL" >> $GITHUB_OUTPUT
- name: Get content
uses: 2428392/gh-truncate-string-action@b3ff790d21cf42af3ca7579146eedb93c8fb0757 # v1.4.1
id: get-content
@@ -33,3 +33,33 @@ jobs:
with:
webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
content: ${{ steps.get-content.outputs.string }}
send_release_notes_email:
if: github.repository_owner == 'zed-industries' && !github.event.release.prerelease
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check if release was promoted from preview
id: check-promotion-from-preview
run: |
VERSION="${{ github.event.release.tag_name }}"
PREVIEW_TAG="${VERSION}-pre"
if git rev-parse "$PREVIEW_TAG" >/dev/null 2>&1; then
echo "was_preview=true" >> $GITHUB_OUTPUT
else
echo "was_preview=false" >> $GITHUB_OUTPUT
fi
- name: Send release notes email
if: steps.check-promotion-from-preview.outputs.was_preview == 'true'
run: |
curl -X POST "https://zed.dev/api/send_release_notes_email" \
-H "Authorization: Bearer ${{ secrets.RELEASE_NOTES_API_TOKEN }}" \
-H "Content-Type: application/json" \
-d '{
"version": "${{ github.event.release.tag_name }}",
"markdown_body": ${{ toJSON(github.event.release.body) }}
}'

View File

@@ -1,39 +0,0 @@
name: Docs
on:
pull_request:
paths:
- "docs/**"
push:
branches:
- main
jobs:
check_formatting:
name: "Check formatting"
if: github.repository_owner == 'zed-industries'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
with:
version: 9
- name: Prettier Check on /docs
working-directory: ./docs
run: |
pnpm dlx prettier@${PRETTIER_VERSION} . --check || {
echo "To fix, run from the root of the zed repo:"
echo " cd docs && pnpm dlx prettier@${PRETTIER_VERSION} . --write && cd .."
false
}
env:
PRETTIER_VERSION: 3.5.0
- name: Check for Typos with Typos-CLI
uses: crate-ci/typos@8e6a4285bcbde632c5d79900a7779746e8b7ea3f # v1.24.6
with:
config: ./typos.toml
files: ./docs/

224
Cargo.lock generated
View File

@@ -358,6 +358,19 @@ dependencies = [
"zbus",
]
[[package]]
name = "askpass"
version = "0.1.0"
dependencies = [
"anyhow",
"futures 0.3.31",
"gpui",
"smol",
"tempfile",
"util",
"which 6.0.3",
]
[[package]]
name = "assets"
version = "0.1.0"
@@ -405,6 +418,7 @@ dependencies = [
"pretty_assertions",
"project",
"prompt_library",
"prompt_store",
"proto",
"rand 0.8.5",
"rope",
@@ -472,6 +486,7 @@ dependencies = [
"picker",
"project",
"prompt_library",
"prompt_store",
"proto",
"rand 0.8.5",
"rope",
@@ -526,7 +541,7 @@ dependencies = [
"picker",
"pretty_assertions",
"project",
"prompt_library",
"prompt_store",
"rand 0.8.5",
"regex",
"rope",
@@ -617,7 +632,7 @@ dependencies = [
"log",
"pretty_assertions",
"project",
"prompt_library",
"prompt_store",
"rope",
"schemars",
"semantic_index",
@@ -1176,9 +1191,9 @@ dependencies = [
[[package]]
name = "aws-config"
version = "1.5.17"
version = "1.5.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "490aa7465ee685b2ced076bb87ef654a47724a7844e2c7d3af4e749ce5b875dd"
checksum = "50236e4d60fe8458de90a71c0922c761e41755adf091b1b03de1cef537179915"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -1269,9 +1284,9 @@ dependencies = [
[[package]]
name = "aws-sdk-bedrockruntime"
version = "1.75.0"
version = "1.74.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ddf7475b6f50a1a5be8edb1bcdf6e4ae00feed5b890d14a3f1f0e14d76f5a16"
checksum = "6938541d1948a543bca23303fec4cff9c36bf0e63b8fa3ae1b337bcb9d5b81af"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -1293,9 +1308,9 @@ dependencies = [
[[package]]
name = "aws-sdk-kinesis"
version = "1.62.0"
version = "1.61.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e31622345afd0c35d33c1cbba73ccf9fb88e09857413d8963dea2c493e00704d"
checksum = "89f2163d8704e8fdcd51ec6c2e0441c418471e422ee9690451b17a1c46344e1a"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -1315,9 +1330,9 @@ dependencies = [
[[package]]
name = "aws-sdk-s3"
version = "1.77.0"
version = "1.76.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34e87342432a3de0e94e82c99a7cbd9042f99de029ae1f4e368160f9e9929264"
checksum = "66e83401ad7287ad15244d557e35502c2a94105ca5b41d656c391f1a4fc04ca2"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -1349,9 +1364,9 @@ dependencies = [
[[package]]
name = "aws-sdk-sso"
version = "1.60.0"
version = "1.58.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60186fab60b24376d3e33b9ff0a43485f99efd470e3b75a9160c849741d63d56"
checksum = "16ff718c9ee45cc1ebd4774a0e086bb80a6ab752b4902edf1c9f56b86ee1f770"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -1371,9 +1386,9 @@ dependencies = [
[[package]]
name = "aws-sdk-ssooidc"
version = "1.61.0"
version = "1.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7033130ce1ee13e6018905b7b976c915963755aef299c1521897679d6cd4f8ef"
checksum = "5183e088715cc135d8d396fdd3bc02f018f0da4c511f53cb8d795b6a31c55809"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -1393,9 +1408,9 @@ dependencies = [
[[package]]
name = "aws-sdk-sts"
version = "1.61.0"
version = "1.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5c1cac7677179d622b4448b0d31bcb359185295dc6fca891920cfb17e2b5156"
checksum = "c9f944ef032717596639cea4a2118a3a457268ef51bbb5fde9637e54c465da00"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -1456,9 +1471,9 @@ dependencies = [
[[package]]
name = "aws-smithy-checksums"
version = "0.63.0"
version = "0.62.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db2dc8d842d872529355c72632de49ef8c5a2949a4472f10e802f28cf925770c"
checksum = "f2f45a1c384d7a393026bc5f5c177105aa9fa68e4749653b985707ac27d77295"
dependencies = [
"aws-smithy-http",
"aws-smithy-types",
@@ -1808,7 +1823,7 @@ dependencies = [
"bitflags 2.8.0",
"cexpr",
"clang-sys",
"itertools 0.10.5",
"itertools 0.12.1",
"lazy_static",
"lazycell",
"log",
@@ -1831,7 +1846,7 @@ dependencies = [
"bitflags 2.8.0",
"cexpr",
"clang-sys",
"itertools 0.10.5",
"itertools 0.12.1",
"log",
"prettyplease",
"proc-macro2",
@@ -2076,6 +2091,7 @@ name = "buffer_diff"
version = "0.1.0"
dependencies = [
"anyhow",
"clock",
"ctor",
"env_logger 0.11.6",
"futures 0.3.31",
@@ -2401,6 +2417,25 @@ dependencies = [
"cipher",
]
[[package]]
name = "cbindgen"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fce8dd7fcfcbf3a0a87d8f515194b49d6135acab73e18bd380d1d93bb1a15eb"
dependencies = [
"clap",
"heck 0.4.1",
"indexmap",
"log",
"proc-macro2",
"quote",
"serde",
"serde_json",
"syn 2.0.90",
"tempfile",
"toml 0.8.20",
]
[[package]]
name = "cbindgen"
version = "0.28.0"
@@ -2498,9 +2533,9 @@ dependencies = [
[[package]]
name = "chrono"
version = "0.4.40"
version = "0.4.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"
dependencies = [
"android-tzdata",
"iana-time-zone",
@@ -2508,7 +2543,7 @@ dependencies = [
"num-traits",
"serde",
"wasm-bindgen",
"windows-link",
"windows-targets 0.52.6",
]
[[package]]
@@ -2841,7 +2876,7 @@ dependencies = [
"pretty_assertions",
"project",
"prometheus",
"prompt_library",
"prompt_store",
"prost 0.9.0",
"rand 0.8.5",
"recent_projects",
@@ -3011,8 +3046,12 @@ dependencies = [
name = "component_preview"
version = "0.1.0"
dependencies = [
"client",
"component",
"gpui",
"languages",
"notifications",
"project",
"ui",
"workspace",
]
@@ -3505,10 +3544,11 @@ dependencies = [
[[package]]
name = "crc64fast-nvme"
version = "1.2.0"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4955638f00a809894c947f85a024020a20815b65a5eea633798ea7924edab2b3"
checksum = "d5e2ee08013e3f228d6d2394116c4549a6df77708442c62d887d83f68ef2ee37"
dependencies = [
"cbindgen 0.27.0",
"crc",
]
@@ -4411,7 +4451,6 @@ dependencies = [
"env_logger 0.11.6",
"feature_flags",
"fs",
"git",
"gpui",
"http_client",
"language",
@@ -5334,9 +5373,11 @@ name = "git"
version = "0.1.0"
dependencies = [
"anyhow",
"askpass",
"async-trait",
"collections",
"derive_more",
"futures 0.3.31",
"git2",
"gpui",
"http_client",
@@ -5393,31 +5434,46 @@ name = "git_ui"
version = "0.1.0"
dependencies = [
"anyhow",
"askpass",
"assistant_settings",
"buffer_diff",
"chrono",
"collections",
"command_palette_hooks",
"component",
"ctor",
"db",
"editor",
"feature_flags",
"env_logger 0.11.6",
"futures 0.3.31",
"fuzzy",
"git",
"gpui",
"itertools 0.14.0",
"language",
"language_model",
"linkify",
"linkme",
"log",
"menu",
"multi_buffer",
"notifications",
"panel",
"picker",
"postage",
"pretty_assertions",
"project",
"schemars",
"serde",
"serde_derive",
"serde_json",
"settings",
"smallvec",
"strum",
"telemetry",
"theme",
"time",
"time_format",
"ui",
"unindent",
"util",
@@ -5554,7 +5610,7 @@ dependencies = [
"bytemuck",
"calloop",
"calloop-wayland-source",
"cbindgen",
"cbindgen 0.28.0",
"cocoa 0.26.0",
"collections",
"core-foundation 0.9.4",
@@ -7227,9 +7283,9 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
[[package]]
name = "libc"
version = "0.2.170"
version = "0.2.169"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828"
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
[[package]]
name = "libdbus-sys"
@@ -8277,13 +8333,17 @@ dependencies = [
"channel",
"client",
"collections",
"component",
"db",
"gpui",
"linkme",
"rpc",
"settings",
"sum_tree",
"time",
"ui",
"util",
"workspace",
]
[[package]]
@@ -9756,15 +9816,6 @@ dependencies = [
"indexmap",
]
[[package]]
name = "pgvector"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0e8871b6d7ca78348c6cd29b911b94851f3429f0cd403130ca17f26c1fb91a6"
dependencies = [
"serde",
]
[[package]]
name = "phf"
version = "0.11.2"
@@ -10182,6 +10233,7 @@ version = "0.1.0"
dependencies = [
"aho-corasick",
"anyhow",
"askpass",
"async-trait",
"buffer_diff",
"client",
@@ -10309,12 +10361,36 @@ dependencies = [
[[package]]
name = "prompt_library"
version = "0.1.0"
dependencies = [
"anyhow",
"collections",
"editor",
"gpui",
"language",
"language_model",
"log",
"menu",
"picker",
"prompt_store",
"release_channel",
"rope",
"serde",
"settings",
"theme",
"ui",
"util",
"workspace",
"zed_actions",
]
[[package]]
name = "prompt_store"
version = "0.1.0"
dependencies = [
"anyhow",
"assets",
"chrono",
"collections",
"editor",
"fs",
"futures 0.3.31",
"fuzzy",
@@ -10322,23 +10398,14 @@ dependencies = [
"handlebars 4.5.0",
"heed",
"language",
"language_model",
"log",
"menu",
"parking_lot",
"paths",
"picker",
"release_channel",
"rope",
"serde",
"settings",
"text",
"theme",
"ui",
"util",
"uuid",
"workspace",
"zed_actions",
]
[[package]]
@@ -10389,7 +10456,7 @@ checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4"
dependencies = [
"bytes 1.10.0",
"heck 0.5.0",
"itertools 0.10.5",
"itertools 0.12.1",
"log",
"multimap 0.10.0",
"once_cell",
@@ -10422,7 +10489,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1"
dependencies = [
"anyhow",
"itertools 0.10.5",
"itertools 0.12.1",
"proc-macro2",
"quote",
"syn 2.0.90",
@@ -10988,6 +11055,7 @@ name = "remote"
version = "0.1.0"
dependencies = [
"anyhow",
"askpass",
"async-trait",
"collections",
"fs",
@@ -11008,7 +11076,6 @@ dependencies = [
"tempfile",
"thiserror 1.0.69",
"util",
"which 6.0.3",
]
[[package]]
@@ -11450,9 +11517,9 @@ dependencies = [
[[package]]
name = "rust-embed"
version = "8.6.0"
version = "8.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b3aba5104622db5c9fc61098de54708feb732e7763d7faa2fa625899f00bf6f"
checksum = "fa66af4a4fdd5e7ebc276f115e895611a34739a9c1c01028383d612d550953c0"
dependencies = [
"rust-embed-impl",
"rust-embed-utils",
@@ -11461,9 +11528,9 @@ dependencies = [
[[package]]
name = "rust-embed-impl"
version = "8.6.0"
version = "8.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f198c73be048d2c5aa8e12f7960ad08443e56fd39cc26336719fdb4ea0ebaae"
checksum = "6125dbc8867951125eec87294137f4e9c2c96566e61bf72c45095a7c77761478"
dependencies = [
"proc-macro2",
"quote",
@@ -11474,9 +11541,9 @@ dependencies = [
[[package]]
name = "rust-embed-utils"
version = "8.6.0"
version = "8.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a2fcdc9f40c8dc2922842ca9add611ad19f332227fc651d015881ad1552bd9a"
checksum = "2e5347777e9aacb56039b0e1f28785929a8a3b709e87482e7442c72e7c12529d"
dependencies = [
"globset",
"sha2",
@@ -11751,9 +11818,9 @@ dependencies = [
[[package]]
name = "schemars"
version = "0.8.22"
version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615"
checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92"
dependencies = [
"dyn-clone",
"indexmap",
@@ -11764,9 +11831,9 @@ dependencies = [
[[package]]
name = "schemars_derive"
version = "0.8.22"
version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d"
checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e"
dependencies = [
"proc-macro2",
"quote",
@@ -11829,18 +11896,17 @@ dependencies = [
[[package]]
name = "sea-orm"
version = "1.1.6"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13fba7b2c749b2d0a00303d5cb13e6761e39a4172554bdf930852cac4e7aeabd"
checksum = "00733e5418e8ae3758cdb988c3654174e716230cc53ee2cb884207cf86a23029"
dependencies = [
"async-stream",
"async-trait",
"bigdecimal",
"chrono",
"futures-util",
"futures 0.3.31",
"log",
"ouroboros",
"pgvector",
"rust_decimal",
"sea-orm-macros",
"sea-query",
@@ -11858,9 +11924,9 @@ dependencies = [
[[package]]
name = "sea-orm-macros"
version = "1.1.6"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2568cff8d35d5150b4276cc0dd766192a587f64b6ece60ae3706e0872c4eb209"
checksum = "a98408f82fb4875d41ef469a79944a7da29767c7b3e4028e22188a3dd613b10f"
dependencies = [
"heck 0.4.1",
"proc-macro2",
@@ -13835,6 +13901,7 @@ dependencies = [
"client",
"collections",
"feature_flags",
"git_ui",
"gpui",
"http_client",
"notifications",
@@ -14210,9 +14277,9 @@ dependencies = [
[[package]]
name = "tree-sitter"
version = "0.25.2"
version = "0.25.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5168a515fe492af54c5cc8800ff8c840be09fa5168de45838afaecd3e008bce4"
checksum = "b9ac5ea5e7f2f1700842ec071401010b9c59bf735295f6e9fa079c3dc035b167"
dependencies = [
"cc",
"regex",
@@ -14780,9 +14847,9 @@ dependencies = [
[[package]]
name = "uuid"
version = "1.15.1"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0f540e3240398cce6128b64ba83fdbdd86129c16a3aa1a3a252efd66eb3d587"
checksum = "8c1f41ffb7cf259f1ecc2876861a17e7142e63ead296f671f81f6ae85903e0d6"
dependencies = [
"getrandom 0.3.1",
"serde",
@@ -14884,6 +14951,7 @@ dependencies = [
"multi_buffer",
"nvim-rs",
"parking_lot",
"project",
"project_panel",
"regex",
"release_channel",
@@ -15905,12 +15973,6 @@ dependencies = [
"syn 2.0.90",
]
[[package]]
name = "windows-link"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3"
[[package]]
name = "windows-registry"
version = "0.2.0"
@@ -16746,7 +16808,7 @@ dependencies = [
[[package]]
name = "zed"
version = "0.177.0"
version = "0.177.11"
dependencies = [
"activity_indicator",
"anyhow",
@@ -16824,7 +16886,7 @@ dependencies = [
"project",
"project_panel",
"project_symbols",
"prompt_library",
"prompt_store",
"proto",
"recent_projects",
"release_channel",

View File

@@ -3,6 +3,7 @@ resolver = "2"
members = [
"crates/activity_indicator",
"crates/anthropic",
"crates/askpass",
"crates/assets",
"crates/assistant",
"crates/assistant2",
@@ -103,6 +104,7 @@ members = [
"crates/project_panel",
"crates/project_symbols",
"crates/prompt_library",
"crates/prompt_store",
"crates/proto",
"crates/recent_projects",
"crates/refineable",
@@ -208,6 +210,7 @@ edition = "2021"
activity_indicator = { path = "crates/activity_indicator" }
ai = { path = "crates/ai" }
anthropic = { path = "crates/anthropic" }
askpass = { path = "crates/askpass" }
assets = { path = "crates/assets" }
assistant = { path = "crates/assistant" }
assistant2 = { path = "crates/assistant2" }
@@ -308,6 +311,7 @@ project = { path = "crates/project" }
project_panel = { path = "crates/project_panel" }
project_symbols = { path = "crates/project_symbols" }
prompt_library = { path = "crates/prompt_library" }
prompt_store = { path = "crates/prompt_store" }
proto = { path = "crates/proto" }
recent_projects = { path = "crates/recent_projects" }
refineable = { path = "crates/refineable" }
@@ -536,7 +540,7 @@ tiny_http = "0.8"
toml = "0.8"
tokio = { version = "1" }
tower-http = "0.4.4"
tree-sitter = { version = "0.25.2", features = ["wasm"] }
tree-sitter = { version = "0.25.3", features = ["wasm"] }
tree-sitter-bash = "0.23"
tree-sitter-c = "0.23"
tree-sitter-cpp = "0.23"
@@ -749,4 +753,4 @@ should_implement_trait = { level = "allow" }
let_underscore_future = "allow"
[workspace.metadata.cargo-machete]
ignored = ["bindgen", "cbindgen", "prost_build", "serde"]
ignored = ["bindgen", "cbindgen", "prost_build", "serde", "component", "linkme"]

10
assets/icons/ai_edit.svg Normal file
View File

@@ -0,0 +1,10 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12.5871 5.40624C12.8514 5.14195 13 4.78346 13 4.40965C13 4.03583 12.8516 3.67731 12.5873 3.41295C12.323 3.14859 11.9645 3.00005 11.5907 3C11.2169 2.99995 10.8584 3.14841 10.594 3.4127L3.92098 10.0874C3.80488 10.2031 3.71903 10.3456 3.67097 10.5024L3.01047 12.6784C2.99754 12.7217 2.99657 12.7676 3.00764 12.8113C3.01872 12.8551 3.04143 12.895 3.07337 12.9269C3.1053 12.9588 3.14528 12.9815 3.18905 12.9925C3.23282 13.0035 3.27875 13.0024 3.32197 12.9894L5.49849 12.3294C5.65508 12.2818 5.79758 12.1964 5.91349 12.0809L12.5871 5.40624Z" stroke="black" stroke-width="1.33" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10 4L12 6" stroke="black" stroke-width="1.33" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6.38818 3.53598V2.53598" stroke="black" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9.56982 12.6995L9.56982 13.6995" stroke="black" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2.38818 6.53598H3.38818" stroke="black" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13.5698 9.69949L12.5698 9.69949" stroke="black" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4.38818 4.53598L3.38818 3.53598" stroke="black" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M11.5698 11.6995L12.5698 12.6995" stroke="black" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

1
assets/icons/cloud.svg Normal file
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-cloud"><path d="M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z"/></svg>

After

Width:  |  Height:  |  Size: 279 B

View File

@@ -0,0 +1,6 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.75 3.25C4.02614 3.25 4.25 3.02614 4.25 2.75C4.25 2.47386 4.02614 2.25 3.75 2.25C3.47386 2.25 3.25 2.47386 3.25 2.75C3.25 3.02614 3.47386 3.25 3.75 3.25ZM3.75 4.25C4.57843 4.25 5.25 3.57843 5.25 2.75C5.25 1.92157 4.57843 1.25 3.75 1.25C2.92157 1.25 2.25 1.92157 2.25 2.75C2.25 3.57843 2.92157 4.25 3.75 4.25Z" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.25 3.25C8.52614 3.25 8.75 3.02614 8.75 2.75C8.75 2.47386 8.52614 2.25 8.25 2.25C7.97386 2.25 7.75 2.47386 7.75 2.75C7.75 3.02614 7.97386 3.25 8.25 3.25ZM8.25 4.25C9.07843 4.25 9.75 3.57843 9.75 2.75C9.75 1.92157 9.07843 1.25 8.25 1.25C7.42157 1.25 6.75 1.92157 6.75 2.75C6.75 3.57843 7.42157 4.25 8.25 4.25Z" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.75 9.75C4.02614 9.75 4.25 9.52614 4.25 9.25C4.25 8.97386 4.02614 8.75 3.75 8.75C3.47386 8.75 3.25 8.97386 3.25 9.25C3.25 9.52614 3.47386 9.75 3.75 9.75ZM3.75 10.75C4.57843 10.75 5.25 10.0784 5.25 9.25C5.25 8.42157 4.57843 7.75 3.75 7.75C2.92157 7.75 2.25 8.42157 2.25 9.25C2.25 10.0784 2.92157 10.75 3.75 10.75Z" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.25 3.75H4.25V5.59609C4.67823 5.35824 5.24991 5.25 6 5.25H7.25017C7.5262 5.25 7.75 5.02625 7.75 4.75V3.75H8.75V4.75C8.75 5.57832 8.07871 6.25 7.25017 6.25H6C5.14559 6.25 4.77639 6.41132 4.59684 6.56615C4.42571 6.71373 4.33877 6.92604 4.25 7.30651V8.25H3.25V3.75Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,40 @@
<svg width="400" height="120" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="tilePattern" width="124" height="24" patternUnits="userSpaceOnUse">
<svg width="124" height="24" viewBox="0 0 124 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.2">
<path d="M16.666 12.0013L11.9993 16.668L7.33268 12.0013" stroke="white" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 7.33464L12 16.668" stroke="white" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M29 8.33464C29.3682 8.33464 29.6667 8.03616 29.6667 7.66797C29.6667 7.29978 29.3682 7.0013 29 7.0013C28.6318 7.0013 28.3333 7.29978 28.3333 7.66797C28.3333 8.03616 28.6318 8.33464 29 8.33464ZM29 9.66797C30.1046 9.66797 31 8.77254 31 7.66797C31 6.5634 30.1046 5.66797 29 5.66797C27.8954 5.66797 27 6.5634 27 7.66797C27 8.77254 27.8954 9.66797 29 9.66797Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M35 8.33464C35.3682 8.33464 35.6667 8.03616 35.6667 7.66797C35.6667 7.29978 35.3682 7.0013 35 7.0013C34.6318 7.0013 34.3333 7.29978 34.3333 7.66797C34.3333 8.03616 34.6318 8.33464 35 8.33464ZM35 9.66797C36.1046 9.66797 37 8.77254 37 7.66797C37 6.5634 36.1046 5.66797 35 5.66797C33.8954 5.66797 33 6.5634 33 7.66797C33 8.77254 33.8954 9.66797 35 9.66797Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M29 16.9987C29.3682 16.9987 29.6667 16.7002 29.6667 16.332C29.6667 15.9638 29.3682 15.6654 29 15.6654C28.6318 15.6654 28.3333 15.9638 28.3333 16.332C28.3333 16.7002 28.6318 16.9987 29 16.9987ZM29 18.332C30.1046 18.332 31 17.4366 31 16.332C31 15.2275 30.1046 14.332 29 14.332C27.8954 14.332 27 15.2275 27 16.332C27 17.4366 27.8954 18.332 29 18.332Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M28.334 9H29.6673V11.4615C30.2383 11.1443 31.0005 11 32.0007 11H33.6675C34.0356 11 34.334 10.7017 34.334 10.3333V9H35.6673V10.3333C35.6673 11.4378 34.7723 12.3333 33.6675 12.3333H32.0007C30.8614 12.3333 30.3692 12.5484 30.1298 12.7549C29.9016 12.9516 29.7857 13.2347 29.6673 13.742V15H28.334V9Z" fill="white"/>
<path d="M48.668 8.66406H55.3346V15.3307" stroke="white" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M48.668 15.3307L55.3346 8.66406" stroke="white" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M76.5871 9.40624C76.8514 9.14195 77 8.78346 77 8.40965C77 8.03583 76.8516 7.67731 76.5873 7.41295C76.323 7.14859 75.9645 7.00005 75.5907 7C75.2169 6.99995 74.8584 7.14841 74.594 7.4127L67.921 14.0874C67.8049 14.2031 67.719 14.3456 67.671 14.5024L67.0105 16.6784C66.9975 16.7217 66.9966 16.7676 67.0076 16.8113C67.0187 16.8551 67.0414 16.895 67.0734 16.9269C67.1053 16.9588 67.1453 16.9815 67.1891 16.9925C67.2328 17.0035 67.2788 17.0024 67.322 16.9894L69.4985 16.3294C69.6551 16.2818 69.7976 16.1964 69.9135 16.0809L76.5871 9.40624Z" stroke="white" stroke-width="1.33" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M74 8L76 10" stroke="white" stroke-width="1.33" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M70.3877 7.53516V6.53516" stroke="white" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M73.5693 16.6992V17.6992" stroke="white" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M66.3877 10.5352H67.3877" stroke="white" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M77.5693 13.6992H76.5693" stroke="white" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M68.3877 8.53516L67.3877 7.53516" stroke="white" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M75.5693 15.6992L76.5693 16.6992" stroke="white" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M87.334 11.9987L92.0007 7.33203L96.6673 11.9987" stroke="white" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M92 16.6654V7.33203" stroke="white" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M117 12C117 10.6739 116.473 9.40215 115.536 8.46447C114.598 7.52678 113.326 7 112 7C110.602 7.00526 109.261 7.55068 108.256 8.52222L107 9.77778" stroke="white" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M107 7V9.77778H109.778" stroke="white" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M107 12C107 13.3261 107.527 14.5979 108.464 15.5355C109.402 16.4732 110.674 17 112 17C113.398 16.9947 114.739 16.4493 115.744 15.4778L117 14.2222" stroke="white" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M114.223 14.2188H117V16.9965" stroke="white" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>
</pattern>
<linearGradient id="fade" y2="1" x2="0">
<stop offset="0" stop-color="white" stop-opacity=".52"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<mask id="fadeMask" maskContentUnits="objectBoundingBox">
<rect width="1" height="1" fill="url(#fade)"/>
</mask>
</defs>
<rect width="100%" height="100%" fill="url(#tilePattern)" mask="url(#fadeMask)"/>
</svg>

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -10,8 +10,8 @@
"pagedown": "menu::SelectLast",
"ctrl-n": "menu::SelectNext",
"tab": "menu::SelectNext",
"ctrl-p": "menu::SelectPrev",
"shift-tab": "menu::SelectPrev",
"ctrl-p": "menu::SelectPrevious",
"shift-tab": "menu::SelectPrevious",
"enter": "menu::Confirm",
"ctrl-enter": "menu::SecondaryConfirm",
"ctrl-escape": "menu::Cancel",
@@ -38,14 +38,14 @@
{
"context": "Picker || menu",
"bindings": {
"up": "menu::SelectPrev",
"up": "menu::SelectPrevious",
"down": "menu::SelectNext"
}
},
{
"context": "Prompt",
"bindings": {
"left": "menu::SelectPrev",
"left": "menu::SelectPrevious",
"right": "menu::SelectNext"
}
},
@@ -57,7 +57,7 @@
"backspace": "editor::Backspace",
"delete": "editor::Delete",
"tab": "editor::Tab",
"shift-tab": "editor::TabPrev",
"shift-tab": "editor::Backtab",
"ctrl-k": "editor::CutToEndOfLine",
// "ctrl-t": "editor::Transpose",
"ctrl-k ctrl-q": "editor::Rewrap",
@@ -180,7 +180,7 @@
"ctrl-k c": "assistant::CopyCode",
"ctrl-shift-e": "project_panel::ToggleFocus",
"ctrl-g": "search::SelectNextMatch",
"ctrl-shift-g": "search::SelectPrevMatch",
"ctrl-shift-g": "search::SelectPreviousMatch",
"ctrl-alt-/": "assistant::ToggleModelSelector",
"ctrl-k h": "assistant::DeployHistory",
"ctrl-k l": "assistant::DeployPromptLibrary",
@@ -203,7 +203,7 @@
"escape": "buffer_search::Dismiss",
"tab": "buffer_search::FocusEditor",
"enter": "search::SelectNextMatch",
"shift-enter": "search::SelectPrevMatch",
"shift-enter": "search::SelectPreviousMatch",
"alt-enter": "search::SelectAllMatches",
"find": "search::FocusSearch",
"ctrl-f": "search::FocusSearch",
@@ -272,7 +272,7 @@
"alt-8": ["pane::ActivateItem", 7],
"alt-9": ["pane::ActivateItem", 8],
"alt-0": "pane::ActivateLastItem",
"ctrl-pageup": "pane::ActivatePrevItem",
"ctrl-pageup": "pane::ActivatePreviousItem",
"ctrl-pagedown": "pane::ActivateNextItem",
"ctrl-shift-pageup": "pane::SwapItemLeft",
"ctrl-shift-pagedown": "pane::SwapItemRight",
@@ -290,8 +290,8 @@
"forward": "pane::GoForward",
"ctrl-alt-g": "search::SelectNextMatch",
"f3": "search::SelectNextMatch",
"ctrl-alt-shift-g": "search::SelectPrevMatch",
"shift-f3": "search::SelectPrevMatch",
"ctrl-alt-shift-g": "search::SelectPreviousMatch",
"shift-f3": "search::SelectPreviousMatch",
"shift-find": "project_search::ToggleFocus",
"ctrl-shift-f": "project_search::ToggleFocus",
"ctrl-alt-shift-h": "search::ToggleReplace",
@@ -334,7 +334,7 @@
"ctrl-u": "editor::UndoSelection",
"ctrl-shift-u": "editor::RedoSelection",
"f8": "editor::GoToDiagnostic",
"shift-f8": "editor::GoToPrevDiagnostic",
"shift-f8": "editor::GoToPreviousDiagnostic",
"f2": "editor::Rename",
"f12": "editor::GoToDefinition",
"alt-f12": "editor::GoToDefinitionSplit",
@@ -373,7 +373,7 @@
"alt-y": "git::StageAndNext",
"alt-shift-y": "git::UnstageAndNext",
"alt-.": "editor::GoToHunk",
"alt-,": "editor::GoToPrevHunk"
"alt-,": "editor::GoToPreviousHunk"
}
},
{
@@ -393,6 +393,7 @@
"alt-shift-open": "projects::OpenRemote",
"alt-ctrl-shift-o": "projects::OpenRemote",
"alt-ctrl-shift-b": "branches::OpenRecent",
"alt-shift-enter": "toast::RunAction",
"ctrl-~": "workspace::NewTerminal",
"save": "workspace::Save",
"ctrl-s": "workspace::Save",
@@ -536,8 +537,8 @@
{
"context": "Editor && (showing_code_actions || showing_completions)",
"bindings": {
"ctrl-p": "editor::ContextMenuPrev",
"up": "editor::ContextMenuPrev",
"ctrl-p": "editor::ContextMenuPrevious",
"up": "editor::ContextMenuPrevious",
"ctrl-n": "editor::ContextMenuNext",
"down": "editor::ContextMenuNext",
"pageup": "editor::ContextMenuFirst",
@@ -565,7 +566,7 @@
"ctrl-alt-enter": "editor::OpenExcerptsSplit",
"ctrl-shift-e": "pane::RevealInProjectPanel",
"ctrl-f8": "editor::GoToHunk",
"ctrl-shift-f8": "editor::GoToPrevHunk",
"ctrl-shift-f8": "editor::GoToPreviousHunk",
"ctrl-enter": "assistant::InlineAssist",
"ctrl-:": "editor::ToggleInlayHints"
}
@@ -662,7 +663,7 @@
"alt-ctrl-r": "outline_panel::RevealInFileManager",
"space": "outline_panel::Open",
"shift-down": "menu::SelectNext",
"shift-up": "menu::SelectPrev",
"shift-up": "menu::SelectPrevious",
"alt-enter": "editor::OpenExcerpts",
"ctrl-alt-enter": "editor::OpenExcerptsSplit"
}
@@ -700,7 +701,7 @@
"shift-find": "project_panel::NewSearchInDirectory",
"ctrl-shift-f": "project_panel::NewSearchInDirectory",
"shift-down": "menu::SelectNext",
"shift-up": "menu::SelectPrev",
"shift-up": "menu::SelectPrevious",
"escape": "menu::Cancel"
}
},
@@ -713,30 +714,57 @@
{
"context": "GitPanel && ChangesList",
"bindings": {
"up": "menu::SelectPrev",
"up": "menu::SelectPrevious",
"down": "menu::SelectNext",
"enter": "menu::Confirm",
"alt-y": "git::StageFile",
"alt-shift-y": "git::UnstageFile",
"ctrl-alt-y": "git::ToggleStaged",
"space": "git::ToggleStaged",
"ctrl-space": "git::StageAll",
"ctrl-shift-space": "git::UnstageAll",
"tab": "git_panel::FocusEditor",
"shift-tab": "git_panel::FocusEditor",
"escape": "git_panel::ToggleFocus",
"ctrl-enter": "git::Commit",
"alt-enter": "menu::SecondaryConfirm"
"alt-enter": "menu::SecondaryConfirm",
"backspace": "git::RestoreFile"
}
},
{
"context": "GitCommit > Editor",
"bindings": {
"escape": "menu::Cancel",
"enter": "editor::Newline",
"ctrl-enter": "git::Commit"
"ctrl-enter": "git::Commit",
"alt-l": "git::GenerateCommitMessage"
}
},
{
"context": "GitPanel",
"use_key_equivalents": true,
"bindings": {
"ctrl-g ctrl-g": "git::Fetch",
"ctrl-g up": "git::Push",
"ctrl-g down": "git::Pull",
"ctrl-g shift-up": "git::ForcePush",
"ctrl-g d": "git::Diff",
"ctrl-g backspace": "git::RestoreTrackedFiles",
"ctrl-g shift-backspace": "git::TrashUntrackedFiles",
"ctrl-space": "git::StageAll",
"ctrl-shift-space": "git::UnstageAll"
}
},
{
"context": "GitDiff > Editor",
"bindings": {
"ctrl-enter": "git::Commit"
"ctrl-enter": "git::Commit",
"ctrl-space": "git::StageAll",
"ctrl-shift-space": "git::UnstageAll"
}
},
{
"context": "AskPass > Editor",
"bindings": {
"enter": "menu::Confirm"
}
},
{
@@ -745,16 +773,10 @@
"escape": "git_panel::FocusChanges",
"tab": "git_panel::FocusChanges",
"shift-tab": "git_panel::FocusChanges",
"ctrl-enter": "git::Commit",
"alt-up": "git_panel::FocusChanges"
}
},
{
"context": "GitCommit > Editor",
"use_key_equivalents": true,
"bindings": {
"enter": "editor::Newline",
"ctrl-enter": "git::Commit"
"ctrl-enter": "git::Commit",
"alt-up": "git_panel::FocusChanges",
"alt-l": "git::GenerateCommitMessage"
}
},
{
@@ -779,6 +801,9 @@
{
"context": "Picker > Editor",
"bindings": {
"escape": "menu::Cancel",
"up": "menu::SelectPrevious",
"down": "menu::SelectNext",
"tab": "picker::ConfirmCompletion",
"alt-enter": ["picker::ConfirmInput", { "secondary": false }]
}
@@ -792,7 +817,7 @@
{
"context": "FileFinder || (FileFinder > Picker > Editor) || (FileFinder > Picker > menu)",
"bindings": {
"ctrl-shift-p": "file_finder::SelectPrev",
"ctrl-shift-p": "file_finder::SelectPrevious",
"ctrl-j": "pane::SplitDown",
"ctrl-k": "pane::SplitUp",
"ctrl-h": "pane::SplitLeft",
@@ -802,8 +827,8 @@
{
"context": "TabSwitcher",
"bindings": {
"ctrl-shift-tab": "menu::SelectPrev",
"ctrl-up": "menu::SelectPrev",
"ctrl-shift-tab": "menu::SelectPrevious",
"ctrl-up": "menu::SelectPrevious",
"ctrl-down": "menu::SelectNext",
"ctrl-backspace": "tab_switcher::CloseSelectedItem"
}

View File

@@ -1,4 +1,15 @@
[
// Moved before Standard macOS bindings so that `cmd-w` is not the last binding for
// `workspace::CloseWindow` and displayed/intercepted by macOS
{
"context": "PromptLibrary",
"use_key_equivalents": true,
"bindings": {
"cmd-n": "prompt_library::NewPrompt",
"cmd-shift-s": "prompt_library::ToggleDefaultPrompt",
"cmd-w": "workspace::CloseWindow"
}
},
// Standard macOS bindings
{
"use_key_equivalents": true,
@@ -14,14 +25,14 @@
"tab": "menu::SelectNext",
"ctrl-n": "menu::SelectNext",
"down": "menu::SelectNext",
"shift-tab": "menu::SelectPrev",
"ctrl-p": "menu::SelectPrev",
"up": "menu::SelectPrev",
"shift-tab": "menu::SelectPrevious",
"ctrl-p": "menu::SelectPrevious",
"up": "menu::SelectPrevious",
"enter": "menu::Confirm",
"ctrl-enter": "menu::SecondaryConfirm",
"cmd-enter": "menu::SecondaryConfirm",
"ctrl-escape": "menu::Cancel",
"cmd-escape": "menu::Cancel",
"ctrl-escape": "menu::Cancel",
"ctrl-c": "menu::Cancel",
"escape": "menu::Cancel",
"alt-shift-enter": "menu::Restart",
@@ -54,7 +65,7 @@
"ctrl-d": "editor::Delete",
"delete": "editor::Delete",
"tab": "editor::Tab",
"shift-tab": "editor::TabPrev",
"shift-tab": "editor::Backtab",
"ctrl-t": "editor::Transpose",
"ctrl-k": "editor::KillRingCut",
"ctrl-y": "editor::KillRingYank",
@@ -97,8 +108,8 @@
"cmd-right": ["editor::MoveToEndOfLine", { "stop_at_soft_wraps": true }],
"ctrl-e": ["editor::MoveToEndOfLine", { "stop_at_soft_wraps": false }],
"end": ["editor::MoveToEndOfLine", { "stop_at_soft_wraps": true }],
"cmd-up": "editor::MoveToStartOfExcerpt",
"cmd-down": "editor::MoveToEndOfExcerpt",
"cmd-up": "editor::MoveToBeginning",
"cmd-down": "editor::MoveToEnd",
"cmd-home": "editor::MoveToBeginning", // Typed via `cmd-fn-left`
"cmd-end": "editor::MoveToEnd", // Typed via `cmd-fn-right`
"shift-up": "editor::SelectUp",
@@ -113,11 +124,12 @@
"alt-shift-right": "editor::SelectToNextWordEnd", // cursorWordRightSelect
"ctrl-shift-up": "editor::SelectToStartOfParagraph",
"ctrl-shift-down": "editor::SelectToEndOfParagraph",
"cmd-shift-up": "editor::SelectToStartOfExcerpt",
"cmd-shift-down": "editor::SelectToEndOfExcerpt",
"cmd-shift-up": "editor::SelectToBeginning",
"cmd-shift-down": "editor::SelectToEnd",
"cmd-a": "editor::SelectAll",
"cmd-l": "editor::SelectLine",
"cmd-shift-i": "editor::Format",
"alt-shift-o": "editor::OrganizeImports",
"cmd-shift-left": ["editor::SelectToBeginningOfLine", { "stop_at_soft_wraps": true, "stop_at_indent": true }],
"shift-home": ["editor::SelectToBeginningOfLine", { "stop_at_soft_wraps": true, "stop_at_indent": true }],
"ctrl-shift-a": ["editor::SelectToBeginningOfLine", { "stop_at_soft_wraps": true, "stop_at_indent": true }],
@@ -160,6 +172,16 @@
"alt-enter": "editor::OpenSelectionsInMultibuffer"
}
},
{
"context": "Editor && multibuffer",
"use_key_equivalents": true,
"bindings": {
"cmd-up": "editor::MoveToStartOfExcerpt",
"cmd-down": "editor::MoveToStartOfNextExcerpt",
"cmd-shift-up": "editor::SelectToStartOfExcerpt",
"cmd-shift-down": "editor::SelectToStartOfNextExcerpt"
}
},
{
"context": "Editor && mode == full && edit_prediction",
"use_key_equivalents": true,
@@ -207,7 +229,7 @@
"cmd-k c": "assistant::CopyCode",
"cmd-shift-e": "project_panel::ToggleFocus",
"cmd-g": "search::SelectNextMatch",
"cmd-shift-g": "search::SelectPrevMatch",
"cmd-shift-g": "search::SelectPreviousMatch",
"cmd-alt-/": "assistant::ToggleModelSelector",
"cmd-k h": "assistant::DeployHistory",
"cmd-k l": "assistant::DeployPromptLibrary",
@@ -269,15 +291,6 @@
"backspace": "assistant2::RemoveSelectedThread"
}
},
{
"context": "PromptLibrary",
"use_key_equivalents": true,
"bindings": {
"cmd-n": "prompt_library::NewPrompt",
"cmd-shift-s": "prompt_library::ToggleDefaultPrompt",
"cmd-w": "workspace::CloseWindow"
}
},
{
"context": "BufferSearchBar",
"use_key_equivalents": true,
@@ -285,7 +298,7 @@
"escape": "buffer_search::Dismiss",
"tab": "buffer_search::FocusEditor",
"enter": "search::SelectNextMatch",
"shift-enter": "search::SelectPrevMatch",
"shift-enter": "search::SelectPreviousMatch",
"alt-enter": "search::SelectAllMatches",
"cmd-f": "search::FocusSearch",
"cmd-alt-f": "search::ToggleReplace",
@@ -352,8 +365,8 @@
"context": "Pane",
"use_key_equivalents": true,
"bindings": {
"alt-cmd-left": "pane::ActivatePrevItem",
"cmd-{": "pane::ActivatePrevItem",
"alt-cmd-left": "pane::ActivatePreviousItem",
"cmd-{": "pane::ActivatePreviousItem",
"alt-cmd-right": "pane::ActivateNextItem",
"cmd-}": "pane::ActivateNextItem",
"ctrl-shift-pageup": "pane::SwapItemLeft",
@@ -367,7 +380,7 @@
"cmd-k cmd-w": ["pane::CloseAllItems", { "close_pinned": false }],
"cmd-f": "project_search::ToggleFocus",
"cmd-g": "search::SelectNextMatch",
"cmd-shift-g": "search::SelectPrevMatch",
"cmd-shift-g": "search::SelectPreviousMatch",
"cmd-shift-h": "search::ToggleReplace",
"cmd-alt-l": "search::ToggleSelection",
"alt-enter": "search::SelectAllMatches",
@@ -407,7 +420,7 @@
"cmd-u": "editor::UndoSelection",
"cmd-shift-u": "editor::RedoSelection",
"f8": "editor::GoToDiagnostic",
"shift-f8": "editor::GoToPrevDiagnostic",
"shift-f8": "editor::GoToPreviousDiagnostic",
"f2": "editor::Rename",
"f12": "editor::GoToDefinition",
"alt-f12": "editor::GoToDefinitionSplit",
@@ -484,6 +497,7 @@
"ctrl-~": "workspace::NewTerminal",
"cmd-s": "workspace::Save",
"cmd-k s": "workspace::SaveWithoutFormat",
"alt-shift-enter": "toast::RunAction",
"cmd-shift-s": "workspace::SaveAs",
"cmd-shift-n": "workspace::NewWindow",
"ctrl-`": "terminal_panel::ToggleFocus",
@@ -613,8 +627,8 @@
"context": "Editor && (showing_code_actions || showing_completions)",
"use_key_equivalents": true,
"bindings": {
"up": "editor::ContextMenuPrev",
"ctrl-p": "editor::ContextMenuPrev",
"up": "editor::ContextMenuPrevious",
"ctrl-p": "editor::ContextMenuPrevious",
"down": "editor::ContextMenuNext",
"ctrl-n": "editor::ContextMenuNext",
"pageup": "editor::ContextMenuFirst",
@@ -640,7 +654,7 @@
"cmd-alt-enter": "editor::OpenExcerptsSplit",
"cmd-shift-e": "pane::RevealInProjectPanel",
"cmd-f8": "editor::GoToHunk",
"cmd-shift-f8": "editor::GoToPrevHunk",
"cmd-shift-f8": "editor::GoToPreviousHunk",
"ctrl-enter": "assistant::InlineAssist",
"ctrl-:": "editor::ToggleInlayHints"
}
@@ -683,7 +697,7 @@
"alt-cmd-r": "outline_panel::RevealInFileManager",
"space": "outline_panel::Open",
"shift-down": "menu::SelectNext",
"shift-up": "menu::SelectPrev",
"shift-up": "menu::SelectPrevious",
"alt-enter": "editor::OpenExcerpts",
"cmd-alt-enter": "editor::OpenExcerptsSplit"
}
@@ -713,7 +727,7 @@
"cmd-alt-backspace": ["project_panel::Delete", { "skip_prompt": false }],
"cmd-shift-f": "project_panel::NewSearchInDirectory",
"shift-down": "menu::SelectNext",
"shift-up": "menu::SelectPrev",
"shift-up": "menu::SelectPrevious",
"escape": "menu::Cancel"
}
},
@@ -728,26 +742,30 @@
"context": "GitPanel && ChangesList",
"use_key_equivalents": true,
"bindings": {
"up": "menu::SelectPrev",
"up": "menu::SelectPrevious",
"down": "menu::SelectNext",
"cmd-up": "menu::SelectFirst",
"cmd-down": "menu::SelectLast",
"enter": "menu::Confirm",
"cmd-alt-y": "git::ToggleStaged",
"space": "git::ToggleStaged",
"cmd-shift-space": "git::StageAll",
"ctrl-shift-space": "git::UnstageAll",
"cmd-y": "git::StageFile",
"cmd-shift-y": "git::UnstageFile",
"alt-down": "git_panel::FocusEditor",
"tab": "git_panel::FocusEditor",
"shift-tab": "git_panel::FocusEditor",
"escape": "git_panel::ToggleFocus",
"cmd-enter": "git::Commit"
"cmd-enter": "git::Commit",
"backspace": "git::RestoreFile"
}
},
{
"context": "GitDiff > Editor",
"use_key_equivalents": true,
"bindings": {
"cmd-enter": "git::Commit"
"cmd-enter": "git::Commit",
"cmd-ctrl-y": "git::StageAll",
"cmd-ctrl-shift-y": "git::UnstageAll"
}
},
{
@@ -758,7 +776,24 @@
"cmd-enter": "git::Commit",
"tab": "git_panel::FocusChanges",
"shift-tab": "git_panel::FocusChanges",
"alt-up": "git_panel::FocusChanges"
"alt-up": "git_panel::FocusChanges",
"shift-escape": "git::ExpandCommitEditor",
"alt-tab": "git::GenerateCommitMessage"
}
},
{
"context": "GitPanel",
"use_key_equivalents": true,
"bindings": {
"ctrl-g ctrl-g": "git::Fetch",
"ctrl-g up": "git::Push",
"ctrl-g down": "git::Pull",
"ctrl-g shift-up": "git::ForcePush",
"ctrl-g d": "git::Diff",
"ctrl-g backspace": "git::RestoreTrackedFiles",
"ctrl-g shift-backspace": "git::TrashUntrackedFiles",
"cmd-ctrl-y": "git::StageAll",
"cmd-ctrl-shift-y": "git::UnstageAll"
}
},
{
@@ -766,7 +801,9 @@
"use_key_equivalents": true,
"bindings": {
"enter": "editor::Newline",
"cmd-enter": "git::Commit"
"escape": "menu::Cancel",
"cmd-enter": "git::Commit",
"alt-tab": "git::GenerateCommitMessage"
}
},
{
@@ -795,6 +832,9 @@
"context": "Picker > Editor",
"use_key_equivalents": true,
"bindings": {
"escape": "menu::Cancel",
"up": "menu::SelectPrevious",
"down": "menu::SelectNext",
"tab": "picker::ConfirmCompletion",
"alt-enter": ["picker::ConfirmInput", { "secondary": false }],
"cmd-alt-enter": ["picker::ConfirmInput", { "secondary": true }]
@@ -811,7 +851,7 @@
"context": "FileFinder || (FileFinder > Picker > Editor) || (FileFinder > Picker > menu)",
"use_key_equivalents": true,
"bindings": {
"cmd-shift-p": "file_finder::SelectPrev",
"cmd-shift-p": "file_finder::SelectPrevious",
"cmd-j": "pane::SplitDown",
"cmd-k": "pane::SplitUp",
"cmd-h": "pane::SplitLeft",
@@ -822,8 +862,8 @@
"context": "TabSwitcher",
"use_key_equivalents": true,
"bindings": {
"ctrl-shift-tab": "menu::SelectPrev",
"ctrl-up": "menu::SelectPrev",
"ctrl-shift-tab": "menu::SelectPrevious",
"ctrl-up": "menu::SelectPrevious",
"ctrl-down": "menu::SelectNext",
"ctrl-backspace": "tab_switcher::CloseSelectedItem"
}

View File

@@ -39,7 +39,7 @@
"context": "BufferSearchBar",
"bindings": {
"ctrl-f3": "search::SelectNextMatch", // find-and-replace:find-next-selected
"ctrl-shift-f3": "search::SelectPrevMatch" // find-and-replace:find-previous-selected
"ctrl-shift-f3": "search::SelectPreviousMatch" // find-and-replace:find-previous-selected
}
},
{

View File

@@ -122,7 +122,7 @@
"context": "BufferSearchBar > Editor",
"bindings": {
"ctrl-s": "search::SelectNextMatch",
"ctrl-r": "search::SelectPrevMatch",
"ctrl-r": "search::SelectPreviousMatch",
"ctrl-g": "buffer_search::Dismiss"
}
},

View File

@@ -2,7 +2,7 @@
{
"bindings": {
"ctrl-alt-s": "zed::OpenSettings",
"ctrl-{": "pane::ActivatePrevItem",
"ctrl-{": "pane::ActivatePreviousItem",
"ctrl-}": "pane::ActivateNextItem"
}
},
@@ -41,9 +41,9 @@
"ctrl-shift-b": "editor::GoToTypeDefinition",
"ctrl-alt-shift-b": "editor::GoToTypeDefinitionSplit",
"f2": "editor::GoToDiagnostic",
"shift-f2": "editor::GoToPrevDiagnostic",
"shift-f2": "editor::GoToPreviousDiagnostic",
"ctrl-alt-shift-down": "editor::GoToHunk",
"ctrl-alt-shift-up": "editor::GoToPrevHunk",
"ctrl-alt-shift-up": "editor::GoToPreviousHunk",
"ctrl-alt-z": "git::Restore",
"ctrl-home": "editor::MoveToBeginning",
"ctrl-end": "editor::MoveToEnd",

View File

@@ -1,9 +1,9 @@
[
{
"bindings": {
"ctrl-{": "pane::ActivatePrevItem",
"ctrl-{": "pane::ActivatePreviousItem",
"ctrl-}": "pane::ActivateNextItem",
"ctrl-pageup": "pane::ActivatePrevItem",
"ctrl-pageup": "pane::ActivatePreviousItem",
"ctrl-pagedown": "pane::ActivateNextItem",
"ctrl-1": ["workspace::ActivatePane", 0],
"ctrl-2": ["workspace::ActivatePane", 1],
@@ -44,7 +44,7 @@
"shift-f12": "editor::FindAllReferences",
"ctrl-shift-f12": "editor::FindAllReferences",
"ctrl-.": "editor::GoToHunk",
"ctrl-,": "editor::GoToPrevHunk",
"ctrl-,": "editor::GoToPreviousHunk",
"ctrl-k ctrl-u": "editor::ConvertToUpperCase",
"ctrl-k ctrl-l": "editor::ConvertToLowerCase",
"shift-alt-m": "markdown::OpenPreviewToTheSide",
@@ -62,7 +62,7 @@
"context": "Pane",
"bindings": {
"f4": "search::SelectNextMatch",
"shift-f4": "search::SelectPrevMatch",
"shift-f4": "search::SelectPreviousMatch",
"alt-1": ["pane::ActivateItem", 0],
"alt-2": ["pane::ActivateItem", 1],
"alt-3": ["pane::ActivateItem", 2],

View File

@@ -40,7 +40,7 @@
"context": "BufferSearchBar",
"bindings": {
"cmd-f3": "search::SelectNextMatch",
"cmd-shift-f3": "search::SelectPrevMatch"
"cmd-shift-f3": "search::SelectPreviousMatch"
}
},
{

View File

@@ -122,7 +122,7 @@
"context": "BufferSearchBar > Editor",
"bindings": {
"ctrl-s": "search::SelectNextMatch",
"ctrl-r": "search::SelectPrevMatch",
"ctrl-r": "search::SelectPreviousMatch",
"ctrl-g": "buffer_search::Dismiss"
}
},

View File

@@ -1,7 +1,7 @@
[
{
"bindings": {
"cmd-{": "pane::ActivatePrevItem",
"cmd-{": "pane::ActivatePreviousItem",
"cmd-}": "pane::ActivateNextItem"
}
},
@@ -39,9 +39,9 @@
"cmd-shift-b": "editor::GoToTypeDefinition",
"cmd-alt-shift-b": "editor::GoToTypeDefinitionSplit",
"f2": "editor::GoToDiagnostic",
"shift-f2": "editor::GoToPrevDiagnostic",
"shift-f2": "editor::GoToPreviousDiagnostic",
"ctrl-alt-shift-down": "editor::GoToHunk",
"ctrl-alt-shift-up": "editor::GoToPrevHunk",
"ctrl-alt-shift-up": "editor::GoToPreviousHunk",
"cmd-home": "editor::MoveToBeginning",
"cmd-end": "editor::MoveToEnd",
"cmd-shift-home": "editor::SelectToBeginning",
@@ -61,7 +61,7 @@
{
"context": "BufferSearchBar > Editor",
"bindings": {
"shift-enter": "search::SelectPrevMatch"
"shift-enter": "search::SelectPreviousMatch"
}
},
{

View File

@@ -1,9 +1,9 @@
[
{
"bindings": {
"cmd-{": "pane::ActivatePrevItem",
"cmd-{": "pane::ActivatePreviousItem",
"cmd-}": "pane::ActivateNextItem",
"ctrl-pageup": "pane::ActivatePrevItem",
"ctrl-pageup": "pane::ActivatePreviousItem",
"ctrl-pagedown": "pane::ActivateNextItem",
"ctrl-1": ["workspace::ActivatePane", 0],
"ctrl-2": ["workspace::ActivatePane", 1],
@@ -45,7 +45,7 @@
"ctrl-alt-cmd-down": "editor::GoToDefinitionSplit",
"alt-shift-cmd-down": "editor::FindAllReferences",
"ctrl-.": "editor::GoToHunk",
"ctrl-,": "editor::GoToPrevHunk",
"ctrl-,": "editor::GoToPreviousHunk",
"cmd-k cmd-u": "editor::ConvertToUpperCase",
"cmd-k cmd-l": "editor::ConvertToLowerCase",
"cmd-shift-j": "editor::JoinLines",
@@ -64,7 +64,7 @@
"context": "Pane",
"bindings": {
"f4": "search::SelectNextMatch",
"shift-f4": "search::SelectPrevMatch",
"shift-f4": "search::SelectPreviousMatch",
"cmd-1": ["pane::ActivateItem", 0],
"cmd-2": ["pane::ActivateItem", 1],
"cmd-3": ["pane::ActivateItem", 2],

View File

@@ -47,7 +47,7 @@
"context": "BufferSearchBar",
"bindings": {
"ctrl-s": "search::SelectNextMatch",
"ctrl-shift-s": "search::SelectPrevMatch"
"ctrl-shift-s": "search::SelectPreviousMatch"
}
},
{

View File

@@ -13,9 +13,9 @@
"tab": "menu::SelectNext",
"ctrl-n": "menu::SelectNext",
"down": "menu::SelectNext",
"shift-tab": "menu::SelectPrev",
"ctrl-p": "menu::SelectPrev",
"up": "menu::SelectPrev",
"shift-tab": "menu::SelectPrevious",
"ctrl-p": "menu::SelectPrevious",
"up": "menu::SelectPrevious",
"enter": "menu::Confirm",
"ctrl-enter": "menu::SecondaryConfirm",
"cmd-enter": "menu::SecondaryConfirm",

View File

@@ -62,9 +62,9 @@
"g /": "pane::DeploySearch",
"?": ["vim::Search", { "backwards": true }],
"*": "vim::MoveToNext",
"#": "vim::MoveToPrev",
"#": "vim::MoveToPrevious",
"n": "vim::MoveToNextMatch",
"shift-n": "vim::MoveToPrevMatch",
"shift-n": "vim::MoveToPreviousMatch",
"%": "vim::Matching",
"] }": ["vim::UnmatchedForward", { "char": "}" }],
"[ {": ["vim::UnmatchedBackward", { "char": "{" }],
@@ -106,7 +106,7 @@
"g g": "vim::StartOfDocument",
"g h": "editor::Hover",
"g t": "pane::ActivateNextItem",
"g shift-t": "pane::ActivatePrevItem",
"g shift-t": "pane::ActivatePreviousItem",
"g d": "editor::GoToDefinition",
"g shift-d": "editor::GoToDeclaration",
"g y": "editor::GoToTypeDefinition",
@@ -126,7 +126,7 @@
"g shift-a": "editor::FindAllReferences", // zed specific
"g space": "editor::OpenExcerpts", // zed specific
"g *": ["vim::MoveToNext", { "partial_word": true }],
"g #": ["vim::MoveToPrev", { "partial_word": true }],
"g #": ["vim::MoveToPrevious", { "partial_word": true }],
"g j": ["vim::Down", { "display_lines": true }],
"g down": ["vim::Down", { "display_lines": true }],
"g k": ["vim::Up", { "display_lines": true }],
@@ -138,7 +138,7 @@
"g ^": ["vim::FirstNonWhitespace", { "display_lines": true }],
"g v": "vim::RestoreVisualSelection",
"g ]": "editor::GoToDiagnostic",
"g [": "editor::GoToPrevDiagnostic",
"g [": "editor::GoToPreviousDiagnostic",
"g i": "vim::InsertAtPrevious",
"g ,": "vim::ChangeListNewer",
"g ;": "vim::ChangeListOlder",
@@ -231,15 +231,15 @@
"g w": "vim::PushRewrap",
"g q": "vim::PushRewrap",
"ctrl-pagedown": "pane::ActivateNextItem",
"ctrl-pageup": "pane::ActivatePrevItem",
"ctrl-pageup": "pane::ActivatePreviousItem",
"insert": "vim::InsertBefore",
// tree-sitter related commands
"[ x": "vim::SelectLargerSyntaxNode",
"] x": "vim::SelectSmallerSyntaxNode",
"] d": "editor::GoToDiagnostic",
"[ d": "editor::GoToPrevDiagnostic",
"[ d": "editor::GoToPreviousDiagnostic",
"] c": "editor::GoToHunk",
"[ c": "editor::GoToPrevHunk",
"[ c": "editor::GoToPreviousHunk",
"g c": "vim::PushToggleComments"
}
},
@@ -272,7 +272,7 @@
"shift-s": "vim::SubstituteLine",
"~": "vim::ChangeCase",
"*": ["vim::MoveToNext", { "partial_word": true }],
"#": ["vim::MoveToPrev", { "partial_word": true }],
"#": ["vim::MoveToPrevious", { "partial_word": true }],
"ctrl-a": "vim::Increment",
"ctrl-x": "vim::Decrement",
"g ctrl-a": ["vim::Increment", { "step": true }],
@@ -448,7 +448,10 @@
"d": "vim::CurrentLine",
"s": "vim::PushDeleteSurrounds",
"o": "editor::ToggleSelectedDiffHunks", // "d o"
"p": "git::Restore" // "d p"
"shift-o": "git::ToggleStaged",
"p": "git::Restore", // "d p"
"u": "git::StageAndNext", // "d u"
"shift-u": "git::UnstageAndNext" // "d shift-u"
}
},
{
@@ -620,8 +623,8 @@
"ctrl-w =": "vim::ResetPaneSizes",
"ctrl-w g t": "pane::ActivateNextItem",
"ctrl-w ctrl-g t": "pane::ActivateNextItem",
"ctrl-w g shift-t": "pane::ActivatePrevItem",
"ctrl-w ctrl-g shift-t": "pane::ActivatePrevItem",
"ctrl-w g shift-t": "pane::ActivatePreviousItem",
"ctrl-w ctrl-g shift-t": "pane::ActivatePreviousItem",
"ctrl-w w": "workspace::ActivateNextPane",
"ctrl-w ctrl-w": "workspace::ActivateNextPane",
"ctrl-w p": "workspace::ActivatePreviousPane",
@@ -664,7 +667,7 @@
"escape": "project_panel::ToggleFocus",
"h": "project_panel::CollapseSelectedEntry",
"j": "menu::SelectNext",
"k": "menu::SelectPrev",
"k": "menu::SelectPrevious",
"l": "project_panel::ExpandSelectedEntry",
"o": "project_panel::OpenPermanent",
"shift-d": "project_panel::Delete",
@@ -690,7 +693,7 @@
"context": "OutlinePanel && not_editing",
"bindings": {
"j": "menu::SelectNext",
"k": "menu::SelectPrev",
"k": "menu::SelectPrevious",
"shift-g": "menu::SelectLast",
"g g": "menu::SelectFirst"
}
@@ -699,7 +702,7 @@
"context": "GitPanel && ChangesList",
"use_key_equivalents": true,
"bindings": {
"k": "menu::SelectPrev",
"k": "menu::SelectPrevious",
"j": "menu::SelectNext",
"g g": "menu::SelectFirst",
"shift-g": "menu::SelectLast",

View File

@@ -555,6 +555,12 @@
//
// Default: icon
"status_style": "icon",
// What branch name to use if init.defaultBranch
// is not set
//
// Default: main
"fallback_branch_name": "main",
"scrollbar": {
// When to show the scrollbar in the git panel.
//
@@ -648,11 +654,19 @@
// Show git status colors in the editor tabs.
"git_status": false,
// Position of the close button on the editor tabs.
// One of: ["right", "left", "hidden"]
"close_position": "right",
// Whether to show the file icon for a tab.
"file_icons": false,
// Whether to always show the close button on tabs.
"always_show_close_button": false,
// Controls the appearance behavior of the tab's close button.
//
// 1. Show it just upon hovering the tab. (default)
// "hover"
// 2. Show it persistently.
// "always"
// 3. Never show it, even if hovering it.
// "hidden"
"show_close_button": "hover",
// What to do after closing the current tab.
//
// 1. Activate the tab that was open previously (default)
@@ -843,15 +857,7 @@
// Any addition to this list will be merged with the default list.
// Globs are matched relative to the worktree root,
// except when starting with a slash (/) or equivalent in Windows.
"disabled_globs": [
"**/.env*",
"**/*.pem",
"**/*.key",
"**/*.cert",
"**/*.crt",
"**/.dev.vars",
"**/secrets.yml"
],
"disabled_globs": ["**/.env*", "**/*.pem", "**/*.key", "**/*.cert", "**/*.crt", "**/.dev.vars", "**/secrets.yml"],
// When to show edit predictions previews in buffer.
// This setting takes two possible values:
// 1. Display predictions inline when there are no language server completions available.

View File

@@ -6,15 +6,7 @@
{
"name": "Gruvbox Dark",
"appearance": "dark",
"accents": [
"#cc241dff",
"#98971aff",
"#d79921ff",
"#458588ff",
"#b16286ff",
"#689d6aff",
"#d65d0eff"
],
"accents": ["#cc241dff", "#98971aff", "#d79921ff", "#458588ff", "#b16286ff", "#689d6aff", "#d65d0eff"],
"style": {
"border": "#5b534dff",
"border.variant": "#494340ff",
@@ -105,9 +97,9 @@
"terminal.ansi.bright_white": "#fbf1c7ff",
"terminal.ansi.dim_white": "#b0a189ff",
"link_text.hover": "#83a598ff",
"version_control_added": "#b7bb26ff",
"version_control_modified": "#f9bd2fff",
"version_control_deleted": "#fb4a35ff",
"version_control.added": "#b7bb26ff",
"version_control.modified": "#f9bd2fff",
"version_control.deleted": "#fb4a35ff",
"conflict": "#f9bd2fff",
"conflict.background": "#572e10ff",
"conflict.border": "#754916ff",
@@ -394,15 +386,7 @@
{
"name": "Gruvbox Dark Hard",
"appearance": "dark",
"accents": [
"#cc241dff",
"#98971aff",
"#d79921ff",
"#458588ff",
"#b16286ff",
"#689d6aff",
"#d65d0eff"
],
"accents": ["#cc241dff", "#98971aff", "#d79921ff", "#458588ff", "#b16286ff", "#689d6aff", "#d65d0eff"],
"style": {
"border": "#5b534dff",
"border.variant": "#494340ff",
@@ -493,9 +477,9 @@
"terminal.ansi.bright_white": "#fbf1c7ff",
"terminal.ansi.dim_white": "#b0a189ff",
"link_text.hover": "#83a598ff",
"version_control_added": "#b7bb26ff",
"version_control_modified": "#f9bd2fff",
"version_control_deleted": "#fb4a35ff",
"version_control.added": "#b7bb26ff",
"version_control.modified": "#f9bd2fff",
"version_control.deleted": "#fb4a35ff",
"conflict": "#f9bd2fff",
"conflict.background": "#572e10ff",
"conflict.border": "#754916ff",
@@ -782,15 +766,7 @@
{
"name": "Gruvbox Dark Soft",
"appearance": "dark",
"accents": [
"#cc241dff",
"#98971aff",
"#d79921ff",
"#458588ff",
"#b16286ff",
"#689d6aff",
"#d65d0eff"
],
"accents": ["#cc241dff", "#98971aff", "#d79921ff", "#458588ff", "#b16286ff", "#689d6aff", "#d65d0eff"],
"style": {
"border": "#5b534dff",
"border.variant": "#494340ff",
@@ -881,9 +857,9 @@
"terminal.ansi.bright_white": "#fbf1c7ff",
"terminal.ansi.dim_white": "#b0a189ff",
"link_text.hover": "#83a598ff",
"version_control_added": "#b7bb26ff",
"version_control_modified": "#f9bd2fff",
"version_control_deleted": "#fb4a35ff",
"version_control.added": "#b7bb26ff",
"version_control.modified": "#f9bd2fff",
"version_control.deleted": "#fb4a35ff",
"conflict": "#f9bd2fff",
"conflict.background": "#572e10ff",
"conflict.border": "#754916ff",
@@ -1170,15 +1146,7 @@
{
"name": "Gruvbox Light",
"appearance": "light",
"accents": [
"#cc241dff",
"#98971aff",
"#d79921ff",
"#458588ff",
"#b16286ff",
"#689d6aff",
"#d65d0eff"
],
"accents": ["#cc241dff", "#98971aff", "#d79921ff", "#458588ff", "#b16286ff", "#689d6aff", "#d65d0eff"],
"style": {
"border": "#c8b899ff",
"border.variant": "#ddcca7ff",
@@ -1269,9 +1237,9 @@
"terminal.ansi.bright_white": "#282828ff",
"terminal.ansi.dim_white": "#73675eff",
"link_text.hover": "#0b6678ff",
"version_control_added": "#797410ff",
"version_control_modified": "#b57615ff",
"version_control_deleted": "#9d0308ff",
"version_control.added": "#797410ff",
"version_control.modified": "#b57615ff",
"version_control.deleted": "#9d0308ff",
"conflict": "#b57615ff",
"conflict.background": "#f5e2d0ff",
"conflict.border": "#ebccabff",
@@ -1558,15 +1526,7 @@
{
"name": "Gruvbox Light Hard",
"appearance": "light",
"accents": [
"#cc241dff",
"#98971aff",
"#d79921ff",
"#458588ff",
"#b16286ff",
"#689d6aff",
"#d65d0eff"
],
"accents": ["#cc241dff", "#98971aff", "#d79921ff", "#458588ff", "#b16286ff", "#689d6aff", "#d65d0eff"],
"style": {
"border": "#c8b899ff",
"border.variant": "#ddcca7ff",
@@ -1657,9 +1617,9 @@
"terminal.ansi.bright_white": "#282828ff",
"terminal.ansi.dim_white": "#73675eff",
"link_text.hover": "#0b6678ff",
"version_control_added": "#797410ff",
"version_control_modified": "#b57615ff",
"version_control_deleted": "#9d0308ff",
"version_control.added": "#797410ff",
"version_control.modified": "#b57615ff",
"version_control.deleted": "#9d0308ff",
"conflict": "#b57615ff",
"conflict.background": "#f5e2d0ff",
"conflict.border": "#ebccabff",
@@ -1946,15 +1906,7 @@
{
"name": "Gruvbox Light Soft",
"appearance": "light",
"accents": [
"#cc241dff",
"#98971aff",
"#d79921ff",
"#458588ff",
"#b16286ff",
"#689d6aff",
"#d65d0eff"
],
"accents": ["#cc241dff", "#98971aff", "#d79921ff", "#458588ff", "#b16286ff", "#689d6aff", "#d65d0eff"],
"style": {
"border": "#c8b899ff",
"border.variant": "#ddcca7ff",
@@ -2045,9 +1997,9 @@
"terminal.ansi.bright_white": "#282828ff",
"terminal.ansi.dim_white": "#73675eff",
"link_text.hover": "#0b6678ff",
"version_control_added": "#797410ff",
"version_control_modified": "#b57615ff",
"version_control_deleted": "#9d0308ff",
"version_control.added": "#797410ff",
"version_control.modified": "#b57615ff",
"version_control.deleted": "#9d0308ff",
"conflict": "#b57615ff",
"conflict.background": "#f5e2d0ff",
"conflict.border": "#ebccabff",

View File

@@ -96,9 +96,9 @@
"terminal.ansi.bright_white": "#dce0e5ff",
"terminal.ansi.dim_white": "#575d65ff",
"link_text.hover": "#74ade8ff",
"version_control_added": "#a7c088ff",
"version_control_modified": "#dec184ff",
"version_control_deleted": "#d07277ff",
"version_control.added": "#27a657ff",
"version_control.modified": "#d3b020ff",
"version_control.deleted": "#e06c76ff",
"conflict": "#dec184ff",
"conflict.background": "#dec1841a",
"conflict.border": "#5d4c2fff",
@@ -475,9 +475,9 @@
"terminal.ansi.bright_white": "#242529ff",
"terminal.ansi.dim_white": "#97979aff",
"link_text.hover": "#5c78e2ff",
"version_control_added": "#669f59ff",
"version_control_modified": "#a48819ff",
"version_control_deleted": "#d36151ff",
"version_control.added": "#27a657ff",
"version_control.modified": "#d3b020ff",
"version_control.deleted": "#e06c76ff",
"conflict": "#a48819ff",
"conflict.background": "#faf2e6ff",
"conflict.border": "#f4e7d1ff",

View File

@@ -9,7 +9,10 @@ use gpui::{
};
use language::{LanguageRegistry, LanguageServerBinaryStatus, LanguageServerId};
use lsp::LanguageServerName;
use project::{EnvironmentErrorMessage, LanguageServerProgress, Project, WorktreeId};
use project::{
EnvironmentErrorMessage, LanguageServerProgress, LspStoreEvent, Project,
ProjectEnvironmentEvent, WorktreeId,
};
use smallvec::SmallVec;
use std::{cmp::Reverse, fmt::Write, sync::Arc, time::Duration};
use ui::{prelude::*, ButtonLike, ContextMenu, PopoverMenu, PopoverMenuHandle, Tooltip};
@@ -73,7 +76,22 @@ impl ActivityIndicator {
})
.detach();
cx.observe(&project, |_, _, cx| cx.notify()).detach();
cx.subscribe(
&project.read(cx).lsp_store(),
|_, _, event, cx| match event {
LspStoreEvent::LanguageServerUpdate { .. } => cx.notify(),
_ => {}
},
)
.detach();
cx.subscribe(
&project.read(cx).environment().clone(),
|_, _, event, cx| match event {
ProjectEnvironmentEvent::ErrorsUpdated => cx.notify(),
},
)
.detach();
if let Some(auto_updater) = auto_updater.as_ref() {
cx.observe(auto_updater, |_, _, cx| cx.notify()).detach();
@@ -204,7 +222,7 @@ impl ActivityIndicator {
message: error.0.clone(),
on_click: Some(Arc::new(move |this, window, cx| {
this.project.update(cx, |project, cx| {
project.remove_environment_error(cx, worktree_id);
project.remove_environment_error(worktree_id, cx);
});
window.dispatch_action(Box::new(workspace::OpenLog), cx);
})),

21
crates/askpass/Cargo.toml Normal file
View File

@@ -0,0 +1,21 @@
[package]
name = "askpass"
version = "0.1.0"
edition.workspace = true
publish.workspace = true
license = "GPL-3.0-or-later"
[lints]
workspace = true
[lib]
path = "src/askpass.rs"
[dependencies]
anyhow.workspace = true
futures.workspace = true
gpui.workspace = true
smol.workspace = true
tempfile.workspace = true
util.workspace = true
which.workspace = true

View File

@@ -0,0 +1 @@
../../LICENSE-APACHE

View File

@@ -0,0 +1,194 @@
use std::path::{Path, PathBuf};
use std::time::Duration;
#[cfg(unix)]
use anyhow::Context as _;
use futures::channel::{mpsc, oneshot};
#[cfg(unix)]
use futures::{io::BufReader, AsyncBufReadExt as _};
#[cfg(unix)]
use futures::{select_biased, AsyncWriteExt as _, FutureExt as _};
use futures::{SinkExt, StreamExt};
use gpui::{AsyncApp, BackgroundExecutor, Task};
#[cfg(unix)]
use smol::fs;
#[cfg(unix)]
use smol::{fs::unix::PermissionsExt as _, net::unix::UnixListener};
#[cfg(unix)]
use util::ResultExt as _;
#[derive(PartialEq, Eq)]
pub enum AskPassResult {
CancelledByUser,
Timedout,
}
pub struct AskPassDelegate {
tx: mpsc::UnboundedSender<(String, oneshot::Sender<String>)>,
_task: Task<()>,
}
impl AskPassDelegate {
pub fn new(
cx: &mut AsyncApp,
password_prompt: impl Fn(String, oneshot::Sender<String>, &mut AsyncApp) + Send + Sync + 'static,
) -> Self {
let (tx, mut rx) = mpsc::unbounded::<(String, oneshot::Sender<String>)>();
let task = cx.spawn(|mut cx| async move {
while let Some((prompt, channel)) = rx.next().await {
password_prompt(prompt, channel, &mut cx);
}
});
Self { tx, _task: task }
}
pub async fn ask_password(&mut self, prompt: String) -> anyhow::Result<String> {
let (tx, rx) = oneshot::channel();
self.tx.send((prompt, tx)).await?;
Ok(rx.await?)
}
}
#[cfg(unix)]
pub struct AskPassSession {
script_path: PathBuf,
_askpass_task: Task<()>,
askpass_opened_rx: Option<oneshot::Receiver<()>>,
askpass_kill_master_rx: Option<oneshot::Receiver<()>>,
}
#[cfg(unix)]
impl AskPassSession {
/// This will create a new AskPassSession.
/// You must retain this session until the master process exits.
#[must_use]
pub async fn new(
executor: &BackgroundExecutor,
mut delegate: AskPassDelegate,
) -> anyhow::Result<Self> {
let temp_dir = tempfile::Builder::new().prefix("zed-askpass").tempdir()?;
let askpass_socket = temp_dir.path().join("askpass.sock");
let askpass_script_path = temp_dir.path().join("askpass.sh");
let (askpass_opened_tx, askpass_opened_rx) = oneshot::channel::<()>();
let listener =
UnixListener::bind(&askpass_socket).context("failed to create askpass socket")?;
let (askpass_kill_master_tx, askpass_kill_master_rx) = oneshot::channel::<()>();
let mut kill_tx = Some(askpass_kill_master_tx);
let askpass_task = executor.spawn(async move {
let mut askpass_opened_tx = Some(askpass_opened_tx);
while let Ok((mut stream, _)) = listener.accept().await {
if let Some(askpass_opened_tx) = askpass_opened_tx.take() {
askpass_opened_tx.send(()).ok();
}
let mut buffer = Vec::new();
let mut reader = BufReader::new(&mut stream);
if reader.read_until(b'\0', &mut buffer).await.is_err() {
buffer.clear();
}
let prompt = String::from_utf8_lossy(&buffer);
if let Some(password) = delegate
.ask_password(prompt.to_string())
.await
.context("failed to get askpass password")
.log_err()
{
stream.write_all(password.as_bytes()).await.log_err();
} else {
if let Some(kill_tx) = kill_tx.take() {
kill_tx.send(()).log_err();
}
// note: we expect the caller to drop this task when it's done.
// We need to keep the stream open until the caller is done to avoid
// spurious errors from ssh.
std::future::pending::<()>().await;
drop(stream);
}
}
drop(temp_dir)
});
anyhow::ensure!(
which::which("nc").is_ok(),
"Cannot find `nc` command (netcat), which is required to connect over SSH."
);
// Create an askpass script that communicates back to this process.
let askpass_script = format!(
"{shebang}\n{print_args} | {nc} -U {askpass_socket} 2> /dev/null \n",
// on macOS `brew install netcat` provides the GNU netcat implementation
// which does not support -U.
nc = if cfg!(target_os = "macos") {
"/usr/bin/nc"
} else {
"nc"
},
askpass_socket = askpass_socket.display(),
print_args = "printf '%s\\0' \"$@\"",
shebang = "#!/bin/sh",
);
fs::write(&askpass_script_path, askpass_script).await?;
fs::set_permissions(&askpass_script_path, std::fs::Permissions::from_mode(0o755)).await?;
Ok(Self {
script_path: askpass_script_path,
_askpass_task: askpass_task,
askpass_kill_master_rx: Some(askpass_kill_master_rx),
askpass_opened_rx: Some(askpass_opened_rx),
})
}
pub fn script_path(&self) -> &Path {
&self.script_path
}
// This will run the askpass task forever, resolving as many authentication requests as needed.
// The caller is responsible for examining the result of their own commands and cancelling this
// future when this is no longer needed. Note that this can only be called once, but due to the
// drop order this takes an &mut, so you can `drop()` it after you're done with the master process.
pub async fn run(&mut self) -> AskPassResult {
let connection_timeout = Duration::from_secs(10);
let askpass_opened_rx = self.askpass_opened_rx.take().expect("Only call run once");
let askpass_kill_master_rx = self
.askpass_kill_master_rx
.take()
.expect("Only call run once");
select_biased! {
_ = askpass_opened_rx.fuse() => {
// Note: this await can only resolve after we are dropped.
askpass_kill_master_rx.await.ok();
return AskPassResult::CancelledByUser
}
_ = futures::FutureExt::fuse(smol::Timer::after(connection_timeout)) => {
return AskPassResult::Timedout
}
}
}
}
#[cfg(not(unix))]
pub struct AskPassSession {
path: PathBuf,
}
#[cfg(not(unix))]
impl AskPassSession {
pub async fn new(_: &BackgroundExecutor, _: AskPassDelegate) -> anyhow::Result<Self> {
Ok(Self {
path: PathBuf::new(),
})
}
pub fn script_path(&self) -> &Path {
&self.path
}
pub async fn run(&mut self) -> AskPassResult {
futures::FutureExt::fuse(smol::Timer::after(Duration::from_secs(10))).await;
AskPassResult::Timedout
}
}

View File

@@ -51,6 +51,7 @@ parking_lot.workspace = true
paths.workspace = true
project.workspace = true
prompt_library.workspace = true
prompt_store.workspace = true
proto.workspace = true
rope.workspace = true
schemars.workspace = true

View File

@@ -19,7 +19,7 @@ use gpui::{actions, App, Global, UpdateGlobal};
use language_model::{
LanguageModelId, LanguageModelProviderId, LanguageModelRegistry, LanguageModelResponseMessage,
};
use prompt_library::PromptBuilder;
use prompt_store::PromptBuilder;
use semantic_index::{CloudEmbeddingProvider, SemanticDb};
use serde::Deserialize;
use settings::{Settings, SettingsStore};

View File

@@ -24,7 +24,8 @@ use language_model::{
AuthenticateError, LanguageModelProviderId, LanguageModelRegistry, ZED_CLOUD_PROVIDER_ID,
};
use project::Project;
use prompt_library::{open_prompt_library, PromptBuilder, PromptLibrary};
use prompt_library::{open_prompt_library, PromptLibrary};
use prompt_store::PromptBuilder;
use search::{buffer_search::DivRegistrar, BufferSearchBar};
use settings::{update_settings_file, Settings};
use smol::stream::StreamExt;

View File

@@ -35,11 +35,11 @@ use language_model::{
report_assistant_event, LanguageModel, LanguageModelRegistry, LanguageModelRequest,
LanguageModelRequestMessage, LanguageModelTextStream, Role,
};
use language_model_selector::{InlineLanguageModelSelector, LanguageModelSelector};
use language_model_selector::{LanguageModelSelector, LanguageModelSelectorPopoverMenu};
use multi_buffer::MultiBufferRow;
use parking_lot::Mutex;
use project::{CodeAction, ProjectTransaction};
use prompt_library::PromptBuilder;
use prompt_store::PromptBuilder;
use rope::Rope;
use settings::{update_settings_file, Settings, SettingsStore};
use smol::future::FutureExt;
@@ -1589,10 +1589,29 @@ impl Render for PromptEditor {
.w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0))
.justify_center()
.gap_2()
.child(
InlineLanguageModelSelector::new(self.language_model_selector.clone())
.render(window, cx),
)
.child(LanguageModelSelectorPopoverMenu::new(
self.language_model_selector.clone(),
IconButton::new("context", IconName::SettingsAlt)
.shape(IconButtonShape::Square)
.icon_size(IconSize::Small)
.icon_color(Color::Muted),
move |window, cx| {
Tooltip::with_meta(
format!(
"Using {}",
LanguageModelRegistry::read_global(cx)
.active_model()
.map(|model| model.name().0)
.unwrap_or_else(|| "No model selected".into()),
),
None,
"Change Model",
window,
cx,
)
},
gpui::Corner::TopRight,
))
.map(|el| {
let CodegenStatus::Error(error) = self.codegen.read(cx).status(cx) else {
return el;

View File

@@ -19,8 +19,8 @@ use language_model::{
report_assistant_event, LanguageModelRegistry, LanguageModelRequest,
LanguageModelRequestMessage, Role,
};
use language_model_selector::{InlineLanguageModelSelector, LanguageModelSelector};
use prompt_library::PromptBuilder;
use language_model_selector::{LanguageModelSelector, LanguageModelSelectorPopoverMenu};
use prompt_store::PromptBuilder;
use settings::{update_settings_file, Settings};
use std::{
cmp,
@@ -506,7 +506,7 @@ struct PromptEditor {
impl EventEmitter<PromptEditorEvent> for PromptEditor {}
impl Render for PromptEditor {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let status = &self.codegen.read(cx).status;
let buttons = match status {
CodegenStatus::Idle => {
@@ -641,10 +641,29 @@ impl Render for PromptEditor {
.w_12()
.justify_center()
.gap_2()
.child(
InlineLanguageModelSelector::new(self.language_model_selector.clone())
.render(window, cx),
)
.child(LanguageModelSelectorPopoverMenu::new(
self.language_model_selector.clone(),
IconButton::new("change-model", IconName::SettingsAlt)
.shape(IconButtonShape::Square)
.icon_size(IconSize::Small)
.icon_color(Color::Muted),
move |window, cx| {
Tooltip::with_meta(
format!(
"Using {}",
LanguageModelRegistry::read_global(cx)
.active_model()
.map(|model| model.name().0)
.unwrap_or_else(|| "No model selected".into()),
),
None,
"Change Model",
window,
cx,
)
},
gpui::Corner::TopRight,
))
.children(
if let CodegenStatus::Error(error) = &self.codegen.read(cx).status {
let error_message = SharedString::from(error.to_string());

View File

@@ -56,6 +56,7 @@ paths.workspace = true
picker.workspace = true
project.workspace = true
prompt_library.workspace = true
prompt_store.workspace = true
proto.workspace = true
rope.workspace = true
serde.workspace = true

View File

@@ -270,8 +270,15 @@ impl ActiveThread {
let model_registry = LanguageModelRegistry::read_global(cx);
if let Some(model) = model_registry.active_model() {
self.thread.update(cx, |thread, cx| {
// Insert an empty user message to contain the tool results.
thread.insert_user_message("", Vec::new(), cx);
// Insert a user message to contain the tool results.
thread.insert_user_message(
// TODO: Sending up a user message without any content results in the model sending back
// responses that also don't have any content. We currently don't handle this case well,
// so for now we provide some text to keep the model on track.
"Here are the tool results.",
Vec::new(),
cx,
);
thread.send_to_model(model, RequestKind::Chat, true, cx);
});
}
@@ -295,10 +302,7 @@ impl ActiveThread {
let colors = cx.theme().colors();
// Don't render user messages that are just there for returning tool results.
if message.role == Role::User
&& message.text.is_empty()
&& self.thread.read(cx).message_has_tool_results(message_id)
{
if message.role == Role::User && self.thread.read(cx).message_has_tool_results(message_id) {
return Empty.into_any();
}

View File

@@ -27,7 +27,7 @@ use command_palette_hooks::CommandPaletteFilter;
use feature_flags::{Assistant2FeatureFlag, FeatureFlagAppExt};
use fs::Fs;
use gpui::{actions, App};
use prompt_library::PromptBuilder;
use prompt_store::PromptBuilder;
use settings::Settings as _;
pub use crate::assistant_panel::{AssistantPanel, ConcreteAssistantPanelDelegate};

View File

@@ -1,19 +1,24 @@
use assistant_settings::AssistantSettings;
use fs::Fs;
use gpui::{Entity, FocusHandle};
use language_model_selector::{AssistantLanguageModelSelector, LanguageModelSelector};
use gpui::{Entity, FocusHandle, SharedString};
use language_model::LanguageModelRegistry;
use language_model_selector::{
LanguageModelSelector, LanguageModelSelectorPopoverMenu, ToggleModelSelector,
};
use settings::update_settings_file;
use std::sync::Arc;
use ui::prelude::*;
use ui::{prelude::*, ButtonLike, PopoverMenuHandle, Tooltip};
pub struct AssistantModelSelector {
pub selector: Entity<LanguageModelSelector>,
selector: Entity<LanguageModelSelector>,
menu_handle: PopoverMenuHandle<LanguageModelSelector>,
focus_handle: FocusHandle,
}
impl AssistantModelSelector {
pub(crate) fn new(
fs: Arc<dyn Fs>,
menu_handle: PopoverMenuHandle<LanguageModelSelector>,
focus_handle: FocusHandle,
window: &mut Window,
cx: &mut App,
@@ -33,14 +38,54 @@ impl AssistantModelSelector {
cx,
)
}),
menu_handle,
focus_handle,
}
}
pub fn toggle(&self, window: &mut Window, cx: &mut Context<Self>) {
self.menu_handle.toggle(window, cx);
}
}
impl Render for AssistantModelSelector {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
AssistantLanguageModelSelector::new(self.focus_handle.clone(), self.selector.clone())
.render(window, cx)
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let active_model = LanguageModelRegistry::read_global(cx).active_model();
let focus_handle = self.focus_handle.clone();
let model_name = match active_model {
Some(model) => model.name().0,
_ => SharedString::from("No model selected"),
};
LanguageModelSelectorPopoverMenu::new(
self.selector.clone(),
ButtonLike::new("active-model")
.style(ButtonStyle::Subtle)
.child(
h_flex()
.gap_0p5()
.child(
Label::new(model_name)
.size(LabelSize::Small)
.color(Color::Muted),
)
.child(
Icon::new(IconName::ChevronDown)
.color(Color::Muted)
.size(IconSize::XSmall),
),
),
move |window, cx| {
Tooltip::for_action_in(
"Change Model",
&ToggleModelSelector,
&focus_handle,
window,
cx,
)
},
gpui::Corner::BottomRight,
)
.with_handle(self.menu_handle.clone())
}
}

View File

@@ -20,7 +20,8 @@ use gpui::{
use language::LanguageRegistry;
use language_model::{LanguageModelProviderTosView, LanguageModelRegistry};
use project::Project;
use prompt_library::{open_prompt_library, PromptBuilder, PromptLibrary};
use prompt_library::{open_prompt_library, PromptLibrary};
use prompt_store::PromptBuilder;
use settings::{update_settings_file, Settings};
use time::UtcOffset;
use ui::{prelude::*, ContextMenu, KeyBinding, PopoverMenu, PopoverMenuHandle, Tab, Tooltip};
@@ -608,7 +609,7 @@ impl AssistantPanel {
.id("title")
.overflow_x_scroll()
.px(DynamicSpacing::Base08.rems(cx))
.child(Label::new(title).text_ellipsis()),
.child(Label::new(title).truncate()),
)
.child(
h_flex()

View File

@@ -14,7 +14,7 @@ use language_model::{
};
use multi_buffer::MultiBufferRow;
use parking_lot::Mutex;
use prompt_library::PromptBuilder;
use prompt_store::PromptBuilder;
use rope::Rope;
use smol::future::FutureExt;
use std::{

View File

@@ -167,8 +167,8 @@ impl PickerDelegate for FetchContextPickerDelegate {
}
}
fn no_matches_text(&self, _window: &mut Window, _cx: &mut App) -> SharedString {
"Enter the URL that you would like to fetch".into()
fn no_matches_text(&self, _window: &mut Window, _cx: &mut App) -> Option<SharedString> {
Some("Enter the URL that you would like to fetch".into())
}
fn selected_index(&self) -> usize {

View File

@@ -28,7 +28,7 @@ use language_model::{report_assistant_event, LanguageModelRegistry};
use multi_buffer::MultiBufferRow;
use parking_lot::Mutex;
use project::{CodeAction, ProjectTransaction};
use prompt_library::PromptBuilder;
use prompt_store::PromptBuilder;
use settings::{Settings, SettingsStore};
use telemetry_events::{AssistantEvent, AssistantKind, AssistantPhase};
use terminal_view::{terminal_panel::TerminalPanel, TerminalView};

View File

@@ -20,6 +20,7 @@ use gpui::{
EventEmitter, FocusHandle, Focusable, FontWeight, Subscription, TextStyle, WeakEntity, Window,
};
use language_model::{LanguageModel, LanguageModelRegistry};
use language_model_selector::ToggleModelSelector;
use parking_lot::Mutex;
use settings::Settings;
use std::cmp;
@@ -102,11 +103,9 @@ impl<T: 'static> Render for PromptEditor<T> {
.items_start()
.cursor(CursorStyle::Arrow)
.on_action(cx.listener(Self::toggle_context_picker))
.on_action(cx.listener(|this, action, window, cx| {
let selector = this.model_selector.read(cx).selector.clone();
selector.update(cx, |selector, cx| {
selector.toggle_model_selector(action, window, cx);
})
.on_action(cx.listener(|this, _: &ToggleModelSelector, window, cx| {
this.model_selector
.update(cx, |model_selector, cx| model_selector.toggle(window, cx));
}))
.on_action(cx.listener(Self::confirm))
.on_action(cx.listener(Self::cancel))
@@ -858,6 +857,7 @@ impl PromptEditor<BufferCodegen> {
editor
});
let context_picker_menu_handle = PopoverMenuHandle::default();
let model_selector_menu_handle = PopoverMenuHandle::default();
let context_strip = cx.new(|cx| {
ContextStrip::new(
@@ -881,7 +881,13 @@ impl PromptEditor<BufferCodegen> {
context_strip,
context_picker_menu_handle,
model_selector: cx.new(|cx| {
AssistantModelSelector::new(fs, prompt_editor.focus_handle(cx), window, cx)
AssistantModelSelector::new(
fs,
model_selector_menu_handle,
prompt_editor.focus_handle(cx),
window,
cx,
)
}),
edited_since_done: false,
prompt_history,
@@ -1006,6 +1012,7 @@ impl PromptEditor<TerminalCodegen> {
editor
});
let context_picker_menu_handle = PopoverMenuHandle::default();
let model_selector_menu_handle = PopoverMenuHandle::default();
let context_strip = cx.new(|cx| {
ContextStrip::new(
@@ -1029,7 +1036,13 @@ impl PromptEditor<TerminalCodegen> {
context_strip,
context_picker_menu_handle,
model_selector: cx.new(|cx| {
AssistantModelSelector::new(fs, prompt_editor.focus_handle(cx), window, cx)
AssistantModelSelector::new(
fs,
model_selector_menu_handle.clone(),
prompt_editor.focus_handle(cx),
window,
cx,
)
}),
edited_since_done: false,
prompt_history,

View File

@@ -8,6 +8,7 @@ use gpui::{
TextStyle, WeakEntity,
};
use language_model::LanguageModelRegistry;
use language_model_selector::ToggleModelSelector;
use rope::Point;
use settings::Settings;
use std::time::Duration;
@@ -53,6 +54,7 @@ impl MessageEditor {
let context_store = cx.new(|_cx| ContextStore::new(workspace.clone()));
let context_picker_menu_handle = PopoverMenuHandle::default();
let inline_context_picker_menu_handle = PopoverMenuHandle::default();
let model_selector_menu_handle = PopoverMenuHandle::default();
let editor = cx.new(|cx| {
let mut editor = Editor::auto_height(10, window, cx);
@@ -105,8 +107,15 @@ impl MessageEditor {
context_picker_menu_handle,
inline_context_picker,
inline_context_picker_menu_handle,
model_selector: cx
.new(|cx| AssistantModelSelector::new(fs, editor.focus_handle(cx), window, cx)),
model_selector: cx.new(|cx| {
AssistantModelSelector::new(
fs,
model_selector_menu_handle,
editor.focus_handle(cx),
window,
cx,
)
}),
use_tools: false,
_subscriptions: subscriptions,
}
@@ -297,11 +306,9 @@ impl Render for MessageEditor {
v_flex()
.key_context("MessageEditor")
.on_action(cx.listener(Self::chat))
.on_action(cx.listener(|this, action, window, cx| {
let selector = this.model_selector.read(cx).selector.clone();
selector.update(cx, |this, cx| {
this.toggle_model_selector(action, window, cx);
})
.on_action(cx.listener(|this, _: &ToggleModelSelector, window, cx| {
this.model_selector
.update(cx, |model_selector, cx| model_selector.toggle(window, cx));
}))
.on_action(cx.listener(Self::toggle_context_picker))
.on_action(cx.listener(Self::remove_all_context))

View File

@@ -16,7 +16,7 @@ use language_model::{
report_assistant_event, LanguageModelRegistry, LanguageModelRequest,
LanguageModelRequestMessage, Role,
};
use prompt_library::PromptBuilder;
use prompt_store::PromptBuilder;
use std::sync::Arc;
use telemetry_events::{AssistantEvent, AssistantKind, AssistantPhase};
use terminal_view::TerminalView;

View File

@@ -33,9 +33,9 @@ impl ThreadHistory {
}
}
pub fn select_prev(
pub fn select_previous(
&mut self,
_: &menu::SelectPrev,
_: &menu::SelectPrevious,
window: &mut Window,
cx: &mut Context<Self>,
) {
@@ -166,7 +166,7 @@ impl Render for ThreadHistory {
.overflow_y_scroll()
.size_full()
.p_1()
.on_action(cx.listener(Self::select_prev))
.on_action(cx.listener(Self::select_previous))
.on_action(cx.listener(Self::select_next))
.on_action(cx.listener(Self::select_first))
.on_action(cx.listener(Self::select_last))
@@ -260,7 +260,7 @@ impl RenderOnce for PastThread {
.start_slot(
div()
.max_w_4_5()
.child(Label::new(summary).size(LabelSize::Small).text_ellipsis()),
.child(Label::new(summary).size(LabelSize::Small).truncate()),
)
.end_slot(
h_flex()
@@ -356,7 +356,7 @@ impl RenderOnce for PastContext {
.start_slot(
div()
.max_w_4_5()
.child(Label::new(summary).size(LabelSize::Small).text_ellipsis()),
.child(Label::new(summary).size(LabelSize::Small).truncate()),
)
.end_slot(
h_flex()

View File

@@ -37,7 +37,7 @@ parking_lot.workspace = true
paths.workspace = true
picker.workspace = true
project.workspace = true
prompt_library.workspace = true
prompt_store.workspace = true
regex.workspace = true
rope.workspace = true
rpc.workspace = true

View File

@@ -27,7 +27,7 @@ use language_model::{
use open_ai::Model as OpenAiModel;
use paths::contexts_dir;
use project::Project;
use prompt_library::PromptBuilder;
use prompt_store::PromptBuilder;
use serde::{Deserialize, Serialize};
use smallvec::SmallVec;
use std::{

View File

@@ -20,7 +20,7 @@ use language_model::{LanguageModelCacheConfiguration, LanguageModelRegistry, Rol
use parking_lot::Mutex;
use pretty_assertions::assert_eq;
use project::Project;
use prompt_library::PromptBuilder;
use prompt_store::PromptBuilder;
use rand::prelude::*;
use serde_json::json;
use settings::SettingsStore;
@@ -671,7 +671,7 @@ async fn test_slash_commands(cx: &mut TestAppContext) {
#[gpui::test]
async fn test_workflow_step_parsing(cx: &mut TestAppContext) {
cx.update(prompt_library::init);
cx.update(prompt_store::init);
let mut settings_store = cx.update(SettingsStore::test);
cx.update(|cx| {
settings_store

View File

@@ -37,7 +37,9 @@ use language_model::{
LanguageModelImage, LanguageModelProvider, LanguageModelProviderTosView, LanguageModelRegistry,
Role,
};
use language_model_selector::{AssistantLanguageModelSelector, LanguageModelSelector};
use language_model_selector::{
LanguageModelSelector, LanguageModelSelectorPopoverMenu, ToggleModelSelector,
};
use multi_buffer::MultiBufferRow;
use picker::Picker;
use project::lsp_store::LocalLspAdapterDelegate;
@@ -196,6 +198,7 @@ pub struct ContextEditor {
// context editor, we keep a reference here.
dragged_file_worktrees: Vec<Entity<Worktree>>,
language_model_selector: Entity<LanguageModelSelector>,
language_model_selector_menu_handle: PopoverMenuHandle<LanguageModelSelector>,
}
pub const DEFAULT_TAB_TITLE: &str = "New Chat";
@@ -249,21 +252,6 @@ impl ContextEditor {
cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
];
let fs_clone = fs.clone();
let language_model_selector = cx.new(|cx| {
LanguageModelSelector::new(
move |model, cx| {
update_settings_file::<AssistantSettings>(
fs_clone.clone(),
cx,
move |settings, _| settings.set_model(model.clone()),
);
},
window,
cx,
)
});
let sections = context.read(cx).slash_command_output_sections().to_vec();
let patch_ranges = context.read(cx).patch_ranges().collect::<Vec<_>>();
let slash_commands = context.read(cx).slash_commands().clone();
@@ -276,7 +264,7 @@ impl ContextEditor {
image_blocks: Default::default(),
scroll_position: None,
remote_id: None,
fs,
fs: fs.clone(),
workspace,
project,
pending_slash_command_creases: HashMap::default(),
@@ -288,7 +276,20 @@ impl ContextEditor {
show_accept_terms: false,
slash_menu_handle: Default::default(),
dragged_file_worktrees: Vec::new(),
language_model_selector,
language_model_selector: cx.new(|cx| {
LanguageModelSelector::new(
move |model, cx| {
update_settings_file::<AssistantSettings>(
fs.clone(),
cx,
move |settings, _| settings.set_model(model.clone()),
);
},
window,
cx,
)
}),
language_model_selector_menu_handle: PopoverMenuHandle::default(),
};
this.update_message_headers(cx);
this.update_image_blocks(cx);
@@ -2388,6 +2389,46 @@ impl ContextEditor {
)
}
fn render_language_model_selector(&self, cx: &mut Context<Self>) -> impl IntoElement {
let active_model = LanguageModelRegistry::read_global(cx).active_model();
let focus_handle = self.editor().focus_handle(cx).clone();
let model_name = match active_model {
Some(model) => model.name().0,
None => SharedString::from("No model selected"),
};
LanguageModelSelectorPopoverMenu::new(
self.language_model_selector.clone(),
ButtonLike::new("active-model")
.style(ButtonStyle::Subtle)
.child(
h_flex()
.gap_0p5()
.child(
Label::new(model_name)
.size(LabelSize::Small)
.color(Color::Muted),
)
.child(
Icon::new(IconName::ChevronDown)
.color(Color::Muted)
.size(IconSize::XSmall),
),
),
move |window, cx| {
Tooltip::for_action_in(
"Change Model",
&ToggleModelSelector,
&focus_handle,
window,
cx,
)
},
gpui::Corner::BottomLeft,
)
.with_handle(self.language_model_selector_menu_handle.clone())
}
fn render_last_error(&self, cx: &mut Context<Self>) -> Option<AnyElement> {
let last_error = self.last_error.as_ref()?;
@@ -2832,7 +2873,7 @@ impl Render for ContextEditor {
None
};
let language_model_selector = self.language_model_selector.clone();
let language_model_selector = self.language_model_selector_menu_handle.clone();
v_flex()
.key_context("ContextEditor")
.capture_action(cx.listener(ContextEditor::cancel))
@@ -2845,10 +2886,8 @@ impl Render for ContextEditor {
.on_action(cx.listener(ContextEditor::edit))
.on_action(cx.listener(ContextEditor::assist))
.on_action(cx.listener(ContextEditor::split))
.on_action(move |action, window, cx| {
language_model_selector.update(cx, |this, cx| {
this.toggle_model_selector(action, window, cx);
})
.on_action(move |_: &ToggleModelSelector, window, cx| {
language_model_selector.toggle(window, cx);
})
.size_full()
.children(self.render_notice(cx))
@@ -2887,14 +2926,11 @@ impl Render for ContextEditor {
.gap_1()
.child(self.render_inject_context_menu(cx))
.child(ui::Divider::vertical())
.child(div().pl_0p5().child({
let focus_handle = self.editor().focus_handle(cx).clone();
AssistantLanguageModelSelector::new(
focus_handle,
self.language_model_selector.clone(),
)
.render(window, cx)
})),
.child(
div()
.pl_0p5()
.child(self.render_language_model_selector(cx)),
),
)
.child(
h_flex()

View File

@@ -16,7 +16,7 @@ use gpui::{App, AppContext as _, AsyncApp, Context, Entity, EventEmitter, Task,
use language::LanguageRegistry;
use paths::contexts_dir;
use project::Project;
use prompt_library::PromptBuilder;
use prompt_store::PromptBuilder;
use regex::Regex;
use rpc::AnyProtoClient;
use std::sync::LazyLock;
@@ -104,49 +104,53 @@ impl ContextStore {
const CONTEXT_WATCH_DURATION: Duration = Duration::from_millis(100);
let (mut events, _) = fs.watch(contexts_dir(), CONTEXT_WATCH_DURATION).await;
let this = cx.new(|cx: &mut Context<Self>| {
let context_server_factory_registry =
ContextServerFactoryRegistry::default_global(cx);
let context_server_manager = cx.new(|cx| {
ContextServerManager::new(context_server_factory_registry, project.clone(), cx)
});
let mut this = Self {
contexts: Vec::new(),
contexts_metadata: Vec::new(),
context_server_manager,
context_server_slash_command_ids: HashMap::default(),
host_contexts: Vec::new(),
fs,
languages,
slash_commands,
telemetry,
_watch_updates: cx.spawn(|this, mut cx| {
async move {
while events.next().await.is_some() {
this.update(&mut cx, |this, cx| this.reload(cx))?
.await
.log_err();
let this =
cx.new(|cx: &mut Context<Self>| {
let context_server_factory_registry =
ContextServerFactoryRegistry::default_global(cx);
let context_server_manager = cx.new(|cx| {
ContextServerManager::new(
context_server_factory_registry,
project.clone(),
cx,
)
});
let mut this = Self {
contexts: Vec::new(),
contexts_metadata: Vec::new(),
context_server_manager,
context_server_slash_command_ids: HashMap::default(),
host_contexts: Vec::new(),
fs,
languages,
slash_commands,
telemetry,
_watch_updates: cx.spawn(|this, mut cx| {
async move {
while events.next().await.is_some() {
this.update(&mut cx, |this, cx| this.reload(cx))?
.await
.log_err();
}
anyhow::Ok(())
}
anyhow::Ok(())
}
.log_err()
}),
client_subscription: None,
_project_subscriptions: vec![
cx.observe(&project, Self::handle_project_changed),
cx.subscribe(&project, Self::handle_project_event),
],
project_is_shared: false,
client: project.read(cx).client(),
project: project.clone(),
prompt_builder,
};
this.handle_project_changed(project.clone(), cx);
this.synchronize_contexts(cx);
this.register_context_server_handlers(cx);
this.reload(cx).detach_and_log_err(cx);
this
})?;
.log_err()
}),
client_subscription: None,
_project_subscriptions: vec![
cx.subscribe(&project, Self::handle_project_event)
],
project_is_shared: false,
client: project.read(cx).client(),
project: project.clone(),
prompt_builder,
};
this.handle_project_shared(project.clone(), cx);
this.synchronize_contexts(cx);
this.register_context_server_handlers(cx);
this.reload(cx).detach_and_log_err(cx);
this
})?;
Ok(this)
})
@@ -288,7 +292,7 @@ impl ContextStore {
})?
}
fn handle_project_changed(&mut self, _: Entity<Project>, cx: &mut Context<Self>) {
fn handle_project_shared(&mut self, _: Entity<Project>, cx: &mut Context<Self>) {
let is_shared = self.project.read(cx).is_shared();
let was_shared = mem::replace(&mut self.project_is_shared, is_shared);
if is_shared == was_shared {
@@ -318,11 +322,14 @@ impl ContextStore {
fn handle_project_event(
&mut self,
_: Entity<Project>,
project: Entity<Project>,
event: &project::Event,
cx: &mut Context<Self>,
) {
match event {
project::Event::RemoteIdChanged(_) => {
self.handle_project_shared(project, cx);
}
project::Event::Reshared => {
self.advertise_contexts(cx);
}

View File

@@ -140,7 +140,7 @@ impl ResolvedPatch {
buffer.edit(
edits,
Some(AutoindentMode::Block {
original_start_columns: Vec::new(),
original_indent_columns: Vec::new(),
}),
cx,
);

View File

@@ -207,24 +207,31 @@ impl PickerDelegate for SlashCommandDelegate {
.child(
h_flex()
.gap_1p5()
.child(Icon::new(info.icon).size(IconSize::XSmall))
.child(div().font_buffer(cx).child({
.child(
Icon::new(info.icon)
.size(IconSize::XSmall)
.color(Color::Muted),
)
.child({
let mut label = format!("{}", info.name);
if let Some(args) = info.args.as_ref().filter(|_| selected)
{
label.push_str(&args);
}
Label::new(label).single_line().size(LabelSize::Small)
}))
Label::new(label)
.single_line()
.size(LabelSize::Small)
.buffer_font(cx)
})
.children(info.args.clone().filter(|_| !selected).map(
|args| {
div()
.font_buffer(cx)
.child(
Label::new(args)
.single_line()
.size(LabelSize::Small)
.color(Color::Muted),
.color(Color::Muted)
.buffer_font(cx),
)
.visible_on_hover(format!(
"command-entry-label-{ix}"
@@ -236,7 +243,7 @@ impl PickerDelegate for SlashCommandDelegate {
Label::new(info.description.clone())
.size(LabelSize::Small)
.color(Color::Muted)
.text_ellipsis(),
.truncate(),
),
),
),
@@ -294,10 +301,9 @@ where
.gap_1p5()
.child(Icon::new(IconName::Plus).size(IconSize::XSmall))
.child(
div().font_buffer(cx).child(
Label::new("create-your-command")
.size(LabelSize::Small),
),
Label::new("create-your-command")
.size(LabelSize::Small)
.buffer_font(cx),
),
)
.child(
@@ -341,7 +347,7 @@ where
.anchor(gpui::Corner::BottomLeft)
.offset(gpui::Point {
x: px(0.0),
y: px(-16.0),
y: px(-2.0),
})
.when_some(handle, |this, handle| this.with_handle(handle))
}

View File

@@ -32,7 +32,7 @@ language.workspace = true
language_model.workspace = true
log.workspace = true
project.workspace = true
prompt_library.workspace = true
prompt_store.workspace = true
rope.workspace = true
schemars.workspace = true
semantic_index.workspace = true

View File

@@ -5,7 +5,7 @@ use assistant_slash_command::{
};
use gpui::{Task, WeakEntity};
use language::{BufferSnapshot, LspAdapterDelegate};
use prompt_library::PromptStore;
use prompt_store::PromptStore;
use std::{
fmt::Write,
sync::{atomic::AtomicBool, Arc},

View File

@@ -13,7 +13,7 @@ use feature_flags::FeatureFlag;
use gpui::{App, Task, WeakEntity};
use language::{Anchor, CodeLabel, LspAdapterDelegate};
use language_model::{LanguageModelRegistry, LanguageModelTool};
use prompt_library::PromptBuilder;
use prompt_store::PromptBuilder;
use schemars::JsonSchema;
use semantic_index::SemanticDb;
use serde::Deserialize;

View File

@@ -5,7 +5,7 @@ use assistant_slash_command::{
};
use gpui::{Task, WeakEntity};
use language::{BufferSnapshot, LspAdapterDelegate};
use prompt_library::PromptStore;
use prompt_store::PromptStore;
use std::sync::{atomic::AtomicBool, Arc};
use ui::prelude::*;
use workspace::Workspace;

View File

@@ -141,19 +141,20 @@ pub fn notify_if_app_was_updated(cx: &mut App) {
cx,
move |cx| {
let workspace_handle = cx.entity().downgrade();
cx.new(|_cx| {
MessageNotification::new(format!("Updated to {app_name} {}", version))
.primary_message("View Release Notes")
.primary_on_click(move |window, cx| {
if let Some(workspace) = workspace_handle.upgrade() {
workspace.update(cx, |workspace, cx| {
crate::view_release_notes_locally(
workspace, window, cx,
);
})
}
cx.emit(DismissEvent);
})
cx.new(|cx| {
MessageNotification::new(
format!("Updated to {app_name} {}", version),
cx,
)
.primary_message("View Release Notes")
.primary_on_click(move |window, cx| {
if let Some(workspace) = workspace_handle.upgrade() {
workspace.update(cx, |workspace, cx| {
crate::view_release_notes_locally(workspace, window, cx);
})
}
cx.emit(DismissEvent);
})
})
},
);

View File

@@ -82,7 +82,7 @@ impl Render for Breadcrumbs {
text_style.color = Color::Muted.color(cx);
StyledText::new(segment.text.replace('\n', ""))
.with_highlights(&text_style, segment.highlights.unwrap_or_default())
.with_default_highlights(&text_style, segment.highlights.unwrap_or_default())
.into_any()
});
let breadcrumbs = Itertools::intersperse_with(highlighted_segments, || {

View File

@@ -16,11 +16,13 @@ test-support = []
[dependencies]
anyhow.workspace = true
clock.workspace = true
futures.workspace = true
git2.workspace = true
gpui.workspace = true
language.workspace = true
log.workspace = true
pretty_assertions.workspace = true
rope.workspace = true
sum_tree.workspace = true
text.workspace = true
@@ -30,7 +32,6 @@ util.workspace = true
ctor.workspace = true
env_logger.workspace = true
gpui = { workspace = true, features = ["test-support"] }
pretty_assertions.workspace = true
rand.workspace = true
serde_json.workspace = true
text = { workspace = true, features = ["test-support"] }

File diff suppressed because it is too large Load Diff

View File

@@ -614,12 +614,19 @@ mod windows {
let path = if let Some(path) = path {
path.to_path_buf().canonicalize()?
} else {
std::env::current_exe()?
.parent()
.context("no parent path for cli")?
.parent()
.context("no parent path for cli folder")?
.join("Zed.exe")
let cli = std::env::current_exe()?;
let dir = cli.parent().context("no parent path for cli")?;
// ../Zed.exe is the standard, lib/zed is for MSYS2, ./zed.exe is for the target
// directory in development builds.
let possible_locations = ["../Zed.exe", "../lib/zed/zed-editor.exe", "./zed.exe"];
possible_locations
.iter()
.find_map(|p| dir.join(p).canonicalize().ok().filter(|path| path != &cli))
.context(format!(
"could not find any of: {}",
possible_locations.join(", ")
))?
};
Ok(App(path))

View File

@@ -418,6 +418,8 @@ impl Telemetry {
fn report_event(self: &Arc<Self>, event: Event) {
let mut state = self.state.lock();
// RUST_LOG=telemetry=trace to debug telemetry events
log::trace!(target: "telemetry", "{:?}", event);
if !state.settings.metrics {
return;

View File

@@ -111,7 +111,7 @@ node_runtime.workspace = true
notifications = { workspace = true, features = ["test-support"] }
pretty_assertions.workspace = true
project = { workspace = true, features = ["test-support"] }
prompt_library.workspace = true
prompt_store.workspace = true
recent_projects = { workspace = true }
release_channel.workspace = true
remote = { workspace = true, features = ["test-support"] }

View File

@@ -308,7 +308,7 @@ impl Server {
.add_request_handler(forward_read_only_project_request::<proto::InlayHints>)
.add_request_handler(forward_read_only_project_request::<proto::ResolveInlayHint>)
.add_request_handler(forward_read_only_project_request::<proto::OpenBufferByPath>)
.add_request_handler(forward_read_only_project_request::<proto::GitBranches>)
.add_request_handler(forward_read_only_project_request::<proto::GitGetBranches>)
.add_request_handler(forward_read_only_project_request::<proto::OpenUnstagedDiff>)
.add_request_handler(forward_read_only_project_request::<proto::OpenUncommittedDiff>)
.add_request_handler(
@@ -328,6 +328,7 @@ impl Server {
.add_request_handler(forward_mutating_project_request::<proto::PrepareRename>)
.add_request_handler(forward_mutating_project_request::<proto::PerformRename>)
.add_request_handler(forward_mutating_project_request::<proto::ReloadBuffers>)
.add_request_handler(forward_mutating_project_request::<proto::ApplyCodeActionKind>)
.add_request_handler(forward_mutating_project_request::<proto::FormatBuffers>)
.add_request_handler(forward_mutating_project_request::<proto::CreateProjectEntry>)
.add_request_handler(forward_mutating_project_request::<proto::RenameProjectEntry>)
@@ -392,18 +393,20 @@ impl Server {
.add_request_handler(forward_mutating_project_request::<proto::OpenContext>)
.add_request_handler(forward_mutating_project_request::<proto::CreateContext>)
.add_request_handler(forward_mutating_project_request::<proto::SynchronizeContexts>)
.add_request_handler(forward_mutating_project_request::<proto::Push>)
.add_request_handler(forward_mutating_project_request::<proto::Pull>)
.add_request_handler(forward_mutating_project_request::<proto::Fetch>)
.add_request_handler(forward_mutating_project_request::<proto::Stage>)
.add_request_handler(forward_mutating_project_request::<proto::Unstage>)
.add_request_handler(forward_mutating_project_request::<proto::Commit>)
.add_request_handler(forward_mutating_project_request::<proto::GitInit>)
.add_request_handler(forward_read_only_project_request::<proto::GetRemotes>)
.add_request_handler(forward_read_only_project_request::<proto::GitShow>)
.add_request_handler(forward_read_only_project_request::<proto::GitReset>)
.add_request_handler(forward_read_only_project_request::<proto::GitCheckoutFiles>)
.add_request_handler(forward_mutating_project_request::<proto::SetIndexText>)
.add_request_handler(forward_mutating_project_request::<proto::OpenCommitMessageBuffer>)
.add_request_handler(forward_mutating_project_request::<proto::GitDiff>)
.add_request_handler(forward_mutating_project_request::<proto::GitCreateBranch>)
.add_request_handler(forward_mutating_project_request::<proto::GitChangeBranch>)
.add_request_handler(forward_mutating_project_request::<proto::CheckForPushedCommits>)
.add_message_handler(broadcast_project_message_from_host::<proto::AdvertiseContexts>)
.add_message_handler(update_context)
.add_request_handler({

View File

@@ -3,7 +3,6 @@ use crate::{
tests::{rust_lang, TestServer},
};
use call::ActiveCall;
use collections::HashMap;
use editor::{
actions::{
ConfirmCodeAction, ConfirmCompletion, ConfirmRename, ContextMenuFirst, Redo, Rename,
@@ -1983,7 +1982,6 @@ async fn test_git_blame_is_forwarded(cx_a: &mut TestAppContext, cx_b: &mut TestA
blame_entry("3a3a3a", 2..3),
blame_entry("4c4c4c", 3..4),
],
permalinks: HashMap::default(), // This field is deprecrated
messages: [
("1b1b1b", "message for idx-0"),
("0d0d0d", "message for idx-1"),
@@ -2027,11 +2025,20 @@ async fn test_git_blame_is_forwarded(cx_a: &mut TestAppContext, cx_b: &mut TestA
.unwrap()
.downcast::<Editor>()
.unwrap();
let buffer_id_b = editor_b.update(cx_b, |editor_b, cx| {
editor_b
.buffer()
.read(cx)
.as_singleton()
.unwrap()
.read(cx)
.remote_id()
});
// client_b now requests git blame for the open buffer
editor_b.update_in(cx_b, |editor_b, window, cx| {
assert!(editor_b.blame().is_none());
editor_b.toggle_git_blame(&editor::actions::ToggleGitBlame {}, window, cx);
editor_b.toggle_git_blame(&git::Blame {}, window, cx);
});
cx_a.executor().run_until_parked();
@@ -2045,6 +2052,7 @@ async fn test_git_blame_is_forwarded(cx_a: &mut TestAppContext, cx_b: &mut TestA
&(0..4)
.map(|row| RowInfo {
buffer_row: Some(row),
buffer_id: Some(buffer_id_b),
..Default::default()
})
.collect::<Vec<_>>(),
@@ -2092,6 +2100,7 @@ async fn test_git_blame_is_forwarded(cx_a: &mut TestAppContext, cx_b: &mut TestA
&(0..4)
.map(|row| RowInfo {
buffer_row: Some(row),
buffer_id: Some(buffer_id_b),
..Default::default()
})
.collect::<Vec<_>>(),
@@ -2127,6 +2136,7 @@ async fn test_git_blame_is_forwarded(cx_a: &mut TestAppContext, cx_b: &mut TestA
&(0..4)
.map(|row| RowInfo {
buffer_row: Some(row),
buffer_id: Some(buffer_id_b),
..Default::default()
})
.collect::<Vec<_>>(),

View File

@@ -14,7 +14,7 @@ use client::{User, RECEIVE_TIMEOUT};
use collections::{HashMap, HashSet};
use fs::{FakeFs, Fs as _, RemoveOptions};
use futures::{channel::mpsc, StreamExt as _};
use prompt_library::PromptBuilder;
use prompt_store::PromptBuilder;
use git::status::{FileStatus, StatusCode, TrackedStatus, UnmergedStatus, UnmergedStatusCode};
use gpui::{
@@ -6741,19 +6741,24 @@ async fn test_remote_git_branches(
.collect::<HashSet<_>>();
let (project_a, worktree_id) = client_a.build_local_project("/project", cx_a).await;
let project_id = active_call_a
.update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
.await
.unwrap();
let project_b = client_b.join_remote_project(project_id, cx_b).await;
let root_path = ProjectPath::root_path(worktree_id);
// Client A sees that a guest has joined.
// Client A sees that a guest has joined and the repo has been populated
executor.run_until_parked();
let repo_b = cx_b.update(|cx| project_b.read(cx).active_repository(cx).unwrap());
let root_path = ProjectPath::root_path(worktree_id);
let branches_b = cx_b
.update(|cx| project_b.update(cx, |project, cx| project.branches(root_path.clone(), cx)))
.update(|cx| repo_b.update(cx, |repository, _| repository.branches()))
.await
.unwrap()
.unwrap();
let new_branch = branches[2];
@@ -6765,13 +6770,10 @@ async fn test_remote_git_branches(
assert_eq!(branches_b, branches_set);
cx_b.update(|cx| {
project_b.update(cx, |project, cx| {
project.update_or_create_branch(root_path.clone(), new_branch.to_string(), cx)
})
})
.await
.unwrap();
cx_b.update(|cx| repo_b.read(cx).change_branch(new_branch.to_string()))
.await
.unwrap()
.unwrap();
executor.run_until_parked();
@@ -6789,11 +6791,21 @@ async fn test_remote_git_branches(
// Also try creating a new branch
cx_b.update(|cx| {
project_b.update(cx, |project, cx| {
project.update_or_create_branch(root_path.clone(), "totally-new-branch".to_string(), cx)
})
repo_b
.read(cx)
.create_branch("totally-new-branch".to_string())
})
.await
.unwrap()
.unwrap();
cx_b.update(|cx| {
repo_b
.read(cx)
.change_branch("totally-new-branch".to_string())
})
.await
.unwrap()
.unwrap();
executor.run_until_parked();

View File

@@ -276,11 +276,13 @@ async fn test_ssh_collaboration_git_branches(
// has some git repositories
executor.run_until_parked();
let repo_b = cx_b.update(|cx| project_b.read(cx).active_repository(cx).unwrap());
let root_path = ProjectPath::root_path(worktree_id);
let branches_b = cx_b
.update(|cx| project_b.update(cx, |project, cx| project.branches(root_path.clone(), cx)))
.update(|cx| repo_b.read(cx).branches())
.await
.unwrap()
.unwrap();
let new_branch = branches[2];
@@ -292,13 +294,10 @@ async fn test_ssh_collaboration_git_branches(
assert_eq!(&branches_b, &branches_set);
cx_b.update(|cx| {
project_b.update(cx, |project, cx| {
project.update_or_create_branch(root_path.clone(), new_branch.to_string(), cx)
})
})
.await
.unwrap();
cx_b.update(|cx| repo_b.read(cx).change_branch(new_branch.to_string()))
.await
.unwrap()
.unwrap();
executor.run_until_parked();
@@ -318,11 +317,21 @@ async fn test_ssh_collaboration_git_branches(
// Also try creating a new branch
cx_b.update(|cx| {
project_b.update(cx, |project, cx| {
project.update_or_create_branch(root_path.clone(), "totally-new-branch".to_string(), cx)
})
repo_b
.read(cx)
.create_branch("totally-new-branch".to_string())
})
.await
.unwrap()
.unwrap();
cx_b.update(|cx| {
repo_b
.read(cx)
.change_branch("totally-new-branch".to_string())
})
.await
.unwrap()
.unwrap();
executor.run_until_parked();

View File

@@ -271,7 +271,7 @@ impl TestServer {
let git_hosting_provider_registry = cx.update(GitHostingProviderRegistry::default_global);
git_hosting_provider_registry
.register_hosting_provider(Arc::new(git_hosting_providers::Github));
.register_hosting_provider(Arc::new(git_hosting_providers::Github::new()));
let user_store = cx.new(|cx| UserStore::new(client.clone(), cx));
let workspace_store = cx.new(|cx| WorkspaceStore::new(client.clone(), cx));

View File

@@ -17,7 +17,7 @@ use gpui::{
ListState, MouseDownEvent, ParentElement, Pixels, Point, PromptLevel, Render, SharedString,
Styled, Subscription, Task, TextStyle, WeakEntity, Window,
};
use menu::{Cancel, Confirm, SecondaryConfirm, SelectNext, SelectPrev};
use menu::{Cancel, Confirm, SecondaryConfirm, SelectNext, SelectPrevious};
use project::{Fs, Project};
use rpc::{
proto::{self, ChannelVisibility, PeerId},
@@ -1430,7 +1430,7 @@ impl CollabPanel {
cx.notify();
}
fn select_prev(&mut self, _: &SelectPrev, _: &mut Window, cx: &mut Context<Self>) {
fn select_previous(&mut self, _: &SelectPrevious, _: &mut Window, cx: &mut Context<Self>) {
let ix = self.selection.take().unwrap_or(0);
if ix > 0 {
self.selection = Some(ix - 1);
@@ -2878,7 +2878,7 @@ impl Render for CollabPanel {
.key_context("CollabPanel")
.on_action(cx.listener(CollabPanel::cancel))
.on_action(cx.listener(CollabPanel::select_next))
.on_action(cx.listener(CollabPanel::select_prev))
.on_action(cx.listener(CollabPanel::select_previous))
.on_action(cx.listener(CollabPanel::confirm))
.on_action(cx.listener(CollabPanel::insert_space))
.on_action(cx.listener(CollabPanel::remove_selected_channel))

View File

@@ -22,7 +22,7 @@ use ui::{
h_flex, prelude::*, v_flex, Avatar, Button, Icon, IconButton, IconName, Label, Tab, Tooltip,
};
use util::{ResultExt, TryFutureExt};
use workspace::notifications::NotificationId;
use workspace::notifications::{Notification as WorkspaceNotification, NotificationId};
use workspace::{
dock::{DockPosition, Panel, PanelEvent},
Workspace,
@@ -570,11 +570,12 @@ impl NotificationPanel {
workspace.dismiss_notification(&id, cx);
workspace.show_notification(id, cx, |cx| {
let workspace = cx.entity().downgrade();
cx.new(|_| NotificationToast {
cx.new(|cx| NotificationToast {
notification_id,
actor,
text,
workspace,
focus_handle: cx.focus_handle(),
})
})
})
@@ -771,8 +772,17 @@ pub struct NotificationToast {
actor: Option<Arc<User>>,
text: String,
workspace: WeakEntity<Workspace>,
focus_handle: FocusHandle,
}
impl Focusable for NotificationToast {
fn focus_handle(&self, _cx: &App) -> FocusHandle {
self.focus_handle.clone()
}
}
impl WorkspaceNotification for NotificationToast {}
impl NotificationToast {
fn focus_notification_panel(&self, window: &mut Window, cx: &mut Context<Self>) {
let workspace = self.workspace.clone();

View File

@@ -1,3 +1,4 @@
use std::fmt::Display;
use std::ops::{Deref, DerefMut};
use std::sync::LazyLock;
@@ -8,7 +9,7 @@ use parking_lot::RwLock;
use theme::ActiveTheme;
pub trait Component {
fn scope() -> Option<&'static str>;
fn scope() -> Option<ComponentScope>;
fn name() -> &'static str {
std::any::type_name::<Self>()
}
@@ -18,7 +19,7 @@ pub trait Component {
}
pub trait ComponentPreview: Component {
fn preview(_window: &mut Window, _cx: &App) -> AnyElement;
fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement;
}
#[distributed_slice]
@@ -31,8 +32,8 @@ pub static COMPONENT_DATA: LazyLock<RwLock<ComponentRegistry>> =
LazyLock::new(|| RwLock::new(ComponentRegistry::new()));
pub struct ComponentRegistry {
components: Vec<(Option<&'static str>, &'static str, Option<&'static str>)>,
previews: HashMap<&'static str, fn(&mut Window, &App) -> AnyElement>,
components: Vec<(Option<ComponentScope>, &'static str, Option<&'static str>)>,
previews: HashMap<&'static str, fn(&mut Window, &mut App) -> AnyElement>,
}
impl ComponentRegistry {
@@ -62,7 +63,10 @@ pub fn register_component<T: Component>() {
}
pub fn register_preview<T: ComponentPreview>() {
let preview_data = (T::name(), T::preview as fn(&mut Window, &App) -> AnyElement);
let preview_data = (
T::name(),
T::preview as fn(&mut Window, &mut App) -> AnyElement,
);
COMPONENT_DATA
.write()
.previews
@@ -75,9 +79,9 @@ pub struct ComponentId(pub &'static str);
#[derive(Clone)]
pub struct ComponentMetadata {
name: SharedString,
scope: Option<SharedString>,
scope: Option<ComponentScope>,
description: Option<SharedString>,
preview: Option<fn(&mut Window, &App) -> AnyElement>,
preview: Option<fn(&mut Window, &mut App) -> AnyElement>,
}
impl ComponentMetadata {
@@ -85,7 +89,7 @@ impl ComponentMetadata {
self.name.clone()
}
pub fn scope(&self) -> Option<SharedString> {
pub fn scope(&self) -> Option<ComponentScope> {
self.scope.clone()
}
@@ -93,7 +97,7 @@ impl ComponentMetadata {
self.description.clone()
}
pub fn preview(&self) -> Option<fn(&mut Window, &App) -> AnyElement> {
pub fn preview(&self) -> Option<fn(&mut Window, &mut App) -> AnyElement> {
self.preview
}
}
@@ -149,14 +153,14 @@ pub fn components() -> AllComponents {
let data = COMPONENT_DATA.read();
let mut all_components = AllComponents::new();
for &(scope, name, description) in &data.components {
let scope = scope.map(Into::into);
for (ref scope, name, description) in &data.components {
let preview = data.previews.get(name).cloned();
let component_name = SharedString::new_static(name);
all_components.insert(
ComponentId(name),
ComponentMetadata {
name: name.into(),
scope,
name: component_name,
scope: scope.clone(),
description: description.map(Into::into),
preview,
},
@@ -166,6 +170,59 @@ pub fn components() -> AllComponents {
all_components
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ComponentScope {
Layout,
Input,
Notification,
Editor,
Collaboration,
VersionControl,
Unknown(SharedString),
}
impl Display for ComponentScope {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ComponentScope::Layout => write!(f, "Layout"),
ComponentScope::Input => write!(f, "Input"),
ComponentScope::Notification => write!(f, "Notification"),
ComponentScope::Editor => write!(f, "Editor"),
ComponentScope::Collaboration => write!(f, "Collaboration"),
ComponentScope::VersionControl => write!(f, "Version Control"),
ComponentScope::Unknown(name) => write!(f, "Unknown: {}", name),
}
}
}
impl From<&str> for ComponentScope {
fn from(value: &str) -> Self {
match value {
"Layout" => ComponentScope::Layout,
"Input" => ComponentScope::Input,
"Notification" => ComponentScope::Notification,
"Editor" => ComponentScope::Editor,
"Collaboration" => ComponentScope::Collaboration,
"Version Control" | "VersionControl" => ComponentScope::VersionControl,
_ => ComponentScope::Unknown(SharedString::new(value)),
}
}
}
impl From<String> for ComponentScope {
fn from(value: String) -> Self {
match value.as_str() {
"Layout" => ComponentScope::Layout,
"Input" => ComponentScope::Input,
"Notification" => ComponentScope::Notification,
"Editor" => ComponentScope::Editor,
"Collaboration" => ComponentScope::Collaboration,
"Version Control" | "VersionControl" => ComponentScope::VersionControl,
_ => ComponentScope::Unknown(SharedString::new(value)),
}
}
}
/// Which side of the preview to show labels on
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExampleLabelSide {
@@ -174,8 +231,8 @@ pub enum ExampleLabelSide {
/// Right side
Right,
/// Top side
Top,
#[default]
Top,
/// Bottom side
Bottom,
}
@@ -205,6 +262,7 @@ impl RenderOnce for ComponentExample {
.text_size(px(10.))
.text_color(cx.theme().colors().text_muted)
.when(self.grow, |this| this.flex_1())
.when(!self.grow, |this| this.flex_none())
.child(self.element)
.child(self.variant_name)
.into_any_element()
@@ -235,6 +293,7 @@ pub struct ComponentExampleGroup {
pub title: Option<SharedString>,
pub examples: Vec<ComponentExample>,
pub grow: bool,
pub vertical: bool,
}
impl RenderOnce for ComponentExampleGroup {
@@ -270,6 +329,7 @@ impl RenderOnce for ComponentExampleGroup {
.child(
div()
.flex()
.when(self.vertical, |this| this.flex_col())
.items_start()
.w_full()
.gap_6()
@@ -287,6 +347,7 @@ impl ComponentExampleGroup {
title: None,
examples,
grow: false,
vertical: false,
}
}
@@ -296,6 +357,7 @@ impl ComponentExampleGroup {
title: Some(title.into()),
examples,
grow: false,
vertical: false,
}
}
@@ -304,6 +366,12 @@ impl ComponentExampleGroup {
self.grow = true;
self
}
/// Lay the group out vertically.
pub fn vertical(mut self) -> Self {
self.vertical = true;
self
}
}
/// Create a single example

View File

@@ -15,7 +15,11 @@ path = "src/component_preview.rs"
default = []
[dependencies]
client.workspace = true
component.workspace = true
gpui.workspace = true
languages.workspace = true
project.workspace = true
ui.workspace = true
workspace.workspace = true
notifications.workspace = true

View File

@@ -2,18 +2,49 @@
//!
//! A view for exploring Zed components.
use std::iter::Iterator;
use std::sync::Arc;
use client::UserStore;
use component::{components, ComponentMetadata};
use gpui::{list, prelude::*, uniform_list, App, EventEmitter, FocusHandle, Focusable, Window};
use gpui::{
list, prelude::*, uniform_list, App, Entity, EventEmitter, FocusHandle, Focusable, Task,
WeakEntity, Window,
};
use gpui::{ListState, ScrollHandle, UniformListScrollHandle};
use ui::{prelude::*, ListItem};
use languages::LanguageRegistry;
use notifications::status_toast::{StatusToast, ToastIcon};
use project::Project;
use ui::{prelude::*, Divider, ListItem, ListSubHeader};
use workspace::{item::ItemEvent, Item, Workspace, WorkspaceId};
use workspace::{AppState, ItemId, SerializableItem};
pub fn init(app_state: Arc<AppState>, cx: &mut App) {
let app_state = app_state.clone();
cx.observe_new(move |workspace: &mut Workspace, _, cx| {
let app_state = app_state.clone();
let weak_workspace = cx.entity().downgrade();
pub fn init(cx: &mut App) {
cx.observe_new(|workspace: &mut Workspace, _, _cx| {
workspace.register_action(
|workspace, _: &workspace::OpenComponentPreview, window, cx| {
let component_preview = cx.new(|cx| ComponentPreview::new(window, cx));
move |workspace, _: &workspace::OpenComponentPreview, window, cx| {
let app_state = app_state.clone();
let language_registry = app_state.languages.clone();
let user_store = app_state.user_store.clone();
let component_preview = cx.new(|cx| {
ComponentPreview::new(
weak_workspace.clone(),
language_registry,
user_store,
None,
cx,
)
});
workspace.add_item_to_active_pane(
Box::new(component_preview),
None,
@@ -27,6 +58,23 @@ pub fn init(cx: &mut App) {
.detach();
}
enum PreviewEntry {
Component(ComponentMetadata),
SectionHeader(SharedString),
}
impl From<ComponentMetadata> for PreviewEntry {
fn from(component: ComponentMetadata) -> Self {
PreviewEntry::Component(component)
}
}
impl From<SharedString> for PreviewEntry {
fn from(section_header: SharedString) -> Self {
PreviewEntry::SectionHeader(section_header)
}
}
struct ComponentPreview {
focus_handle: FocusHandle,
_view_scroll_handle: ScrollHandle,
@@ -34,31 +82,55 @@ struct ComponentPreview {
components: Vec<ComponentMetadata>,
component_list: ListState,
selected_index: usize,
language_registry: Arc<LanguageRegistry>,
workspace: WeakEntity<Workspace>,
user_store: Entity<UserStore>,
}
impl ComponentPreview {
pub fn new(_window: &mut Window, cx: &mut Context<Self>) -> Self {
pub fn new(
workspace: WeakEntity<Workspace>,
language_registry: Arc<LanguageRegistry>,
user_store: Entity<UserStore>,
selected_index: impl Into<Option<usize>>,
cx: &mut Context<Self>,
) -> Self {
let components = components().all_sorted();
let initial_length = components.len();
let selected_index = selected_index.into().unwrap_or(0);
let component_list = ListState::new(initial_length, gpui::ListAlignment::Top, px(500.0), {
let this = cx.entity().downgrade();
move |ix, window: &mut Window, cx: &mut App| {
this.update(cx, |this, cx| {
this.render_preview(ix, window, cx).into_any_element()
})
.unwrap()
}
});
let component_list =
ListState::new(initial_length, gpui::ListAlignment::Top, px(1500.0), {
let this = cx.entity().downgrade();
move |ix, window: &mut Window, cx: &mut App| {
this.update(cx, |this, cx| {
let component = this.get_component(ix);
this.render_preview(ix, &component, window, cx)
.into_any_element()
})
.unwrap()
}
});
Self {
let mut component_preview = Self {
focus_handle: cx.focus_handle(),
_view_scroll_handle: ScrollHandle::new(),
nav_scroll_handle: UniformListScrollHandle::new(),
language_registry,
user_store,
workspace,
components,
component_list,
selected_index: 0,
selected_index,
};
if component_preview.selected_index > 0 {
component_preview.scroll_to_preview(component_preview.selected_index, cx);
}
component_preview.update_component_list(cx);
component_preview
}
fn scroll_to_preview(&mut self, ix: usize, cx: &mut Context<Self>) {
@@ -71,32 +143,158 @@ impl ComponentPreview {
self.components[ix].clone()
}
fn scope_ordered_entries(&self) -> Vec<PreviewEntry> {
use std::collections::HashMap;
// Group components by scope
let mut scope_groups: HashMap<Option<ComponentScope>, Vec<ComponentMetadata>> =
HashMap::default();
for component in &self.components {
scope_groups
.entry(component.scope())
.or_insert_with(Vec::new)
.push(component.clone());
}
// Sort components within each scope by name
for components in scope_groups.values_mut() {
components.sort_by_key(|c| c.name().to_lowercase());
}
// Build entries with scopes in a defined order
let mut entries = Vec::new();
// Define scope order (we want Unknown at the end)
let known_scopes = [
ComponentScope::Layout,
ComponentScope::Input,
ComponentScope::Editor,
ComponentScope::Notification,
ComponentScope::Collaboration,
ComponentScope::VersionControl,
];
// First add components with known scopes
for scope in known_scopes.iter() {
let scope_key = Some(scope.clone());
if let Some(components) = scope_groups.remove(&scope_key) {
if !components.is_empty() {
// Add section header
entries.push(PreviewEntry::SectionHeader(scope.to_string().into()));
// Add all components under this scope
for component in components {
entries.push(PreviewEntry::Component(component));
}
}
}
}
// Handle components with Unknown scope
for (scope, components) in &scope_groups {
if let Some(ComponentScope::Unknown(_)) = scope {
if !components.is_empty() {
// Add the unknown scope header
if let Some(scope_value) = scope {
entries.push(PreviewEntry::SectionHeader(scope_value.to_string().into()));
}
// Add all components under this unknown scope
for component in components {
entries.push(PreviewEntry::Component(component.clone()));
}
}
}
}
// Handle components with no scope
if let Some(components) = scope_groups.get(&None) {
if !components.is_empty() {
entries.push(PreviewEntry::SectionHeader("Uncategorized".into()));
for component in components {
entries.push(PreviewEntry::Component(component.clone()));
}
}
}
entries
}
fn render_sidebar_entry(
&self,
ix: usize,
entry: &PreviewEntry,
selected: bool,
cx: &Context<Self>,
) -> impl IntoElement {
let component = self.get_component(ix);
match entry {
PreviewEntry::Component(component_metadata) => ListItem::new(ix)
.child(Label::new(component_metadata.name().clone()).color(Color::Default))
.selectable(true)
.toggle_state(selected)
.inset(true)
.on_click(cx.listener(move |this, _, _, cx| {
this.scroll_to_preview(ix, cx);
}))
.into_any_element(),
PreviewEntry::SectionHeader(shared_string) => ListSubHeader::new(shared_string)
.inset(true)
.into_any_element(),
}
}
ListItem::new(ix)
.child(Label::new(component.name().clone()).color(Color::Default))
.selectable(true)
.toggle_state(selected)
.inset(true)
.on_click(cx.listener(move |this, _, _, cx| {
this.scroll_to_preview(ix, cx);
}))
fn update_component_list(&mut self, cx: &mut Context<Self>) {
let new_len = self.scope_ordered_entries().len();
let entries = self.scope_ordered_entries();
let weak_entity = cx.entity().downgrade();
let new_list = ListState::new(
new_len,
gpui::ListAlignment::Top,
px(1500.0),
move |ix, window, cx| {
let entry = &entries[ix];
weak_entity
.update(cx, |this, cx| match entry {
PreviewEntry::Component(component) => this
.render_preview(ix, component, window, cx)
.into_any_element(),
PreviewEntry::SectionHeader(shared_string) => this
.render_scope_header(ix, shared_string.clone(), window, cx)
.into_any_element(),
})
.unwrap()
},
);
self.component_list = new_list;
}
fn render_scope_header(
&self,
_ix: usize,
title: SharedString,
_window: &Window,
_cx: &App,
) -> impl IntoElement {
h_flex()
.w_full()
.h_10()
.items_center()
.child(Headline::new(title).size(HeadlineSize::XSmall))
.child(Divider::horizontal())
}
fn render_preview(
&self,
ix: usize,
_ix: usize,
component: &ComponentMetadata,
window: &mut Window,
cx: &Context<Self>,
cx: &mut App,
) -> impl IntoElement {
let component = self.get_component(ix);
let name = component.name();
let scope = component.scope();
@@ -142,10 +340,27 @@ impl ComponentPreview {
)
.into_any_element()
}
fn test_status_toast(&self, cx: &mut Context<Self>) {
if let Some(workspace) = self.workspace.upgrade() {
workspace.update(cx, |workspace, cx| {
let status_toast =
StatusToast::new("`zed/new-notification-system` created!", cx, |this, _cx| {
this.icon(ToastIcon::new(IconName::GitBranchSmall).color(Color::Muted))
.action("Open Pull Request", |_, cx| {
cx.open_url("https://github.com/")
})
});
workspace.toggle_status_toast(status_toast, cx)
});
}
}
}
impl Render for ComponentPreview {
fn render(&mut self, _window: &mut Window, cx: &mut Context<'_, Self>) -> impl IntoElement {
let sidebar_entries = self.scope_ordered_entries();
h_flex()
.id("component-preview")
.key_context("ComponentPreview")
@@ -156,21 +371,44 @@ impl Render for ComponentPreview {
.px_2()
.bg(cx.theme().colors().editor_background)
.child(
uniform_list(
cx.entity().clone(),
"component-nav",
self.components.len(),
move |this, range, _window, cx| {
range
.map(|ix| this.render_sidebar_entry(ix, ix == this.selected_index, cx))
.collect()
},
)
.track_scroll(self.nav_scroll_handle.clone())
.pt_4()
.w(px(240.))
.h_full()
.flex_grow(),
v_flex()
.h_full()
.child(
uniform_list(
cx.entity().clone(),
"component-nav",
sidebar_entries.len(),
move |this, range, _window, cx| {
range
.map(|ix| {
this.render_sidebar_entry(
ix,
&sidebar_entries[ix],
ix == this.selected_index,
cx,
)
})
.collect()
},
)
.track_scroll(self.nav_scroll_handle.clone())
.pt_4()
.w(px(240.))
.h_full()
.flex_1(),
)
.child(
div().w_full().pb_4().child(
Button::new("toast-test", "Launch Toast")
.on_click(cx.listener({
move |this, _, _window, cx| {
this.test_status_toast(cx);
cx.notify();
}
}))
.full_width(),
),
),
)
.child(
v_flex()
@@ -213,16 +451,86 @@ impl Item for ComponentPreview {
fn clone_on_split(
&self,
_workspace_id: Option<WorkspaceId>,
window: &mut Window,
_window: &mut Window,
cx: &mut Context<Self>,
) -> Option<gpui::Entity<Self>>
where
Self: Sized,
{
Some(cx.new(|cx| Self::new(window, cx)))
let language_registry = self.language_registry.clone();
let user_store = self.user_store.clone();
let weak_workspace = self.workspace.clone();
let selected_index = self.selected_index;
Some(cx.new(|cx| {
Self::new(
weak_workspace,
language_registry,
user_store,
selected_index,
cx,
)
}))
}
fn to_item_events(event: &Self::Event, mut f: impl FnMut(workspace::item::ItemEvent)) {
f(*event)
}
}
impl SerializableItem for ComponentPreview {
fn serialized_item_kind() -> &'static str {
"ComponentPreview"
}
fn deserialize(
project: Entity<Project>,
workspace: WeakEntity<Workspace>,
_workspace_id: WorkspaceId,
_item_id: ItemId,
window: &mut Window,
cx: &mut App,
) -> Task<gpui::Result<Entity<Self>>> {
let user_store = project.read(cx).user_store().clone();
let language_registry = project.read(cx).languages().clone();
window.spawn(cx, |mut cx| async move {
let user_store = user_store.clone();
let language_registry = language_registry.clone();
let weak_workspace = workspace.clone();
cx.update(|_, cx| {
Ok(cx.new(|cx| {
ComponentPreview::new(weak_workspace, language_registry, user_store, None, cx)
}))
})?
})
}
fn cleanup(
_workspace_id: WorkspaceId,
_alive_items: Vec<ItemId>,
_window: &mut Window,
_cx: &mut App,
) -> Task<gpui::Result<()>> {
Task::ready(Ok(()))
// window.spawn(cx, |_| {
// ...
// })
}
fn serialize(
&mut self,
_workspace: &mut Workspace,
_item_id: ItemId,
_closing: bool,
_window: &mut Window,
_cx: &mut Context<Self>,
) -> Option<Task<gpui::Result<()>>> {
// TODO: Serialize the active index so we can re-open to the same place
None
}
fn should_serialize(&self, _event: &Self::Event) -> bool {
false
}
}

View File

@@ -995,7 +995,7 @@ fn diagnostic_header_renderer(diagnostic: Diagnostic) -> RenderBlock {
h_flex()
.gap_1()
.child(
StyledText::new(message.clone()).with_highlights(
StyledText::new(message.clone()).with_default_highlights(
&cx.window.text_style(),
code_ranges
.iter()

View File

@@ -35,6 +35,13 @@ pub struct SelectToBeginningOfLine {
pub stop_at_indent: bool,
}
#[derive(PartialEq, Clone, Deserialize, Default, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct DeleteToBeginningOfLine {
#[serde(default)]
pub(super) stop_at_indent: bool,
}
#[derive(PartialEq, Clone, Deserialize, Default, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct MovePageUp {
@@ -212,6 +219,7 @@ impl_actions!(
ComposeCompletion,
ConfirmCodeAction,
ConfirmCompletion,
DeleteToBeginningOfLine,
DeleteToNextWordEnd,
DeleteToPreviousWordStart,
ExpandExcerpts,
@@ -257,7 +265,7 @@ gpui::actions!(
ContextMenuFirst,
ContextMenuLast,
ContextMenuNext,
ContextMenuPrev,
ContextMenuPrevious,
ConvertToKebabCase,
ConvertToLowerCamelCase,
ConvertToLowerCase,
@@ -276,7 +284,6 @@ gpui::actions!(
CutToEndOfLine,
Delete,
DeleteLine,
DeleteToBeginningOfLine,
DeleteToEndOfLine,
DeleteToNextSubwordEnd,
DeleteToPreviousSubwordStart,
@@ -301,10 +308,10 @@ gpui::actions!(
GoToDefinitionSplit,
GoToDiagnostic,
GoToHunk,
GoToPreviousHunk,
GoToImplementation,
GoToImplementationSplit,
GoToPrevDiagnostic,
GoToPrevHunk,
GoToPreviousDiagnostic,
GoToTypeDefinition,
GoToTypeDefinitionSplit,
HalfPageDown,
@@ -333,7 +340,9 @@ gpui::actions!(
MoveToPreviousWordStart,
MoveToStartOfParagraph,
MoveToStartOfExcerpt,
MoveToStartOfNextExcerpt,
MoveToEndOfExcerpt,
MoveToEndOfPreviousExcerpt,
MoveUp,
Newline,
NewlineAbove,
@@ -348,6 +357,7 @@ gpui::actions!(
OpenPermalinkToLine,
OpenSelectionsInMultibuffer,
OpenUrl,
OrganizeImports,
Outdent,
AutoIndent,
PageDown,
@@ -370,7 +380,9 @@ gpui::actions!(
SelectAll,
SelectAllMatches,
SelectToStartOfExcerpt,
SelectToStartOfNextExcerpt,
SelectToEndOfExcerpt,
SelectToEndOfPreviousExcerpt,
SelectDown,
SelectEnclosingSymbol,
SelectLargerSyntaxNode,
@@ -398,9 +410,8 @@ gpui::actions!(
SplitSelectionIntoLines,
SwitchSourceHeader,
Tab,
TabPrev,
Backtab,
ToggleAutoSignatureHelp,
ToggleGitBlame,
ToggleGitBlameInline,
ToggleIndentGuides,
ToggleInlayHints,

View File

@@ -2,6 +2,7 @@ use anyhow::Context as _;
use gpui::{App, Context, Entity, Window};
use language::Language;
use url::Url;
use workspace::{OpenOptions, OpenVisible};
use crate::lsp_ext::find_specific_language_server_in_selection;
@@ -72,7 +73,7 @@ pub fn switch_source_header(
workspace
.update_in(&mut cx, |workspace, window, cx| {
workspace.open_abs_path(path, false, window, cx)
workspace.open_abs_path(path, OpenOptions { visible: Some(OpenVisible::None), ..Default::default() }, window, cx)
})
.with_context(|| {
format!(

View File

@@ -514,7 +514,7 @@ impl CompletionsMenu {
);
let completion_label = StyledText::new(completion.label.text.clone())
.with_highlights(&style.text, highlights);
.with_default_highlights(&style.text, highlights);
let documentation_label = if let Some(
CompletionDocumentation::SingleLine(text),
) = documentation

View File

@@ -1124,6 +1124,11 @@ impl DisplaySnapshot {
self.block_snapshot.is_block_line(BlockRow(display_row.0))
}
pub fn is_folded_buffer_header(&self, display_row: DisplayRow) -> bool {
self.block_snapshot
.is_folded_buffer_header(BlockRow(display_row.0))
}
pub fn soft_wrap_indent(&self, display_row: DisplayRow) -> Option<u32> {
let wrap_row = self
.block_snapshot

View File

@@ -1618,6 +1618,15 @@ impl BlockSnapshot {
cursor.item().map_or(false, |t| t.block.is_some())
}
pub(super) fn is_folded_buffer_header(&self, row: BlockRow) -> bool {
let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>(&());
cursor.seek(&row, Bias::Right, &());
let Some(transform) = cursor.item() else {
return false;
};
matches!(transform.block, Some(Block::FoldedBuffer { .. }))
}
pub(super) fn is_line_replaced(&self, row: MultiBufferRow) -> bool {
let wrap_point = self
.wrap_snapshot

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ use crate::{
},
JoinLines,
};
use buffer_diff::{BufferDiff, DiffHunkStatus, DiffHunkStatusKind};
use buffer_diff::{BufferDiff, DiffHunkSecondaryStatus, DiffHunkStatus, DiffHunkStatusKind};
use futures::StreamExt;
use gpui::{
div, BackgroundExecutor, SemanticVersion, TestAppContext, UpdateGlobal, VisualTestContext,
@@ -1514,6 +1514,10 @@ fn test_beginning_end_of_line(cx: &mut TestAppContext) {
stop_at_indent: true,
};
let delete_to_beg = DeleteToBeginningOfLine {
stop_at_indent: false,
};
let move_to_end = MoveToEndOfLine {
stop_at_soft_wraps: true,
};
@@ -1672,7 +1676,7 @@ fn test_beginning_end_of_line(cx: &mut TestAppContext) {
});
_ = editor.update(cx, |editor, window, cx| {
editor.delete_to_beginning_of_line(&DeleteToBeginningOfLine, window, cx);
editor.delete_to_beginning_of_line(&delete_to_beg, window, cx);
assert_eq!(editor.display_text(cx), "\n");
assert_eq!(
editor.selections.display_ranges(cx),
@@ -1778,6 +1782,107 @@ fn test_beginning_end_of_line_ignore_soft_wrap(cx: &mut TestAppContext) {
});
}
#[gpui::test]
fn test_beginning_of_line_stop_at_indent(cx: &mut TestAppContext) {
init_test(cx, |_| {});
let move_to_beg = MoveToBeginningOfLine {
stop_at_soft_wraps: true,
stop_at_indent: true,
};
let select_to_beg = SelectToBeginningOfLine {
stop_at_soft_wraps: true,
stop_at_indent: true,
};
let delete_to_beg = DeleteToBeginningOfLine {
stop_at_indent: true,
};
let move_to_end = MoveToEndOfLine {
stop_at_soft_wraps: false,
};
let editor = cx.add_window(|window, cx| {
let buffer = MultiBuffer::build_simple("abc\n def", cx);
build_editor(buffer, window, cx)
});
_ = editor.update(cx, |editor, window, cx| {
editor.change_selections(None, window, cx, |s| {
s.select_display_ranges([
DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 1),
DisplayPoint::new(DisplayRow(1), 4)..DisplayPoint::new(DisplayRow(1), 4),
]);
});
// Moving to the beginning of the line should put the first cursor at the beginning of the line,
// and the second cursor at the first non-whitespace character in the line.
editor.move_to_beginning_of_line(&move_to_beg, window, cx);
assert_eq!(
editor.selections.display_ranges(cx),
&[
DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0),
DisplayPoint::new(DisplayRow(1), 2)..DisplayPoint::new(DisplayRow(1), 2),
]
);
// Moving to the beginning of the line again should be a no-op for the first cursor,
// and should move the second cursor to the beginning of the line.
editor.move_to_beginning_of_line(&move_to_beg, window, cx);
assert_eq!(
editor.selections.display_ranges(cx),
&[
DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0),
DisplayPoint::new(DisplayRow(1), 0)..DisplayPoint::new(DisplayRow(1), 0),
]
);
// Moving to the beginning of the line again should still be a no-op for the first cursor,
// and should move the second cursor back to the first non-whitespace character in the line.
editor.move_to_beginning_of_line(&move_to_beg, window, cx);
assert_eq!(
editor.selections.display_ranges(cx),
&[
DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 0),
DisplayPoint::new(DisplayRow(1), 2)..DisplayPoint::new(DisplayRow(1), 2),
]
);
// Selecting to the beginning of the line should select to the beginning of the line for the first cursor,
// and to the first non-whitespace character in the line for the second cursor.
editor.move_to_end_of_line(&move_to_end, window, cx);
editor.move_left(&MoveLeft, window, cx);
editor.select_to_beginning_of_line(&select_to_beg, window, cx);
assert_eq!(
editor.selections.display_ranges(cx),
&[
DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 0),
DisplayPoint::new(DisplayRow(1), 4)..DisplayPoint::new(DisplayRow(1), 2),
]
);
// Selecting to the beginning of the line again should be a no-op for the first cursor,
// and should select to the beginning of the line for the second cursor.
editor.select_to_beginning_of_line(&select_to_beg, window, cx);
assert_eq!(
editor.selections.display_ranges(cx),
&[
DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 0),
DisplayPoint::new(DisplayRow(1), 4)..DisplayPoint::new(DisplayRow(1), 0),
]
);
// Deleting to the beginning of the line should delete to the beginning of the line for the first cursor,
// and should delete to the first non-whitespace character in the line for the second cursor.
editor.move_to_end_of_line(&move_to_end, window, cx);
editor.move_left(&MoveLeft, window, cx);
editor.delete_to_beginning_of_line(&delete_to_beg, window, cx);
assert_eq!(editor.text(cx), "c\n f");
});
}
#[gpui::test]
fn test_prev_next_word_boundary(cx: &mut TestAppContext) {
init_test(cx, |_| {});
@@ -2295,7 +2400,13 @@ async fn test_delete_to_beginning_of_line(cx: &mut TestAppContext) {
let mut cx = EditorTestContext::new(cx).await;
cx.set_state("one «two threeˇ» four");
cx.update_editor(|editor, window, cx| {
editor.delete_to_beginning_of_line(&DeleteToBeginningOfLine, window, cx);
editor.delete_to_beginning_of_line(
&DeleteToBeginningOfLine {
stop_at_indent: false,
},
window,
cx,
);
assert_eq!(editor.text(cx), " four");
});
}
@@ -2854,7 +2965,7 @@ async fn test_indent_outdent(cx: &mut TestAppContext) {
four
"});
cx.update_editor(|e, window, cx| e.tab_prev(&TabPrev, window, cx));
cx.update_editor(|e, window, cx| e.backtab(&Backtab, window, cx));
cx.assert_editor_state(indoc! {"
«oneˇ» «twoˇ»
three
@@ -2874,7 +2985,7 @@ async fn test_indent_outdent(cx: &mut TestAppContext) {
ˇ» four
"});
cx.update_editor(|e, window, cx| e.tab_prev(&TabPrev, window, cx));
cx.update_editor(|e, window, cx| e.backtab(&Backtab, window, cx));
cx.assert_editor_state(indoc! {"
one two
t«hree
@@ -2899,7 +3010,7 @@ async fn test_indent_outdent(cx: &mut TestAppContext) {
ˇ three
four
"});
cx.update_editor(|e, window, cx| e.tab_prev(&TabPrev, window, cx));
cx.update_editor(|e, window, cx| e.backtab(&Backtab, window, cx));
cx.assert_editor_state(indoc! {"
one two
ˇthree
@@ -2933,13 +3044,13 @@ async fn test_indent_outdent_with_hard_tabs(cx: &mut TestAppContext) {
three
four
"});
cx.update_editor(|e, window, cx| e.tab_prev(&TabPrev, window, cx));
cx.update_editor(|e, window, cx| e.backtab(&Backtab, window, cx));
cx.assert_editor_state(indoc! {"
\t«oneˇ» «twoˇ»
three
four
"});
cx.update_editor(|e, window, cx| e.tab_prev(&TabPrev, window, cx));
cx.update_editor(|e, window, cx| e.backtab(&Backtab, window, cx));
cx.assert_editor_state(indoc! {"
«oneˇ» «twoˇ»
three
@@ -2964,13 +3075,13 @@ async fn test_indent_outdent_with_hard_tabs(cx: &mut TestAppContext) {
\t\tt«hree
ˇ»four
"});
cx.update_editor(|e, window, cx| e.tab_prev(&TabPrev, window, cx));
cx.update_editor(|e, window, cx| e.backtab(&Backtab, window, cx));
cx.assert_editor_state(indoc! {"
one two
\tt«hree
ˇ»four
"});
cx.update_editor(|e, window, cx| e.tab_prev(&TabPrev, window, cx));
cx.update_editor(|e, window, cx| e.backtab(&Backtab, window, cx));
cx.assert_editor_state(indoc! {"
one two
t«hree
@@ -2983,7 +3094,7 @@ async fn test_indent_outdent_with_hard_tabs(cx: &mut TestAppContext) {
ˇthree
four
"});
cx.update_editor(|e, window, cx| e.tab_prev(&TabPrev, window, cx));
cx.update_editor(|e, window, cx| e.backtab(&Backtab, window, cx));
cx.assert_editor_state(indoc! {"
one two
ˇthree
@@ -2995,7 +3106,7 @@ async fn test_indent_outdent_with_hard_tabs(cx: &mut TestAppContext) {
\tˇthree
four
"});
cx.update_editor(|e, window, cx| e.tab_prev(&TabPrev, window, cx));
cx.update_editor(|e, window, cx| e.backtab(&Backtab, window, cx));
cx.assert_editor_state(indoc! {"
one two
ˇthree
@@ -3100,7 +3211,7 @@ fn test_indent_outdent_with_excerpts(cx: &mut TestAppContext) {
"},
cx,
);
editor.tab_prev(&TabPrev, window, cx);
editor.backtab(&Backtab, window, cx);
assert_text_with_selections(
&mut editor,
indoc! {"
@@ -4626,6 +4737,31 @@ async fn test_rewrap(cx: &mut TestAppContext) {
}
}
#[gpui::test]
async fn test_hard_wrap(cx: &mut TestAppContext) {
init_test(cx, |_| {});
let mut cx = EditorTestContext::new(cx).await;
cx.update_editor(|editor, _, cx| {
editor.set_hard_wrap(Some(14), cx);
});
cx.set_state(indoc!(
"
one two three ˇ
"
));
cx.simulate_input("four");
cx.run_until_parked();
cx.assert_editor_state(indoc!(
"
one two three
fourˇ
"
));
}
#[gpui::test]
async fn test_clipboard(cx: &mut TestAppContext) {
init_test(cx, |_| {});
@@ -4820,6 +4956,34 @@ async fn test_paste_multiline(cx: &mut TestAppContext) {
)
);
"});
// Copy an indented block, starting mid-line
cx.set_state(indoc! {"
const a: B = (
c(),
somethin«g(
e,
f
)ˇ»
);
"});
cx.update_editor(|e, window, cx| e.copy(&Copy, window, cx));
// Paste it on a line with a lower indent level
cx.update_editor(|e, window, cx| e.move_to_end(&Default::default(), window, cx));
cx.update_editor(|e, window, cx| e.paste(&Paste, window, cx));
cx.assert_editor_state(indoc! {"
const a: B = (
c(),
something(
e,
f
)
);
g(
e,
f
"});
}
#[gpui::test]
@@ -7875,6 +8039,157 @@ async fn test_document_format_manual_trigger(cx: &mut TestAppContext) {
);
}
#[gpui::test]
async fn test_organize_imports_manual_trigger(cx: &mut TestAppContext) {
init_test(cx, |settings| {
settings.defaults.formatter = Some(language_settings::SelectedFormatter::List(
FormatterList(vec![Formatter::LanguageServer { name: None }].into()),
))
});
let fs = FakeFs::new(cx.executor());
fs.insert_file(path!("/file.ts"), Default::default()).await;
let project = Project::test(fs, [path!("/").as_ref()], cx).await;
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
language_registry.add(Arc::new(Language::new(
LanguageConfig {
name: "TypeScript".into(),
matcher: LanguageMatcher {
path_suffixes: vec!["ts".to_string()],
..Default::default()
},
..LanguageConfig::default()
},
Some(tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into()),
)));
update_test_language_settings(cx, |settings| {
settings.defaults.prettier = Some(PrettierSettings {
allowed: true,
..PrettierSettings::default()
});
});
let mut fake_servers = language_registry.register_fake_lsp(
"TypeScript",
FakeLspAdapter {
capabilities: lsp::ServerCapabilities {
code_action_provider: Some(lsp::CodeActionProviderCapability::Simple(true)),
..Default::default()
},
..Default::default()
},
);
let buffer = project
.update(cx, |project, cx| {
project.open_local_buffer(path!("/file.ts"), cx)
})
.await
.unwrap();
let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
let (editor, cx) = cx.add_window_view(|window, cx| {
build_editor_with_project(project.clone(), buffer, window, cx)
});
editor.update_in(cx, |editor, window, cx| {
editor.set_text(
"import { a } from 'module';\nimport { b } from 'module';\n\nconst x = a;\n",
window,
cx,
)
});
cx.executor().start_waiting();
let fake_server = fake_servers.next().await.unwrap();
let format = editor
.update_in(cx, |editor, window, cx| {
editor.perform_code_action_kind(
project.clone(),
CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
window,
cx,
)
})
.unwrap();
fake_server
.handle_request::<lsp::request::CodeActionRequest, _, _>(move |params, _| async move {
assert_eq!(
params.text_document.uri,
lsp::Url::from_file_path(path!("/file.ts")).unwrap()
);
Ok(Some(vec![lsp::CodeActionOrCommand::CodeAction(
lsp::CodeAction {
title: "Organize Imports".to_string(),
kind: Some(lsp::CodeActionKind::SOURCE_ORGANIZE_IMPORTS),
edit: Some(lsp::WorkspaceEdit {
changes: Some(
[(
params.text_document.uri.clone(),
vec![lsp::TextEdit::new(
lsp::Range::new(
lsp::Position::new(1, 0),
lsp::Position::new(2, 0),
),
"".to_string(),
)],
)]
.into_iter()
.collect(),
),
..Default::default()
}),
..Default::default()
},
)]))
})
.next()
.await;
cx.executor().start_waiting();
format.await;
assert_eq!(
editor.update(cx, |editor, cx| editor.text(cx)),
"import { a } from 'module';\n\nconst x = a;\n"
);
editor.update_in(cx, |editor, window, cx| {
editor.set_text(
"import { a } from 'module';\nimport { b } from 'module';\n\nconst x = a;\n",
window,
cx,
)
});
// Ensure we don't lock if code action hangs.
fake_server.handle_request::<lsp::request::CodeActionRequest, _, _>(
move |params, _| async move {
assert_eq!(
params.text_document.uri,
lsp::Url::from_file_path(path!("/file.ts")).unwrap()
);
futures::future::pending::<()>().await;
unreachable!()
},
);
let format = editor
.update_in(cx, |editor, window, cx| {
editor.perform_code_action_kind(
project,
CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
window,
cx,
)
})
.unwrap();
cx.executor().advance_clock(super::CODE_ACTION_TIMEOUT);
cx.executor().start_waiting();
format.await;
assert_eq!(
editor.update(cx, |editor, cx| editor.text(cx)),
"import { a } from 'module';\nimport { b } from 'module';\n\nconst x = a;\n"
);
}
#[gpui::test]
async fn test_concurrent_format_requests(cx: &mut TestAppContext) {
init_test(cx, |_| {});
@@ -10764,7 +11079,7 @@ async fn go_to_prev_overlapping_diagnostic(executor: BackgroundExecutor, cx: &mu
executor.run_until_parked();
cx.update_editor(|editor, window, cx| {
editor.go_to_prev_diagnostic(&GoToPrevDiagnostic, window, cx);
editor.go_to_prev_diagnostic(&GoToPreviousDiagnostic, window, cx);
});
cx.assert_editor_state(indoc! {"
@@ -10773,7 +11088,7 @@ async fn go_to_prev_overlapping_diagnostic(executor: BackgroundExecutor, cx: &mu
"});
cx.update_editor(|editor, window, cx| {
editor.go_to_prev_diagnostic(&GoToPrevDiagnostic, window, cx);
editor.go_to_prev_diagnostic(&GoToPreviousDiagnostic, window, cx);
});
cx.assert_editor_state(indoc! {"
@@ -10782,7 +11097,7 @@ async fn go_to_prev_overlapping_diagnostic(executor: BackgroundExecutor, cx: &mu
"});
cx.update_editor(|editor, window, cx| {
editor.go_to_prev_diagnostic(&GoToPrevDiagnostic, window, cx);
editor.go_to_prev_diagnostic(&GoToPreviousDiagnostic, window, cx);
});
cx.assert_editor_state(indoc! {"
@@ -10791,7 +11106,7 @@ async fn go_to_prev_overlapping_diagnostic(executor: BackgroundExecutor, cx: &mu
"});
cx.update_editor(|editor, window, cx| {
editor.go_to_prev_diagnostic(&GoToPrevDiagnostic, window, cx);
editor.go_to_prev_diagnostic(&GoToPreviousDiagnostic, window, cx);
});
cx.assert_editor_state(indoc! {"
@@ -10871,7 +11186,7 @@ async fn cycle_through_same_place_diagnostics(
// Fourth diagnostic
cx.update_editor(|editor, window, cx| {
editor.go_to_prev_diagnostic(&GoToPrevDiagnostic, window, cx);
editor.go_to_prev_diagnostic(&GoToPreviousDiagnostic, window, cx);
});
cx.assert_editor_state(indoc! {"
fn func(abc def: i32) -> ˇu32 {
@@ -10880,7 +11195,7 @@ async fn cycle_through_same_place_diagnostics(
// Third diagnostic
cx.update_editor(|editor, window, cx| {
editor.go_to_prev_diagnostic(&GoToPrevDiagnostic, window, cx);
editor.go_to_prev_diagnostic(&GoToPreviousDiagnostic, window, cx);
});
cx.assert_editor_state(indoc! {"
fn func(abc ˇdef: i32) -> u32 {
@@ -10889,7 +11204,7 @@ async fn cycle_through_same_place_diagnostics(
// Second diagnostic, same place
cx.update_editor(|editor, window, cx| {
editor.go_to_prev_diagnostic(&GoToPrevDiagnostic, window, cx);
editor.go_to_prev_diagnostic(&GoToPreviousDiagnostic, window, cx);
});
cx.assert_editor_state(indoc! {"
fn func(abc ˇdef: i32) -> u32 {
@@ -10898,7 +11213,7 @@ async fn cycle_through_same_place_diagnostics(
// First diagnostic
cx.update_editor(|editor, window, cx| {
editor.go_to_prev_diagnostic(&GoToPrevDiagnostic, window, cx);
editor.go_to_prev_diagnostic(&GoToPreviousDiagnostic, window, cx);
});
cx.assert_editor_state(indoc! {"
fn func(abcˇ def: i32) -> u32 {
@@ -10907,7 +11222,7 @@ async fn cycle_through_same_place_diagnostics(
// Wrapped over, fourth diagnostic
cx.update_editor(|editor, window, cx| {
editor.go_to_prev_diagnostic(&GoToPrevDiagnostic, window, cx);
editor.go_to_prev_diagnostic(&GoToPreviousDiagnostic, window, cx);
});
cx.assert_editor_state(indoc! {"
fn func(abc def: i32) -> ˇu32 {
@@ -11173,7 +11488,7 @@ async fn test_go_to_hunk(executor: BackgroundExecutor, cx: &mut TestAppContext)
cx.update_editor(|editor, window, cx| {
//Wrap around the top of the buffer
for _ in 0..2 {
editor.go_to_prev_hunk(&GoToPrevHunk, window, cx);
editor.go_to_prev_hunk(&GoToPreviousHunk, window, cx);
}
});
@@ -11193,7 +11508,7 @@ async fn test_go_to_hunk(executor: BackgroundExecutor, cx: &mut TestAppContext)
);
cx.update_editor(|editor, window, cx| {
editor.go_to_prev_hunk(&GoToPrevHunk, window, cx);
editor.go_to_prev_hunk(&GoToPreviousHunk, window, cx);
});
cx.assert_editor_state(
@@ -11212,7 +11527,7 @@ async fn test_go_to_hunk(executor: BackgroundExecutor, cx: &mut TestAppContext)
);
cx.update_editor(|editor, window, cx| {
editor.go_to_prev_hunk(&GoToPrevHunk, window, cx);
editor.go_to_prev_hunk(&GoToPreviousHunk, window, cx);
});
cx.assert_editor_state(
@@ -11232,7 +11547,7 @@ async fn test_go_to_hunk(executor: BackgroundExecutor, cx: &mut TestAppContext)
cx.update_editor(|editor, window, cx| {
for _ in 0..2 {
editor.go_to_prev_hunk(&GoToPrevHunk, window, cx);
editor.go_to_prev_hunk(&GoToPreviousHunk, window, cx);
}
});
@@ -11967,7 +12282,7 @@ async fn test_completions_resolve_happens_once(cx: &mut TestAppContext) {
});
cx.run_until_parked();
cx.update_editor(|editor, window, cx| {
editor.context_menu_prev(&ContextMenuPrev, window, cx);
editor.context_menu_prev(&ContextMenuPrevious, window, cx);
});
cx.run_until_parked();
cx.update_editor(|editor, window, cx| {
@@ -12157,7 +12472,7 @@ async fn test_completions_default_resolve_data_handling(cx: &mut TestAppContext)
resolved_items.lock().clear();
cx.update_editor(|editor, window, cx| {
editor.context_menu_prev(&ContextMenuPrev, window, cx);
editor.context_menu_prev(&ContextMenuPrevious, window, cx);
});
cx.run_until_parked();
// Completions that have already been resolved are skipped.
@@ -12404,7 +12719,7 @@ async fn test_addition_reverts(cx: &mut TestAppContext) {
struct Row9.2;
struct Row9.3;
struct Row10;"#},
vec![DiffHunkStatus::added_none(), DiffHunkStatus::added_none()],
vec![DiffHunkStatusKind::Added, DiffHunkStatusKind::Added],
indoc! {r#"struct Row;
struct Row1;
struct Row1.1;
@@ -12442,7 +12757,7 @@ async fn test_addition_reverts(cx: &mut TestAppContext) {
struct Row8;
struct Row9;
struct Row10;"#},
vec![DiffHunkStatus::added_none(), DiffHunkStatus::added_none()],
vec![DiffHunkStatusKind::Added, DiffHunkStatusKind::Added],
indoc! {r#"struct Row;
struct Row1;
struct Row2;
@@ -12489,11 +12804,11 @@ async fn test_addition_reverts(cx: &mut TestAppContext) {
«ˇ// something on bottom»
struct Row10;"#},
vec![
DiffHunkStatus::added_none(),
DiffHunkStatus::added_none(),
DiffHunkStatus::added_none(),
DiffHunkStatus::added_none(),
DiffHunkStatus::added_none(),
DiffHunkStatusKind::Added,
DiffHunkStatusKind::Added,
DiffHunkStatusKind::Added,
DiffHunkStatusKind::Added,
DiffHunkStatusKind::Added,
],
indoc! {r#"struct Row;
ˇstruct Row1;
@@ -12541,10 +12856,7 @@ async fn test_modification_reverts(cx: &mut TestAppContext) {
struct Row99;
struct Row9;
struct Row10;"#},
vec![
DiffHunkStatus::modified_none(),
DiffHunkStatus::modified_none(),
],
vec![DiffHunkStatusKind::Modified, DiffHunkStatusKind::Modified],
indoc! {r#"struct Row;
struct Row1;
struct Row33;
@@ -12571,10 +12883,7 @@ async fn test_modification_reverts(cx: &mut TestAppContext) {
struct Row99;
struct Row9;
struct Row10;"#},
vec![
DiffHunkStatus::modified_none(),
DiffHunkStatus::modified_none(),
],
vec![DiffHunkStatusKind::Modified, DiffHunkStatusKind::Modified],
indoc! {r#"struct Row;
struct Row1;
struct Row33;
@@ -12603,12 +12912,12 @@ async fn test_modification_reverts(cx: &mut TestAppContext) {
struct Row9;
struct Row1011;ˇ"#},
vec![
DiffHunkStatus::modified_none(),
DiffHunkStatus::modified_none(),
DiffHunkStatus::modified_none(),
DiffHunkStatus::modified_none(),
DiffHunkStatus::modified_none(),
DiffHunkStatus::modified_none(),
DiffHunkStatusKind::Modified,
DiffHunkStatusKind::Modified,
DiffHunkStatusKind::Modified,
DiffHunkStatusKind::Modified,
DiffHunkStatusKind::Modified,
DiffHunkStatusKind::Modified,
],
indoc! {r#"struct Row;
ˇstruct Row1;
@@ -12686,10 +12995,7 @@ struct Row10;"#};
ˇ
struct Row8;
struct Row10;"#},
vec![
DiffHunkStatus::deleted_none(),
DiffHunkStatus::deleted_none(),
],
vec![DiffHunkStatusKind::Deleted, DiffHunkStatusKind::Deleted],
indoc! {r#"struct Row;
struct Row2;
@@ -12712,10 +13018,7 @@ struct Row10;"#};
ˇ»
struct Row8;
struct Row10;"#},
vec![
DiffHunkStatus::deleted_none(),
DiffHunkStatus::deleted_none(),
],
vec![DiffHunkStatusKind::Deleted, DiffHunkStatusKind::Deleted],
indoc! {r#"struct Row;
struct Row2;
@@ -12740,10 +13043,7 @@ struct Row10;"#};
struct Row8;ˇ
struct Row10;"#},
vec![
DiffHunkStatus::deleted_none(),
DiffHunkStatus::deleted_none(),
],
vec![DiffHunkStatusKind::Deleted, DiffHunkStatusKind::Deleted],
indoc! {r#"struct Row;
struct Row1;
ˇstruct Row2;
@@ -12768,9 +13068,9 @@ struct Row10;"#};
struct Row8;ˇ»
struct Row10;"#},
vec![
DiffHunkStatus::deleted_none(),
DiffHunkStatus::deleted_none(),
DiffHunkStatus::deleted_none(),
DiffHunkStatusKind::Deleted,
DiffHunkStatusKind::Deleted,
DiffHunkStatusKind::Deleted,
],
indoc! {r#"struct Row;
struct Row1;
@@ -16687,14 +16987,13 @@ pub(crate) fn init_test(cx: &mut TestAppContext, f: fn(&mut AllLanguageSettingsC
#[track_caller]
fn assert_hunk_revert(
not_reverted_text_with_selections: &str,
expected_hunk_statuses_before: Vec<DiffHunkStatus>,
expected_hunk_statuses_before: Vec<DiffHunkStatusKind>,
expected_reverted_text_with_selections: &str,
base_text: &str,
cx: &mut EditorLspTestContext,
) {
cx.set_state(not_reverted_text_with_selections);
cx.set_head_text(base_text);
cx.clear_index_text();
cx.executor().run_until_parked();
let actual_hunk_statuses_before = cx.update_editor(|editor, window, cx| {
@@ -16702,7 +17001,7 @@ fn assert_hunk_revert(
let reverted_hunk_statuses = snapshot
.buffer_snapshot
.diff_hunks_in_range(0..snapshot.buffer_snapshot.len())
.map(|hunk| hunk.status())
.map(|hunk| hunk.status().kind)
.collect::<Vec<_>>();
editor.git_restore(&Default::default(), window, cx);

View File

@@ -19,28 +19,29 @@ use crate::{
BlockId, ChunkReplacement, CursorShape, CustomBlockId, DisplayDiffHunk, DisplayPoint,
DisplayRow, DocumentHighlightRead, DocumentHighlightWrite, EditDisplayMode, Editor, EditorMode,
EditorSettings, EditorSnapshot, EditorStyle, ExpandExcerpts, FocusedBlock, GoToHunk,
GoToPrevHunk, GutterDimensions, HalfPageDown, HalfPageUp, HandleInput, HoveredCursor,
InlayHintRefreshReason, InlineCompletion, JumpData, LineDown, LineUp, OpenExcerpts, PageDown,
PageUp, Point, RowExt, RowRangeExt, SelectPhase, SelectedTextHighlight, Selection, SoftWrap,
StickyHeaderExcerpt, ToPoint, ToggleFold, COLUMNAR_SELECTION_MODIFIERS, CURSORS_VISIBLE_FOR,
FILE_HEADER_HEIGHT, GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED, MAX_LINE_LEN,
GoToPreviousHunk, GutterDimensions, HalfPageDown, HalfPageUp, HandleInput, HoveredCursor,
InlayHintRefreshReason, InlineCompletion, JumpData, LineDown, LineHighlight, LineUp,
OpenExcerpts, PageDown, PageUp, Point, RowExt, RowRangeExt, SelectPhase, SelectedTextHighlight,
Selection, SoftWrap, StickyHeaderExcerpt, ToPoint, ToggleFold, COLUMNAR_SELECTION_MODIFIERS,
CURSORS_VISIBLE_FOR, FILE_HEADER_HEIGHT, GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED, MAX_LINE_LEN,
MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
};
use buffer_diff::{DiffHunkSecondaryStatus, DiffHunkStatus, DiffHunkStatusKind};
use buffer_diff::{DiffHunkStatus, DiffHunkStatusKind};
use client::ParticipantIndex;
use collections::{BTreeMap, HashMap, HashSet};
use file_icons::FileIcons;
use git::{blame::BlameEntry, status::FileStatus, Oid};
use gpui::{
anchored, deferred, div, fill, linear_color_stop, linear_gradient, outline, point, px, quad,
relative, size, svg, transparent_black, Action, AnyElement, App, AvailableSpace, Axis, Bounds,
ClickEvent, ClipboardItem, ContentMask, Context, Corner, Corners, CursorStyle, DispatchPhase,
Edges, Element, ElementInputHandler, Entity, Focusable as _, FontId, GlobalElementId, Hitbox,
Hsla, InteractiveElement, IntoElement, Keystroke, Length, ModifiersChangedEvent, MouseButton,
MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad, ParentElement, Pixels, ScrollDelta,
ScrollWheelEvent, ShapedLine, SharedString, Size, StatefulInteractiveElement, Style, Styled,
Subscription, TextRun, TextStyleRefinement, Window,
relative, size, solid_background, svg, transparent_black, Action, AnyElement, App,
AvailableSpace, Axis, Bounds, ClickEvent, ClipboardItem, ContentMask, Context, Corner, Corners,
CursorStyle, DispatchPhase, Edges, Element, ElementInputHandler, Entity, Focusable as _,
FontId, GlobalElementId, Hitbox, Hsla, InteractiveElement, IntoElement, Keystroke, Length,
ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad,
ParentElement, Pixels, ScrollDelta, ScrollWheelEvent, ShapedLine, SharedString, Size,
StatefulInteractiveElement, Style, Styled, Subscription, TextRun, TextStyleRefinement, Window,
};
use inline_completion::Direction;
use itertools::Itertools;
use language::{
language_settings::{
@@ -75,7 +76,7 @@ use ui::{
POPOVER_Y_PADDING,
};
use unicode_segmentation::UnicodeSegmentation;
use util::{debug_panic, maybe, RangeExt, ResultExt};
use util::{debug_panic, RangeExt, ResultExt};
use workspace::{item::Item, notifications::NotifyTaskExt};
const INLINE_BLAME_PADDING_EM_WIDTHS: f32 = 7.;
@@ -195,7 +196,7 @@ impl EditorElement {
register_action(editor, window, Editor::backspace);
register_action(editor, window, Editor::delete);
register_action(editor, window, Editor::tab);
register_action(editor, window, Editor::tab_prev);
register_action(editor, window, Editor::backtab);
register_action(editor, window, Editor::indent);
register_action(editor, window, Editor::outdent);
register_action(editor, window, Editor::autoindent);
@@ -280,7 +281,9 @@ impl EditorElement {
register_action(editor, window, Editor::move_to_beginning);
register_action(editor, window, Editor::move_to_end);
register_action(editor, window, Editor::move_to_start_of_excerpt);
register_action(editor, window, Editor::move_to_start_of_next_excerpt);
register_action(editor, window, Editor::move_to_end_of_excerpt);
register_action(editor, window, Editor::move_to_end_of_previous_excerpt);
register_action(editor, window, Editor::select_up);
register_action(editor, window, Editor::select_down);
register_action(editor, window, Editor::select_left);
@@ -294,7 +297,9 @@ impl EditorElement {
register_action(editor, window, Editor::select_to_start_of_paragraph);
register_action(editor, window, Editor::select_to_end_of_paragraph);
register_action(editor, window, Editor::select_to_start_of_excerpt);
register_action(editor, window, Editor::select_to_start_of_next_excerpt);
register_action(editor, window, Editor::select_to_end_of_excerpt);
register_action(editor, window, Editor::select_to_end_of_previous_excerpt);
register_action(editor, window, Editor::select_to_beginning);
register_action(editor, window, Editor::select_to_end);
register_action(editor, window, Editor::select_all);
@@ -429,6 +434,13 @@ impl EditorElement {
cx.propagate();
}
});
register_action(editor, window, |editor, action, window, cx| {
if let Some(task) = editor.organize_imports(action, window, cx) {
task.detach_and_notify_err(window, cx);
} else {
cx.propagate();
}
});
register_action(editor, window, Editor::restart_language_server);
register_action(editor, window, Editor::show_character_palette);
register_action(editor, window, |editor, action, window, cx| {
@@ -1682,7 +1694,7 @@ impl EditorElement {
let pos_y = content_origin.y
+ line_height * (row.0 as f32 - scroll_pixel_position.y / line_height);
let window_ix = row.minus(start_row) as usize;
let window_ix = row.0.saturating_sub(start_row.0) as usize;
let pos_x = {
let crease_trailer_layout = &crease_trailers[window_ix];
let line_layout = &line_layouts[window_ix];
@@ -2009,7 +2021,7 @@ impl EditorElement {
scroll_pixel_position: gpui::Point<Pixels>,
gutter_dimensions: &GutterDimensions,
gutter_hitbox: &Hitbox,
rows_with_hunk_bounds: &HashMap<DisplayRow, Bounds<Pixels>>,
display_hunks: &[(DisplayDiffHunk, Option<Hitbox>)],
snapshot: &EditorSnapshot,
window: &mut Window,
cx: &mut App,
@@ -2085,7 +2097,7 @@ impl EditorElement {
gutter_dimensions,
scroll_pixel_position,
gutter_hitbox,
rows_with_hunk_bounds,
display_hunks,
window,
cx,
);
@@ -2103,7 +2115,7 @@ impl EditorElement {
scroll_pixel_position: gpui::Point<Pixels>,
gutter_dimensions: &GutterDimensions,
gutter_hitbox: &Hitbox,
rows_with_hunk_bounds: &HashMap<DisplayRow, Bounds<Pixels>>,
display_hunks: &[(DisplayDiffHunk, Option<Hitbox>)],
window: &mut Window,
cx: &mut App,
) -> Option<AnyElement> {
@@ -2128,7 +2140,7 @@ impl EditorElement {
gutter_dimensions,
scroll_pixel_position,
gutter_hitbox,
rows_with_hunk_bounds,
display_hunks,
window,
cx,
);
@@ -2667,24 +2679,21 @@ impl EditorElement {
window: &mut Window,
cx: &mut App,
) -> Div {
let file_status = maybe!({
let project = self.editor.read(cx).project.as_ref()?.read(cx);
let (repo, path) =
project.repository_and_path_for_buffer_id(for_excerpt.buffer_id, cx)?;
let status = repo.read(cx).repository_entry.status_for_path(&path)?;
Some(status.status)
})
.filter(|_| {
self.editor
.read(cx)
.buffer
.read(cx)
.all_diff_hunks_expanded()
});
let include_root = self
.editor
let editor = self.editor.read(cx);
let file_status = editor
.buffer
.read(cx)
.all_diff_hunks_expanded()
.then(|| {
editor
.project
.as_ref()?
.read(cx)
.status_for_buffer_id(for_excerpt.buffer_id, cx)
})
.flatten();
let include_root = editor
.project
.as_ref()
.map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
@@ -2696,7 +2705,7 @@ impl EditorElement {
let parent_path = path.as_ref().and_then(|path| {
Some(path.parent()?.to_string_lossy().to_string() + std::path::MAIN_SEPARATOR_STR)
});
let focus_handle = self.editor.focus_handle(cx);
let focus_handle = editor.focus_handle(cx);
let colors = cx.theme().colors();
div()
@@ -2715,7 +2724,10 @@ impl EditorElement {
.shadow_md()
.border_1()
.map(|div| {
let border_color = if is_selected && is_folded {
let border_color = if is_selected
&& is_folded
&& focus_handle.contains_focused(window, cx)
{
colors.border_focused
} else {
colors.border
@@ -2766,8 +2778,7 @@ impl EditorElement {
)
})
.children(
self.editor
.read(cx)
editor
.addons
.values()
.filter_map(|addon| {
@@ -3940,6 +3951,7 @@ impl EditorElement {
display_row_range,
multi_buffer_range,
status,
is_created_file,
..
} = &hunk
{
@@ -3971,6 +3983,7 @@ impl EditorElement {
display_row_range.start.0,
status,
multi_buffer_range.clone(),
*is_created_file,
line_height,
&editor,
cx,
@@ -4122,46 +4135,74 @@ impl EditorElement {
}
}
let mut paint_highlight =
|highlight_row_start: DisplayRow, highlight_row_end: DisplayRow, color| {
let origin = point(
layout.hitbox.origin.x,
layout.hitbox.origin.y
+ (highlight_row_start.as_f32() - scroll_top)
* layout.position_map.line_height,
);
let size = size(
layout.hitbox.size.width,
layout.position_map.line_height
* highlight_row_end.next_row().minus(highlight_row_start) as f32,
);
window.paint_quad(fill(Bounds { origin, size }, color));
};
let mut paint_highlight = |highlight_row_start: DisplayRow,
highlight_row_end: DisplayRow,
highlight: crate::LineHighlight,
edges| {
let origin = point(
layout.hitbox.origin.x,
layout.hitbox.origin.y
+ (highlight_row_start.as_f32() - scroll_top)
* layout.position_map.line_height,
);
let size = size(
layout.hitbox.size.width,
layout.position_map.line_height
* highlight_row_end.next_row().minus(highlight_row_start) as f32,
);
let mut quad = fill(Bounds { origin, size }, highlight.background);
if let Some(border_color) = highlight.border {
quad.border_color = border_color;
quad.border_widths = edges
}
window.paint_quad(quad);
};
let mut current_paint: Option<(gpui::Background, Range<DisplayRow>)> = None;
let mut current_paint: Option<(LineHighlight, Range<DisplayRow>, Edges<Pixels>)> =
None;
for (&new_row, &new_background) in &layout.highlighted_rows {
match &mut current_paint {
Some((current_background, current_range)) => {
Some((current_background, current_range, mut edges)) => {
let current_background = *current_background;
let new_range_started = current_background != new_background
|| current_range.end.next_row() != new_row;
if new_range_started {
if current_range.end.next_row() == new_row {
edges.bottom = px(0.);
};
paint_highlight(
current_range.start,
current_range.end,
current_background,
edges,
);
current_paint = Some((new_background, new_row..new_row));
let edges = Edges {
top: if current_range.end.next_row() != new_row {
px(1.)
} else {
px(0.)
},
bottom: px(1.),
..Default::default()
};
current_paint = Some((new_background, new_row..new_row, edges));
continue;
} else {
current_range.end = current_range.end.next_row();
}
}
None => current_paint = Some((new_background, new_row..new_row)),
None => {
let edges = Edges {
top: px(1.),
bottom: px(1.),
..Default::default()
};
current_paint = Some((new_background, new_row..new_row, edges))
}
};
}
if let Some((color, range)) = current_paint {
paint_highlight(range.start, range.end, color);
if let Some((color, range, edges)) = current_paint {
paint_highlight(range.start, range.end, color, edges);
}
let scroll_left =
@@ -4336,7 +4377,7 @@ impl EditorElement {
}
}
fn paint_diff_hunks(layout: &mut EditorLayout, window: &mut Window, cx: &mut App) {
fn paint_gutter_diff_hunks(layout: &mut EditorLayout, window: &mut Window, cx: &mut App) {
if layout.display_hunks.is_empty() {
return;
}
@@ -4356,7 +4397,7 @@ impl EditorElement {
hunk_bounds,
cx.theme().colors().version_control_modified,
Corners::all(px(0.)),
DiffHunkSecondaryStatus::None,
DiffHunkStatus::modified_none(),
))
}
DisplayDiffHunk::Unfolded {
@@ -4368,19 +4409,19 @@ impl EditorElement {
hunk_hitbox.bounds,
cx.theme().colors().version_control_added,
Corners::all(px(0.)),
status.secondary,
*status,
),
DiffHunkStatusKind::Modified => (
hunk_hitbox.bounds,
cx.theme().colors().version_control_modified,
Corners::all(px(0.)),
status.secondary,
*status,
),
DiffHunkStatusKind::Deleted if !display_row_range.is_empty() => (
hunk_hitbox.bounds,
cx.theme().colors().version_control_deleted,
Corners::all(px(0.)),
status.secondary,
*status,
),
DiffHunkStatusKind::Deleted => (
Bounds::new(
@@ -4392,23 +4433,24 @@ impl EditorElement {
),
cx.theme().colors().version_control_deleted,
Corners::all(1. * line_height),
status.secondary,
*status,
),
}),
};
if let Some((hunk_bounds, background_color, corner_radii, secondary_status)) =
hunk_to_paint
{
let background_color = if secondary_status != DiffHunkSecondaryStatus::None {
background_color.opacity(0.3)
} else {
background_color.opacity(1.0)
};
if let Some((hunk_bounds, background_color, corner_radii, _)) = hunk_to_paint {
// Flatten the background color with the editor color to prevent
// elements below transparent hunks from showing through
let flattened_background_color = cx
.theme()
.colors()
.editor_background
.blend(background_color);
window.paint_quad(quad(
hunk_bounds,
corner_radii,
background_color,
flattened_background_color,
Edges::default(),
transparent_black(),
));
@@ -4536,7 +4578,7 @@ impl EditorElement {
)
});
if show_git_gutter {
Self::paint_diff_hunks(layout, window, cx)
Self::paint_gutter_diff_hunks(layout, window, cx)
}
let highlight_width = 0.275 * layout.position_map.line_height;
@@ -4674,7 +4716,7 @@ impl EditorElement {
.read(cx)
.buffer
.read(cx)
.settings_at(0, cx)
.language_settings(cx)
.show_whitespaces;
for (ix, line_with_invisibles) in layout.position_map.line_layouts.iter().enumerate() {
@@ -5095,9 +5137,15 @@ impl EditorElement {
end_display_row.0 -= 1;
}
let color = match &hunk.status().kind {
DiffHunkStatusKind::Added => theme.status().created,
DiffHunkStatusKind::Modified => theme.status().modified,
DiffHunkStatusKind::Deleted => theme.status().deleted,
DiffHunkStatusKind::Added => {
theme.colors().version_control_added
}
DiffHunkStatusKind::Modified => {
theme.colors().version_control_modified
}
DiffHunkStatusKind::Deleted => {
theme.colors().version_control_deleted
}
};
ColoredRange {
start: start_display_row,
@@ -5661,7 +5709,7 @@ fn prepaint_gutter_button(
gutter_dimensions: &GutterDimensions,
scroll_pixel_position: gpui::Point<Pixels>,
gutter_hitbox: &Hitbox,
rows_with_hunk_bounds: &HashMap<DisplayRow, Bounds<Pixels>>,
display_hunks: &[(DisplayDiffHunk, Option<Hitbox>)],
window: &mut Window,
cx: &mut App,
) -> AnyElement {
@@ -5673,9 +5721,23 @@ fn prepaint_gutter_button(
let indicator_size = button.layout_as_root(available_space, window, cx);
let blame_width = gutter_dimensions.git_blame_entries_width;
let gutter_width = rows_with_hunk_bounds
.get(&row)
.map(|bounds| bounds.size.width);
let gutter_width = display_hunks
.binary_search_by(|(hunk, _)| match hunk {
DisplayDiffHunk::Folded { display_row } => display_row.cmp(&row),
DisplayDiffHunk::Unfolded {
display_row_range, ..
} => {
if display_row_range.end <= row {
Ordering::Less
} else if display_row_range.start > row {
Ordering::Greater
} else {
Ordering::Equal
}
}
})
.ok()
.and_then(|ix| Some(display_hunks[ix].1.as_ref()?.size.width));
let left_offset = blame_width.max(gutter_width).unwrap_or_default();
let mut x = left_offset;
@@ -6693,14 +6755,13 @@ impl Element for EditorElement {
.editor
.update(cx, |editor, cx| editor.highlighted_display_rows(window, cx));
let is_light = cx.theme().appearance().is_light();
for (ix, row_info) in row_infos.iter().enumerate() {
let Some(diff_status) = row_info.diff_status else {
continue;
};
let staged_opacity = 0.10;
let unstaged_opacity = 0.04;
let background_color = match diff_status.kind {
DiffHunkStatusKind::Added => cx.theme().colors().version_control_added,
DiffHunkStatusKind::Deleted => {
@@ -6711,16 +6772,36 @@ impl Element for EditorElement {
continue;
}
};
let background_color =
if diff_status.secondary == DiffHunkSecondaryStatus::None {
background_color.opacity(staged_opacity)
let unstaged = diff_status.has_secondary_hunk();
let hunk_opacity = if is_light { 0.16 } else { 0.12 };
let staged_highlight = LineHighlight {
background: (background_color.opacity(if is_light {
0.08
} else {
background_color.opacity(unstaged_opacity)
};
0.06
}))
.into(),
border: Some(if is_light {
background_color.opacity(0.48)
} else {
background_color.opacity(0.36)
}),
};
let unstaged_highlight =
solid_background(background_color.opacity(hunk_opacity)).into();
let background = if unstaged {
unstaged_highlight
} else {
staged_highlight
};
highlighted_rows
.entry(start_row + DisplayRow(ix as u32))
.or_insert(background_color.into());
.or_insert(background);
}
let highlighted_ranges = self.editor.read(cx).background_highlights_in_range(
@@ -7170,27 +7251,6 @@ impl Element for EditorElement {
let gutter_settings = EditorSettings::get_global(cx).gutter;
let rows_with_hunk_bounds = display_hunks
.iter()
.filter_map(|(hunk, hitbox)| Some((hunk, hitbox.as_ref()?.bounds)))
.fold(
HashMap::default(),
|mut rows_with_hunk_bounds, (hunk, bounds)| {
match hunk {
DisplayDiffHunk::Folded { display_row } => {
rows_with_hunk_bounds.insert(*display_row, bounds);
}
DisplayDiffHunk::Unfolded {
display_row_range, ..
} => {
for display_row in display_row_range.iter_rows() {
rows_with_hunk_bounds.insert(display_row, bounds);
}
}
}
rows_with_hunk_bounds
},
);
let mut code_actions_indicator = None;
if let Some(newest_selection_head) = newest_selection_head {
let newest_selection_point =
@@ -7240,7 +7300,7 @@ impl Element for EditorElement {
scroll_pixel_position,
&gutter_dimensions,
&gutter_hitbox,
&rows_with_hunk_bounds,
&display_hunks,
window,
cx,
);
@@ -7268,7 +7328,7 @@ impl Element for EditorElement {
scroll_pixel_position,
&gutter_dimensions,
&gutter_hitbox,
&rows_with_hunk_bounds,
&display_hunks,
&snapshot,
window,
cx,
@@ -7585,7 +7645,7 @@ pub struct EditorLayout {
indent_guides: Option<Vec<IndentGuideLayout>>,
visible_display_row_range: Range<DisplayRow>,
active_rows: BTreeMap<DisplayRow, bool>,
highlighted_rows: BTreeMap<DisplayRow, gpui::Background>,
highlighted_rows: BTreeMap<DisplayRow, LineHighlight>,
line_elements: SmallVec<[AnyElement; 1]>,
line_numbers: Arc<HashMap<MultiBufferRow, LineNumberLayout>>,
display_hunks: Vec<(DisplayDiffHunk, Option<Hitbox>)>,
@@ -8748,6 +8808,7 @@ fn diff_hunk_controls(
row: u32,
status: &DiffHunkStatus,
hunk_range: Range<Anchor>,
is_created_file: bool,
line_height: Pixels,
editor: &Entity<Editor>,
cx: &mut App,
@@ -8756,75 +8817,73 @@ fn diff_hunk_controls(
.h(line_height)
.mr_1()
.gap_1()
.px_1()
.px_0p5()
.pb_1()
.border_x_1()
.border_b_1()
.border_color(cx.theme().colors().border_variant)
.rounded_b_lg()
.bg(cx.theme().colors().editor_background)
.gap_1()
.when(status.secondary == DiffHunkSecondaryStatus::None, |el| {
el.child(
Button::new("unstage", "Unstage")
.tooltip({
let focus_handle = editor.focus_handle(cx);
move |window, cx| {
Tooltip::for_action_in(
"Unstage Hunk",
&::git::ToggleStaged,
&focus_handle,
window,
.occlude()
.shadow_md()
.child(if status.has_secondary_hunk() {
Button::new(("stage", row as u64), "Stage")
.alpha(if status.is_pending() { 0.66 } else { 1.0 })
.tooltip({
let focus_handle = editor.focus_handle(cx);
move |window, cx| {
Tooltip::for_action_in(
"Stage Hunk",
&::git::ToggleStaged,
&focus_handle,
window,
cx,
)
}
})
.on_click({
let editor = editor.clone();
move |_event, _window, cx| {
editor.update(cx, |editor, cx| {
editor.stage_or_unstage_diff_hunks(
true,
vec![hunk_range.start..hunk_range.start],
cx,
)
}
})
.on_click({
let editor = editor.clone();
move |_event, window, cx| {
editor.update(cx, |editor, cx| {
editor.stage_or_unstage_diff_hunks(
false,
&[hunk_range.start..hunk_range.start],
window,
cx,
);
});
}
}),
)
})
.when(status.secondary != DiffHunkSecondaryStatus::None, |el| {
el.child(
Button::new("stage", "Stage")
.tooltip({
let focus_handle = editor.focus_handle(cx);
move |window, cx| {
Tooltip::for_action_in(
"Stage Hunk",
&::git::ToggleStaged,
&focus_handle,
window,
);
});
}
})
} else {
Button::new(("unstage", row as u64), "Unstage")
.alpha(if status.is_pending() { 0.66 } else { 1.0 })
.tooltip({
let focus_handle = editor.focus_handle(cx);
move |window, cx| {
Tooltip::for_action_in(
"Unstage Hunk",
&::git::ToggleStaged,
&focus_handle,
window,
cx,
)
}
})
.on_click({
let editor = editor.clone();
move |_event, _window, cx| {
editor.update(cx, |editor, cx| {
editor.stage_or_unstage_diff_hunks(
false,
vec![hunk_range.start..hunk_range.start],
cx,
)
}
})
.on_click({
let editor = editor.clone();
move |_event, window, cx| {
editor.update(cx, |editor, cx| {
editor.stage_or_unstage_diff_hunks(
true,
&[hunk_range.start..hunk_range.start],
window,
cx,
);
});
}
}),
)
);
});
}
})
})
.child(
Button::new("discard", "Restore")
Button::new("restore", "Restore")
.tooltip({
let focus_handle = editor.focus_handle(cx);
move |window, cx| {
@@ -8846,7 +8905,8 @@ fn diff_hunk_controls(
editor.restore_hunks_in_ranges(vec![point..point], window, cx);
});
}
}),
})
.disabled(is_created_file),
)
.when(
!editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
@@ -8875,8 +8935,13 @@ fn diff_hunk_controls(
let snapshot = editor.snapshot(window, cx);
let position =
hunk_range.end.to_point(&snapshot.buffer_snapshot);
editor
.go_to_hunk_after_position(&snapshot, position, window, cx);
editor.go_to_hunk_before_or_after_position(
&snapshot,
position,
Direction::Next,
window,
cx,
);
editor.expand_selected_diff_hunks(cx);
});
}
@@ -8892,7 +8957,7 @@ fn diff_hunk_controls(
move |window, cx| {
Tooltip::for_action_in(
"Previous Hunk",
&GoToPrevHunk,
&GoToPreviousHunk,
&focus_handle,
window,
cx,
@@ -8906,7 +8971,13 @@ fn diff_hunk_controls(
let snapshot = editor.snapshot(window, cx);
let point =
hunk_range.start.to_point(&snapshot.buffer_snapshot);
editor.go_to_hunk_before_position(&snapshot, point, window, cx);
editor.go_to_hunk_before_or_after_position(
&snapshot,
point,
Direction::Prev,
window,
cx,
);
editor.expand_selected_diff_hunks(cx);
});
}

View File

@@ -195,9 +195,12 @@ impl GitBlame {
) -> impl 'a + Iterator<Item = Option<BlameEntry>> {
self.sync(cx);
let buffer_id = self.buffer_snapshot.remote_id();
let mut cursor = self.entries.cursor::<u32>(&());
rows.into_iter().map(move |info| {
let row = info.buffer_row?;
let row = info
.buffer_row
.filter(|_| info.buffer_id == Some(buffer_id))?;
cursor.seek_forward(&row, Bias::Right, &());
cursor.item()?.blame.clone()
})
@@ -367,7 +370,6 @@ impl GitBlame {
async move {
let Some(Blame {
entries,
permalinks,
messages,
remote_url,
}) = blame.await?
@@ -376,13 +378,8 @@ impl GitBlame {
};
let entries = build_blame_entry_sum_tree(entries, snapshot.max_point().row);
let commit_details = parse_commit_messages(
messages,
remote_url,
&permalinks,
provider_registry,
)
.await;
let commit_details =
parse_commit_messages(messages, remote_url, provider_registry).await;
anyhow::Ok(Some((entries, commit_details)))
}
@@ -474,7 +471,6 @@ fn build_blame_entry_sum_tree(entries: Vec<BlameEntry>, max_row: u32) -> SumTree
async fn parse_commit_messages(
messages: impl IntoIterator<Item = (Oid, String)>,
remote_url: Option<String>,
deprecated_permalinks: &HashMap<Oid, Url>,
provider_registry: Arc<GitHostingProviderRegistry>,
) -> HashMap<Oid, ParsedCommitMessage> {
let mut commit_details = HashMap::default();
@@ -492,11 +488,7 @@ async fn parse_commit_messages(
},
))
} else {
// DEPRECATED (18 Apr 24): Sending permalinks over the wire is deprecated. Clients
// now do the parsing. This is here for backwards compatibility, so that
// when an old peer sends a client no `parsed_remote_url` but `deprecated_permalinks`,
// we fall back to that.
deprecated_permalinks.get(&oid).cloned()
None
};
let remote = parsed_remote_url
@@ -535,6 +527,7 @@ mod tests {
use serde_json::json;
use settings::SettingsStore;
use std::{cmp, env, ops::Range, path::Path};
use text::BufferId;
use unindent::Unindent as _;
use util::{path, RandomCharIter};
@@ -552,16 +545,18 @@ mod tests {
#[track_caller]
fn assert_blame_rows(
blame: &mut GitBlame,
buffer_id: BufferId,
rows: Range<u32>,
expected: Vec<Option<BlameEntry>>,
cx: &mut Context<GitBlame>,
) {
assert_eq!(
pretty_assertions::assert_eq!(
blame
.blame_for_rows(
&rows
.map(|row| RowInfo {
buffer_row: Some(row),
buffer_id: Some(buffer_id),
..Default::default()
})
.collect::<Vec<_>>(),
@@ -694,6 +689,7 @@ mod tests {
})
.await
.unwrap();
let buffer_id = buffer.update(cx, |buffer, _| buffer.remote_id());
let git_blame = cx.new(|cx| GitBlame::new(buffer.clone(), project, false, true, cx));
@@ -701,12 +697,13 @@ mod tests {
git_blame.update(cx, |blame, cx| {
// All lines
assert_eq!(
pretty_assertions::assert_eq!(
blame
.blame_for_rows(
&(0..8)
.map(|buffer_row| RowInfo {
buffer_row: Some(buffer_row),
buffer_id: Some(buffer_id),
..Default::default()
})
.collect::<Vec<_>>(),
@@ -725,12 +722,13 @@ mod tests {
]
);
// Subset of lines
assert_eq!(
pretty_assertions::assert_eq!(
blame
.blame_for_rows(
&(1..4)
.map(|buffer_row| RowInfo {
buffer_row: Some(buffer_row),
buffer_id: Some(buffer_id),
..Default::default()
})
.collect::<Vec<_>>(),
@@ -744,12 +742,13 @@ mod tests {
]
);
// Subset of lines, with some not displayed
assert_eq!(
pretty_assertions::assert_eq!(
blame
.blame_for_rows(
&[
RowInfo {
buffer_row: Some(1),
buffer_id: Some(buffer_id),
..Default::default()
},
Default::default(),
@@ -800,6 +799,7 @@ mod tests {
})
.await
.unwrap();
let buffer_id = buffer.update(cx, |buffer, _| buffer.remote_id());
let git_blame = cx.new(|cx| GitBlame::new(buffer.clone(), project, false, true, cx));
@@ -810,6 +810,7 @@ mod tests {
// lines.
assert_blame_rows(
blame,
buffer_id,
0..4,
vec![
Some(blame_entry("1b1b1b", 0..4)),
@@ -828,6 +829,7 @@ mod tests {
git_blame.update(cx, |blame, cx| {
assert_blame_rows(
blame,
buffer_id,
0..2,
vec![None, Some(blame_entry("1b1b1b", 0..4))],
cx,
@@ -840,6 +842,7 @@ mod tests {
git_blame.update(cx, |blame, cx| {
assert_blame_rows(
blame,
buffer_id,
1..4,
vec![
None,
@@ -852,7 +855,13 @@ mod tests {
// Before we insert a newline at the end, sanity check:
git_blame.update(cx, |blame, cx| {
assert_blame_rows(blame, 3..4, vec![Some(blame_entry("1b1b1b", 0..4))], cx);
assert_blame_rows(
blame,
buffer_id,
3..4,
vec![Some(blame_entry("1b1b1b", 0..4))],
cx,
);
});
// Insert a newline at the end
buffer.update(cx, |buffer, cx| {
@@ -862,6 +871,7 @@ mod tests {
git_blame.update(cx, |blame, cx| {
assert_blame_rows(
blame,
buffer_id,
3..5,
vec![Some(blame_entry("1b1b1b", 0..4)), None],
cx,
@@ -870,7 +880,13 @@ mod tests {
// Before we insert a newline at the start, sanity check:
git_blame.update(cx, |blame, cx| {
assert_blame_rows(blame, 2..3, vec![Some(blame_entry("1b1b1b", 0..4))], cx);
assert_blame_rows(
blame,
buffer_id,
2..3,
vec![Some(blame_entry("1b1b1b", 0..4))],
cx,
);
});
// Usage example
@@ -882,6 +898,7 @@ mod tests {
git_blame.update(cx, |blame, cx| {
assert_blame_rows(
blame,
buffer_id,
2..4,
vec![None, Some(blame_entry("1b1b1b", 0..4))],
cx,

View File

@@ -25,7 +25,7 @@ use theme::ThemeSettings;
use ui::{prelude::*, theme_is_transparent, Scrollbar, ScrollbarState};
use url::Url;
use util::TryFutureExt;
use workspace::Workspace;
use workspace::{OpenOptions, OpenVisible, Workspace};
pub const HOVER_REQUEST_DELAY_MILLIS: u64 = 200;
pub const MIN_POPOVER_CHARACTER_WIDTH: f32 = 20.;
@@ -632,8 +632,15 @@ pub fn open_markdown_url(link: SharedString, window: &mut Window, cx: &mut App)
if uri.scheme() == "file" {
if let Some(workspace) = window.root::<Workspace>().flatten() {
workspace.update(cx, |workspace, cx| {
let task =
workspace.open_abs_path(PathBuf::from(uri.path()), false, window, cx);
let task = workspace.open_abs_path(
PathBuf::from(uri.path()),
OpenOptions {
visible: Some(OpenVisible::None),
..Default::default()
},
window,
cx,
);
cx.spawn_in(window, |_, mut cx| async move {
let item = task.await?;

View File

@@ -581,6 +581,7 @@ impl InlayHintCache {
self.version += 1;
}
self.update_tasks.clear();
self.refresh_task = Task::ready(());
self.hints.clear();
}

View File

@@ -38,10 +38,14 @@ use text::{BufferId, Selection};
use theme::{Theme, ThemeSettings};
use ui::{prelude::*, IconDecorationKind};
use util::{paths::PathExt, ResultExt, TryFutureExt};
use workspace::item::{Dedup, ItemSettings, SerializableItem, TabContentParams};
use workspace::{
item::{BreadcrumbText, FollowEvent},
searchable::SearchOptions,
OpenVisible,
};
use workspace::{
item::{Dedup, ItemSettings, SerializableItem, TabContentParams},
OpenOptions,
};
use workspace::{
item::{FollowableItem, Item, ItemEvent, ProjectItem},
@@ -1160,7 +1164,15 @@ impl SerializableItem for Editor {
}
None => {
let open_by_abs_path = workspace.update(cx, |workspace, cx| {
workspace.open_abs_path(abs_path.clone(), false, window, cx)
workspace.open_abs_path(
abs_path.clone(),
OpenOptions {
visible: Some(OpenVisible::None),
..Default::default()
},
window,
cx,
)
});
window.spawn(cx, |mut cx| async move {
let editor = open_by_abs_path?.await?.downcast::<Editor>().with_context(|| format!("Failed to downcast to Editor after opening abs path {abs_path:?}"))?;

View File

@@ -448,7 +448,9 @@ pub fn end_of_excerpt(
if start.row() > DisplayRow(0) {
*start.row_mut() -= 1;
}
map.clip_point(start, Bias::Left)
start = map.clip_point(start, Bias::Left);
*start.column_mut() = 0;
start
}
Direction::Next => {
let mut end = excerpt.end_anchor().to_display_point(&map);

View File

@@ -185,7 +185,7 @@ impl ProposedChangesEditor {
} else {
branch_buffer = location.buffer.update(cx, |buffer, cx| buffer.branch(cx));
new_diffs.push(cx.new(|cx| {
let mut diff = BufferDiff::new(branch_buffer.read(cx));
let mut diff = BufferDiff::new(&branch_buffer.read(cx).snapshot(), cx);
let _ = diff.set_base_text(
location.buffer.clone(),
branch_buffer.read(cx).text_snapshot(),

View File

@@ -310,7 +310,7 @@ impl SignatureHelpPopover {
.child(
div().px_4().pb_1().child(
StyledText::new(self.label.clone())
.with_highlights(&self.style, self.highlights.iter().cloned()),
.with_default_highlights(&self.style, self.highlights.iter().cloned()),
),
)
.into_any_element()

View File

@@ -12,7 +12,7 @@ use gpui::{
};
use itertools::Itertools;
use language::{Buffer, BufferSnapshot, LanguageRegistry};
use multi_buffer::{ExcerptRange, MultiBufferRow};
use multi_buffer::{Anchor, ExcerptRange, MultiBufferRow};
use parking_lot::RwLock;
use project::{FakeFs, Project};
use std::{
@@ -89,6 +89,16 @@ impl EditorTestContext {
Path::new("/root")
}
pub async fn for_editor_in(editor: Entity<Editor>, cx: &mut gpui::VisualTestContext) -> Self {
cx.focus(&editor);
Self {
window: cx.windows()[0],
cx: cx.clone(),
editor,
assertion_cx: AssertionContextManager::new(),
}
}
pub async fn for_editor(editor: WindowHandle<Editor>, cx: &mut gpui::TestAppContext) -> Self {
let editor_view = editor.root(cx).unwrap();
Self {
@@ -381,6 +391,85 @@ impl EditorTestContext {
assert_state_with_diff(&self.editor, &mut self.cx, &expected_diff_text);
}
#[track_caller]
pub fn assert_excerpts_with_selections(&mut self, marked_text: &str) {
let expected_excerpts = marked_text
.strip_prefix("[EXCERPT]\n")
.unwrap()
.split("[EXCERPT]\n")
.collect::<Vec<_>>();
let (multibuffer_snapshot, selections, excerpts) = self.update_editor(|editor, _, cx| {
let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
let selections = editor.selections.disjoint_anchors();
let excerpts = multibuffer_snapshot
.excerpts()
.map(|(e_id, snapshot, range)| (e_id, snapshot.clone(), range))
.collect::<Vec<_>>();
(multibuffer_snapshot, selections, excerpts)
});
assert!(
excerpts.len() == expected_excerpts.len(),
"should have {} excerpts, got {}",
expected_excerpts.len(),
excerpts.len()
);
for (ix, (excerpt_id, snapshot, range)) in excerpts.into_iter().enumerate() {
let is_folded = self
.update_editor(|editor, _, cx| editor.is_buffer_folded(snapshot.remote_id(), cx));
let (expected_text, expected_selections) =
marked_text_ranges(expected_excerpts[ix], true);
if expected_text == "[FOLDED]\n" {
assert!(is_folded, "excerpt {} should be folded", ix);
let is_selected = selections.iter().any(|s| s.head().excerpt_id == excerpt_id);
if expected_selections.len() > 0 {
assert!(
is_selected,
"excerpt {} should be selected. Got {:?}",
ix,
self.editor_state()
);
} else {
assert!(!is_selected, "excerpt {} should not be selected", ix);
}
continue;
}
assert!(!is_folded, "excerpt {} should not be folded", ix);
assert_eq!(
multibuffer_snapshot
.text_for_range(Anchor::range_in_buffer(
excerpt_id,
snapshot.remote_id(),
range.context.clone()
))
.collect::<String>(),
expected_text
);
let selections = selections
.iter()
.filter(|s| s.head().excerpt_id == excerpt_id)
.map(|s| {
let head = text::ToOffset::to_offset(&s.head().text_anchor, &snapshot)
- text::ToOffset::to_offset(&range.context.start, &snapshot);
let tail = text::ToOffset::to_offset(&s.head().text_anchor, &snapshot)
- text::ToOffset::to_offset(&range.context.start, &snapshot);
tail..head
})
.collect::<Vec<_>>();
// todo: selections that cross excerpt boundaries..
assert_eq!(
selections, expected_selections,
"excerpt {} has incorrect selections",
ix,
);
}
}
/// Make an assertion about the editor's text and the ranges and directions
/// of its selections using a string containing embedded range markers.
///
@@ -392,6 +481,17 @@ impl EditorTestContext {
self.assert_selections(expected_selections, marked_text.to_string())
}
/// Make an assertion about the editor's text and the ranges and directions
/// of its selections using a string containing embedded range markers.
///
/// See the `util::test::marked_text_ranges` function for more information.
#[track_caller]
pub fn assert_display_state(&mut self, marked_text: &str) {
let (expected_text, expected_selections) = marked_text_ranges(marked_text, true);
pretty_assertions::assert_eq!(self.display_text(), expected_text, "unexpected buffer text");
self.assert_selections(expected_selections, marked_text.to_string())
}
pub fn editor_state(&mut self) -> String {
generate_marked_text(self.buffer_text().as_str(), &self.editor_selections(), true)
}

View File

@@ -22,7 +22,6 @@ collections.workspace = true
env_logger.workspace = true
feature_flags.workspace = true
fs.workspace = true
git.workspace = true
gpui.workspace = true
http_client.workspace = true
language.workspace = true

View File

@@ -5,7 +5,6 @@ use client::{Client, UserStore};
use clock::RealSystemClock;
use collections::BTreeMap;
use feature_flags::FeatureFlagAppExt as _;
use git::GitHostingProviderRegistry;
use gpui::{AppContext as _, AsyncApp, BackgroundExecutor, Entity};
use http_client::{HttpClient, Method};
use language::LanguageRegistry;
@@ -274,8 +273,7 @@ async fn run_evaluation(
let repos_dir = Path::new(EVAL_REPOS_DIR);
let db_path = Path::new(EVAL_DB_PATH);
let api_key = std::env::var("OPENAI_API_KEY").unwrap();
let git_hosting_provider_registry = Arc::new(GitHostingProviderRegistry::new());
let fs = Arc::new(RealFs::new(git_hosting_provider_registry, None)) as Arc<dyn Fs>;
let fs = Arc::new(RealFs::new(None)) as Arc<dyn Fs>;
let clock = Arc::new(RealSystemClock);
let client = cx
.update(|cx| {

View File

@@ -339,6 +339,20 @@ async fn test_themes(
let theme_path = extension_path.join(relative_theme_path);
let theme_family = theme::read_user_theme(&theme_path, fs.clone()).await?;
log::info!("loaded theme family {}", theme_family.name);
for theme in &theme_family.themes {
if theme
.style
.colors
.deprecated_scrollbar_thumb_background
.is_some()
{
bail!(
r#"Theme "{theme_name}" is using a deprecated style property: scrollbar_thumb.background. Use `scrollbar.thumb.background` instead."#,
theme_name = theme.name
)
}
}
}
Ok(())

View File

@@ -168,11 +168,14 @@ pub(crate) fn suggest(buffer: Entity<Buffer>, window: &mut Window, cx: &mut Cont
);
workspace.show_notification(notification_id, cx, |cx| {
cx.new(move |_cx| {
MessageNotification::new(format!(
"Do you want to install the recommended '{}' extension for '{}' files?",
extension_id, file_name_or_extension
))
cx.new(move |cx| {
MessageNotification::new(
format!(
"Do you want to install the recommended '{}' extension for '{}' files?",
extension_id, file_name_or_extension
),
cx,
)
.primary_message("Yes, install extension")
.primary_icon(IconName::Check)
.primary_icon_color(Color::Success)

View File

@@ -522,7 +522,7 @@ impl ExtensionsPage {
extension.authors.join(", ")
))
.size(LabelSize::Small)
.text_ellipsis(),
.truncate(),
)
.child(Label::new("<>").size(LabelSize::Small)),
)
@@ -534,7 +534,7 @@ impl ExtensionsPage {
Label::new(description.clone())
.size(LabelSize::Small)
.color(Color::Default)
.text_ellipsis()
.truncate()
}))
.children(repository_url.map(|repository_url| {
IconButton::new(
@@ -665,7 +665,7 @@ impl ExtensionsPage {
extension.manifest.authors.join(", ")
))
.size(LabelSize::Small)
.text_ellipsis(),
.truncate(),
)
.child(
Label::new(format!(
@@ -683,7 +683,7 @@ impl ExtensionsPage {
Label::new(description.clone())
.size(LabelSize::Small)
.color(Color::Default)
.text_ellipsis()
.truncate()
}))
.child(
h_flex()

View File

@@ -80,11 +80,6 @@ impl FeatureFlag for PredictEditsNonEagerModeFeatureFlag {
}
}
pub struct GitUiFeatureFlag;
impl FeatureFlag for GitUiFeatureFlag {
const NAME: &'static str = "git-ui";
}
pub struct Remoting {}
impl FeatureFlag for Remoting {
const NAME: &'static str = "remoting";

View File

@@ -40,11 +40,11 @@ use ui::{
};
use util::{maybe, paths::PathWithPosition, post_inc, ResultExt};
use workspace::{
item::PreviewTabsSettings, notifications::NotifyResultExt, pane, ModalView, SplitDirection,
Workspace,
item::PreviewTabsSettings, notifications::NotifyResultExt, pane, ModalView, OpenOptions,
OpenVisible, SplitDirection, Workspace,
};
actions!(file_finder, [SelectPrev, ToggleMenu]);
actions!(file_finder, [SelectPrevious, ToggleMenu]);
impl ModalView for FileFinder {
fn on_before_dismiss(
@@ -199,9 +199,14 @@ impl FileFinder {
}
}
fn handle_select_prev(&mut self, _: &SelectPrev, window: &mut Window, cx: &mut Context<Self>) {
fn handle_select_prev(
&mut self,
_: &SelectPrevious,
window: &mut Window,
cx: &mut Context<Self>,
) {
self.init_modifiers = Some(window.modifiers());
window.dispatch_action(Box::new(menu::SelectPrev), cx);
window.dispatch_action(Box::new(menu::SelectPrevious), cx);
}
fn handle_toggle_menu(&mut self, _: &ToggleMenu, window: &mut Window, cx: &mut Context<Self>) {
@@ -1232,7 +1237,10 @@ impl PickerDelegate for FileFinderDelegate {
} else {
workspace.open_abs_path(
abs_path.to_path_buf(),
false,
OpenOptions {
visible: Some(OpenVisible::None),
..Default::default()
},
window,
cx,
)

View File

@@ -3,11 +3,11 @@ use std::{assert_eq, future::IntoFuture, path::Path, time::Duration};
use super::*;
use editor::Editor;
use gpui::{Entity, TestAppContext, VisualTestContext};
use menu::{Confirm, SelectNext, SelectPrev};
use menu::{Confirm, SelectNext, SelectPrevious};
use project::{RemoveOptions, FS_WATCH_LATENCY};
use serde_json::json;
use util::path;
use workspace::{AppState, ToggleFileFinder, Workspace};
use workspace::{AppState, OpenOptions, ToggleFileFinder, Workspace};
#[ctor::ctor]
fn init_logger() {
@@ -951,7 +951,10 @@ async fn test_external_files_history(cx: &mut gpui::TestAppContext) {
.update_in(cx, |workspace, window, cx| {
workspace.open_abs_path(
PathBuf::from(path!("/external-src/test/third.rs")),
false,
OpenOptions {
visible: Some(OpenVisible::None),
..Default::default()
},
window,
cx,
)
@@ -2059,7 +2062,7 @@ async fn test_switches_between_release_norelease_modes_on_backward_nav(
// Switch to navigating with other shortcuts
// Don't open file on modifiers release
cx.simulate_modifiers_change(Modifiers::control());
cx.dispatch_action(menu::SelectPrev);
cx.dispatch_action(menu::SelectPrevious);
cx.simulate_modifiers_change(Modifiers::none());
picker.update(cx, |finder, _| {
assert_eq!(finder.delegate.matches.len(), 3);
@@ -2071,7 +2074,7 @@ async fn test_switches_between_release_norelease_modes_on_backward_nav(
// Back to navigation with initial shortcut
// Open file on modifiers release
cx.simulate_modifiers_change(Modifiers::secondary_key());
cx.dispatch_action(SelectPrev); // <-- File Finder's SelectPrev, not menu's
cx.dispatch_action(SelectPrevious); // <-- File Finder's SelectPrevious, not menu's
cx.simulate_modifiers_change(Modifiers::none());
cx.read(|cx| {
let active_editor = workspace.read(cx).active_item_as::<Editor>(cx).unwrap();

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