Compare commits

..

581 Commits

Author SHA1 Message Date
Joseph T. Lyons
f6f061838d v0.179.x stable 2025-03-26 11:14:49 -04:00
gcp-cherry-pick-bot[bot]
7fe42e860f Fix strikethrough and underline in Linux (cherry-pick #27267) (#27380)
Cherry-picked Fix strikethrough and underline in Linux (#27267)

Follow up to #26827 and #24721, which introduced a bug in Linux.

|before|now|
|---|---|


|![image](https://github.com/user-attachments/assets/6471502d-bf92-4808-ad42-9e0c66569d4f)|!![image](https://github.com/user-attachments/assets/ae45510a-8bc9-4f89-90a0-7496842fecb6)|


Release Notes:

- N/A

Co-authored-by: Jason Lee <huacnlee@gmail.com>

Co-authored-by: João Marcos <marcospb19@hotmail.com>
Co-authored-by: Jason Lee <huacnlee@gmail.com>
2025-03-25 14:40:42 +02:00
gcp-cherry-pick-bot[bot]
3386e34f1a Don't assume that the excerpt can be found (cherry-pick #27395) (#27398)
Cherry-picked Don't assume that the excerpt can be found (#27395)

Release Notes:

- Fix (rare) panic in the project diff view

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-25 14:37:56 +02:00
Joseph T. Lyons
087f58206a zed 0.179.2 2025-03-21 15:50:39 -04:00
Conrad Irwin
bdd39bb012 Bump up default timeout (#27250)
Release Notes:

- Extended timeout used when connecting to remote instances
2025-03-21 15:48:42 -04:00
Nate Butler
f24086ecf8 editor: Fix regression in git label colors due to status color changes (#27272)
This PR fixes the new awkward-looking git status labels due to the
change in version control colors. We want to enable styling version
control colors distinctly from other statuses, but these colors aren't
great for labels as they are meant to be quite high contrast.

We may need to split version control colors into a primary color and a
text color if we want to improve theming this overall.

| Before | After |
|--------|-------|
| ![CleanShot 2025-03-21 at 14 12
22@2x](https://github.com/user-attachments/assets/fadb93b1-06b6-44cc-bf16-7e1279166ed0)
| ![CleanShot 2025-03-21 at 14 12
49@2x](https://github.com/user-attachments/assets/262ffc23-60b9-4cee-8a2b-9e864130912f)
|

Release Notes:

- Fixes a regression in git status colors in the project panel
2025-03-21 14:52:52 -04:00
Joseph T. Lyons
c86019ec68 Pre-fill body of email with system specs (#27210)
I think we still want to be able to easily capture system spec info from
users. They can decide if they want to include it or not.

Release Notes:

- N/A
2025-03-20 14:35:09 -04:00
Zed Bot
64892107e1 Bump to 0.179.1 for @SomeoneToIgnore 2025-03-20 17:07:39 +00:00
gcp-cherry-pick-bot[bot]
3c538f40d3 Fix code action formatters creating separate transaction (cherry-pick #26311) (#27198)
Cherry-picked Fix code action formatters creating separate transaction
(#26311)

Closes #24588
Closes #25419

Restructures `LspStore.format_local` a decent bit in order to make how
the transaction history is preserved more clear, and in doing so fix
various bugs with how the transaction history is handled during a format
request (especially when formatting in remote dev)

Release Notes:

- Fixed an issue that prevented formatting from working when working
with remote dev
- Fixed an issue when using code actions as a format step where the
edits made by the code actions would not be grouped with the other
format edits in the undo history

Co-authored-by: Ben Kunkle <ben@zed.dev>
2025-03-20 10:30:20 -05:00
Joseph T. Lyons
494cccf3fc Rework feedback modal (#27186)
After our last community sync, we came to the conclusion that feedback
being sent outside of email is difficult to reply to. Our decision was
to use the old, tried and true email system, so that we can better
respond to people asking questions.

<img width="392" alt="SCR-20250320-igub"
src="https://github.com/user-attachments/assets/f1d01771-30eb-4b6f-b031-c68ddaac5700"
/>

Release Notes:

- N/A

---------

Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
2025-03-20 10:34:22 -04:00
gcp-cherry-pick-bot[bot]
e840961f1c debugger: Ensure both debug and regular global tasks are correctly merged (cherry-pick #27184) (#27187)
Cherry-picked debugger: Ensure both debug and regular global tasks are
correctly merged (#27184)

Follow-up of https://github.com/zed-industries/zed/pull/13433
Closes https://github.com/zed-industries/zed/issues/27124
Closes https://github.com/zed-industries/zed/issues/27066

After this change, both old global task source, `tasks.json` and new,
`debug.json` started to call for the same task update method:



14920ab910/crates/project/src/task_inventory.rs (L414)

erasing previous declarations.

The PR puts this data under different paths instead and adjusts the code
around it.

Release Notes:

- Fixed custom tasks not shown

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
2025-03-20 15:42:21 +02:00
Peter Tripp
bfbbe881c3 ci: Send emails for weekly release (#27102)
Release Notes:

- N/A
2025-03-19 16:19:12 -04:00
gcp-cherry-pick-bot[bot]
e2fc17d486 theme: Add fallback colors for version_control.<variant> properties (cherry-pick #27104) (#27106)
Cherry-picked theme: Add fallback colors for `version_control.<variant>`
properties (#27104)

This PR adds fallback colors for the `version_control.<variant>` theme
properties.

This fixes the colors when themes do not provide the properties.

Related to  https://github.com/zed-industries/zed/pull/26951.

Release Notes:

- Added fallback colors for the `version_control.<variant>` theme
properties.

Co-authored-by: Marshall Bowers <git@maxdeviant.com>
2025-03-19 15:11:59 -04:00
Joseph T. Lyons
9b75c88498 Fix release notes API call with heredoc syntax (#27096)
Release Notes:

- N/A
2025-03-19 13:51:20 -04:00
Joseph T. Lyons
f2c27bdcc3 v0.179.x preview 2025-03-19 11:32:35 -04:00
Marshall Bowers
394215599a assistant2: Fix broken merge (#27081)
This PR fixes a broken merge caused by
https://github.com/zed-industries/zed/pull/26987 landing after
https://github.com/zed-industries/zed/pull/26758.

Release Notes:

- N/A
2025-03-19 15:26:19 +00:00
Richard Feldman
e8a40085de Allow tools to read unsaved buffers (#26987)
If the tool asks to read a path, we don't need to verify whether that
path exists on disk; an unsaved buffer with that path is fine.

Release Notes:

- N/A
2025-03-19 14:59:10 +00:00
Richard Feldman
6303751325 Record token usage telemetry (#26962)
<img width="1103" alt="Screenshot 2025-03-17 at 9 47 32 PM"
src="https://github.com/user-attachments/assets/947cf33d-4464-4305-8ff0-3630529d2f81"
/>


Release Notes:

- N/A
2025-03-19 10:47:46 -04:00
Antonio Scandurra
3edf930007 Revert "Start tracking edits performed by the agent" (#27077)
Reverts zed-industries/zed#27064
2025-03-19 15:33:08 +01:00
Jakub Čermák
584a70ca5e Refactor Git panel styling & status colors for consistency (#26951)
Closes #26847

Release Notes:

- Updated Git panel background to use panel_background instead of
ElevationIndex::Surface.bg(cx) for consistency with other panels.
- Removed redundant GitStatusColors struct from status.rs and refactored
to use existing theme colors.
- Adjusted Color enum mappings in color.rs to reference
version_control_* colors instead of status() for better alignment with
the theme system.
- Cleaned up unused or redundant code.
2025-03-19 10:26:36 -04:00
Smit Barmase
2230f3b09d editor: Preserve expand excerpt down button position (#27058)
When you press the "Expand Excerpt Down" button, the editor will scroll
up by the same amount to keep the button in same place. This allows you
to expand the excerpt rapidly without moving your mouse.

Before:


https://github.com/user-attachments/assets/376350ac-6f21-4ce0-a383-b2c9ca4f45bb

After:


https://github.com/user-attachments/assets/4fba4173-5f01-4220-990a-65820ac40cf5

Release Notes:

- Improved "Expand Excerpt Down" so the button stays in place, allowing
rapid expansion without moving the mouse.
2025-03-19 19:54:52 +05:30
5brian
84a8d48178 vim: Fix space not handling non-ascii characters (#27053)
Closes #26806

Changes: Clips the new point with `Bias::Right` like in
`saturating_right`

Release Notes:

- vim: Fixed `space` not handling non-ascii characters
2025-03-19 07:28:50 -06:00
Antonio Scandurra
ac5dafc6b2 Start tracking edits performed by the agent (#27064)
Release Notes:

- N/A

---------

Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
Co-authored-by: Agus Zubiaga <hi@aguz.me>
2025-03-19 13:07:25 +00:00
Piotr Osiewicz
23686aa394 debugger: Do not use Disclosure for attach button (#27068)
Closes #ISSUE

Release Notes:

- N/A
2025-03-19 14:01:33 +01:00
Danilo Leal
3874d315ec assistant2: Adjust text and padding alignment between messages (#27067)
Ensuring that text between the "you" messages align with text in the
assistant response. This also creates a nice subtle hierarchy effect
where the "you" message card is wider than the message, making it
slightly easier to tell them apart.

<img
src="https://github.com/user-attachments/assets/616c1776-ca51-454e-9d52-e480bf26c843"
width="600px" />

Release Notes:

- N/A
2025-03-19 09:43:33 -03:00
Agus Zubiaga
1d33bfde37 assistant edit tool: Replace with flexible indentation (#27039)
Sometimes the model produces SEARCH queries that don't match the
indentation of the source file exactly.

When we can't find an exact match, we'll now attempt to match the lines
while being more flexible about the leading whitespace as long as all
lines are consistently offset from the source, and extend the leading
whitespace in the REPLACE string accordingly.

Release Notes:

- N/A
2025-03-19 09:39:00 -03:00
Piotr Osiewicz
9377ef9817 feature_flags: Do not enable feature flags by default in dev builds (#27065)
Closes #ISSUE

Release Notes:

- N/A
2025-03-19 12:20:26 +00:00
Piotr Osiewicz
c3b5046347 editor: Do not use breakpoint color for run indicators (#27063)
Closes #ISSUE

Release Notes:

- N/A
2025-03-19 11:54:14 +00:00
Piotr Osiewicz
44fff08ed6 util: Include path to asset in panic message from asset_str (#27059)
Somebody on Discord ran into issues with running the debugger which goes
down to an unwrap in asset_str. Let's print a path that was accessed.

Release Notes:

- N/A
2025-03-19 11:09:51 +00:00
Anthony Eid
d4daa0a3a2 Show debug console evaluation response (#27050)
We weren't incrementing the output token when getting responses from the
debug evaluation request which caused some output to not be displayed.
(Usually the evaluation response, but that could cascade into other
output events not showing)


Release Notes:
- N/A

Co-authored-by: Remco Smits <djsmits12@gmail.com>
Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
2025-03-19 05:37:32 +00:00
Conrad Irwin
81582cd7f3 Don't render breakpoint indicators on top of expand arrows (#27048)
Closes #ISSUE

cc @Anthony-Eid. One thing I noticed while doing this is that we do an
invalid cast here from DisplayPoint.row to MultiBufferRow. These are not
the same if you have soft-wrap enabled (or anything else in the display
map that's not in the editor).

Release Notes:

- N/A
2025-03-19 05:00:41 +00:00
Ryan Hawkins
0f5a3afe94 Support built-in Zed prompts for all platforms (#26201)
This pull request does two things:

1. Adds a setting to force Zed to use the built-in prompts, instead of
the system provided ones. I've personally found the system prompts on
macOS often fail to respond to keyboard input, are slow to render
initially, and don't match Zed's style.
2. Makes the previously Linux-only Zed provided prompts available to
everybody using the above setting.

Release Notes:
- Added support for a built-in prompting system, regardless of platform.
Use the new `use_system_prompts` setting to control whether to use the
system provided prompts or Zed's built-in system. Note that on Linux,
this setting has no effect, as Linux doesn't have a system prompting
mechanism.
2025-03-18 22:27:09 -06:00
CharlesChen0823
382f9f6151 language_tools: Fix buffer search keeping focusing when pressing enter in vim mode (#26266)
Closes #25643 

Release Notes:

- Fixed buffer search keep focus when pressing enter in vim mode

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-19 04:25:29 +00:00
5brian
15d2420031 workspace::Open: Fix trapped cursor/selection on update (#25402)
Closes #ISSUE

Issue: Selection index does not reset when the matches update, which can
lead to the selection getting trapped when that index does not exist in
the next matches.


https://github.com/user-attachments/assets/d3fab23f-750c-47fb-bd3b-a0c42f214c83

This is in workspace::Open with   "use_system_path_prompts": false

Release Notes:

- N/A

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-18 22:19:11 -06:00
CharlesChen0823
026c7274d9 workspace: Add function to save new file in directory nearest tab (#22563)
Closes #15685

Release Notes:

- save new file in directory neasrest tab

---------

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-19 03:41:04 +00:00
Mikayla Maki
1aefa5178b Move "async move" a few characters to the left in cx.spawn() (#26758)
This is the core change:
https://github.com/zed-industries/zed/pull/26758/files#diff-044302c0d57147af17e68a0009fee3e8dcdfb4f32c27a915e70cfa80e987f765R1052

TODO:
- [x] Use AsyncFn instead of Fn() -> Future in GPUI spawn methods
- [x] Implement it in the whole app
- [x] Implement it in the debugger 
- [x] Glance at the RPC crate, and see if those box future methods can
be switched over. Answer: It can't directly, as you can't make an
AsyncFn* into a trait object. There's ways around that, but they're all
more complex than just keeping the code as is.
- [ ] Fix platform specific code

Release Notes:

- N/A
2025-03-19 02:09:02 +00:00
João Marcos
7f2e3fb5bd Fix git stage race condition with delayed fs events (#27036)
This PR adds a failing test `test_staging_hunks_with_delayed_fs_event`
and makes it pass

Also skips a queued read for git diff states if another read was
requested (less work)

This still doesn't catch all race conditions, but the PR is getting long
so I'll yield this and start another branch

Release Notes:

- N/A
2025-03-18 22:44:36 -03:00
Agus Zubiaga
68a572873b assistant edit tool: Improve bad search output (#27012)
When we failed to match a search string, we were reporting the replace
string as not found, this confuses the model and can make it go into a
doom loop. This PR fixes that improves the error output in general to
help it recover faster.

Release Notes:

- N/A
2025-03-18 21:53:20 -03:00
Piotr Osiewicz
c042a02cf4 debugger: First slight pass at UI (#27034)
- Collapse Launch and Attach into a single split button
- Fix code actions indicator being colored red.

Release Notes:

- N/A
2025-03-19 00:15:48 +00:00
Julia Ryan
73ac3d9a99 nix: Fix LDFLAGS rpath (#26912)
By default stdenv strips all unused rpaths, but we use a few libraries
that are `dlopen`'d so we need to stop it from removing those. The
[`dontPatchELF`
flag](https://ryantm.github.io/nixpkgs/stdenv/stdenv/#var-stdenv-dontPatchELF)
disables that and makes the nix build work on wayland again.

Fix #26905
Close #26864

Release Notes:

- N/A
2025-03-18 17:04:27 -07:00
Peter Tripp
2269f996f7 Add more shortcuts for delete/restore in Git Panel (#27004)
Release Notes:

- N/A
2025-03-18 18:52:28 -04:00
Marshall Bowers
e9033a75ac assistant2: Remove unneeded debug logging (#27030)
This PR removes the debug logging added in
https://github.com/zed-industries/zed/pull/23722, as we no longer need
it.

Release Notes:

- N/A
2025-03-18 22:12:04 +00:00
Marshall Bowers
a2ae6a1c77 assistant2: Add tool lists for each context server (#27029)
This PR updates the list of context servers with the ability to view the
tools provided by the context server:

<img width="1394" alt="Screenshot 2025-03-18 at 5 53 05 PM"
src="https://github.com/user-attachments/assets/4ffe93dd-f9e9-44e7-877f-656ebf45a326"
/>

Release Notes:

- N/A
2025-03-18 22:04:47 +00:00
Jason Lee
985ac4e5f2 gpui: Reduce window.refresh to improve cache hit of the cached views (#25009)
Release Notes:

- Improved performance when using the scroll wheel and some other mouse
interactions.

Based on some cache details about GPUI `AnyView::cached` that I found in
the discussion of
https://github.com/zed-industries/zed/discussions/24260#discussioncomment-12135749,
and combined with the optimization points found in actual applications.

This change may have some scenarios that I have not considered, so I
just make a draft to put forward my ideas first for discussion.

From my analysis, `AnyView::cached` will always invalid by Div's mouse
events, because of it called `window.refresh`. I understand that (mouse
move event) this is because the interface changes related to hover and
mouse_move will be affected style, so `window.refresh` is required.
Since Div does not have the `entity_id` of View, it is impossible to
know which View should be refreshed, so the entire window can only be
refreshed.

With this change, we can reduce a lot of `render` method calls on
ScrollWheel or Mouse Event.
2025-03-18 14:52:20 -07:00
Kirill Bulatov
89ae4ca9a3 Fix debugger docs a bit (#27026)
Tried adding a custom debugging tasks to discover two more required
properties missing from the docs.

Release Notes:

- N/A
2025-03-18 21:46:11 +00:00
Marshall Bowers
1d4afe6daa assistant2: Add context server list to configuration view (#27028)
This PR adds a context server list to the configuration view in
Assistant2:

<img width="1394" alt="Screenshot 2025-03-18 at 5 26 23 PM"
src="https://github.com/user-attachments/assets/58bf3920-1e35-4cb8-a32a-5ae9f98ce387"
/>

Release Notes:

- N/A
2025-03-18 21:41:39 +00:00
Joseph T. Lyons
777c88bcea Clean up community_release_actions file (#27027)
Release Notes:

- N/A
2025-03-18 21:29:22 +00:00
Kirill Bulatov
959a024861 Omit json-language-server from the scope_opt_in_language_servers (#27023)
Follow-up of https://github.com/zed-industries/zed/pull/26574/files

After that PR, settings.json stopped giving completions when `"` was
typed as a key:

https://github.com/user-attachments/assets/5ff03863-024c-4c28-a7cd-8ef48a1695d8

This goes down to 


fb12863999/crates/language/src/language.rs (L1736-L1748)

which was empty before the PR, hence leading to lower `true` branch.
Now, when typing `"`, there's no scope according to 


fb12863999/crates/project/src/lsp_store.rs (L4529-L4532)

return result.

Removing `json-language-server` from `scope_opt_in_language_servers`
seems to preserve the `:` fix and restore the completions behavior.


Release Notes:

- N/A
2025-03-18 21:08:43 +00:00
Joseph T. Lyons
ed510b5e93 Remove unused AssistantThreadFeedback event (#27021)
It looks like:

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

accidentally added a new event type, `AssistantThreadFeedback`, using
the old event system, that it didn't end up actually using, as the code
actually relies on using the newer (preferred) `telemetry::event!()`.

Release Notes:

- N/A
2025-03-18 20:39:54 +00:00
Peter Tripp
674c572a28 ci: Run stalebot checks multiple times to ensure completion (#27017)
Stalebot has a maximum operations-per-run which is set at 1000. As a
result it may require multiple runs to successfully complete.

This morning it took [three
runs](https://github.com/zed-industries/zed/actions/runs/13921563707/attempts/1)
so set it to run three times two hours apart to avoid hitting github API
limits.

Release Notes:

- N/A
2025-03-18 16:34:24 -04:00
Martin Fischer
4a39fc2644 gpui: Provide workaround for AMD Linux driver bug (#26890)
There apparently is some amdgpu/radv bug that rendering with
multisample anti-aliasing (MSAA) results in a crash when the bounds
of a triangle list exceed 1024px, which in Zed happens with the default
buffer font size when you select a line with more than 144 characters.

This crash has been reported as #26143.

This commit introduces a workaround: you can set the
ZED_PATH_SAMPLE_COUNT=0
environment variable to disable MSAA and the error message we print
when a GPU crash is encountered with radv now suggests trying this
environment
variable as a workaround and links the respective issue.

Sidenote: MSAA was introduced in
f08b1d78ec
so you didn't run into this driver bug with versions < 0.173.8.

Release Notes:

- Added a workaround for an AMD Linux driver bug that causes Zed to
crash when selecting long lines.
2025-03-18 20:11:09 +00:00
Agus Zubiaga
48fe134408 assistant edit tool: Create file when search/replace is empty (#27009)
We used to fail when this happened, but we saw the model use it as a way
to create empty files, which makes sense.

Release Notes:

- N/A
2025-03-18 18:35:11 +00:00
Cole Miller
22b8662275 Fix syntax highlighting of git commit messages (#26988)
- Load syntax colors into commit message editors
- Fix name mismatches that were preventing the git commit grammar and
language config from being matched up

Release Notes:

- Fixed git commit messages not being syntax-highlighted
2025-03-18 18:18:56 +00:00
Marshall Bowers
cc36cd9768 extensions_ui: Add ability to filter extensions by category (#27005)
This PR adds the ability to filter the list of extensions by category:


https://github.com/user-attachments/assets/ea7b518e-4769-4e2e-8bbe-e75f9f01edf9

Release Notes:

- Added the ability to filter the list of extensions by category.
2025-03-18 17:59:58 +00:00
KyleBarton
628a61d929 docs: Specify the command for activating prompt library from the command palette (#27007)
Quickfix of the docs as I read through and get familiar with the
assistant interface.
`prompt-library: toggle` does not appear to be a live command in
`cmd-shift-p` - instead I see `assistant: deploy prompt library`. This
change to the docs reflects that. It also notes that this command can
only be activated from within the assistant panel (the command is not
accessible from a standard editor panel).

Release Notes:

- N/A
2025-03-18 13:56:22 -04:00
Cole Miller
7f23875c5e 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 17:21:20 +00:00
Cole Miller
e7bba1c252 Improvements to interactive hard wrap behavior (#26953)
Release Notes:

- Fixed involuntary joining of lines when typing in the commit message
editor
- Fixed being unable to type whitespace after a comment character at the
start of a line in the commit message editor
2025-03-18 17:05:08 +00:00
Remco Smits
41a60ffecf Debugger implementation (#13433)
###  DISCLAIMER

> As of 6th March 2025, debugger is still in development. We plan to
merge it behind a staff-only feature flag for staff use only, followed
by non-public release and then finally a public one (akin to how Git
panel release was handled). This is done to ensure the best experience
when it gets released.

### END OF DISCLAIMER 

**The current state of the debugger implementation:**


https://github.com/user-attachments/assets/c4deff07-80dd-4dc6-ad2e-0c252a478fe9


https://github.com/user-attachments/assets/e1ed2345-b750-4bb6-9c97-50961b76904f

----

All the todo's are in the following channel, so it's easier to work on
this together:
https://zed.dev/channel/zed-debugger-11370

If you are on Linux, you can use the following command to join the
channel:
```cli
zed https://zed.dev/channel/zed-debugger-11370 
```

## Current Features

- Collab
  - Breakpoints
    - Sync when you (re)join a project
    - Sync when you add/remove a breakpoint
  - Sync active debug line
  - Stack frames
    - Click on stack frame
      - View variables that belong to the stack frame
      - Visit the source file
    - Restart stack frame (if adapter supports this)
  - Variables
  - Loaded sources
  - Modules
  - Controls
    - Continue
    - Step back
      - Stepping granularity (configurable)
    - Step into
      - Stepping granularity (configurable)
    - Step over
      - Stepping granularity (configurable)
    - Step out
      - Stepping granularity (configurable)
  - Debug console
- Breakpoints
  - Log breakpoints
  - line breakpoints
  - Persistent between zed sessions (configurable)
  - Multi buffer support
  - Toggle disable/enable all breakpoints
- Stack frames
  - Click on stack frame
    - View variables that belong to the stack frame
    - Visit the source file
    - Show collapsed stack frames
  - Restart stack frame (if adapter supports this)
- Loaded sources
  - View all used loaded sources if supported by adapter.
- Modules
  - View all used modules (if adapter supports this)
- Variables
  - Copy value
  - Copy name
  - Copy memory reference
  - Set value (if adapter supports this)
  - keyboard navigation
- Debug Console
  - See logs
  - View output that was sent from debug adapter
    - Output grouping
  - Evaluate code
    - Updates the variable list
    - Auto completion
- If not supported by adapter, we will show auto-completion for existing
variables
- Debug Terminal
- Run custom commands and change env values right inside your Zed
terminal
- Attach to process (if adapter supports this)
  - Process picker
- Controls
  - Continue
  - Step back
    - Stepping granularity (configurable)
  - Step into
    - Stepping granularity (configurable)
  - Step over
    - Stepping granularity (configurable)
  - Step out
    - Stepping granularity (configurable)
  - Disconnect
  - Restart
  - Stop
- Warning when a debug session exited without hitting any breakpoint
- Debug view to see Adapter/RPC log messages
- Testing
  - Fake debug adapter
    - Fake requests & events

---

Release Notes:

- N/A

---------

Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com>
Co-authored-by: Anthony Eid <hello@anthonyeid.me>
Co-authored-by: Anthony <anthony@zed.dev>
Co-authored-by: Piotr Osiewicz <peterosiewicz@gmail.com>
Co-authored-by: Piotr <piotr@zed.dev>
2025-03-18 12:55:25 -04:00
Marshall Bowers
ed4e654fdf assistant_tools: Add fetch tool (#26999)
This PR adds a new `fetch` tool to the set of tools the Assistant has
available.

This tool accepts a URL and fetches the content as Markdown.

<img width="1394" alt="Screenshot 2025-03-18 at 11 52 21 AM"
src="https://github.com/user-attachments/assets/e5bcde14-a0dd-4835-9d42-8f45def68f4d"
/>

<img width="1394" alt="Screenshot 2025-03-18 at 11 52 37 AM"
src="https://github.com/user-attachments/assets/3bcce4f5-f61b-40d7-8b30-2c673ce3c06a"
/>

Release Notes:

- N/A
2025-03-18 16:25:51 +00:00
Cole Miller
baaafddbeb worktree: Fix tracking of git status scans and re-enable tests (#26926)
Closes #ISSUE

Release Notes:

- N/A
2025-03-18 12:23:46 -04:00
Marshall Bowers
b70f21c08d assistant_tools: Rename RegexSearchTool module to match the others (#27001)
This PR renames the `RegexSearchTool` module to `regex_search_tool.rs`
to match the other tools.

Release Notes:

- N/A
2025-03-18 16:20:15 +00:00
Agus Zubiaga
5615be51cc assistant edit tool: Revert fuzzy matching (#26996)
#26935 is leading to bad edits, so let's revert it for now. I'll bring
back a version of this, but it'll likely just focus on indentation
instead of making the whole search fuzzy.

Release Notes: 

- N/A
2025-03-18 13:08:09 -03:00
Richard Feldman
06e9f0e309 Paginate regex and path search tools (#26997)
<img width="630" alt="Screenshot 2025-03-18 at 10 50 17 AM"
src="https://github.com/user-attachments/assets/0aee5367-402a-405a-8676-f2f8af425b1e"
/>

Release Notes:

- N/A
2025-03-18 15:44:41 +00:00
Marshall Bowers
41a2be7e54 assistant2: Keep the tool selector open when toggling tools (#26994)
This PR makes it so the tool selector will stay open when toggling tools
instead of closing after each selection:


https://github.com/user-attachments/assets/eb987785-cfb5-4b07-8d63-510fbd9d9bf1

This involved making a change to `ContextMenu` to allow it to rebuild
its menu items after each confirmation in order for them to reflect
their selected/unselected status. I intend to clean up the `ContextMenu`
API a bit at a later point, but that is out of scope for this PR.

Release Notes:

- N/A
2025-03-18 15:30:05 +00:00
Cole Miller
e38ae423f1 Add missing commit event reporting (#26990)
cc @morgankrey 

Release Notes:

- N/A
2025-03-18 14:52:32 +00:00
Peter Tripp
68bb3bd5eb Add more shortcuts for editor::OrganizeImports (#26932)
Follow-up to:
- https://github.com/zed-industries/zed/pull/25793

Release Notes:

- N/A
2025-03-18 10:51:12 -04:00
Richard Feldman
122e73f152 Allow read-file tool to read a subset of a file (#26966)
Release Notes:

- N/A
2025-03-18 10:03:15 -04:00
Smit Barmase
4b775505f5 migrator: Fix case where users see migration banner despite no diff changes (#26982)
Fixes edge case where after carrying out all migrations if final text is
same as existing text, we don't need to ask user to do anything, despite
migrations edits are being applied internally. E.g. A -> B - > C -> A

Release Notes:

- N/A
2025-03-18 19:24:24 +05:30
Marshall Bowers
a9f7c0549c docs: Use correct name for Intelephense license file (#26986)
This PR updates the Intelephense section of the PHP docs to use the
correct name for the license file.

Intelephense uses British English:

<img width="1185" alt="Screenshot 2025-03-18 at 8 30 20 AM"
src="https://github.com/user-attachments/assets/a675e854-bedf-4f70-bf8f-90488d196242"
/>

Release Notes:

- N/A
2025-03-18 12:31:57 +00:00
Kirill Bulatov
ac617e278e Keep and filter word completions on input, if the menu is open (#26979)
Follow-up of https://github.com/zed-industries/zed/pull/26410

Release Notes:

- N/A
2025-03-18 13:19:32 +02:00
Bennet Bo Fenner
26f4b2a491 assistant2: Combine file & directory picker (#26975)
In the process of adding `@mentions` we realized that we do not want to
make a distinction between Files & Directories in the UI, therefore this
PR combines the File & Directory pickers into a unified version



https://github.com/user-attachments/assets/f3bf189c-8b69-4f5f-90ce-0b83b12dbca3

(Ignore the `@mentions`, they are broken also on main)

Release Notes:

- N/A
2025-03-18 09:49:25 +00:00
Sheik Althaf
fdcacb3849 typescript: Add highlighting for Angular inline components (#26553)
Closes #ISSUE

Release Notes:

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

Before
<img width="1004" alt="image"
src="https://github.com/user-attachments/assets/9a611e8d-e00e-4dc7-b4c9-bd76fec95525"
/>

After
<img width="936" alt="Image"
src="https://github.com/user-attachments/assets/b83d3309-1aab-492c-a2f1-c45cd19e6bcc"
/>
2025-03-18 09:27:48 +00:00
Michael Sloan
f61d3d28e0 Use futures::future::join_all instead of futures::stream in assistant_eval (#26974)
Release Notes:

- N/A
2025-03-18 08:22:18 +00:00
tidely
a5621662b2 Update to git2 0.20.1 (#26972)
Switch back to git2 releases after
https://github.com/rust-lang/git2-rs/pull/1120 got merged in 0.20.1

Release Notes:

- N/A
2025-03-18 10:05:15 +02:00
Michael Sloan
b6198ad516 Add Ord and PartialOrd impls for gpui entity types (#26968)
Motivation is to be able to use entities as TreeMap keys.

Release Notes:

- N/A

Co-authored-by: Nathan <nathan@zed.dev>
2025-03-18 06:20:21 +00:00
Conrad Irwin
5210d9e8b4 Tidier multibuffer (#26954)
Makes multibuffer headers less close to the top of the file.

Moves multibuffer line numbers one em to the right to make space for the
expand excerpt button on large line numbers.

Release Notes:

- N/A

---------

Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
2025-03-17 22:26:27 -06:00
Michael Sloan
1139904ef5 Remove unnecessary conditional definition of FS_WATCH_LATENCY (#26967)
This was added in #8343 to make it only visible for tests. #9189 then
made it visible regardless of `test-support`, so the definitions became
identical.

Release Notes:

- N/A
2025-03-17 22:10:16 -06:00
Joseph T. Lyons
b4ef3791bb Send stable release notes email (#26964)
Release Notes:

- N/A
2025-03-17 23:25:41 -04:00
Cole Miller
88907eeb38 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-17 22:54:21 -04:00
Marshall Bowers
cd5d7e82d0 collab: Make account age-related fields required in LlmTokenClaims (#26959)
This PR makes the account age-related fields required in
`LlmTokenClaims`.

We've also removed the account age check from the LLM token issuance
endpoint, instead having it solely be enforced in the `POST /completion`
endpoint.

This change will be safe to deploy at ~8:01PM EDT.

Release Notes:

- N/A
2025-03-17 19:54:44 -04:00
Marshall Bowers
0851842d2c collab: Defer account age check to POST /completion endpoint (#26956)
This PR defers the account age check to the `POST /completion` endpoint
instead of doing it when an LLM token is generated.

This will allow us to lift the account age restriction for using Edit
Prediction.

Note: We're still temporarily performing the account age check when
issuing the LLM token until this change is deployed and the LLM tokens
have had a chance to cycle.

Release Notes:

- N/A
2025-03-17 22:42:29 +00:00
Marshall Bowers
1397e01735 collab: Clean up LLM token creation (#26955)
This PR cleans up the LLM token creation a bit.

We now pass in the entire list of feature flags to the
`LlmTokenClaims::create` method to prevent having a bunch of confusable
`bool` parameters.

Release Notes:

- N/A
2025-03-17 22:25:43 +00:00
Max Brunsfeld
2b2b9c1624 Make repo and branch popovers extend up from their trigger buttons (#26950)
Previously, when clicking on the branch, the popover would obscure the
button you just clicked, which was awkward.

Release Notes:

- Improved the placement of the repo and branch picker popovers in the
git panel.
- Added a 'SelectRepo' action that opens the repository selector in a
modal.
2025-03-17 15:05:17 -07:00
Agus Zubiaga
a05066cd83 assistant edit tool: Track read buffers and notify model of user edits (#26952)
When the model reads file, we'll track the version it read, and let it
know if the user makes edits to the buffer. This helps prevent edit
failures because it'll know to re-read the file before.

Release Notes:

- N/A
2025-03-17 21:50:16 +00:00
Smit Barmase
cb439e672d editor: Fix navigate back for locations opened via preview item (#26943)
Closes #25458

When navigating code from a preview tab with
`enable_preview_from_code_navigation` set to `true`, "Go Back" from a
newly opened tab could focus on the tab to the right instead of
returning to the original preview tab.

Before, we killed the existing preview tab before opening a new one,
which breaking history as the new tab had no reference to the old one.
This caused navigation to shift to the next tab on the right.

Now, we first add the new tab at the preview index, and then kill the
existing preview tab. This preserves the history by linking new preview
tab to existing tab.

Release Notes:

- Fixes an issue where navigating code from a preview tab with
`enable_preview_from_code_navigation` set to `true`, "Go Back" from a
newly opened tab could focus on the tab to the right instead of
returning to the original preview tab.
2025-03-18 00:59:36 +05:30
Mostafa Mahmoud
6b0a282c9c docs: Fix wrong html-like tags shortcut for Vim (#26792)
Release Notes:

- N/A
2025-03-17 12:40:07 -06:00
Conrad Irwin
25772b8777 Fix sticky header in last buffer of a multibuffer (#26944)
This also simplifies our code to stop generating a last excerpt boundary
that we always ignore.

Closes #ISSUE

Release Notes:

- N/A
2025-03-17 18:39:57 +00:00
Agus Zubiaga
94b63808e0 assistant edit tool: Fuzzy match search block (#26935)
Release Notes:

- N/A

Co-authored-by: Antonio Scandurra <me@as-cii.com>
2025-03-17 18:33:20 +00:00
Cole Miller
798af67dc1 Disable the other flaky tests (#26942)
I thought it might be just `test_file_status` this time, but it seems to
be all four of the tests that we were previously seeing issues with.

Release Notes:

- N/A
2025-03-17 18:10:42 +00:00
Anthony Eid
db1d2defa5 Sync git button states between project diff & git panel (#26938)
Closes #ISSUE

Release Notes:

- Git action buttons are now synced between the project diff and git
panel

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
Co-authored-by: Piotr Osiewicz <peterosiewicz@gmail.com>
2025-03-17 14:08:32 -04:00
Max Brunsfeld
430bd83e4d Don't open the commit editor when staging last hunk (#26939)
Closes #26880

Release Notes:

- Removed a behavior where staging the last hunk in the project diff
would open the commit modal.
2025-03-17 10:58:04 -07:00
Cole Miller
dbe5399fc4 Remove disabling effect on the stage and unstage toolbar buttons (#26936)
Closes #26883

Release Notes:

- N/A
2025-03-17 13:48:04 -04:00
João Marcos
aba242d576 Document gutter_debounce (#26940)
Release Notes:

- N/A
2025-03-17 14:47:37 -03:00
Mikayla Maki
ddc210abfc Add website docs for the hunk_style variants (#26937)
Follow up to https://github.com/zed-industries/zed/pull/26816

Release Notes:

- N/A
2025-03-17 10:36:31 -07:00
Jakub Charvat
65994c0576 Add git.hunk_style setting for gutter hollow hunk behavior (#26816)
This is a follow up to #26809, introducing `git.hunk_style` setting to
control whether staged or unstaged hunks are shown as hollow.

Reused `GitHunkStyleSetting` which was left over from #26504.

Release Notes:

- Added `git.hunk_style` setting to control whether staged or unstaged
hunks are hollow.
2025-03-17 10:24:49 -07:00
João Marcos
011f823f33 Move buffer diff storage from BufferStore to GitStore (#26795)
Release Notes:

- N/A

---------

Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
Co-authored-by: max <max@zed.dev>
2025-03-17 17:02:32 +00:00
Marco Roth
3d1ae68f83 docs: Remove duplicate indent_guides setting in Project panel options (#26927)
Just a small docs pull request to remove the duplicate `indent_guides`
setting in the Project panel options section of the docs. There is also
another `indent_guides` on
[L2585](https://github.com/zed-industries/zed/pull/26927/files#diff-c2decf822f3085926bd23bdf175700222dfd8193d48ea39908d4bb1d1a7c6240R2584).
~~Let me know if you prefer to remove the other instance, thank you!~~

Edit: I just realized it's the old setting, `indent_guides` now expects
a object.
2025-03-17 16:22:39 +00:00
Agus Zubiaga
1f62274a89 assistant edit tool: Return applied actions back to main model (#26810)
We'll now include the search/replace block that got applied as part of
the tool output. We think this will help the model have a better idea of
how the file changed and prevent later edit failures.

Release Notes:

- N/A
2025-03-17 13:21:35 -03:00
Cole Miller
c2f62d261b 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-17 15:44:55 +00:00
khayyam
7d433a30ec git_hosting_providers: Allow configuring additional hosting providers via settings (#26879)
Release Notes:

- Added a new `git_hosting_providers` setting for configuring custom Git
hosting providers.

---------

Co-authored-by: Marshall Bowers <git@maxdeviant.com>
2025-03-17 15:39:52 +00:00
Max Brunsfeld
52567f4b72 Eliminate unnecessary macros in languages crate (#26813)
I vibe coded this in Zed, dawg.

This avoids a number of cases where we created multiple copies of the
same lsp adapter. Now we clone the Arcs.

Release Notes:

- N/A
2025-03-17 08:13:32 -07:00
Richard Feldman
a0ee84d3ac Use the main thread less on search tool (#26732)
Release Notes:

- N/A
2025-03-17 16:02:22 +01:00
Danilo Leal
6cac0b33dc docs: Add marker to signal which languages are built into Zed (#26913)
I saw over the weekend some social media posts that indicated people
didn't know which languages are included in Zed by default. We do say
that on each language-specific page, but I figured having this
high-level view on the languages page wouldn't hurt.

Release Notes:

- N/A
2025-03-17 11:27:52 -03:00
Marshall Bowers
45606abfdb git_hosting_providers: Refactor constructors (#26919)
This PR refactors the constructors for the various Git hosting providers
to facilitate adding support for more self-hosted variants.

Release Notes:

- N/A
2025-03-17 13:46:58 +00:00
Marshall Bowers
8ba6ce43ac git_hosting_providers: Fix incorrect name for SourceHut (#26915)
This PR fixes an issue where the SourceHut Git hosting provider was
using the wrong name.

Release Notes:

- N/A
2025-03-17 13:32:23 +00:00
Agus Zubiaga
040d42fc24 assistant tools: Fix running tests locally (#26914)
Without this, we running into the following error:

```
Running into this when running tests. Is this  
dyld[45041]: Library not loaded: @rpath/WebRTC.framework/WebRTC
  Referenced from: <B2EA63A5-994E-3FB0-A74B-C9C4F7E5C1EF> /Users/aguz/zed/zed/target/debug/deps/assistant_tools-522d7745dd439dfb
  Reason: no LC_RPATH's found
```

Thanks Piotr!

Release Notes:

- N/A
2025-03-17 13:32:19 +00:00
Julia Ryan
22d905dc03 nix: Allow auto-update in the devshell (#26911)
Our direnv integration was making zed refuse to auto-update when you had
the zed repo open with the devshell active. This was happening even when
you used a non-nix build of zed, which actually should be able to
auto-update.

I'm a bit unsure of why we check for the `ZED_UPDATE_EXPLANATION` env
var [both at build time _and_ at
runtime](2828dcb67b/crates/auto_update/src/auto_update.rs (L149)),
but I can see an argument for why people might want that so I'll just do
the less intrusive change for now and leave the var out of the devshell.

Release Notes:

- N/A
2025-03-17 04:49:56 -07:00
0x2CA
bf735da3f2 Support extended keys on Mac (F20-F35) (#26899)
Closes #4640

About the support limit of Fn:

Mac F1-F35
Win F1-F24
Linux F1-F35
Terminal F1-F20

Release Notes:

- Improved support for extended keyboards on Mac (F20-F35)
2025-03-17 12:56:46 +02:00
Antonio Scandurra
210d8d5530 Allow cancellation of tool uses (#26906)
Release Notes:

- N/A
2025-03-17 09:53:18 +00:00
Color Fuzzy
a0f995d2ae Support SSH usernames which contain @ symbols (#25314)
Closes #25246

Release Notes:

- SSH: Improved handling of multiple `@` in connection strings: e.g.
`ssh jim.lv@es2@10.220.67.57@11.239.1.231` improving support of jump
hosts running JumpServer.

---------

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-17 05:10:21 +00:00
Piotr Osiewicz
8f560daec2 chore: Extract http-client-tls crate (#26895)
http-client pulled in rustls which in turn meant that gpui depended on
rustls/aws-lc-sys. This commit extracts http-client-tls crate to
separate the http-client and tls dependencies.

Closes #ISSUE

Release Notes:

- N/A
2025-03-17 02:36:37 +00:00
Richard Feldman
d5bb12631a Delete tool uses paths instead of globs (#26715)
Also made `run` avoid doing work on the main thread.

Release Notes:

- N/A
2025-03-16 11:58:25 +01:00
Kirill Bulatov
8a31dcaeb0 Use textDocument/codeLens data in the actions menu when applicable #2 (#26848)
Re-applies what's been reverted in
https://github.com/zed-industries/zed/pull/26832 with an action-related
fix in
64b5d37d32

Before, actions were resolved only if `data` is present and either of
the possible fields is empty:

e842b4eade/crates/project/src/lsp_store.rs (L1632-L1633)

But Zed resolves completions and inlays once, unconditionally, and the
reverted PR applied the same strategy to actions.
That did not work despite the spec not forbidding `data`-less actions to
be resolved.

Soon, it starts to work due to
https://github.com/rust-lang/rust-analyzer/pull/19369 but it seems safer
to restore the original filtering code.

Code lens have no issues with `data`-less resolves:

220d913cbc/crates/rust-analyzer/src/handlers/request.rs (L1618-L1620)

so the same approach as completions and inlays is kept: resolve once.


Release Notes:

- N/A
2025-03-15 20:09:32 +00:00
Michael Sloan
ef91e7afae Minor optimization of line number length logic (#26845)
In `layout_excerpt_gutter`, compute max line number length once instead
of for every row

In `max_line_number_width`, use ilog10 instead of converting to floats
and back

Release Notes:

- N/A
2025-03-15 19:28:50 +00:00
Michael Sloan
c220fb387d Fix panic when providing 0 to ilog10 in line number length logic (#26844)
Introduced in #24428

Release Notes:

- N/A
2025-03-15 19:10:54 +00:00
Smit Barmase
adbde210fd termina: Fix text selection for first line scrolls up (#26842)
Closes #21626
 
Now scroll will only happen when cursor goes beyond the bounds of
terminal.
 
 Before:
 


https://github.com/user-attachments/assets/9ac48e80-d0e0-44c9-87ad-14ed748de78d


 After:


https://github.com/user-attachments/assets/c697c1fc-a6d2-4b9a-aad4-5b0c79837c2a
 
Release Notes:

- Fixed an issue where selecting the first line in the terminal would
cause it to scroll.
2025-03-15 22:33:16 +05:30
Jason Lee
b81a1ad91d gpui: Fix text underline width (#26827)
Release Notes:

- N/A 

Fix #24721 mistake to make sure underline width same as the text.

## Before


![image](https://github.com/user-attachments/assets/1fe6a8c2-517f-41be-bdf0-0ee777b7f8aa)

## After

<img width="912" alt="image"
src="https://github.com/user-attachments/assets/222b5dcb-c0fb-4ec1-8e23-d68247621375"
/>
2025-03-15 09:18:11 -07:00
Peter Tripp
5f390f1bf8 Initial PyLSP documentation (#26835)
Closes https://github.com/zed-industries/zed/issues/26820

Release Notes:

- N/A
2025-03-15 11:03:35 -04:00
Richard Hao
c282acbe65 terminal: Don’t include line breaks for soft wrap in Assistant terminal context (#25415)
> Detects and combines wrapped lines into single logical lines, more
accurately representing the actual terminal content.


```shell
perl -i -pe \
    's/"vscode-languageserver(\/node)?"/"\@zed-industries\/vscode-languageserver$1"/g' packages/css/lib/node/cssServerMain.js
```

<img width="518" alt="image"
src="https://github.com/user-attachments/assets/52d9327c-c381-4e5f-a676-0cf84c824388"
/>

<img width="1314" alt="image"
src="https://github.com/user-attachments/assets/0a32e1f9-7e95-482e-9beb-2e8a6c40584c"
/>




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

Release Notes:

- Fixed a bug where context for the terminal assistant would add line
breaks in the presence of soft wrapped lines.

---------

Co-authored-by: Peter Tripp <peter@zed.dev>
2025-03-15 14:28:26 +00:00
Marshall Bowers
021d6584cc Revert "Use textDocument/codeLens data in the actions menu when applicable (#26811)" (#26832)
This reverts commit b61171f152.

This PR reverts #26811, as it has broken `rust-analyzer` code actions.

With this commit reverted my code actions are working again. 

Release Notes:

- Community: Reverted https://github.com/zed-industries/zed/pull/26811.
2025-03-15 14:14:29 +00:00
Marshall Bowers
b547cd1c70 ci: Remove migration_checks as a required check (#26833)
This PR removes the `migration_checks` job as a required check.

This was not required before, and we shouldn't make it required, as
there are cases where we need to bypass it, as is the case in
https://github.com/zed-industries/zed/pull/26832.

Release Notes:

- N/A
2025-03-15 13:59:25 +00:00
张小白
8f841d1ab7 Revert unintended Cargo.lock changes (#26830)
This PR reverts some of the changes made to `Cargo.lock` in #25702. In
that PR, several crate versions were unintentionally downgraded,
including `aws-lc-rs`, which has caused release builds to fail on
Windows again.

Release Notes:

- N/A
2025-03-15 21:08:55 +08:00
Jason Lee
4b153e7f7f gpui: Fix line_through, underline position when used text center or right (#24721)
Release Notes:

- N/A

---

| Before | After |
| --- | --- |
| <img width="912" alt="image"
src="https://github.com/user-attachments/assets/0640ac85-ee5d-4707-b866-997e36608c18"
/> | <img width="912" alt="image"
src="https://github.com/user-attachments/assets/caf84477-a7bc-4c22-a9e6-f44c3b6f86ef"
/> |
 
And fix the `line_through` doc link.
2025-03-15 11:44:51 +02:00
Kirill Bulatov
b61171f152 Use textDocument/codeLens data in the actions menu when applicable (#26811)
Similar to how tasks are fetched via LSP, also queries for document's
code lens and filters the ones with the commands, supported in server
capabilities.

Whatever's left and applicable to the range given, is added to the
actions menu:


![image](https://github.com/user-attachments/assets/6161e87f-f4b4-4173-8bf9-30db5e94b1ce)

This way, Zed can get more actions to run, albeit neither r-a nor vtsls
seem to provide anything by default.

Currently, there are no plans to render code lens the way as in VSCode,
it's just the extra actions that are show in the menu.

------------------

As part of the attempts to use rust-analyzer LSP data about the
runnables, I've explored a way to get this data via standard LSP.

When particular experimental client capabilities are enabled (similar to
how clangd does this now), r-a starts to send back code lens with the
data needed to run a cargo command:

```
{"jsonrpc":"2.0","id":48,"result":{"range":{"start":{"line":0,"character":0},"end":{"line":98,"character":0}},"command":{"title":"▶︎ Run Tests","command":"rust-analyzer.runSingle","arguments":[{"label":"test-mod tests::ecparser","location":{"targetUri":"file:///Users/someonetoignore/work/ec4rs/src/tests/ecparser.rs","targetRange":{"start":{"line":0,"character":0},"end":{"line":98,"character":0}},"targetSelectionRange":{"start":{"line":0,"character":0},"end":{"line":98,"character":0}}},"kind":"cargo","args":{"environment":{"RUSTC_TOOLCHAIN":"/Users/someonetoignore/.rustup/toolchains/1.85-aarch64-apple-darwin"},"cwd":"/Users/someonetoignore/work/ec4rs","overrideCargo":null,"workspaceRoot":"/Users/someonetoignore/work/ec4rs","cargoArgs":["test","--package","ec4rs","--lib"],"executableArgs":["tests::ecparser","--show-output"]}}]}}}
```

This data is passed as is to VSCode task processor, registered in


60cd01864a/editors/code/src/main.ts (L195)

where it gets eventually executed as a VSCode's task, all handled by the
r-a's extension code.

rust-analyzer does not declare server capabilities for such tasks, and
has no `workspace/executeCommand` handle, and Zed needs an interactive
terminal output during the test runs, so we cannot ask rust-analyzer
more than these descriptions.

Given that Zed needs experimental capabilities set to get these lens:

60cd01864a/editors/code/src/client.ts (L318-L327)

and that the lens may contain other odd tasks (e.g. docs opening or
references lookup), a protocol extension to get runnables looks more
preferred than lens:
https://rust-analyzer.github.io/book/contributing/lsp-extensions.html#runnables

This PR does not include any work on this direction, limiting to the
general code lens support.

As a proof of concept, it's possible to get the lens and even attempt to
run it, to no avail:

![image](https://github.com/user-attachments/assets/56950880-d387-48f9-b865-727f97b5633b)


Release Notes:

- Used `textDocument/codeLens` data in the actions menu when applicable
2025-03-15 09:50:32 +02:00
张小白
0b492c11de Use line_endings macro for the edit tool tests (#26642)
This aligns with how we handle other tests on Windows.

Release Notes:

- N/A
2025-03-15 14:16:10 +08:00
AidanV
265caed15e vim: Add global marks (#25702)
Closes https://github.com/zed-industries/zed/issues/13111

Release Notes:

- vim: Added global marks `'[A-Z]`
- vim: Added persistence for global (and local) marks. When re-opening
the same workspace your previous marks will be available.

---------

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-15 05:58:34 +00:00
Ryan Hawkins
148131786f Reveal always_included entries in Project Panel (#26197)
If the user has the `auto_reveal` option enabled, as well as
`file_scan_inclusions` and opens a file that is gitignored but is also
set to be always included, that file won't be revealed in the project
panel. I've personally found this annoying, as the project panel can
provide useful context on where you are in a codebase. It also just
feels weird for it to be out of sync with the editor state.

Release Notes:

- Fixed the interaction between `auto_reveal`, `file_scan_inclusions`,
and `.gitignore` within the Project Panel. Files that are always
included will now be auto-revealed in the Project Panel, even if those
files are also gitignored.
2025-03-15 01:42:11 +00:00
Jakub Charvat
7c1405db37 Update rendering of gutter diff hunks to show whether a hunk is staged or not (#26809)
In the gutter, it seems more intuitive to me for the unstaged hunks to
be hollow, indicating an action left to complete, and the staged hunks
to be filled. I therefore flipped the style of expanded hunks to match
the gutter icons. Is that acceptable? And would it be a breaking change?
If it is not acceptable, then 058dc216d5
contains the opposite behaviour, it is not a problem to revert to it.

In the following images, the first hunk is always ~unstaged~ staged and
the second is ~staged~ unstaged.

<img width="138" alt="image"
src="https://github.com/user-attachments/assets/35927069-da90-424a-8988-a4eb984d865f"
/>
<img width="133" alt="image"
src="https://github.com/user-attachments/assets/4edd0e0d-a2b5-453a-8172-47684e065c82"
/>

<br />
<img width="143" alt="image"
src="https://github.com/user-attachments/assets/2f295944-81aa-45f3-a103-c13b92bc2aba"
/>
<img width="133" alt="image"
src="https://github.com/user-attachments/assets/35248218-7104-4059-8742-ae0e54da6c6b"
/>


Release Notes:

- Improved gutter diff hunks to show whether a hunk is staged
2025-03-14 16:49:53 -07:00
Finn Evers
96b747e31d editor: Disable edit predictions in read-only buffers (#26804)
Closes #26797

Release Notes:

- Fixed edit predictions appearing in read-only buffers.

Co-authored-by: Marshall Bowers <git@maxdeviant.com>
2025-03-14 23:15:49 +00:00
Michael Sloan
7a888de9f5 Add initial implementation of evaluating changes generated by the assistant (#26799)
Release Notes:

- N/A

---------

Co-authored-by: Richard Feldman <oss@rtfeldman.com>
Co-authored-by: Thomas <thomas@zed.dev>
2025-03-14 23:10:25 +00:00
Finn Evers
e9b4fa1465 rust: Follow-up fixes for attribute highlighting (#26172)
Closes #26124

This PR fixes some more cases of improper attribute highlights for rust.

In #25501 I tried to address the regression in highlighting rust
attributes which were introduced by #25333 . However, I failed to
properly check all cases of attribute highlights as shown in the linked
issue - really sorry for that! Thus, this is a follow-up fix aiming to
resolve the issues the previous PR did not cover.

The changes do not affect any highlighting shown in the [previous
PR](https://github.com/zed-industries/zed/pull/25501):

| `main` | <img width="719" alt="main-working"
src="https://github.com/user-attachments/assets/9aa0e611-7bda-4b50-9335-c87da4c38057"
/> |
| --- | --- |
| This PR | <img width="719" alt="PR-working"
src="https://github.com/user-attachments/assets/605b275c-1d68-4bd7-97c6-251d7614a7ed"
/> |

But resolves the mentioned regressions in the linked issue:

| `main` | <img width="371" alt="main_broken"
src="https://github.com/user-attachments/assets/ebbb47b7-7945-41e0-b030-2fe3f2198653"
/> |
| --- | --- |
| This PR | <img width="371" alt="PR_broken"
src="https://github.com/user-attachments/assets/fa97408b-e1d6-4d99-81c1-cfb8073961a4"
/> |

Again, sorry for not checking this more thoroughly.


Release Notes:

- Fixed attributes in Rust being improperly highlighted.

Co-authored-by: Marshall Bowers <git@maxdeviant.com>
2025-03-14 23:02:45 +00:00
Devzeth
ead60d1857 docs: Add documentation for icon theme (#25973)
Adds documentation for the icon theme setting (mostly based on the
documentation from theme but adjusted for icon theme).

Release Notes:

- N/A

---------

Co-authored-by: Peter Tripp <peter@zed.dev>
Co-authored-by: Marshall Bowers <git@maxdeviant.com>
2025-03-14 22:39:11 +00:00
Cole Miller
768dfc8b6b Reinstate failing worktree tests (#26733)
Just debugging for now

Release Notes:

- N/A
2025-03-14 22:20:24 +00:00
Cole Miller
f2f9c786da Fix the feedback modal (#26793)
Closes #26787

Release Notes:

- Fixed a bug that prevented typing in the in-app feedback form
2025-03-14 17:55:52 -04:00
Smit Barmase
e5d2678d94 editor: Disable selection highlights for single line editor (#26805)
Fixes the selection highlight appearing in single-line editors like the
file picker, command palette, etc.

Release Notes:

- Fixed selection highlight appearing in input fields like the file
picker, command palette, etc.
2025-03-15 03:02:40 +05:30
Smit Barmase
3ad9074e63 editor: Fix auto-closing quotes after word character (#26803)
Closes #14349

When typing quotes immediately after a word character, it resulted in
auto-closing the quote.

```js
const thing = this is text^;
```

Typing a quote resulted in `this is text""^;` which is not correct, and
should be `this is text"^;`.

This PR changes logic for auto close:

1. We now prevent auto-closing in case of brackets where start == end
when they're typed immediately after a word character. i.e. For, ``` `,
", ' ```.
2. Other bracket pairs like `{}, (), etc` continue to auto-close
regardless of preceding character. So, `func^` to `func()^` will keep
working.
3. Auto-closing in other contexts like after spaces, punctuation, etc.
will still work.

Before:

![before](https://github.com/user-attachments/assets/6be02c95-4c71-488b-901d-b7b98c4170a4)

After:

![after](https://github.com/user-attachments/assets/680ece4d-20cb-428c-b430-846da3a2d643)

Release Notes:

- Fixed auto-paired quotes being inserted when typing a quote
immediately next to a word character.
2025-03-15 02:46:57 +05:30
Richard Feldman
f40b22c02a Add action log to thinking tool (#26802)
Release Notes:

- N/A
2025-03-14 20:44:36 +00:00
Richard Feldman
8490d0d4ef Add thinking tool (#26675)
Release Notes:

- N/A
2025-03-14 16:26:22 -04:00
Finn Evers
afd0da97b9 language_selector: Improve lookup for language icons (#26376)
This PR fixes a rare case where icons could be missing in the language
selector.

Currently, whilst looking up an icon, all file suffixes starting with a
dot are filtered out. While this works fine for some languages, there
are some languages having only file suffixes starting with a dot, e.g.
the "Git Attributes" language provided from the "Git Firefly" extension.
This results in no icon being displayed in the list, as shown in the
screenshots below.

To solve this, we can just simply remove the check for this special case
as well as the construction of an artificial file name in the code, as
both are not needed. A simple path just consisting of the extension is
sufficient, as we currently do not differentiate between file names and
file suffixes during an icon lookup. see the relevant code below:


013a646799/crates/file_icons/src/file_icons.rs (L23-L52)

As the first lookup is directly done using the entire file name and then
checked against all suffixes, we actually do not have to construct an
artificial file name at all. Should that produce no match, we check for
a hidden file right after, so we do not have to filter hidden file names
out.

With this fix, nothing changes for "normal" file suffixes, for some
cases where languges provide entire file names as a path suffix, the
matching might improve, and for languages with only hidden associated
file names, the initially described issue is resolved.

I do believe the behavior of matching icons to languages could be
improved in general. Fowever, I do think this is beyond the scope of
this change.

| Current main | <img width="546" alt="main"
src="https://github.com/user-attachments/assets/5c3c9fdc-cadf-4e44-9667-2530374aa0d2"
/> |
| --- | --- |
| This PR |<img width="546" alt="PR"
src="https://github.com/user-attachments/assets/82e59108-e31f-4ca9-8bbd-b9fd2b34feb0"
/>|

Aditionally, in 4395f78fb2 I refactored
the code which acquires the label and icon for a match, since I found it
a bit hard to read initially. The majority of this diff comes from this
change. Should that not be wanted, I can revert that change.

Release Notes:

- Fixed a rare case where languages had no associated icon in the
language selector.
2025-03-14 20:13:59 +00:00
Agus Zubiaga
1bf1c7223f assistant edit tool: Fix editing files in context (#26751)
When the user attached context in the thread, the editor model request
would fail because its tool use wouldn't be removed properly leading to
an API error.

Also, after an edit, we'd keep the old file snapshot in the context.
This would make the model think that the edits didn't apply and make it
go in a loop.

Release Notes:

- N/A
2025-03-14 17:07:43 -03:00
0x2CA
ba8b9ec2c7 gpui: Add interval in pattern (#26459)
Closes #ISSUE

[git: Use font size to determine pattern slash width
#26446](https://github.com/zed-industries/zed/pull/26446)

This PR only uses font size as the slant line width, and here it further
uses line height as the slant line interval control.

before


![image](https://github.com/user-attachments/assets/a8f2406e-5eed-4528-a9a2-867513613fc7)


now


![image](https://github.com/user-attachments/assets/9b8ccca9-8023-4cb2-a6fe-0e42e19642a4)

big line height


![image](https://github.com/user-attachments/assets/4498e858-4f25-432c-80ee-355726d9c41b)


Release Notes:

- N/A *or* Added/Fixed/Improved ...
2025-03-14 12:51:09 -07:00
Ben Kunkle
685536c27e editor: Change order of format and timeout futures (#26796)
Very small change, simply changing the order of the futures we pass to
`select_biased!` so that if the format request and the timeout resolve
at the same time (highly unlikely) we choose the format request instead
of choosing the timeout and throwing away our work!

Release Notes:

- N/A
2025-03-14 18:42:00 +00:00
Smit Barmase
ae017c3f96 file_finder: Fix panic when file name contains new line (#26791)
Closes #26777

This PR fixes a panic when a file name contains a newline and a
multi-byte character like 👋 (4 bytes in UTF-8). The issue was in the
regex not considering newlines in file names, causing it to match only
the latter part of the file name.

For example:

```
 left: PathWithPosition { path: "ab", row: None, column: None } // matched
 right: PathWithPosition { path: "ab\ncd", row: None, column: None } // actual file name
```


This resulted in incorrect index calculation later in the code, which
went unnoticed until now due to the lack of tests with file names
containing newlines.

We discovered this issue when a panic occurred due to incorrect index
calculation while trying to get the index of a multi-byte character.
After the newline fix, the index calculation is always correct, even in
the case of multi-byte characters.

Release Notes:

- Fixed an issue where file names with newlines and multi-byte
characters could cause a crash in certain cases.
2025-03-14 22:50:33 +05:30
João Marcos
f587e95a7e Add seed argument to #[gpui::test] attribute macro (#26764)
This PR introduces the arguments `seed` and `seeds` to `gpui::test`,
e.g.:
- `#[gpui::test(seed = 10)]`
- `#[gpui::test(seeds(10, 20, 30, 40))]`

Which allows us to run a test against a specific seed value without
slowing
down our tests like `iterations` does with high values.

This was motivated by a diff hunk test that only fails in a 400+ seed,
but is
slow to run 400+ times for every `cargo test`.

If your test failed with a specific seed, you can now add the `seed` arg
to
increase the chances of detecting a regression.

There are now three ways of setting seeds, the `SEED` env var,
`iterations`,
and the args this PR adds. See docs in `gpui::test`.

---

I also relaxed the limitation on `retries` not working with
`iterations`, as
that seemed unnecessary.

Release Notes:

- N/A
2025-03-14 13:40:02 -03:00
Danilo Leal
83dfdb0cfe assistant2: Add "running" status feedback in the disclosure (#26786)
Just a tiny bit of polish here, so that if the user expands the
disclosure, an equivalent loading state is at the response container.

<img
src="https://github.com/user-attachments/assets/a2ecb7f4-c9ea-4a14-8a60-9f7f2983a1a1"
width="600px" />

Release Notes:

- N/A
2025-03-14 12:31:26 -03:00
Kirill Bulatov
566c5f91a7 Refine word completions (#26779)
Follow-up of https://github.com/zed-industries/zed/pull/26410

* Extract word completions into their own, `editor::ShowWordCompletions`
action so those could be triggered independently of completions
* Assign `ctrl-shift-space` binding to this new action
* Still keep words returned along the completions as in the original PR,
but:
* Tone down regular completions' fallback logic, skip words when the
language server responds with empty list of completions, but keep on
adding words if nothing or an error were returned instead
    * Adjust the defaults to wait for LSP completions infinitely
* Skip "words" with digits such as `0_usize` or `2.f32` from completion
items, unless a completion query has digits in it

Release Notes:

- N/A
2025-03-14 15:18:55 +00:00
Danilo Leal
21057e3af7 assistant2: Refine thread design (#26783)
Just some light design polish while we're in-flight with this.

<img
src="https://github.com/user-attachments/assets/40a68fe6-f37e-4df1-b669-824c7dd8ff11"
width="600px" />

---

Release Notes:

- N/A
2025-03-14 12:09:24 -03:00
Antonio Scandurra
f68a475eca Introduce rating for assistant threads (#26780)
Release Notes:

- N/A

---------

Co-authored-by: Richard Feldman <oss@rtfeldman.com>
Co-authored-by: Agus Zubiaga <hi@aguz.me>
2025-03-14 14:41:50 +00:00
Smit Barmase
c62210b178 copilot: Handle sign out when copilot language server is not running (#26776)
When copilot is not being used as the edit prediction provider and you
open a fresh Zed instance, we don’t run the copilot language server.
This is because copilot chat is purely handled via oauth token and
doesn’t require the language server.

In this case, if you click sign out, instead of asking the language
server to sign out (which isn’t running), we can manually clear the
config directory, which contains the oauth tokens. We already watch this
directory, and if the token is not found, we update the sign-in status.

Release Notes:

- N/A
2025-03-14 19:41:27 +05:30
Danilo Leal
ad14dcc57b assistant2: Truncate thread title in context picker (#26775)
Similar issue as in https://github.com/zed-industries/zed/pull/26721.

Release Notes:

- N/A
2025-03-14 11:03:57 -03:00
Smit Barmase
b9432dbe42 macOS: Disable fullscreen window tabbing (take 2) (#26774)
Take 2 on https://github.com/zed-industries/zed/pull/26600. Now, it
doesn't break remote development.

Instead of using it in `build_classes`, it's now used in the `open`
method while creating a window. I found similar usage in other places
over internet.

Release Notes:

- Fixed issue where Zed would show mac native tabs when opening new
fullscreen windows on macOS.
2025-03-14 19:13:01 +05:30
Kamal Ahmad
41c373eff1 gpui: Add support for text in SVGs (#26335)
Closes #21319
Before: 

![image](https://github.com/user-attachments/assets/f75d7d59-75b1-4836-ae3b-6a1f526a5833)
After:

![image](https://github.com/user-attachments/assets/5fa28a6d-c417-4777-99f8-2a17edf759a0)

Use fontdb to load system fonts and pass it to resvg renderer. This adds
a small increase in startup time (around 30ms on my Linux system to
traverse fonts on a cold start). In the future once cosmic-text bumps
their version of fontdb we could clone the Database from
CosmicTextSystem

Release Notes: 
- Added: support for rendering text in SVGs
2025-03-14 08:25:11 -05:00
Smit Barmase
6a95ec6a64 copilot: Decouple copilot sign in from edit prediction settings (#26689)
Closes #25883

This PR allows you to use copilot chat for assistant without setting
copilot as the edit prediction provider.


[copilot.webm](https://github.com/user-attachments/assets/fecfbde1-d72c-4c0c-b080-a07671fb846e)

Todos:
- [x] Remove redudant "copilot" key from settings
- [x] Do not disable copilot LSP when `edit_prediction_provider` is not
set to `copilot`
- [x] Start copilot LSP when:
  - [x]  `edit_prediction_provider` is set to `copilot`
  - [x] Copilot sign in clicked from assistant settings
- [x] Handle flicker for frame after starting LSP, but before signing in
caused due to signed out status
- [x] Fixed this by adding intermediate state for awaiting signing in in
sign out enum
- [x] Handle cancel button should sign out from `copilot` (existing bug)
- [x] Handle modal dismissal should sign out if not in signed in state
(existing bug)

Release Notes:

- You can now sign into Copilot from assistant settings without making
it your edit prediction provider. This is useful if you want to use
Copilot chat while keeping a different provider, like Zed, for
predictions.
- Removed the `copilot` key from `features` in settings. Use
`edit_prediction_provider` instead.
2025-03-14 15:10:56 +05:30
Anthony Eid
8d7b021f92 Fix editor's outline view confirm not working before any queries have (#26761)
## Summary
This PR fixes a minor bug where editor's outline view wouldn't move the
cursor on confirm before any outline queries have been made.

### Before 

https://github.com/user-attachments/assets/6ccca0c1-c0fa-46cb-b700-28a666d62ce8

### After

https://github.com/user-attachments/assets/d508e20b-90fb-471a-b974-431205501c89

Release Notes:

- Fixes bug where editor's outline view wouldn't move cursor on confirm
action
2025-03-14 07:19:43 +00:00
Conrad Irwin
798a34bfc2 Show git toasts for 10s (#26714)
Release Notes:

- N/A
2025-03-13 22:51:07 -06:00
Conrad Irwin
a4a9f6bd07 Merge excerpts in project diff (#26739)
This adds code to merge excerpts when you expand them and they would
overlap. It is only enabled for callers who use the
`set_excerpts_for_path` API for multibuffers (which is currently just
project diff), as other users of multibuffer care too much about the
exact excerpts that they have.

Release Notes:

- N/A
2025-03-13 22:50:42 -06:00
Conrad Irwin
bfe4c40f73 Revert "Disable automatic window tabbing (cherry-pick #26600) (#26652)" (#26749)
This reverts commit 391eb380b5.

For some reason that is very unclear to me, this broke ssh'ing into
macOS remotes.
The remote process aborts with:

```
-------------------------------------
Translated Report (Full Report Below)
-------------------------------------

Process:               zed-remote-server-dev-build [78088]
Path:                  /Users/USER/*/zed-remote-server-dev-build
Identifier:            zed-remote-server-dev-build
Version:               ???
Code Type:             ARM-64 (Native)
Parent Process:        launchd [1]
Responsible:           iTerm2 [62245]
User ID:               501

Date/Time:             2025-03-13 19:30:37.6827 -0600
OS Version:            macOS 15.3.1 (24D70)
Report Version:        12
Anonymous UUID:        3A9631EB-5468-8CA4-7A0F-E36C3FF9D04F

Sleep/Wake UUID:       C935AE4C-E06A-4F6D-BE97-101E4E03482F

Time Awake Since Boot: 910000 seconds
Time Since Wake:       1265 seconds

System Integrity Protection: enabled

Crashed Thread:        0  Dispatch queue: com.apple.main-thread

Exception Type:        EXC_CRASH (SIGABRT)
Exception Codes:       0x0000000000000000, 0x0000000000000000

Termination Reason:    Namespace OBJC, Code 1 

Application Specific Information:
crashed on child side of fork pre-exec


Thread 0 Crashed::  Dispatch queue: com.apple.main-thread
0   libsystem_kernel.dylib        	       0x18653fc6c __abort_with_payload + 8
1   libsystem_kernel.dylib        	       0x186565eb8 abort_with_payload_wrapper_internal + 104
2   libsystem_kernel.dylib        	       0x186565e50 abort_with_reason + 32
3   libobjc.A.dylib               	       0x1861dc040 _objc_fatalv(unsigned long long, unsigned long long, char const*, char*) + 128
4   libobjc.A.dylib               	       0x1861dbfc0 _objc_fatal(char const*, ...) + 44
5   libobjc.A.dylib               	       0x1861c1674 performForkChildInitialize(objc_class*, objc_class*) + 400
6   libobjc.A.dylib               	       0x1861a67f0 initializeNonMetaClass + 592
7   libobjc.A.dylib               	       0x1861c4a3c initializeAndMaybeRelock(objc_class*, objc_object*, locker_mixin<lockdebug::lock_mixin<objc_lock_base_t>>&, bool) + 164
8   libobjc.A.dylib               	       0x1861a5f98 lookUpImpOrForward + 304
9   libobjc.A.dylib               	       0x1861a5b84 _objc_msgSend_uncached + 68
10  zed-remote-server-dev-build   	       0x104f9ec4c _$LT$$LP$$RP$$u20$as$u20$objc..message..MessageArguments$GT$::invoke::hf68c58806f4b5702 + 56
11  zed-remote-server-dev-build   	       0x104f9d4c8 objc::message::platform::send_unverified::h2ec8392957fd6551 + 120
12  zed-remote-server-dev-build   	       0x104e5631c cocoa::appkit::NSPasteboard::generalPasteboard::h68122d7f32549cba + 512
13  zed-remote-server-dev-build   	       0x104e3b3b4 gpui::platform::mac::platform::MacPlatform::new::hb68d7ae2c5fdea7e + 336
14  zed-remote-server-dev-build   	       0x104e48008 gpui::platform::current_platform::h931999673c8c6468 + 28
15  zed-remote-server-dev-build   	       0x104ee4284 gpui::app::Application::headless::h3bffec62c65240ce + 32
16  zed-remote-server-dev-build   	       0x1023746ac remote_server::unix::execute_run::h7ac8de1a7e257f61 + 1200
17  zed-remote-server-dev-build   	       0x102368e1c remote_server::main::h42e4b18462b32dcf + 252 (main.rs:56)
18  zed-remote-server-dev-build   	       0x10236717c core::ops::function::FnOnce::call_once::h8534244cea12c898 + 16 (function.rs:250)
19  zed-remote-server-dev-build   	       0x102368154 std::sys::backtrace::__rust_begin_short_backtrace::h22fd48e0f46eb10b + 12 (backtrace.rs:152)
20  zed-remote-server-dev-build   	       0x10236bf74 std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hf8bd0081bf8d785b + 16 (rt.rs:195)
21  zed-remote-server-dev-build   	       0x105723d20 std::rt::lang_start_internal::h5f91760815528aa2 + 1092
22  zed-remote-server-dev-build   	       0x10236bf50 std::rt::lang_start::hb88fe48ac1498ea6 + 60 (rt.rs:194)
23  zed-remote-server-dev-build   	       0x10236b67c main + 36
24  dyld                          	       0x1861f4274 start + 2840
```

Which is not even (apparently) on the line that calls this function.

To reproduce this, run `ZED_BUILD_REMOTE_SERVER=true cargo run
ssh://127.0.0.1/~/`.

Release Notes:

- N/A
2025-03-13 20:55:22 -06:00
Ben Kunkle
daa16bcf42 cli: Support opening anonymous file descriptors via the cli on MacOS and Linux (#26744)
Closes #4770

(really closes issue described in [this
comment](https://github.com/zed-industries/zed/issues/4770#issuecomment-2258728884)
on #4770)

Only implemented for MacOS and Linux for now as I have no way to test on
Windows or BSD.
PRs welcome!

Release Notes:

- Added support for reading from anonymous file descriptors (e.g.
created as part of process substitution) on MacOS and Linux
2025-03-13 20:53:47 -05:00
renovate[bot]
22ad7b17c5 Update Rust crate clap to v4.5.32 (#26592)
This PR contains the following updates:

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

---

### Release Notes

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

###
[`v4.5.32`](https://redirect.github.com/clap-rs/clap/blob/HEAD/CHANGELOG.md#4532---2025-03-10)

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

##### Features

-   Add `Error::remove`

##### Documentation

-   *(cookbook)* Switch from `humantime` to `jiff`
-   *(tutorial)* Better cover required vs optional

##### Internal

-   Update `pulldown-cmark`

</details>

---

### Configuration

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

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

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

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

---

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

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xOTQuMSIsInVwZGF0ZWRJblZlciI6IjM5LjIwMC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-13 23:36:04 +00:00
renovate[bot]
728a5eb388 Update Rust crate ctor to v0.4.1 (#26593)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [ctor](https://redirect.github.com/mmastrac/rust-ctor) |
workspace.dependencies | patch | `0.4.0` -> `0.4.1` |

---

### Configuration

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

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

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

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

---

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

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xOTQuMSIsInVwZGF0ZWRJblZlciI6IjM5LjIwMC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-14 01:17:43 +02:00
renovate[bot]
8d8e5d3635 Update Rust crate mdbook to v0.4.47 (#26611)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [mdbook](https://redirect.github.com/rust-lang/mdBook) | dependencies
| patch | `0.4.45` -> `0.4.47` |

---

### Release Notes

<details>
<summary>rust-lang/mdBook (mdbook)</summary>

###
[`v0.4.47`](https://redirect.github.com/rust-lang/mdBook/blob/HEAD/CHANGELOG.md#mdBook-0447)

[Compare
Source](https://redirect.github.com/rust-lang/mdBook/compare/v0.4.46...v0.4.47)


[v0.4.46...v0.4.47](https://redirect.github.com/rust-lang/mdBook/compare/v0.4.46...v0.4.47)

##### Fixed

-   Fixed search not showing up in sub-directories.
[#&#8203;2586](https://redirect.github.com/rust-lang/mdBook/pull/2586)

###
[`v0.4.46`](https://redirect.github.com/rust-lang/mdBook/blob/HEAD/CHANGELOG.md#mdBook-0446)

[Compare
Source](https://redirect.github.com/rust-lang/mdBook/compare/v0.4.45...v0.4.46)


[v0.4.45...v0.4.46](https://redirect.github.com/rust-lang/mdBook/compare/v0.4.45...v0.4.46)

##### Changed

- The `output.html.hash-files` config option has been added to add
hashes to static filenames to bust any caches when a book is updated.
`{{resource}}` template tags have been added so that links can be
properly generated to those files.
[#&#8203;1368](https://redirect.github.com/rust-lang/mdBook/pull/1368)

##### Fixed

-   Playground links for Rust 2024 now set the edition correctly.
[#&#8203;2557](https://redirect.github.com/rust-lang/mdBook/pull/2557)

</details>

---

### Configuration

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

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

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

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

---

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

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xOTQuMSIsInVwZGF0ZWRJblZlciI6IjM5LjIwMC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-14 01:17:26 +02:00
renovate[bot]
a05a480ed9 Update Rust crate rsa to v0.9.8 (#26619)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [rsa](https://redirect.github.com/RustCrypto/RSA) |
workspace.dependencies | patch | `0.9.7` -> `0.9.8` |

---

### Release Notes

<details>
<summary>RustCrypto/RSA (rsa)</summary>

###
[`v0.9.8`](https://redirect.github.com/RustCrypto/RSA/blob/HEAD/CHANGELOG.md#098-2025-03-12)

[Compare
Source](https://redirect.github.com/RustCrypto/RSA/compare/v0.9.7...v0.9.8)

##### Added

-   Doc comments to specify the `rand` version ([#&#8203;473])

[#&#8203;473]: https://redirect.github.com/RustCrypto/RSA/pull/473

</details>

---

### Configuration

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

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

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

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

---

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

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xOTQuMSIsInVwZGF0ZWRJblZlciI6IjM5LjIwMC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-14 01:17:14 +02:00
renovate[bot]
d141fa027e Update Rust crate schemars to v0.8.22 (#26626)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [schemars](https://graham.cool/schemars/)
([source](https://redirect.github.com/GREsau/schemars)) |
workspace.dependencies | patch | `0.8.21` -> `0.8.22` |

---

### Release Notes

<details>
<summary>GREsau/schemars (schemars)</summary>

###
[`v0.8.22`](https://redirect.github.com/GREsau/schemars/blob/HEAD/CHANGELOG.md#0822---2025-02-25)

[Compare
Source](https://redirect.github.com/GREsau/schemars/compare/v0.8.21...v0.8.22)

##### Fixed:

- Fix compatibility with rust 2024 edition
([https://github.com/GREsau/schemars/pull/378](https://redirect.github.com/GREsau/schemars/pull/378))

</details>

---

### Configuration

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

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

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

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

---

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

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xOTQuMSIsInVwZGF0ZWRJblZlciI6IjM5LjIwMC4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-14 01:16:57 +02:00
Michael Sloan
8e0e291bd5 Track cumulative token usage in assistant2 when using anthropic API (#26738)
Release Notes:

- N/A
2025-03-13 22:56:16 +00:00
Conrad Irwin
e3c0f56a96 New excerpt controls (#24428)
Release Notes:

- Multibuffers now use less vertical space for excerpt boundaries.
Additionally the expand up/down arrows are hidden at the start and end
of the buffers

---------

Co-authored-by: Nate Butler <iamnbutler@gmail.com>
Co-authored-by: Zed AI <claude-3.5-sonnet@zed.dev>
2025-03-13 15:52:47 -06:00
Conrad Irwin
3935e8343a Allow parsing commits when we can't resolve the permalink (#26709)
Closes #26577

Release Notes:

- git: Fix showing commit messages for all repos
2025-03-13 15:41:08 -06:00
renovate[bot]
0c84170071 Update Rust crate quote to v1.0.40 (#26618)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [quote](https://redirect.github.com/dtolnay/quote) |
workspace.dependencies | patch | `1.0.38` -> `1.0.40` |

---

### Release Notes

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

###
[`v1.0.40`](https://redirect.github.com/dtolnay/quote/releases/tag/1.0.40)

[Compare
Source](https://redirect.github.com/dtolnay/quote/compare/1.0.39...1.0.40)

- Optimize construction of lifetime tokens
([#&#8203;293](https://redirect.github.com/dtolnay/quote/issues/293),
thanks [@&#8203;aatifsyed](https://redirect.github.com/aatifsyed))

###
[`v1.0.39`](https://redirect.github.com/dtolnay/quote/releases/tag/1.0.39)

[Compare
Source](https://redirect.github.com/dtolnay/quote/compare/1.0.38...1.0.39)

-   Documentation improvements

</details>

---

### Configuration

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

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

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

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

---

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

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xOTQuMSIsInVwZGF0ZWRJblZlciI6IjM5LjE5NC4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-13 23:14:13 +02:00
renovate[bot]
a38687d278 Update Rust crate libc to v0.2.171 (#26604)
This PR contains the following updates:

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

---

### Release Notes

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

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

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

##### Added

- Android: Add `if_nameindex`/`if_freenameindex` support
([#&#8203;4247](https://redirect.github.com/rust-lang/libc/pull/4247))
- Apple: Add missing proc types and constants
([#&#8203;4310](https://redirect.github.com/rust-lang/libc/pull/4310))
- BSD: Add `devname`
([#&#8203;4285](https://redirect.github.com/rust-lang/libc/pull/4285))
- Cygwin: Add PTY and group API
([#&#8203;4309](https://redirect.github.com/rust-lang/libc/pull/4309))
- Cygwin: Add support
([#&#8203;4279](https://redirect.github.com/rust-lang/libc/pull/4279))
- FreeBSD: Make `spawn.h` interfaces available on all FreeBSD-like
systems
([#&#8203;4294](https://redirect.github.com/rust-lang/libc/pull/4294))
- Linux: Add `AF_XDP` structs for all Linux environments
([#&#8203;4163](https://redirect.github.com/rust-lang/libc/pull/4163))
- Linux: Add SysV semaphore constants
([#&#8203;4286](https://redirect.github.com/rust-lang/libc/pull/4286))
- Linux: Add `F_SEAL_EXEC`
([#&#8203;4316](https://redirect.github.com/rust-lang/libc/pull/4316))
- Linux: Add `SO_PREFER_BUSY_POLL` and `SO_BUSY_POLL_BUDGET`
([#&#8203;3917](https://redirect.github.com/rust-lang/libc/pull/3917))
- Linux: Add `devmem` structs
([#&#8203;4299](https://redirect.github.com/rust-lang/libc/pull/4299))
- Linux: Add socket constants up to `SO_DEVMEM_DONTNEED`
([#&#8203;4299](https://redirect.github.com/rust-lang/libc/pull/4299))
- NetBSD, OpenBSD, DragonflyBSD: Add `closefrom`
([#&#8203;4290](https://redirect.github.com/rust-lang/libc/pull/4290))
- NuttX: Add `pw_passwd` field to `passwd`
([#&#8203;4222](https://redirect.github.com/rust-lang/libc/pull/4222))
- Solarish: define `IP_BOUND_IF` and `IPV6_BOUND_IF`
([#&#8203;4287](https://redirect.github.com/rust-lang/libc/pull/4287))
- Wali: Add bindings for `wasm32-wali-linux-musl` target
([#&#8203;4244](https://redirect.github.com/rust-lang/libc/pull/4244))

##### Changed

- AIX: Use `sa_sigaction` instead of a union
([#&#8203;4250](https://redirect.github.com/rust-lang/libc/pull/4250))
- Make `msqid_ds.__msg_cbytes` public
([#&#8203;4301](https://redirect.github.com/rust-lang/libc/pull/4301))
- Unix: Make all `major`, `minor`, `makedev` into `const fn`
([#&#8203;4208](https://redirect.github.com/rust-lang/libc/pull/4208))

##### Deprecated

- Linux: Deprecate obsolete packet filter interfaces
([#&#8203;4267](https://redirect.github.com/rust-lang/libc/pull/4267))

##### Fixed

- Cygwin: Fix strerror_r
([#&#8203;4308](https://redirect.github.com/rust-lang/libc/pull/4308))
- Cygwin: Fix usage of f!
([#&#8203;4308](https://redirect.github.com/rust-lang/libc/pull/4308))
- Hermit: Make `stat::st_size` signed
([#&#8203;4298](https://redirect.github.com/rust-lang/libc/pull/4298))
- Linux: Correct values for `SI_TIMER`, `SI_MESGQ`, `SI_ASYNCIO`
([#&#8203;4292](https://redirect.github.com/rust-lang/libc/pull/4292))
- NuttX: Update `tm_zone` and `d_name` fields to use `c_char` type
([#&#8203;4222](https://redirect.github.com/rust-lang/libc/pull/4222))
- Xous: Include the prelude to define `c_int`
([#&#8203;4304](https://redirect.github.com/rust-lang/libc/pull/4304))

##### Other

- Add labels to FIXMEs
([#&#8203;4231](https://redirect.github.com/rust-lang/libc/pull/4231),
[#&#8203;4232](https://redirect.github.com/rust-lang/libc/pull/4232),
[#&#8203;4234](https://redirect.github.com/rust-lang/libc/pull/4234),
[#&#8203;4235](https://redirect.github.com/rust-lang/libc/pull/4235),
[#&#8203;4236](https://redirect.github.com/rust-lang/libc/pull/4236))
- CI: Fix "cannot find libc" error on Sparc64
([#&#8203;4317](https://redirect.github.com/rust-lang/libc/pull/4317))
- CI: Fix "cannot find libc" error on s390x
([#&#8203;4317](https://redirect.github.com/rust-lang/libc/pull/4317))
- CI: Pass `--no-self-update` to `rustup update`
([#&#8203;4306](https://redirect.github.com/rust-lang/libc/pull/4306))
- CI: Remove tests for the `i586-pc-windows-msvc` target
([#&#8203;4311](https://redirect.github.com/rust-lang/libc/pull/4311))
- CI: Remove the `check_cfg` job
([#&#8203;4322](https://redirect.github.com/rust-lang/libc/pull/4312))
- Change the range syntax that is giving `ctest` problems
([#&#8203;4311](https://redirect.github.com/rust-lang/libc/pull/4311))
- Linux: Split out the stat struct for gnu/b32/mips
([#&#8203;4276](https://redirect.github.com/rust-lang/libc/pull/4276))

##### Removed

- NuttX: Remove `pthread_set_name_np`
([#&#8203;4251](https://redirect.github.com/rust-lang/libc/pull/4251))

</details>

---

### Configuration

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

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

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

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

---

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

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xOTQuMSIsInVwZGF0ZWRJblZlciI6IjM5LjE5NC4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-13 23:13:58 +02:00
renovate[bot]
b75b308459 Update Rust crate env_logger to v0.11.7 (#26603)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [env_logger](https://redirect.github.com/rust-cli/env_logger) |
workspace.dependencies | patch | `0.11.6` -> `0.11.7` |

---

### Release Notes

<details>
<summary>rust-cli/env_logger (env_logger)</summary>

###
[`v0.11.7`](https://redirect.github.com/rust-cli/env_logger/blob/HEAD/CHANGELOG.md#0117---2025-03-10)

[Compare
Source](https://redirect.github.com/rust-cli/env_logger/compare/v0.11.6...v0.11.7)

##### Internal

-   Replaced `humantime` with `jiff`

</details>

---

### Configuration

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

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

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

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

---

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

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xOTQuMSIsInVwZGF0ZWRJblZlciI6IjM5LjE5NC4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-13 23:13:43 +02:00
Cole Miller
dffa725c7d 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 21:09:16 +00:00
Marshall Bowers
22f1429f97 assistant2: Prevent sending messages when the button is disabled (#26722)
This PR updates the `Chat` action handler to prevent sending messages in
the states when the submit button is disabled.

Release Notes:

- N/A
2025-03-13 20:49:21 +00:00
KyleBarton
6bdd2cf7db Consider the colon to be a word character when inside a string in JSON (#26574)
Partially addresses #25698

Part of why autocomplete suggestions for `keymap.json` aren't great is
because `:` is (correctly) considered a punctuation character, rather
than a word character, in JSON. But since `::` is part of the name of
zed commands, it means that the autocomplete context window loses
context after the user types colon:

Suggestion here is to use overrides for JSON and JSONC such that colon
is considered a word character when it's inside a string. This improves
the experience:

I believe this is more broadly correct anyway, since `:` loses it's
punctuation meaning when inside a string.

Hope this is helpful!

Release Notes:

- Improved autocomplete for keymap.json by treating `::` like word characters when inside a string.
2025-03-13 16:21:34 -04:00
Cole Miller
a7f3b22051 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
2025-03-13 16:17:23 -04:00
Cole Miller
f3703fa8be 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.
2025-03-13 16:14:28 -04:00
Marshall Bowers
a0be6c8cb2 assistant2: Consider tool use as part of the "streaming" state (#26723)
This PR updates the `Thread::is_streaming` method so that it includes
tool use in the "streaming" state.

This will prevent the streaming indicator from disappearing when we're
doing tool use.

Release Notes:

- N/A
2025-03-13 20:11:44 +00:00
Cole Miller
b5a7fb13c3 Remove github issue template for git beta and improve related CI (#26707)
Remove the git beta issue template.
Improve ci.yml `job_spec` so that changes like this will not require CI in the future.
Improve ci.yml `job_spec` ensuring `output.run_license` exported for Cargo.lock.

Release Notes:

- N/A

---------

Co-authored-by: Peter Tripp <peter@zed.dev>
2025-03-13 16:07:32 -04:00
Danilo Leal
2183fc674d assistant2: Truncate context pill labels (#26721)
To solve a problem that mostly happens if the pill is of kind `Thread`
and the corresponding thread has a super long title.

<img
src="https://github.com/user-attachments/assets/4ee8038d-9467-41a9-9b30-76019d0b9c0b"
width="500px"/>

Release Notes:

- N/A
2025-03-13 16:56:49 -03:00
renovate[bot]
0ad5979f19 Update Rust crate proc-macro2 to v1.0.94 (#26612)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [proc-macro2](https://redirect.github.com/dtolnay/proc-macro2) |
workspace.dependencies | patch | `1.0.93` -> `1.0.94` |

---

### Release Notes

<details>
<summary>dtolnay/proc-macro2 (proc-macro2)</summary>

###
[`v1.0.94`](https://redirect.github.com/dtolnay/proc-macro2/releases/tag/1.0.94)

[Compare
Source](https://redirect.github.com/dtolnay/proc-macro2/compare/1.0.93...1.0.94)

-   Documentation improvements

</details>

---

### Configuration

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

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

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

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

---

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

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xOTQuMSIsInVwZGF0ZWRJblZlciI6IjM5LjE5NC4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-13 15:38:02 -04:00
Peter Tripp
ed1938dd9a 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:16:30 -04:00
Peter Tripp
f7927d3fa4 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 19:02:59 +00:00
Conrad Irwin
8361c32a34 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
2025-03-13 18:49:18 +00:00
Agus Zubiaga
2edadd9352 bash tool: Rename working_directory to cd and improve command wrap (#26702)
This helps its do the right thing

Release Notes:

- N/A

Co-authored-by: Antonio Scandurra <me@as-cii.com>
2025-03-13 18:29:25 +00:00
Joseph T. Lyons
85384fb9c6 Update issue response script to only consider replies from staff (#26703)
Release Notes:

- N/A

Co-authored-by: Ben Kunkle <ben.kunkle@gmail.com>
2025-03-13 14:15:38 -04:00
João Marcos
00359271d1 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: Cole <cole@zed.dev>
Co-authored-by: Max <max@zed.dev>
2025-03-13 10:41:04 -07:00
Ben Kunkle
18fcdf1d2c terminal: Fix issues with highlighted ranges of paths (#26695)
Fixes a few problems,

- Uses `Boundary::Grid` instead of `Boundary::Cursor` for highlighted
range adjustments.

This fixes quite a few wierd behaviors around highlighting paths that
had to be scrolled into view (i.e. were in the terminal history)
including the issue described in the release notes as well as a
regression caused by #26401 where the highlight range would span from
the start of the path to the cursor location in the shell prompt

- Strips all trailing `:`s from the paths, updating the highlighted
range accordingly.

This worked fine before and is just a visual improvement.


Release Notes:

- Fixed an issue where file paths in the terminal surrounded by `()` or
`[]` would not be highlighted properly
2025-03-13 12:25:20 -05:00
renovate[bot]
55c927b039 Update Rust crate async-trait to v0.1.87 (#26578)
This PR contains the following updates:

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

---

### Release Notes

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

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

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

-   Documentation improvements

</details>

---

### Configuration

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

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

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

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

---

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

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xOTQuMSIsInVwZGF0ZWRJblZlciI6IjM5LjE5NC4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Marshall Bowers <git@maxdeviant.com>
2025-03-13 17:07:01 +00:00
Marshall Bowers
1be3f81920 assistant2: Include the thread summary in the Markdown representation (#26693)
This PR adds the thread's summary (if it has one) as a heading in the
Markdown representation.

Release Notes:

- N/A
2025-03-13 16:59:35 +00:00
Cole Miller
2eb4d6b7eb 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>
2025-03-13 16:56:54 +00:00
Ben Kunkle
25f407baab settings: Auto-update JSON schemas for settings when extensions are un/installed (#26633)
Because of #26562, it is now possible to subscribe to extension update
events within the LSP store, where we can then update the Schemas sent
to the JSON LSP resulting in dynamic updates to the auto-complete
suggestions and diagnostics in settings. Notably, this means newly
installed languages and (icon) themes will auto-complete correctly as
soon as the extension is installed.

Closes #15436

Release Notes:

- Fixed an issue where autocomplete suggestions and diagnostics for
languages and (icon) themes in settings would not update when the
extension with which they were added was installed or uninstalled
2025-03-13 16:50:07 +00:00
Marshall Bowers
79874872cb assistant2: Add ability to open the active thread as Markdown (#26690)
This PR adds a new `assistant2: open active thread as markdown` action
that opens up the active thread in a Markdown representation:

<img width="1394" alt="Screenshot 2025-03-13 at 12 25 33 PM"
src="https://github.com/user-attachments/assets/363baaaa-c74b-4e93-af36-a3e04a114af0"
/>

Release Notes:

- N/A
2025-03-13 12:39:01 -04:00
Marshall Bowers
95208a6576 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:06:44 -04:00
Danilo Leal
1034d1a6b5 docs: Add section about Edit Prediction modes (#26683)
To go along the upcoming blog post as well as the new menu item options
(https://github.com/zed-industries/zed/pull/26680).

Release Notes:

- N/A
2025-03-13 12:48:39 -03:00
Danilo Leal
d4eab557b2 edit prediction: Add eager and subtle modes toggle to menu (#26680)
Now, users can toggle the display modes for Edit Prediction via the UI.

<img
src="https://github.com/user-attachments/assets/974cd3cc-43b4-46ba-9ce5-b2345ef3323d"
width="600px"/>

Release Notes:

- N/A
2025-03-13 12:46:22 -03:00
Nate Butler
b75964a636 Revert "ui: Color cleanup (#26673)" (#26681)
This reverts commit 6767e98e00.

Somehow that PR automerged itself even with failed CI checks.

Release Notes:

- N/A
2025-03-13 15:40:57 +00:00
Peter Tripp
87cdb68cca 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 15:39:12 +00:00
Kirill Bulatov
b0b65420f6 Do not repeat proposed LSP completions in the word completions (#26682)
Follow-up of https://github.com/zed-industries/zed/pull/26410

Release Notes:

- N/A
2025-03-13 15:37:46 +00:00
Agus Zubiaga
8ec0309645 assistant edit tool: Use buffer search and replace in background (#26679)
Instead of getting the whole text from the buffer, replacing with
`String::replace`, and getting a whole diff, we'll now use `SearchQuery`
to get a range, diff only that range, and apply it (all in the
background).

When we match zero strings, we'll record a "bad search", keep going and
report it to the model at the end.

Release Notes:

- N/A

---------

Co-authored-by: Max <max@zed.dev>
2025-03-13 12:25:49 -03:00
Nate Butler
6767e98e00 ui: Color cleanup (#26673)
This PR cleans up some color & elevation misc.

### Don't allow deriving Color from Hsla

The point of the [ui::Color] enum is to encourage consistent color
usage, and the the Color::Custom case is really only meant for cases
where we have no other choice.

`impl From<Hsla> for Color` encourages blindly passing colors into
`Color::Custom` – with this in place we might as well remove the entire
`Color` enum.

The usages that were updated due to this removal were for colors that
already exist in the Color enum, making it even more clear that it
didn't make sense to have this.

### `ElevationIndex` -> `Elevation`

This name would make more sense if we had an `Elevation` in the first
place. The new name is more clear.

#### `Button::elevation`

As part of this change I also updated button's `layer` method to
`elevation`, since it takes an elevation. This method still has the
following issue:

You want to use `Button::elevation` when it's default colors are
invisible on the layer you are rendering the button on. However, current
this method uses the elevation's `bg` color, rather than it's
`on_elevation_bg`.

Ideally when you use `Button::elevation` you want to pass the elevation
you are _on_, not choosing one that will show up the elevation you are
on.

This change will be in a separate PR, as it likely will have widespread
visual impact across the app.

Release Notes:

- N/A
2025-03-13 15:18:40 +00:00
Antonio Scandurra
8cf5af1a84 Introduce DiagnosticsTool (#26670)
Release Notes:

- N/A
2025-03-13 14:53:00 +01:00
Albin Kocheril Chacko
247ee880d2 Fix typo in default.json (#26666)
minor typo fix

Release Notes:

- N/A
2025-03-13 13:39:28 +00:00
Nate Butler
2e217759c0 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 13:13:35 +00:00
Danilo Leal
0a0c163692 assistant2: Use icons for tool call status communication (#26617)
It was hard to catch the running & pending states, though. When running,
it will appear as a spinning arrow circle icon.

<img
src="https://github.com/user-attachments/assets/dbf1bc0a-6fa3-41c6-bcd7-2226e89c87b4"
width="500px" />

Release Notes:

- N/A
2025-03-13 10:01:20 -03:00
Antonio Scandurra
e80df25386 Iterate on tools some more (#26663)
Release Notes:

- N/A
2025-03-13 12:42:02 +00:00
Danilo Leal
d9590f3f0e docs: Improve introduction to Edit Prediction (#26620)
As I was writing a blog post about Edit Prediction, I realized we didn't
have a great section in the docs I could link to talking about
configuring it. We weren't: 1) explicitly exposing the settings code to
add Zed as the edit prediction provider, and 2) not showing an image of
the title bar banner.

Release Notes:

- N/A
2025-03-13 09:03:49 -03:00
Antonio Scandurra
4ecd1b5174 Fix bad cd sometimes used by BashTool and set edit model temperature to 0 (#26656)
Release Notes:

- N/A
2025-03-13 10:47:00 +00:00
Antonio Scandurra
70c973f6c3 Fix issues in EditFilesTool, ListDirectoryTool and BashTool (#26647)
Release Notes:

- N/A
2025-03-13 09:41:27 +00:00
Stanislav Alekseev
e842b4eade macOS: Disable automatic window tabbing in fullscreen mode (#26600)
Fixes #26534 (this time for real)

Release Notes:

- Fixed issue where Zed would behave weirdly when opening new fullscreen
windows by disabling window tabbing

Apple docs:
https://developer.apple.com/documentation/appkit/nswindow/allowsautomaticwindowtabbing
2025-03-13 12:45:01 +05:30
Agus Zubiaga
606aa7a78c Edit tool debugging (#26637)
Adds an `debug: edit tool` action that opens a new view which will help
us debug the edit tool internals. As the edit tool runs, the log
displays:

- Instructions provided by the main model
- Response stream from the editor model
- Parsed edit blocks
- Tool output provided back to main model

The log automatically records all edit tool interactions for staff, so
if you notice something weird, you can debug it retroactively without
having to open the debug tool first. We may want to limit the number of
recorded requests later.

I have a few more ideas for it, but this seems like a good starting
point.


https://github.com/user-attachments/assets/c61f5ce8-08b1-4500-accb-db2a480eb3ab


Release Notes:

- N/A
2025-03-13 04:03:01 +00:00
Mikayla Maki
0081b816fe Fix a bug where the modal layer could not be dismissed by the mouse 2025-03-12 16:44:16 -07:00
Peter Tripp
21949bcf1a 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:16:23 -04:00
renovate[bot]
ee7ed6d5b8 Update Rust crate anyhow to v1.0.97 (#26576)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [anyhow](https://redirect.github.com/dtolnay/anyhow) |
workspace.dependencies | patch | `1.0.96` -> `1.0.97` |

---

### Release Notes

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

###
[`v1.0.97`](https://redirect.github.com/dtolnay/anyhow/releases/tag/1.0.97)

[Compare
Source](https://redirect.github.com/dtolnay/anyhow/compare/1.0.96...1.0.97)

-   Documentation improvements

</details>

---

### Configuration

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

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

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

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

---

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

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xOTQuMSIsInVwZGF0ZWRJblZlciI6IjM5LjE5NC4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Marshall Bowers <git@maxdeviant.com>
2025-03-12 23:01:04 +00:00
Marshall Bowers
07b67c1bd3 assistant2: Add ability to enable/disable all tools from a context server (#26610)
This PR adds an option to enable/disable all tools from a specific
context server:

<img width="1297" alt="Screenshot 2025-03-12 at 5 55 45 PM"
src="https://github.com/user-attachments/assets/af6c169e-0462-4a99-9bec-48fbf83dd08a"
/>

Release Notes:

- N/A
2025-03-12 22:14:31 +00:00
Mikayla Maki
f116b44ae8 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:12:42 +00:00
Nate Butler
43ab7fe0e2 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.
2025-03-12 22:07:04 +00:00
Richard Feldman
6044773043 Add path search glob tool (#26567)
<img width="638" alt="Screenshot 2025-03-12 at 1 33 31 PM"
src="https://github.com/user-attachments/assets/f29b9dae-59eb-4d7a-bc26-aa4721cb829a"
/>

Release Notes:

- N/A
2025-03-12 22:00:54 +00:00
Conrad Irwin
81af2c0bed Fix overflow in create branch label (#26591)
Closes #ISSUE

Release Notes:

- N/A
2025-03-12 21:55:31 +00:00
Peter Tripp
ab199fda47 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:32:38 -04:00
Marshall Bowers
e60e8f3a0a assistant_tool: Reduce locking in ToolWorkingSet (#26605)
This PR updates the `ToolWorkingSet` to reduce the amount of locking we
need to do.

A number of the methods have had corresponding versions moved to the
`ToolWorkingSetState` so that we can take out the lock once and do a
number of operations without needing to continually acquire and release
the lock.

Release Notes:

- N/A
2025-03-12 21:26:26 +00:00
brian tan
edeed7b619 workspace::Open: Highlight fuzzy matches (#26320)
Partial: https://github.com/zed-industries/zed/issues/15398

Changes:
Adds highlighting to the matches when using `"use_system_path_prompts":
false`

| before | after |
|---|---|

|![image](https://github.com/user-attachments/assets/60a385a0-abb0-49c5-935c-e71149161562)|![image](https://github.com/user-attachments/assets/d66ce980-cea9-4c22-8e6a-9720344be39a)|

Release Notes:

- N/A
2025-03-12 22:54:38 +02:00
Richard Feldman
9be7934f12 Add Bash tool (#26597)
<img width="636" alt="Screenshot 2025-03-12 at 4 24 18 PM"
src="https://github.com/user-attachments/assets/6f317031-f495-4a5a-8260-79a56b10d628"
/>

<img width="634" alt="Screenshot 2025-03-12 at 4 24 36 PM"
src="https://github.com/user-attachments/assets/27283432-4f94-49f3-9d61-a0a9c737de40"
/>


Release Notes:

- N/A
2025-03-12 20:51:29 +00:00
Peter Tripp
009b90291e Fix formatting in linux.md (#26598)
Merge queue did not require docs tests to pass:
-
https://github.com/zed-industries/zed/actions/runs/13820880465/job/38665664419

This will be fixed with:
- https://github.com/zed-industries/zed/pull/26551

cc: @ConradIrwin 

Release Notes:

- N/A
2025-03-12 16:33:11 -04:00
Michael Kaplan
8b17dc66f6 docs: Document linker issue & workarounds with GCC >= 14 (#26579)
Closes #24880

documents issues with aws-lc-rs and gcc >=14 on linux and provides a
workaround until the issues are fixed in aws-lc-rs
2025-03-12 20:26:08 +00:00
Conrad Irwin
de07b712fd Fix message on push (#26588)
Instead of saying "Successfully pushed new branch" we say "Pushed x to
y"

Release Notes:

- N/A
2025-03-12 20:18:28 +00:00
Richard Feldman
be8f3b3791 Add delete-path tool (#26590)
Release Notes:

- N/A
2025-03-12 20:16:26 +00:00
Richard Feldman
3131b0459f Return which files were touched in the edit tool (#26564)
<img width="631" alt="Screenshot 2025-03-12 at 12 56 43 PM"
src="https://github.com/user-attachments/assets/9ab84a53-829a-4943-ae76-b1d97ee31f55"
/>

<img width="908" alt="Screenshot 2025-03-12 at 12 57 12 PM"
src="https://github.com/user-attachments/assets/bd246231-6c92-4266-b61e-5293adfe2ba0"
/>

Release Notes:

- N/A
2025-03-12 15:56:23 -04:00
Marshall Bowers
3ec323ce0d uiua: Extract to zed-extensions/uiua repository (#26587)
This PR extracts the Uiua extension to the
[zed-extensions/uiua](https://github.com/zed-extensions/uiua)
repository.

Release Notes:

- N/A
2025-03-12 19:55:37 +00:00
Conrad Irwin
c8b782d870 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 13:48:13 -06:00
Conrad Irwin
7bca15704b 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>
2025-03-12 19:39:30 +00:00
Kirill Bulatov
5268e74315 Properly handle goto single file worktrees during terminal cmd-clicks (#26582)
Closes https://github.com/zed-industries/zed/issues/26431
Follow-up of https://github.com/zed-industries/zed/pull/26174

`path_with_position.path.strip_prefix(&worktree_root)` used in the PR is
wrong for cases of single-file worktrees, where it will return empty
paths that will result in incorrect project and FS entries accessed.

Release Notes:

- Fixed goto single file worktrees during terminal cmd-clicks
2025-03-12 19:38:21 +00:00
Kirill Bulatov
91c209900b Support word-based completions (#26410)
Closes https://github.com/zed-industries/zed/issues/4957


https://github.com/user-attachments/assets/ff491378-376d-48ec-b552-6cc80f74200b

Adds `"completions"` language settings section, to configure LSP and
word completions per language.
Word-based completions may be turned on never, always (returned along
with the LSP ones), and as a fallback if no LSP completion items were
returned.

Future work:

* words are matched with the same fuzzy matching code that the rest of
the completions are

This might worsen the completion menu's usability even more, and will
require work on better completion sorting.

* completion entries currently have no icons or other ways to indicate
those are coming from LSP or from word search, or from something else

* we may work with language scopes more intelligently, group words by
them and distinguish during completions

Release Notes:

- Supported word-based completions

---------

Co-authored-by: Max Brunsfeld <max@zed.dev>
2025-03-12 21:27:10 +02:00
Anthony Eid
74c29f1818 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>
2025-03-12 19:07:51 +00:00
Marshall Bowers
5858e61327 purescript: Extract to zed-extensions/purescript repository (#26571)
This PR extracts the PureScript extension to the
[zed-extensions/purescript](https://github.com/zed-extensions/purescript)
repository.

Release Notes:

- N/A
2025-03-12 18:42:12 +00:00
Martim Aires de Sousa
21cf2e38c5 Fix pane magnification causing mouse to drag tabs unexpectedly (#26383)
Previously, if a user clicked a button and moved the cursor out before
releasing, the click event was correctly prevented, but the pending
mouse-down state remained.
This caused unintended drags when the UI shifted due to magnification
settings.

Now, mouse-up clears the pending state:
- If over the button → clear state and trigger click handlers.
- If outside the button → clear state without triggering a click.

This avoids accidental drags while preserving expected click behavior.

Closes #24600

Release Notes:

- N/A

---------

Co-authored-by: Ben Kunkle <ben@zed.dev>
2025-03-12 13:32:42 -05:00
Marshall Bowers
a3ca5554fd zig: Extract to zed-extensions/zig repository (#26569)
This PR extracts the Zig extension to the
[zed-extensions/zig](https://github.com/zed-extensions/zig) repository.

Release Notes:

- N/A
2025-03-12 18:28:26 +00:00
Marshall Bowers
acf9b22466 extension: Add ExtensionEvents for listening to extension-related events (#26562)
This PR adds a new `ExtensionEvents` event bus that can be used to
listen for extension-related events throughout the app.

Today you need to have a handle to the `ExtensionStore` (which entails
depending on `extension_host`) in order to listen for extension events.

With this change subscribers only need to depend on `extension`, which
has a leaner dependency graph.

Release Notes:

- N/A
2025-03-12 17:01:52 +00:00
Joseph T. Lyons
ffcd023f83 Bump Zed to v0.179 (#26563)
Release Notes:

-N/A
2025-03-12 12:53:37 -04:00
Antonio Scandurra
6259ad559b Add RegexSearchTool (#26555)
Release Notes:

- N/A
2025-03-12 16:23:15 +00:00
Nate Butler
8d259a9dbe 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:21:47 -04:00
Danilo Leal
010c5a2c4e 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 09:20:39 -07:00
Mikayla Maki
45b126a977 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 16:17:47 +00:00
Agus Zubiaga
5f74297576 Fix edit tool tests on windows (#26552)
Assertions on the parsed system prompt should use CRLF on Windows. I
didn't see it before because I was testing on my Windows VM from a
shared folder I cloned on macOS.

Release Notes:

- N/A
2025-03-12 15:52:51 +00:00
Antonio Scandurra
349f57381f Add ListDirectoryTool (#26549)
Release Notes:

- N/A
2025-03-12 15:17:12 +00:00
Antonio Scandurra
41eb586ec8 Remove list_worktrees and use relative paths instead (#26546)
Release Notes:

- N/A
2025-03-12 15:06:04 +00:00
Smit Barmase
6bf6fcaa51 macOS: Fix window turning black on fullscreen mode (#26547)
Closes #26534

Recently, we fixed a title bar transparency issue that only occurred on
macOS 15.3 and later. PR:
https://github.com/zed-industries/zed/pull/26403

However, this seems to have broken multi-window fullscreen behavior on
earlier macOS versions. This PR adds versioning so that the title bar
transparency fix only applies to macOS 15.3.0 and later.

No release notes, as this bug only exists on main right now.  

Release Notes:

- N/A

Co-authored-by: MrSubidubi <dev@bahn.sh>
2025-03-12 20:29:27 +05:30
Marshall Bowers
6e89537830 assistant2: Add an option to enable/disable all tools (#26544)
This PR adds an option to enable or disable all tools in the tool
selector.

<img width="1297" alt="Screenshot 2025-03-12 at 10 40 28 AM"
src="https://github.com/user-attachments/assets/9125bdfb-5b54-461c-a065-2882a8585a67"
/>

Release Notes:

- N/A
2025-03-12 14:53:38 +00:00
Agus Zubiaga
669c6a3d5e assistant edit tool: Do not include \r in old/new str (#26542)
#26538 fixed part of the issue, but it would keep trailing carriage
returns in the old/new strings. The model is unlikely to produce those,
but we might as well support them.

Release Notes:

- N/A
2025-03-12 11:34:40 -03:00
Nils Koch
910531bc33 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:25:31 -04:00
Kirill Bulatov
690f26cf8b Disable clangd's inactiveRegions support (#26539)
Disables https://github.com/zed-industries/zed/pull/26146 until a better
way to add diagnostics is found.
Overall, the PR had made changes that are worth keeping instead of
reverting, such as finally extracting out r-a's language server logic
into an `_ext.rs` file.

Release Notes:

- N/A
2025-03-12 14:20:05 +00:00
Agus Zubiaga
6b56fee6b0 assistant edit tool: Support \r\n around markers (#26538)
This should fix the tests on Windows

Release Notes:

- N/A
2025-03-12 11:00:16 -03:00
Cole Miller
d94001f445 git: Fix placeholder dots in untracked files (#26537)
This regressed at some point.

Release Notes:

- N/A
2025-03-12 13:50:25 +00:00
Antonio Scandurra
6bcfc4014b Introduce a system prompt for the new assistant (#26536)
This should be less eager in terms of invoking tools. But we should keep
iterating on it as we add more tools.

Also, this disables the Lua interpreter by default (it can still be
enabled manually from the tools icon).

Release Notes:

- N/A

---------

Co-authored-by: Richard Feldman <oss@rtfeldman.com>
2025-03-12 13:48:53 +00:00
Agus Zubiaga
47a89ad243 assistant: Edit files tool (#26506)
Exposes a new "edit files" tool that the model can use to apply
modifications to files in the project. The main model provides
instructions and the tool uses a separate "editor" model (Claude 3.5 by
default) to generate search/replace blocks like Aider does:

````markdown
mathweb/flask/app.py
```python
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
````

The search/replace blocks are parsed and applied as they stream in. If a
block fails to parse, the tool will apply the other edits and report an
error pointing to the part of the input where it occurred. This should
allow the model to fix it.


Release Notes:

- N/A

---------

Co-authored-by: Antonio Scandurra <me@as-cii.com>
2025-03-12 12:30:47 +00:00
Antonio Scandurra
f3f97895a9 Improve script tool description and add lines iterator to Lua file objects (#26529)
Release Notes:

- N/A

---------

Co-authored-by: Agus Zubiaga <hi@aguz.me>
2025-03-12 07:58:11 +00:00
Antonio Scandurra
30afba50a9 Start tracking diffs in ScriptingSession (#26463)
The diff is not exposed yet, but we'll take care of that next.

Release Notes:

- N/A
2025-03-12 08:32:29 +01:00
Mikayla Maki
036c123488 Add git init button (#26522)
Because why not

Release Notes:

- N/A
2025-03-12 07:25:19 +00:00
Mikayla Maki
050f5f6723 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.
2025-03-12 05:55:41 +00:00
Cole Miller
2cd970f137 git: Remove hunk style setting (#26504) 2025-03-12 00:35:34 -04:00
Cole Miller
d6255fb3d2 git: Prevent up and down motions leaking out of the commit editor (#26501)
Closes #ISSUE

Release Notes:

- Git Beta: fixed an issue where pressing `up` or `down` in the git
panel's commit message editor would change the selected status entry
2025-03-12 00:01:08 -04:00
Nils Koch
f9a66ecaed 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-11 21:46:17 -06:00
Cole Miller
cfb9a4beb0 Fix git panel entries getting cut off (#26499)
Closes #26497 

Release Notes:

- N/A
2025-03-11 23:43:36 +00:00
Marshall Bowers
9902cd54ce extension_host: Remove restriction of extension API v0.3.0 to development builds (#26498)
Forgot to do this in #26495.

Release Notes:

- N/A
2025-03-11 23:22:31 +00:00
Marshall Bowers
96510b72b8 zed_extension_api: Release v0.3.0 (#26495)
This PR releases v0.3.0 of the Zed extension API.

Support for this version of the extension API will land in Zed v0.178.x.

Release Notes:

- N/A
2025-03-11 22:54:44 +00:00
Cristiano Pantea
a364a13458 Fix panel not resizing after external file deletion (#26378)
Previously, when a file was deleted externally and the warning prompt
was dismissed with "Close", the panel remained but was empty, leaving an
unused split space.

This happened because pane.remove_item(...) was being called with
close_pane_if_empty set to false, preventing the panel from being
removed even when it had no remaining items.

This fix changes the third boolean parameter to true, ensuring that the
panel is removed if it becomes empty, allowing the layout to properly
resize.

Closes #23904

Release Notes:

- N/A
2025-03-11 22:52:55 +00:00
Nate Butler
09a4cfd307 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>
2025-03-11 15:47:39 -07:00
Conrad Irwin
5d66c3db85 Git panel editor scroll (#26465)
Release Notes:

- N/A
2025-03-11 16:27:47 -06:00
Conrad Irwin
28f33d0103 Fix conflict marker in project diff view (#26466)
Closes #ISSUE

Release Notes:

- N/A

Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
2025-03-11 16:27:25 -06:00
Marshall Bowers
55a90f576a ui: Split up ContextMenu::render into smaller methods (#26489)
This PR refactors the `ContextMenu::render` method to extract a couple
smaller methods from it.

The existing `render` method was suffering from its size, with some of
the `match` arms not being able to be formatted with `rustfmt`.

Release Notes:

- N/A
2025-03-11 22:26:22 +00:00
Kirill Bulatov
8d6abf6537 Improve terminal hover tooltips (#26487)
Follow-up of https://github.com/zed-industries/zed/pull/26174

* Fixes `./path/foo.bar` not properly parsed as valid open target
* Shows full open target's path in cmd-hover tooltips

Before:

<img width="864" alt="before_1"
src="https://github.com/user-attachments/assets/2575b887-6c4d-486e-8e92-dd76aedf8103"
/>
<img width="864" alt="before_2"
src="https://github.com/user-attachments/assets/ded1f203-523c-4b75-afe9-fe541c785798"
/>

After:

<img width="864" alt="after_1"
src="https://github.com/user-attachments/assets/c50d9ba3-5dfb-4cfb-aed6-00e6fa6f088e"
/>
<img width="864" alt="after_2"
src="https://github.com/user-attachments/assets/0cdc8f34-7faa-4aab-87f3-dc0c8b499842"
/>

Release Notes:



- N/A
2025-03-12 00:17:12 +02:00
Cole Miller
04961a0186 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
2025-03-11 18:17:04 -04:00
Mikayla Maki
fd7ab20ea4 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
2025-03-11 22:02:22 +00:00
Nate Butler
7019aca59d 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
2025-03-11 21:58:36 +00:00
Marshall Bowers
d43bcc04db assistant2: Remove "Tools" switch (#26485)
This PR removes the "Tools" switch from Assistant 2, as we can manage
tools from the tool selector now.

Release Notes:

- N/A
2025-03-11 21:46:51 +00:00
Julia Ryan
2b94a35aaa 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-11 21:39:29 +00:00
Marshall Bowers
e8208643bb assistant2: Show scripting tool in the tool selector (#26484)
This PR adds the scripting tool to the tool selector.

Release Notes:

- N/A
2025-03-11 21:35:39 +00:00
Ben Kunkle
a90f80725f settings: Enable JSX tag auto-close by default (#26481)
Based on conversation with @maxbrunsfeld. Enabling Tag auto closing by
default so that it is discoverable for new and existing users

Release Notes:

- Made it so JSX tag auto-closing is automatically enabled in supported
languages
2025-03-11 21:01:41 +00:00
Marshall Bowers
4e6c37d23b assistant2: Add tool selector (#26480)
This PR adds a tool selector to Assistant 2 to facilitate customizing
the tools that the model sees:

<img width="1297" alt="Screenshot 2025-03-11 at 4 25 31 PM"
src="https://github.com/user-attachments/assets/7a656343-83bc-4546-9430-6a5f7ff1fd08"
/>

Release Notes:

- N/A
2025-03-11 20:50:18 +00:00
Peter Tripp
0cf6259fec Make nano save (ctrl-o) work by-default in terminal (linux) (#26479)
Closes: https://github.com/zed-industries/zed/issues/15770

Release Notes:

- Make nano save (`ctrl-o`) work by-default in terminal (linux)
2025-03-11 20:29:02 +00:00
Kirill Bulatov
5cb5e92185 Bump aws-lc-rs to fix Windows release builds (#26477)
Closes https://github.com/zed-industries/zed/discussions/24816

https://github.com/aws/aws-lc-rs/releases/tag/v1.12.6 release includes a
fix for https://github.com/aws/aws-lc-rs/issues/707

Release Notes:

- N/A
2025-03-11 19:43:14 +00:00
Marshall Bowers
da61a28839 assistant_tool: Fix inaccurate parameter name (#26473)
This PR fixes an inaccurate parameter name in the
`ToolWorkingSet::insert` method.

Release Notes:

- N/A
2025-03-11 19:15:03 +00:00
Marshall Bowers
efdb769f9b terraform: Extract to zed-extensions/terraform repository (#26475)
This PR extracts the Terraform extension to the
[zed-extensions/terraform](https://github.com/zed-extensions/terraform)
repository.

Release Notes:

- N/A
2025-03-11 19:10:51 +00:00
Marshall Bowers
9cce5a650e assistant_tool: Add a source to the Tool trait (#26471)
This PR adds a `source` method to the `Tool` trait.

This will allow us to track where a tool is coming from.

Release Notes:

- N/A
2025-03-11 19:10:48 +00:00
Piotr Osiewicz
2021ca5bff terraform: Do not add each string constraint to the outline (#26453)
Closes #26336

Release Notes:

- N/A
2025-03-11 19:46:18 +01:00
Peter Tripp
1771250b04 Add 'Open Remote...' to File Menu (#26288)
Added some spacers while I was at it.

Release Notes:

- Added 'Open Remote...' to File menu
2025-03-11 14:18:13 +00:00
张小白
18259c0fd4 chore: Bump windows crate version (#26455)
Closes #ISSUE

Release Notes:

- N/A
2025-03-11 21:14:36 +08:00
Smit Barmase
41ddd1cc97 editor: Fix text selection not visible on text background (#26454)
Closes #25014

Previously, we painted in the order: highlights -> text background ->
text -> etc. This caused text selection to be invisible when the text
had a background.

This PR changes the painting order to: text background -> highlights ->
text -> etc.

Before:


https://github.com/user-attachments/assets/5d9647c4-3ab2-4960-b6b9-e399882a0c50

After:


https://github.com/user-attachments/assets/c699f5b9-4077-45f8-85e5-86c89130eb71

Release Notes:

- Fixed an issue where text selection was not visible on top of a text
background in the editor.
2025-03-11 18:43:11 +05:30
Smit Barmase
e175878008 macOS: Remove multi-keystroke rendering in title of menu item (#26448)
Closes #25483

Currently, macOS doesn't support showing multi-keystroke shortcuts in
menu items. We can use an attributed string to differentiate them, but
that breaks consistency with traditional shortcuts.

This PR removes the hack of concatenating the multi-keystroke shortcut
to the title, as it looked a bit janky.

Release Notes:

- N/A
2025-03-11 18:42:02 +05:30
张小白
1cfbfc199c windows: Fix tests (#26450)
Closes #ISSUE

Release Notes:

- N/A *or* Added/Fixed/Improved ...
2025-03-11 11:43:24 +00:00
张小白
f59f2caf7e Fix tests on Windows (#26449)
Closes #ISSUE

Release Notes:

- N/A *or* Added/Fixed/Improved ...
2025-03-11 11:17:48 +00:00
Agus Zubiaga
401342c6ec assistant: Display edits from scripts in panel (#26441)
https://github.com/user-attachments/assets/a486ff2a-4aa1-4c0d-be6c-1dea2a8d60c8
 
- [x] Track buffer changes in `ScriptingSession`
- [x] Show edited files in thread

Reviewing diffs and displaying line counts will be part of an upcoming
PR.

Release Notes:

- N/A

---------

Co-authored-by: Antonio Scandurra <me@as-cii.com>
2025-03-11 10:12:52 +00:00
Cole Miller
0df1e4a489 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
2025-03-11 03:04:56 -04:00
Cole Miller
9bd3e156f5 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
2025-03-11 00:26:13 -04:00
Conrad Irwin
42c655751b Show a disabled stage all button for no entries (#26436)
Closes #ISSUE

Release Notes:

- N/A
2025-03-10 22:25:33 -06:00
Conrad Irwin
ff1d78df3b Go back to "create branch" in the list (#26433)
Closes #ISSUE

Release Notes:

- N/A
2025-03-11 04:24:52 +00:00
Conrad Irwin
c2e4fdf63d 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
2025-03-10 22:10:52 -06:00
Agus Zubiaga
bf11b888c3 scripting tool: Use project buffers in io.open (#26425)
This PR makes `io.open` use our own implementation again, but instead of
the real filesystem, it will now use the project's to check file
metadata and perform read and writes using project buffers.

This also cleans up the `io.open` implementation by splitting it into
multiple methods, adds tests for various File I/O patterns, and fixes a
few bugs in read formats.

Release Notes:

- N/A
2025-03-11 00:52:16 -03:00
Angelk90
d562f58e76 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>
2025-03-10 21:05:29 -06:00
Conrad Irwin
94e4aa626d 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"
2025-03-10 20:53:46 -06:00
lydiandy
8ceba89d81 ui: Fix error code in button comment (#26423)
Closes #ISSUE

Release Notes:
ui: Fix error code in button comment.

- N/A *or* Added/Fixed/Improved ...
2025-03-11 02:15:39 +00:00
Conrad Irwin
c37d6d5fed Unwind deprecated permalinks code (#26395)
Release Notes:

- N/A
2025-03-10 19:57:10 -06:00
Max Brunsfeld
1a3597d726 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:52:18 -07:00
Kirill Bulatov
c747cccde3 Revert "Return back a proper resolved value (#26406)" (#26419)
This reverts commit 1f8b14f4f1.

Release Notes:

- N/A
2025-03-10 23:33:41 +00:00
Kirill Bulatov
d81e7683ea Use proper order of Completion::Source field to have sane default (#26416)
Follow-up of https://github.com/zed-industries/zed/pull/26300

Release Notes:

- N/A
2025-03-10 18:58:21 -04:00
edwloef
8b29ee6033 Add variable.special color to Gruvbox themes (#26271)
This adds the `variable.special` color to the Gruvbox family of themes,
which colors special variables (in Rust's case `self`) differently than
normal ones. The colors were taken from the old Gruvbox `variable`
highlighting (see https://github.com/zed-industries/zed/pull/25464).

before:

![image](https://github.com/user-attachments/assets/3f329ac0-fbdf-480c-9074-5db99591f4e1)

![image](https://github.com/user-attachments/assets/43efdddd-7daf-440f-8c11-d6279330912a)

after:

![image](https://github.com/user-attachments/assets/052c05b8-55c5-495a-a9cc-a5f73aa5aa00)

![image](https://github.com/user-attachments/assets/f598b75f-8d2d-4710-b804-9282de9f8d15)

fixes half of https://github.com/zed-industries/zed/issues/26206. Since
I don't use the Ayu themes I'd prefer someone who knows what looks good
there does those changes.

Release Notes:

- Gruvbox themes: Added a color for `@variable.special` syntax
highlights.
2025-03-10 18:43:18 -04:00
Conrad Irwin
96a75e08af Fix panic opening branch picker in commit modal (#26407)
Closes #ISSUE

Release Notes:

- N/A
2025-03-10 16:36:23 -06:00
Marshall Bowers
06cbff6714 assistant2: Remove excess padding around scripting tool inputs (#26412)
This PR removes some excess padding around the rendered scripting tool
inputs.

Release Notes:

- N/A
2025-03-10 22:29:50 +00:00
Marshall Bowers
ce05813e7c assistant2: Render scripting tool inputs when opening past threads (#26408)
This PR makes it so we render the scripting tool inputs to Markdown when
opening past threads.

Release Notes:

- N/A
2025-03-10 22:11:36 +00:00
Conrad Irwin
4d1d8d6d78 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
2025-03-10 16:10:53 -06:00
Kirill Bulatov
1f8b14f4f1 Return back a proper resolved value (#26406)
Follow-up of https://github.com/zed-industries/zed/pull/26300


https://github.com/zed-industries/zed/pull/26300/files#diff-a3da3181e4ab4f73aa1697d7b6dc0caa0c17b2a187fb83b076dfc0234ec91f54L16900
changed the snippets' `resolved` value but it should have not.

Release Notes:

- N/A
2025-03-10 23:48:04 +02:00
Marshall Bowers
082cc6184c assistant2: Persist scripting tool uses in saved threads (#26404)
This PR makes it so the scripting tool uses are persisted to and
restored from saved threads.

Release Notes:

- N/A
2025-03-10 21:42:23 +00:00
Smit Barmase
6cfc4dc857 gpui: Fix transparent titlebar in fullscreen mode on macOS (#26403)
Closes #23735

This PR fixes an issue where Zed shows a transparent title bar in
fullscreen mode on macOS instead of the default gray one.

When switching to fullscreen mode, we change the title bar appearance to
opaque. When exiting fullscreen mode, we check the existing
`appears_transparent` flag that we pass to gpui to decide whether to
change the title bar back to transparent or not.

Note: Regardless of the `appears_transparent` flag, gpui should always
show an opaque title bar in fullscreen mode to prevent a broken
appearance, as macOS always displays the title bar in fullscreen mode
upon mouse interaction.


https://github.com/user-attachments/assets/211fb185-239b-454e-ac7f-b93b25d33805

Release Notes:

- Fixed issue where Zed showed transparent titlebar in fullscreen mode
on macOS.
2025-03-11 03:02:52 +05:30
Ben Kunkle
b9c48685e8 terminal: Support trailing :description or error message after file path (#26401)
Closes #25086

Release Notes:

- Fixed a bug where file paths in the built in terminal of the format
`path/to/file.ext:row:col:description or error message` would not be
correctly identified as file paths due to the colon & additional text at
the end
2025-03-10 16:20:48 -05:00
Marshall Bowers
570c396e84 assistant2: Remove unneeded pub on field (#26399)
This PR removes an unneeded `pub` on a field in the `ContextStrip`, as
it was never accessed externally.

Release Notes:

- N/A
2025-03-10 20:55:53 +00:00
Ben Kunkle
5fd034e604 docs: Add documentation for using debuggers with Zed (#26391)
Just some basic documentation for using debuggers in Zed development.
Goes over configuring cargo to include full debug info, attaching to an
instance of Zed, and using a debugger to debug panics and crashes

Release Notes:

- N/A
2025-03-10 15:51:51 -05:00
Cole Miller
63dab5f891 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>
2025-03-10 16:47:35 -04:00
Marshall Bowers
a2d6df3ed6 scripting_tool: Fix formatting of tool description (#26397)
This PR fixes the formatting of the scripting tool description, as it
had acquired some strange whitespaces.

Release Notes:

- N/A
2025-03-10 20:35:02 +00:00
Mikayla Maki
30e86ac939 Add a "secondary" meta key to GPUI keystroke parsing (#26390)
"secondary" means "cmd" on macOS and "ctrl" on not macOS.

Release Notes:

- Added a "secondary" meta key to the zed keystroke parser, which maps
to 'cmd' on macOS and 'ctrl' off of macOS
2025-03-10 13:32:13 -07:00
Nate Butler
976fc3ee97 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)

### Previous message truncation:

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)

### Make branch icon match when menu is disabled

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 13:19:02 -07:00
Conrad Irwin
63091459d8 Allow too many arguments (#26375)
This is nearly half of our #allows, and seems like something we happily
break whenever we need

Release Notes:

- N/A
2025-03-10 13:38:30 -06:00
Conrad Irwin
659fae70f8 Remove GitUiFeatureFlag and enable panel unconditionally (#26386)
Release Notes:

- git: Enable for everyone
2025-03-10 13:38:07 -06:00
Marshall Bowers
02e970192f assistant2: Improve Lua script rendering (#26389)
This PR improves the rendering of Lua scripts provided to the scripting
tool.

We now render them in code blocks with syntax highlighting:

<img width="1297" alt="Screenshot 2025-03-10 at 2 40 51 PM"
src="https://github.com/user-attachments/assets/def65b5c-86a8-490f-aaa5-5cc1687fe01e"
/>

Release Notes:

- N/A
2025-03-10 18:54:03 +00:00
Julia Ryan
5ecc67f2ef Remove --frozen flag for cargo-about (#26385)
This was added to support the nix build but accidentally broke our
bundling. I'll try to re-add it in a way that works for both in the
future.

Release Notes:

- N/A
2025-03-10 18:35:59 +00:00
Conrad Irwin
73dfb10c16 Scroll project diff into view always (#26379)
Closes #ISSUE

Release Notes:

- N/A
2025-03-10 12:28:07 -06:00
Marshall Bowers
e513e81046 assistant2: Decouple scripting tool from the Tool trait (#26382)
This PR decouples the scripting tool from the `Tool` trait while still
allowing it to be used as a tool from the model's perspective.

This will allow us to evolve the scripting tool as more of a first-class
citizen while still retaining the ability to have the model call it as a
regular tool.

Release Notes:

- N/A
2025-03-10 17:57:03 +00:00
Agus Zubiaga
2fc4dec58f assistant: Use tool interface for scripts (#26377)
We decided to expose scripting as tools again. We are aware of the UX
downsides of doing so, but we want to focus on getting it working well
first, and the model seems to make better use of it as an actual tool.

In the future, the tools API might support streaming. If it doesn't and
we need to ship, we can consider reverting this.

Release Notes:

- N/A
2025-03-10 13:59:31 -03:00
Conrad Irwin
3891381d3e 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 10:46:53 -06:00
Cole Miller
b91e929086 git: Pass project environment to git binary invocations (#26301)
Closes #26213 

Release Notes:

- Git Beta: pass down environment variables from project to git
operations
2025-03-10 12:12:46 -04:00
Cole Miller
013a646799 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
2025-03-10 11:39:01 -04:00
Marshall Bowers
ed52e759d7 docs: Fix language links (#26368)
This PR fixes some language links in the docs.

The Shell Script page wasn't being linked from `SUMMARY.md`, so no page
was being generated.

There were also some differences in the language lists in the sidebar
and on the top-level languages page.

Release Notes:

- N/A
2025-03-10 15:22:51 +00:00
Richard Feldman
6da099a9d7 Unsandbox Lua scripts (#26365)
Per a conversation with @nathansobo, have the Lua scripts run
unsandboxed for now (while this feature is behind the staff feature
flag).

Release Notes:

- N/A
2025-03-10 11:04:37 -04:00
Smit Barmase
5f159bc95e go_to_line: Fix goto line + mouse click jumps to previous scroll position (#26362)
Closes #20658

Now, when the "Go to Line" palette is open:  
- Clicking on the editor will dismiss the palette without changing the
scroll position. (PR change)
- Pressing Enter will jump to the line number entered in the palette.
(Unchanged)
- Pressing Escape will jump back to the previous cursor location.
(Unchanged)

Release Notes:

- Fixed an issue where clicking the editor with the mouse while the "Go
to Line" palette is open would cause it to jump to the previous scroll
position.
2025-03-10 20:33:07 +05:30
Marshall Bowers
a4462577bf Sort Cargo.tomls (#26367)
This PR sorts some `Cargo.toml`s that had become unsorted.

Release Notes:

- N/A
2025-03-10 14:48:21 +00:00
João Marcos
c147b58558 Remove redundant checks in do_stage_or_unstage_and_next (#26364)
Release Notes:

- N/A
2025-03-10 14:23:17 +00:00
Devzeth
84fe1bfe9b Recognize ixx as part of the cpp suffix (#26333)
Adds "ixx" as path suffix to be recognized for c++. 

> ixx documentation
https://learn.microsoft.com/en-us/cpp/cpp/modules-cpp?view=msvc-

I've also added it to the icon file. 

Release Notes:

- N/A
2025-03-10 09:10:29 -05:00
Danilo Leal
657d7a911d Add logo for wgsl (WebGPU Shading Language) (#26360)
Was dabbling on the shaders these past few days and felt like we could
have the WGSL logo. This is based on the logo found on the GPU Web
repository: https://github.com/gpuweb/gpuweb/tree/main/logo

Release Notes:

- N/A
2025-03-10 09:44:19 -03:00
Danilo Leal
ee05cc3ad9 Add a line numbers toggle to the editor controls menu (#26318)
Closes https://github.com/zed-industries/zed/issues/26305

<img
src="https://github.com/user-attachments/assets/795029ad-128a-471f-9adf-c0ef26319bbf"
width="400px" />

Release Notes:

- N/A
2025-03-10 09:28:46 -03:00
Smit Barmase
5ed144f9d2 macOS: Add support for external file managers to open directory in Zed (#26357)
Closes #25421

This PR adds support for external file managers to show Zed as an option
in the "Open With" context menu for directories on macOS.

<img width="350" alt="image"
src="https://github.com/user-attachments/assets/c52acd48-73c4-47be-8683-6950e0371b73"
/>


Release Notes:

- Added support for opening folders in Zed from third-party macOS file
managers like Path Finder and Super Charge through their "Open With"
menu.
2025-03-10 15:21:39 +05:30
Julia Ryan
2a862b3c54 nix: Disable checks and remove crane workaround (#26356)
The checkPhase was failing for me in darwin so I turned it off. I think
eventually we'll want to use a separate derivation for tests (which
crane has a helper for).

Crane also solved our issue with spaces in paths so I bumped the flake
to pick up that fix and removed our workaround: ipetkov/crane#808.

Release Notes:

- N/A
2025-03-10 02:00:57 -07:00
Julia Ryan
4a7c84f490 Fix nix build (#26270)
This PR includes lots of small fixes to get our `build.nix` and
`shell.nix` back to a working state.

I've tested this by running `cargo run` (inside the devshell) and `nix
run` on x86 nixos and arm64 darwin machines. I'd appreciate it if others
could test building inside the devshell to double-check that it's not
just working because I happen to have some system-level packages
installed, as well as seeing if it works on other platforms (non-nixos
linux, arm linux, x86 darwin).

I couldn't get the full test suite (`cargo nextest run --workspace`)
passing in the devshell on darwin, but they _are_ all passing on nixos.
nixpkgs [disables some of our
tests](92d11f06d5/pkgs/by-name/ze/zed-editor/package.nix (L226-L234))
that apparently fail or are flakey on hydra, but they don't know why.
I'm going to punt on debugging those for now, especially given that they
seem to be working for me. I'm also unsure of whether we actually want
the nix checkPhase to run the full test suite (it's currently not
passing `--workspace`) given that we have separate CI that should
enforce that those pass on all PRs.

Here's an overview of the changes made:
- Fix our `generate-licenses` script
- Relaxes the `cargo-about` version requirement slightly so it doesn't
try to install an older binary when the nixpkgs one is newer than our
requirement
- Add a workaround for [this cargo-about
issue](https://github.com/zed-industries/zed/issues/19971) obviating the
need for the patching done in the nixpkgs package
- Set the new `--frozen` flag to avoid network access/mutating the
lockfile
- Use dynamic webrtc lib from nixpkgs, and fixes up the build script in
webrtc-sys that hardcodes it to be statically linked.
- Use `inputsFrom` in `shell.nix` and avoid duplicating everything from
`build.nix`
- Add a temporary workaround for an [upstream crane
bug](https://github.com/ipetkov/crane/issues/808).
- Fix shebangs in our `script` dir to not hard-code `/bin/bash`

There are still a bunch of issues that aren't resolved here, I'll make a
tracking issue for those and try to land this first just to get back to
an unbroken state. Eventually among other things I'd like to use a
`libgit2` from `staticPkgs` and musl cross compilation to build the
remote server under nix, and then add that as a separate flake output
and include it in the shell's `inputsFrom` list.

Thanks @niklaskorz, @GaetanLepage, @bbigras and all the other nixpkgs
maintainers that have kept the `zed-editor` package working and up to
date! I seriously considered just making our flake `overrideAttrs` the
package in nixpkgs given how well maintained it is.

Thanks @WeetHet for your volunteer maintinance of this flake. I
referenced #24953 while working on these fixes, and I'd love to
collaborate on adding some of those pieces like treefmt and a github
action. If you're interested I'd really appreciate some help debugging
why crane's `buildDepsOnly` isn't working for us. I'm assuming it'd make
our `nix build` times go way down from the improved dep caching if we
could get it working.

Thanks @rrbutani for all the help on this PR 💙.

Release Notes:

- N/A

---------

Co-authored-by: Rahul Butani <rrbutani@users.noreply.github.com>
Co-authored-by: Rahul Butani <rr.butani@gmail.com>
2025-03-10 01:06:11 -07:00
Mikayla Maki
230e2e4107 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.
2025-03-10 07:08:10 +00:00
Richard Hao
d732b8ba0f 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-09 23:45:25 -07:00
Michael Sloan
7c3eecc9c7 Add support for querying file outline in assistant script (#26351)
Release Notes:

- N/A
2025-03-10 05:26:17 +00:00
Max Brunsfeld
fff37ab823 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:15:38 -07:00
Kirill Bulatov
8a7a78fafb Avoid modifying the LSP message before resolving it (#26347)
Closes https://github.com/zed-industries/zed/issues/21277

To the left is current Zed, right is the improved version.
3rd message, from Zed, to resolve the item, does not have `textEdit` on
the right side, and has one on the left.
Seems to not influence the end result though, but at least Zed behaves
more appropriate now.

<img width="1727" alt="image"
src="https://github.com/user-attachments/assets/ca1236fd-9ce2-41ba-88fe-1f3178cdcbde"
/>


Instead of modifying the original LSP completion item, store completion
list defaults and apply them when the item is requested (except `data`
defaults, needed for resolve).

Now, the only place that can modify the completion items is this method,
and Python impl seems to be the one doing it:


ca9c3af56f/crates/languages/src/python.rs (L182-L204)

Seems ok to leave untouched for now.

Release Notes:

- Fixed LSP completion items modified before resolve request
2025-03-10 00:12:53 +02:00
Ben Kunkle
6de3ac3e17 Revert "Highlight super and this as keywords in JS/TS/TSX" (#26342)
Reverts zed-industries/zed#25135

This approach was not the best as explained in the response to the
original PR. Likely, the better approach is to create a newer specific
scope for these kinds of variables under the `@variable` prefix so that
themes can control these pseudo-keywords specifically
2025-03-09 16:11:37 +00:00
Smit Barmase
5aae3bdc69 copilot: Fix missing sign-out button when Zed is the edit prediction provider (#26340)
Closes #25884

Added a sign-out button for Copilot in Assistant settings, allowing
sign-out even when copilot is disabled.

<img width="500" alt="image"
src="https://github.com/user-attachments/assets/43fc97ad-f73c-49e1-a7b6-a3910434d661"
/>



Release Notes:

- Added a sign-out button for Copilot in Assistant settings.
2025-03-09 21:39:14 +05:30
Agus Zubiaga
e298301b40 assistant: Make scripting a first-class concept instead of a tool (#26338)
This PR makes refactors the scripting functionality to be a first-class
concept of the assistant instead of a generic tool, which will allow us
to build a more customized experience.

- The tool prompt has been slightly tweaked and is now included as a
system message in all conversations. I'm getting decent results, but now
that it isn't in the tools framework, it will probably require more
refining.

- The model will now include an `<eval ...>` tag at the end of the
message with the script. We parse this tag incrementally as it streams
in so that we can indicate that we are generating a script before we see
the closing `</eval>` tag. Later, this will help us interpret the script
as it arrives also.

- Threads now hold a `ScriptSession` entity which manages the state of
all scripts (from parsing to exited) in a centralized way, and will
later collect all script operations so they can be displayed in the UI.

- `script_tool` has been renamed to `assistant_scripting` 

- Script source now opens in a regular read-only buffer  

Note: We still need to handle persistence properly

Release Notes:

- N/A

---------

Co-authored-by: Marshall Bowers <git@maxdeviant.com>
2025-03-09 09:01:49 +00:00
brian tan
ed6bf7f161 diagnostics: Fix losing focus when activating from diagnostics view (#25517)
Closes #25509

Changes:
- If active item is already diagnostics, don't try to focus it again.

Instead of not focusing, should it just not activate instead? Something
like:

            if !workspace
                .active_item(cx)
                .map(|item| item.item_id() == existing.item_id())
                .unwrap_or(false)
            {
workspace.activate_item(&existing, true, true, window, cx);
            }


Release Notes:

- N/A
2025-03-08 22:17:20 +00:00
Smit Barmase
f14d6670ba copilot: Fix onboarding into Copilot requires Zed restart (#26330)
Closes #25594

This PR fixes an issue where signing into Copilot required restarting
Zed.

Copilot depends on an OAuth token that comes from either `hosts.json` or
`apps.json`. Initially, both files don't exist. If neither file is
found, we fallback to watching `hosts.json` for updates. However, if the
auth process creates `apps.json`, we won't receive updates from it,
causing the UI to remain outdated.

This PR fixes that by watching the parent `github-copilot` directory
instead, which will always contain one of those files along with an
additional version file.

I have tested this on macOS and Linux Wayland.

Release Notes:

- Fixed an issue where signing into Copilot required restarting Zed.
2025-03-09 03:19:09 +05:30
Joseph T. Lyons
22d9b5d8ca Update key binding documentation (#26321)
Release Notes:

- N/A
2025-03-08 01:03:52 -05:00
Danilo Leal
6ed6e8bc26 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-08 01:00:47 -03:00
Max Brunsfeld
4846e6fb3a 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-08 02:15:15 +00:00
Mikayla Maki
cb543f9546 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-08 01:49:06 +00:00
Michael Sloan
450d727a04 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`.
2025-03-08 00:58:47 +00:00
Mikayla Maki
60b3eb3f76 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-08 00:02:57 +00:00
Marshall Bowers
bbe7c9a738 assistant2: Factor out Thread::all_tools_finished method (#26314)
This PR factors out a new `Thread::all_tools_finished` method to
encapsulate some of the boilerplate in the `ThreadEvent::ToolFinished`
event handler.

This should make this event handler easier to replicate for the eval
use-case.

Release Notes:

- N/A
2025-03-07 23:35:32 +00:00
Mikayla Maki
f6345a6995 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-07 23:33:48 +00:00
Marshall Bowers
e70d0edfac assistant_tool: Pass an Entity<Project> to Tool::run (#26312)
This PR updates the `Tool::run` method to take an `Entity<Project>`
instead of a `WeakEntity<Project>`.

Release Notes:

- N/A
2025-03-07 23:30:56 +00:00
Marshall Bowers
921c24e274 assistant2: Add helper methods to Thread for dealing with tool use (#26310)
This PR adds two new helper methods to the `Thread` for dealing with
tool use:

- `use_pending_tools` - This uses all of the tools that are pending
- The reason we aren't calling this directly in `stream_completion` is
that we still might need to have a way for users to confirm that they
want tools to be run, which would need to happen at the UI layer in the
`ActiveThread`.
- `send_tool_results_to_model` - This encapsulates inserting a new user
message that contains the tool results and sending them up to the model.

Release Notes:

- N/A
2025-03-07 23:16:45 +00:00
Marshall Bowers
18f3f8097f assistant_tool: Decouple Tool from Workspace (#26309)
This PR decouples the `Tool` trait from the `Workspace` (and from the
UI, in general).

`Tool::run` now takes a `WeakEntity<Project>` instead of a
`WeakEntity<Workspace>` and a `Window`.

Release Notes:

- N/A
2025-03-07 22:41:56 +00:00
Marshall Bowers
4f6682c7fe haskell: Extract to zed-extensions/haskell repository (#26306)
This PR extracts the Haskell extension to the
[zed-extensions/haskell](https://github.com/zed-extensions/haskell)
repository.

Release Notes:

- N/A
2025-03-07 22:07:04 +00:00
Kiran_Peraka
f57dece2d5 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-07 20:57:53 +00:00
Kirill Bulatov
103ad635d9 Refactor Completions to allow non-LSP ones better (#26300)
A preparation for https://github.com/zed-industries/zed/issues/4957 that
pushes all LSP-related data out from the basic completion item, so that
it's possible to create completion items without any trace of LSP
clearly.

Release Notes:

- N/A
2025-03-07 20:19:28 +00:00
Mikayla Maki
ec5e7a2653 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-07 19:56:24 +00:00
Marshall Bowers
05d3ee8555 extension: Require that grammar names are written in snake_case (#26295)
This PR updates the `ExtensionBuilder` to require that grammar names are
written in snake_case.

The grammar names are used to construct identifiers, so we need them to
be valid C identifiers.

Release Notes:

- N/A
2025-03-07 19:02:35 +00:00
Nate Butler
1b34437839 component_preview: Add component pages (#26284)
This PR adds pages to component preview when clicking on a given
component in the sidebar.

This will let us create richer previews & better docs for using
components in the future.

Release Notes:

- N/A
2025-03-07 18:56:17 +00:00
Danilo Leal
3ff2c8fc38 Add file icon for Luau (#26293)
Closes https://github.com/zed-industries/zed/issues/14948

Release Notes:

- N/A
2025-03-07 15:27:00 -03:00
Cole Miller
b0b0b00fae 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
2025-03-07 18:02:05 +00:00
Conrad Irwin
80fb88520f 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>
2025-03-07 10:51:46 -07:00
Conrad Irwin
aef84d453a Update Linux Graphics troubleshooting (#26263)
Try to re-order the tips for clarity, and make it clear that /etc/prime
could be wrong either way around.

Also remove section on FIPS now we nolonger bundle openssl

Updates #15629

Release Notes:

- N/A
2025-03-07 09:57:11 -07:00
João Marcos
e06d010aab Test folded buffers navigation (#26286)
#25944 but now with Vim mode off.

Release Notes:

- N/A
2025-03-07 16:19:12 +00:00
Marshall Bowers
14148f53d4 scripting_tool: Move description into a separate file (#26283)
This PR moves the `scripting_tool` description into a separate file so
it's a bit easier to work with.

Release Notes:

- N/A
2025-03-07 15:52:38 +00:00
Antonio Scandurra
efde5aa2bb Extract a Session struct to hold state about a given thread's scripting session (#26282)
We're still recreating a session for every tool call, but the idea is to
have a long-lived `Session` per assistant thread.

Release Notes:

- N/A

---------

Co-authored-by: Agus Zubiaga <hi@aguz.me>
2025-03-07 15:44:36 +00:00
Guilherme Gonçalves
fcc5e27455 Fix hotkey for toggle filters in project search (#25917)
Closes #24741 

Adjusted the shortcut key handling to properly toggle filters in the project search feature.

Release Notes:

- linux: Fixed `ctrl-alt-f` not correctly toggling search filters in project search.

---------

Co-authored-by: Peter Tripp <peter@zed.dev>
2025-03-07 15:27:10 +00:00
Marshall Bowers
ed417da536 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 15:05:35 +00:00
Piotr Osiewicz
d1c67897c5 chore: Do not bust Rust build cache when opening projects with dev build (#26278)
## Problem
Running `cargo run .` twice in Zed repository required a rebuild two
times in a row. The second rebuild was triggered around libz-sys, which
in practice caused a rebuild of the ~entire project.

Some concrete examples:
```
cargo test -p project # Requires a rebuild (warranted)
cargo run .
cargo test -p project # Requires a rebuild (unwarranted)
```
or
```
cargo run . # Requires a rebuild (warranted)
cargo run . # Requires a rebuild (unwarranted)
```

## What's going on
Zed build script on MacOS sets MACOSX_DEPLOYMENT_TARGET to 10.15. This
is fine. However, **cargo propagates all environment variables to child
processes during `cargo run`**. This then affects Rust Analyzer spawned
by dev Zed - it clobbers build cache of whatever package it touches,
because it's behavior is not same between running it with `cargo run`
(where MACOS_DEPLOYMENT_TARGET gets propagated to child Zed) and running
it directly via `target/debug/zed` or whatever (where the env variable
is not set, so that build behaves roughly like Zed Dev.app).


## Solution
~We'll unset that env variable from user environment when we're
reasonably confident that we're running under `cargo run` by exploiting
other env variables set by cargo:
https://doc.rust-lang.org/cargo/reference/environment-variables.html
CARGO_PKG_NAME is always set to `zed` when running it via `cargo run`,
as it's the value propagated from the build.~

~The alternative I've considered is running [via a custom
runner](https://doc.rust-lang.org/cargo/reference/config.html#targetcfgrunner),
though the problem here is that we'd have to use a shell script to unset
the env variable - that could be problematic with e.g. fish. I just
didn't want to deal with that, though admittedly it would've been
cleaner in other aspects.~

Redact all above. We'll just set MACOSX_DEPLOYMENT_TARGET regardless of
whether you have it in your OG shell environment or not.

Release Notes:

- N/A
2025-03-07 14:06:44 +00:00
Finn Evers
a887f3b340 Remove plain text file type association from default settings (#25420)
Closes #20291

This PR removes the plain text file association from the default
settings, as #21298 added a `LanguageMatcher` for Plain Text files,
which now associates "Plain Text" with `txt`-files (see
10053e2566/crates/language/src/language.rs (L127-L137)).

Thus, the association via the default settings is not required anymore,
which fixes #20291 as described in
https://github.com/zed-industries/zed/issues/20291#issuecomment-2500731743

Release Notes:

- Fixed default file type associations overriding associations provided
by extensions for `txt`-files.

Co-authored-by: Peter Tripp <peter@zed.dev>
2025-03-07 08:45:23 -05:00
Kirill Bulatov
f8deebc6db 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 11:34:37 +00:00
Michael Sloan
205f9a9f03 Add lua script access to code using cx + reuse project search logic (#26269)
Access to `cx` will be needed for anything that queries entities. In
this commit this is use of `WorktreeStore::find_search_candidates`. In
the future it will be things like access to LSP / tree-sitter outlines /
etc.

Changes to support access to `cx` from functions provided to the Lua
script:

* Adds a channel of requests that require a `cx`. Work enqueued to this
channel is run on the foreground thread.

* Adds `async` and `send` features to `mlua` crate so that async rust
functions can be used from Lua.

* Changes uses of `Rc<RefCell<...>>` to `Arc<Mutex<...>>` so that the
futures are `Send`.

One benefit of reusing project search logic for search candidates is
that it properly ignores paths.

Release Notes:

- N/A
2025-03-07 10:02:49 +00:00
Cole Miller
b0d1024f66 Silence a couple of noisy logs (#26262)
Closes #ISSUE

Release Notes:

- N/A
2025-03-06 22:45:47 -05:00
loczek
622ed8a032 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 02:27:29 +00:00
0x2CA
09c51f9641 assistant2: Fix font fallbacks (#26258)
Release Notes:

- N/A
2025-03-06 18:14:53 -08:00
Mikayla Maki
8422a81d88 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 02:13:50 +00:00
Mikayla Maki
6c025507b6 Restore co-author hiding (#26257)
Release Notes:

- N/A
2025-03-07 01:40:17 +00:00
Marshall Bowers
8f4b7aa5db 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 01:21:20 +00:00
Cole Miller
3345666557 Fix paths on Windows in new test (#26255)
Closes #ISSUE

Release Notes:

- N/A *or* Added/Fixed/Improved ...
2025-03-06 20:08:13 -05:00
Max Brunsfeld
40c62cda5f 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:25:27 -08:00
Marshall Bowers
349a48d937 lua: Extract to zed-extensions/lua repository (#26250)
This PR extracts the Lua extension to the
[zed-extensions/lua](https://github.com/zed-extensions/lua) repository.

Release Notes:

- N/A
2025-03-06 23:17:34 +00:00
Cole Miller
a88af7351a Disable restore hunk control for created files (#25841)
Release Notes:

- Git Beta: disable hunk restore action and button for created files
2025-03-06 23:06:03 +00:00
Finn Evers
efaf358876 lua: Update keyword operator highlighting (#26091)
Resolves #26032 

This PR changes the highlighting for `and`, `not` and `or` in Lua from
`operator` to `keyword.operator`. [VS Code also highlights these as
keyword
operators](1483add845/Syntaxes/Lua.plist (L277-L279))
and Zed does this for other languages as well, like
[Python](813e207514/crates/languages/src/python/highlights.scm (L221-L229))
or
[Zig](813e207514/extensions/zig/languages/zig/highlights.scm (L145-L149)).

Additionally, in 813e207514 I removed
duplicate matches for existing keywords to improve readability and align
them to how keywords are generally matched across languages (see
[Rust](813e207514/crates/languages/src/rust/highlights.scm (L79-L119))
and
[Typescript](813e207514/crates/languages/src/typescript/highlights.scm (L210-L269))
for example).
Whilst contributing to the majority of the diff, this does not change
any existing highlights.

| Before | After | 
| --- | --- |
| <img width="309" alt="old"
src="https://github.com/user-attachments/assets/7790817e-4a0d-442b-b176-9a84bcc6f3c4"
/> | <img width="309" alt="PR"
src="https://github.com/user-attachments/assets/34a57962-938a-4465-9406-288f5c456aa3"
/> |


Release Notes:

- N/A

---------

Co-authored-by: Peter Tripp <peter@zed.dev>
2025-03-06 18:01:13 -05:00
Marshall Bowers
06a226dc32 editor: Remove some blank lines (#26249)
This PR removes some blank lines in `blink_manager.rs`.

Release Notes:

- N/A
2025-03-06 22:58:46 +00:00
Cole Miller
1763dd714b Worktree paths in git panel, take 2 (#26047)
Modified version of #25950. We still use worktree paths, but repo paths
with a status that lie outside the worktree are not excluded; instead,
we relativize them by adding `..`. This makes the list in the git panel
match what you'd get from running `git status` (with the repo's worktree
root as the working directory).

- [x] Implement + test new unrelativization logic
- [x] ~~When collecting repositories, dedup by .git abs path, so
worktrees can share a repo at the project level~~ dedup repos at the
repository selector layer, with repos coming from larger worktrees being
preferred
- [x] Open single-file worktree with diff when activating a path not in
the worktree

Release Notes:

- N/A
2025-03-06 22:55:28 +00:00
Marshall Bowers
330e799293 erlang: Extract to zed-extensions/erlang repository (#26248)
This PR extracts the Erlang extension to the
[zed-extensions/erlang](https://github.com/zed-extensions/erlang)
repository.

Release Notes:

- N/A
2025-03-06 22:53:13 +00:00
Max Brunsfeld
51c900366d Enable soft-wrap by default in markdown (#26247)
Release Notes:

- Enabled soft-wrap by default in markdown
2025-03-06 22:30:26 +00:00
Max Brunsfeld
be75f17429 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-06 22:13:34 +00:00
Conrad Irwin
f373383fc1 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-06 15:12:56 -07:00
Joseph T. Lyons
263d9ff755 Add event to track LLM-generated commit messages (#26245)
Release Notes:

- N/A
2025-03-06 21:46:57 +00:00
Naim A.
829ecda370 lsp: Add support for clangd's inactiveRegions extension (#26146)
Closes #13089 

Here we use `experimental` to advertise our support for
`inactiveRegions`. Note that clangd does not currently have a stable
release that reads the `experimental` object (PR
https://github.com/llvm/llvm-project/pull/116531), this can be tested
with one of clangd's recent "unstable snapshots" in their
[releases](https://github.com/clangd/clangd/releases).

Release Notes:

- Added support for clangd's `inactiveRegions` extension.

![Screen Recording 2025-03-05 at 22 39
58](https://github.com/user-attachments/assets/ceade8bd-4d8e-43c3-9520-ad44efa50d2f)

---------

Co-authored-by: Peter Tripp <peter@zed.dev>
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
2025-03-06 21:30:05 +00:00
Kirill Bulatov
af5af9d7c5 Support workspace/executeCommand for actions' data (#26239)
Closes https://github.com/zed-industries/zed/issues/16746
Part of https://github.com/zed-extensions/deno/issues/2

Changes the action-related code so, that

* `lsp::Command` as actions are supported, if server replies with them
* actions with commands are filtered out based on servers'
`executeCommandOptions`
(https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#executeCommandOptions)
— commands that are not listed won't be executed and the corresponding
actions will be hidden in Zed

Release Notes:

- Added support of `workspace/executeCommand` for actions' data

---------

Co-authored-by: Peter Tripp <petertripp@gmail.com>
2025-03-06 23:26:46 +02:00
Marshall Bowers
97c0a0a86e language_models: Remove .unwraps 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.
2025-03-06 21:02:37 +00:00
Nate Butler
7e964290bf 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-06 20:37:54 +00:00
Marshall Bowers
b8a8b9c699 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-06 19:47:52 +00:00
Danilo Leal
d1cec209d4 gpui: Add rounded_md token (#26179)
This PR adds a new rounded/corner border token: `rounded_md` with a
value of 6px.

I feel like I was wanting to use 6px border radius a lot but avoiding
due to it being an arbitrary value... so, not anymore! It's also cool to
have this be consistent with Tailwind v4.

Follow on to the prior renames:

- `rounded_sm` -> `rounded_xs`:
https://github.com/zed-industries/zed/pull/26221
- `rounded_md` -> `rounded_sm`:
https://github.com/zed-industries/zed/pull/26228

Release Notes:

- N/A

---------

Co-authored-by: Marshall Bowers <git@maxdeviant.com>
2025-03-06 13:41:21 -05:00
Marshall Bowers
aceab76ae4 gpui: Rename rounded_md to rounded_sm (#26228)
This PR renames the `rounded_md` style method to `rounded_sm`.

Follow up to https://github.com/zed-industries/zed/pull/26221, which
freed up the `rounded_sm` name.

Release Notes:

- N/A
2025-03-06 17:57:31 +00:00
Conrad Irwin
9c054f207e Git telemetry (#26222)
Release Notes:

- git: Adds telemetry to git actions
2025-03-06 10:56:28 -07:00
smit
219d36f589 migrator: Add versioned migrations (#26215)
There is a drawback to how we currently write our migrations:

For example:

1. Suppose we change one of our actions from a string to an array and
rename it, then roll out the preview build:

      Before: `"ctrl-x": "editor::GoToPrevHunk"`
Latest: `"ctrl-x": ["editor::GoToPreviousHunk", { "center_cursor": true
}]`
      
To handle this, we wrote migration `A` to convert the string to an
array.

2. Now, suppose we decide to change it back to a string:
- User who hasn't migrated yet on Preview: `"ctrl-x":
"editor::GoToPrevHunk"`
- User who has migrated on Preview: `"ctrl-x":
["editor::GoToPreviousHunk", { "center_cursor": true }]`
    - Latest: `"ctrl-x": "editor::GoToPreviousHunk"`

To handle this, we would need to remove migration `A` and add two more
migrations:
- **Migration B**: `"ctrl-x": "editor::GoToPrevHunk"` -> `"ctrl-x":
"editor::GoToPreviousHunk"`
- **Migration C**: `"ctrl-x": ["editor::GoToPreviousHunk", {
"center_cursor": true }]` -> `"ctrl-x": "editor::GoToPreviousHunk"`

Nice. But over time, this keeps increasing, making it impossible to
track outdated versions and handle all cases. Missing a case means users
stuck on `"ctrl-x": "editor::GoToPrevHunk"` will remain there and won't
be automatically migrated to the latest state.

---

To fix this, we introduce versioned migrations. Instead of removing
migration `A`, we simply write a new migration that takes the user to
the latest version—i.e., in this case, migration `C`.

- A user who hasn't migrated before will go through both migrations `A`
and `C` in order.
- A user who has already migrated will only go through `C`, since `A`
wouldn't change anything for them.

With incremental migrations, we only need to write migrations on top of
the latest state (big win!), as know internally they all would be on
latest state. You *must not* modify previous migrations. Always create
new ones instead.

This also serves as base for only prompting user to migrate, when
feature reaches stable. That way, preview and stable keymap and settings
are in sync.

cc: @mgsloan @ConradIrwin @probably-neb 

Release Notes:

- N/A
2025-03-06 23:04:48 +05:30
Marshall Bowers
6fd9708eee extension: Add capabilities for the process API (#26224)
This PR adds support for capabilities for the extension process API.

In order to use the process API, an extension must declare which
commands it wants to use, with arguments:

```toml
[[capabilities]]
kind = "process:exec"
command = "echo"
args = ["hello!"]
```

A `*` can be used to denote a single wildcard in the argument list:

```toml
[[capabilities]]
kind = "process:exec"
command = "echo"
args = ["*"]
```

And `**` can be used to denote a wildcard for the remaining arguments:

```toml
[[capabilities]]
kind = "process:exec"
command = "ls"
args = ["-a", "**"]
```

Release Notes:

- N/A

---------

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-06 11:55:00 -05:00
Marshall Bowers
99216acdec gpui: Rename rounded_sm to rounded_xs (#26221)
This PR renames the `rounded_sm` style method to `rounded_xs`.

This will allow us to add an additional step in the scale.

Release Notes:

- N/A
2025-03-06 16:08:19 +00:00
Chris Boette
aef25a3bc3 slash_commands_example: Improve setup instructions in README (#26217)
This PR improves the setup instructions for the slash-commands-example
extension by:

1. Replacing the `sed` command with a more reliable approach that
completely replaces the Cargo.toml file.

2. Explicitly showing how to create a standalone extension with a
properly configured Cargo.toml file that:
   - Uses `edition = "2021"` instead of `edition.workspace = true`
   - Doesn't include `publish.workspace = true`
   - Doesn't include the `[lints]` section

This change addresses an issue where the extension wouldn't work when
copied as a standalone project due to workspace references that are only
valid when the extension is built as part of the main Zed repository.

The updated instructions provide a clear, reliable path for developers
to create their own Zed extensions based on the slash commands example.

Release Notes:

- N/A
2025-03-06 10:56:17 -05:00
greathongtu
9b07f36199 gpui: Fix Cut action in input example (#26203)
Zed fan trying to learn GPUI here. Notice one problem in input example
which cause cmd-x function not work.
Let me know if any adjustments are needed!

Release Notes:

- N/A
2025-03-06 10:02:52 -05:00
Ben Kunkle
ff25fa24e7 Add support for auto-closing of JSX tags (#25681)
Closes #4271

Implemented by kicking of a task on the main thread at the end of
`Editor::handle_input` which waits for the buffer to be re-parsed before
checking if JSX tag completion possible based on the recent edits, and
if it is then it spawns a task on the background thread to generate the
edits to be auto-applied to the buffer

Release Notes:

- Added support for auto-closing of JSX tags

---------

Co-authored-by: Cole Miller <cole@zed.dev>
Co-authored-by: Max Brunsfeld <max@zed.dev>
Co-authored-by: Marshall Bowers <git@maxdeviant.com>
Co-authored-by: Mikayla <mikayla@zed.dev>
Co-authored-by: Peter Tripp <peter@zed.dev>
2025-03-06 08:36:10 -06:00
张小白
05df3d1bd6 windows: Dock menu impl 2 (#26010)
Closes #ISSUE

Release Notes:

- N/A *or* Added/Fixed/Improved ...
2025-03-06 12:40:34 +00:00
Piotr Osiewicz
84f4d2630f node_runtime: Use user/global configuration when using system node installation (#26209)
This partially reverts https://github.com/zed-industries/zed/pull/3324
We will still blank out user/global config when running managed NPM, to
keep to the spirit of #3324 (which was made at the time we did not allow
user-provided NPM builds - the intent of the change was to make the
behavior of NPM as consistent as possible).

I tested this change by:
1. Setting up a custom NPM registry via Versaccio
2. Adding this new registry to my .npmrc
3. Mirroring `vscode-langservers-extracted` to it 
4. Blocking access to `registry.npmjs.org`
5. Opening up settings.json file in Zed Nightly
- Verifying that language server update fails for it
6. Opening up Zed Dev build of this branch
- Confirming that language server update check goes through for it

Closes #19806
Closes #20749
Closes #9422

Release Notes:

- User and global .npmrc configuration is now respected when running
user-provided NPM binary (which also happens automatically when `npm`
from PATH is newer than 18.0.0)
2025-03-06 12:50:42 +01:00
renovate[bot]
b42930f5be Update Rust crate embed-resource to v3.0.2 (#26171)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[embed-resource](https://redirect.github.com/nabijaczleweli/rust-embed-resource)
| build-dependencies | patch | `3.0.1` -> `3.0.2` |

---

### Release Notes

<details>
<summary>nabijaczleweli/rust-embed-resource (embed-resource)</summary>

###
[`v3.0.2`](https://redirect.github.com/nabijaczleweli/rust-embed-resource/compare/v3.0.1...v3.0.2)

[Compare
Source](https://redirect.github.com/nabijaczleweli/rust-embed-resource/compare/v3.0.1...v3.0.2)

</details>

---

### Configuration

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

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

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

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

---

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

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xODUuNCIsInVwZGF0ZWRJblZlciI6IjM5LjE4NS40IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-06 12:31:11 +02:00
renovate[bot]
cb2eef6fb6 Update Rust crate chrono to v0.4.40 (#26170)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [chrono](https://redirect.github.com/chronotope/chrono) |
workspace.dependencies | patch | `0.4.39` -> `0.4.40` |

---

### Release Notes

<details>
<summary>chronotope/chrono (chrono)</summary>

###
[`v0.4.40`](https://redirect.github.com/chronotope/chrono/releases/tag/v0.4.40):
0.4.40

[Compare
Source](https://redirect.github.com/chronotope/chrono/compare/v0.4.39...v0.4.40)

#### What's Changed

- Add Month::num_days() by
[@&#8203;djc](https://redirect.github.com/djc) in
[https://github.com/chronotope/chrono/pull/1645](https://redirect.github.com/chronotope/chrono/pull/1645)
- Update Windows dependencies by
[@&#8203;kennykerr](https://redirect.github.com/kennykerr) in
[https://github.com/chronotope/chrono/pull/1646](https://redirect.github.com/chronotope/chrono/pull/1646)
- Feature/round_up method on DurationRound trait by
[@&#8203;MagnumTrader](https://redirect.github.com/MagnumTrader) in
[https://github.com/chronotope/chrono/pull/1651](https://redirect.github.com/chronotope/chrono/pull/1651)
- Expose `write_to` for `DelayedFormat` by
[@&#8203;tugtugtug](https://redirect.github.com/tugtugtug) in
[https://github.com/chronotope/chrono/pull/1654](https://redirect.github.com/chronotope/chrono/pull/1654)
- Update LICENSE.txt by
[@&#8203;maximevtush](https://redirect.github.com/maximevtush) in
[https://github.com/chronotope/chrono/pull/1656](https://redirect.github.com/chronotope/chrono/pull/1656)
- docs: fix minor typo by
[@&#8203;samfolo](https://redirect.github.com/samfolo) in
[https://github.com/chronotope/chrono/pull/1659](https://redirect.github.com/chronotope/chrono/pull/1659)
- Use NaiveDateTime for internal tz_info methods. by
[@&#8203;AVee](https://redirect.github.com/AVee) in
[https://github.com/chronotope/chrono/pull/1658](https://redirect.github.com/chronotope/chrono/pull/1658)
- Upgrade to windows-bindgen 0.60 by
[@&#8203;djc](https://redirect.github.com/djc) in
[https://github.com/chronotope/chrono/pull/1665](https://redirect.github.com/chronotope/chrono/pull/1665)
- Add quarter (%q) date string specifier by
[@&#8203;drinkcat](https://redirect.github.com/drinkcat) in
[https://github.com/chronotope/chrono/pull/1666](https://redirect.github.com/chronotope/chrono/pull/1666)

</details>

---

### Configuration

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

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

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

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

---

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

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xODUuNCIsInVwZGF0ZWRJblZlciI6IjM5LjE4NS40IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-06 12:30:56 +02:00
renovate[bot]
73668c2c4b Update Rust crate async-compression to v0.4.20 (#26154)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[async-compression](https://redirect.github.com/Nullus157/async-compression)
| workspace.dependencies | patch | `0.4.18` -> `0.4.20` |

---

### Release Notes

<details>
<summary>Nullus157/async-compression (async-compression)</summary>

###
[`v0.4.20`](https://redirect.github.com/Nullus157/async-compression/blob/HEAD/CHANGELOG.md#0420---2025-02-28)

[Compare
Source](https://redirect.github.com/Nullus157/async-compression/compare/v0.4.19...v0.4.20)

##### Added

-   Add support for `wasm32-wasip1-*` targets.

###
[`v0.4.19`](https://redirect.github.com/Nullus157/async-compression/blob/HEAD/CHANGELOG.md#0419---2025-02-27)

[Compare
Source](https://redirect.github.com/Nullus157/async-compression/compare/v0.4.18...v0.4.19)

##### Changed

-   Update `bzip2` dependency to `0.5`.

##### Fixed

-   Ensure that flush finishes before continuing.

</details>

---

### Configuration

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

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

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

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

---

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

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xODUuNCIsInVwZGF0ZWRJblZlciI6IjM5LjE4NS40IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-06 12:30:38 +02:00
renovate[bot]
07f555ca3b Update Rust crate cargo_metadata to v0.19.2 (#26165)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [cargo_metadata](https://redirect.github.com/oli-obk/cargo_metadata) |
workspace.dependencies | patch | `0.19.1` -> `0.19.2` |

---

### Release Notes

<details>
<summary>oli-obk/cargo_metadata (cargo_metadata)</summary>

###
[`v0.19.2`](https://redirect.github.com/oli-obk/cargo_metadata/compare/0.19.1...0.19.2)

[Compare
Source](https://redirect.github.com/oli-obk/cargo_metadata/compare/0.19.1...0.19.2)

</details>

---

### Configuration

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

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

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

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

---

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

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xODUuNCIsInVwZGF0ZWRJblZlciI6IjM5LjE4NS40IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-06 09:24:48 +00:00
renovate[bot]
b0e2b57462 Update Rust crate linkme to v0.3.32 (#26191)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [linkme](https://redirect.github.com/dtolnay/linkme) |
workspace.dependencies | patch | `0.3.31` -> `0.3.32` |

---

### Release Notes

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

###
[`v0.3.32`](https://redirect.github.com/dtolnay/linkme/releases/tag/0.3.32)

[Compare
Source](https://redirect.github.com/dtolnay/linkme/compare/0.3.31...0.3.32)

-   Documentation improvements

</details>

---

### Configuration

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

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

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

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

---

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

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xODUuNCIsInVwZGF0ZWRJblZlciI6IjM5LjE4NS40IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-06 11:06:55 +02:00
renovate[bot]
d404d7964e Update Rust crate blake3 to v1.6.1 (#26159)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [blake3](https://redirect.github.com/BLAKE3-team/BLAKE3) |
workspace.dependencies | patch | `1.6.0` -> `1.6.1` |

---

### Release Notes

<details>
<summary>BLAKE3-team/BLAKE3 (blake3)</summary>

###
[`v1.6.1`](https://redirect.github.com/BLAKE3-team/BLAKE3/releases/tag/1.6.1)

[Compare
Source](https://redirect.github.com/BLAKE3-team/BLAKE3/compare/1.6.0...1.6.1)

version 1.6.1

Changes since 1.6.0:

-   Remove `mmap` from the default features list. It was added
    accidentally in v1.6.0, last week. This is technically a
backwards-incompatible change, but I would rather not tag v2.0.0 for a
    build-time bugfix with a simple workaround.

</details>

---

### Configuration

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

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

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

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

---

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

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xODUuNCIsInVwZGF0ZWRJblZlciI6IjM5LjE4NS40IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-06 11:06:06 +02:00
renovate[bot]
69af9bedaf Update Rust crate oo7 to v0.4.1 (#26192)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [oo7](https://redirect.github.com/bilelmoussaoui/oo7) | dependencies |
patch | `0.4.0` -> `0.4.1` |

---

### Configuration

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

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

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

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

---

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

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xODUuNCIsInVwZGF0ZWRJblZlciI6IjM5LjE4NS40IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-06 11:05:44 +02:00
Conrad Irwin
2ebbcf15ea Don't deleete non-extant files (#26187)
Closes #ISSUE

Release Notes:

- N/A *or* Added/Fixed/Improved ...
2025-03-05 22:45:25 -07:00
renovate[bot]
631cab5e40 Update Rust crate indoc to v2.0.6 (#26177)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [indoc](https://redirect.github.com/dtolnay/indoc) |
workspace.dependencies | patch | `2.0.5` -> `2.0.6` |

---

### Release Notes

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

###
[`v2.0.6`](https://redirect.github.com/dtolnay/indoc/releases/tag/2.0.6)

[Compare
Source](https://redirect.github.com/dtolnay/indoc/compare/2.0.5...2.0.6)

-   Documentation improvements

</details>

---

### Configuration

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

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

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

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

---

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

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xODUuNCIsInVwZGF0ZWRJblZlciI6IjM5LjE4NS40IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-06 05:39:10 +00:00
renovate[bot]
ba39a47c52 Update Rust crate libc to v0.2.170 (#26181)
This PR contains the following updates:

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

---

### Release Notes

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

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

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

##### Added

- Android: Declare `setdomainname` and `getdomainname`
[#&#8203;4212](https://redirect.github.com/rust-lang/libc/pull/4212)
- FreeBSD: Add `evdev` structures
[#&#8203;3756](https://redirect.github.com/rust-lang/libc/pull/3756)
- FreeBSD: Add the new `st_filerev` field to `stat32`
([#&#8203;4254](https://redirect.github.com/rust-lang/libc/pull/4254))
- Linux: Add ` SI_*`` and `TRAP_\*\`\` signal codes
[#&#8203;4225](https://redirect.github.com/rust-lang/libc/pull/4225)
- Linux: Add experimental configuration to enable 64-bit time in kernel
APIs, set by `RUST_LIBC_UNSTABLE_LINUX_TIME_BITS64`.
[#&#8203;4148](https://redirect.github.com/rust-lang/libc/pull/4148)
- Linux: Add recent socket timestamping flags
[#&#8203;4273](https://redirect.github.com/rust-lang/libc/pull/4273)
- Linux: Added new CANFD_FDF flag for the flags field of canfd_frame
[#&#8203;4223](https://redirect.github.com/rust-lang/libc/pull/4223)
- Musl: add CLONE_NEWTIME
[#&#8203;4226](https://redirect.github.com/rust-lang/libc/pull/4226)
- Solarish: add the posix_spawn family of functions
[#&#8203;4259](https://redirect.github.com/rust-lang/libc/pull/4259)

##### Deprecated

- Linux: deprecate kernel modules syscalls
[#&#8203;4228](https://redirect.github.com/rust-lang/libc/pull/4228)

##### Changed

- Emscripten: Assume version is at least 3.1.42
[#&#8203;4243](https://redirect.github.com/rust-lang/libc/pull/4243)

##### Fixed

- BSD: Correct the definition of `WEXITSTATUS`
[#&#8203;4213](https://redirect.github.com/rust-lang/libc/pull/4213)
- Hurd: Fix CMSG_DATA on 64bit systems
([#&#8203;4240](https://redirect.github.com/rust-lang/libc/pull/424))
- NetBSD: fix `getmntinfo`
([#&#8203;4265](https://redirect.github.com/rust-lang/libc/pull/4265)
- VxWorks: Fix the size of `time_t`
[#&#8203;426](https://redirect.github.com/rust-lang/libc/pull/426)

##### Other

- Add labels to FIXMEs
[#&#8203;4230](https://redirect.github.com/rust-lang/libc/pull/4230),
[#&#8203;4229](https://redirect.github.com/rust-lang/libc/pull/4229),
[#&#8203;4237](https://redirect.github.com/rust-lang/libc/pull/4237)
- CI: Bump FreeBSD CI to 13.4 and 14.2
[#&#8203;4260](https://redirect.github.com/rust-lang/libc/pull/4260)
- Copy definitions from core::ffi and centralize them
[#&#8203;4256](https://redirect.github.com/rust-lang/libc/pull/4256)
- Define c_char at top-level and remove per-target c_char definitions
[#&#8203;4202](https://redirect.github.com/rust-lang/libc/pull/4202)
- Port style.rs to syn and add tests for the style checker
[#&#8203;4220](https://redirect.github.com/rust-lang/libc/pull/4220)

</details>

---

### Configuration

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

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

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

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

---

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

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xODUuNCIsInVwZGF0ZWRJblZlciI6IjM5LjE4NS40IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-06 05:27:23 +00:00
Conrad Irwin
c34357e2ab 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 05:20:06 +00:00
renovate[bot]
6fdb666bb7 Update Rust crate inventory to v0.3.20 (#26180)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [inventory](https://redirect.github.com/dtolnay/inventory) |
workspace.dependencies | patch | `0.3.19` -> `0.3.20` |

---

### Release Notes

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

###
[`v0.3.20`](https://redirect.github.com/dtolnay/inventory/releases/tag/0.3.20)

[Compare
Source](https://redirect.github.com/dtolnay/inventory/compare/0.3.19...0.3.20)

-   Documentation improvements

</details>

---

### Configuration

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

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

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

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

---

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

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xODUuNCIsInVwZGF0ZWRJblZlciI6IjM5LjE4NS40IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-06 00:15:57 -05:00
Peter Tripp
7a9e0b37ed Improve schema_generator CLI (#25898)
Release Notes:

- N/A
2025-03-06 04:59:57 +00:00
renovate[bot]
d44ba92363 Update Rust crate globset to v0.4.16 (#26176)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[globset](https://redirect.github.com/BurntSushi/ripgrep/tree/master/crates/globset)
([source](https://redirect.github.com/BurntSushi/ripgrep/tree/HEAD/crates/globset))
| workspace.dependencies | patch | `0.4.15` -> `0.4.16` |

---

### Configuration

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

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

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

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

---

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

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xODUuNCIsInVwZGF0ZWRJblZlciI6IjM5LjE4NS40IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-06 04:45:26 +00:00
renovate[bot]
ca4d8fc900 Update Rust crate bytes to v1.10.1 (#26164)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [bytes](https://redirect.github.com/tokio-rs/bytes) |
workspace.dependencies | patch | `1.10.0` -> `1.10.1` |

---

### Release Notes

<details>
<summary>tokio-rs/bytes (bytes)</summary>

###
[`v1.10.1`](https://redirect.github.com/tokio-rs/bytes/blob/HEAD/CHANGELOG.md#1101-March-5th-2025)

[Compare
Source](https://redirect.github.com/tokio-rs/bytes/compare/v1.10.0...v1.10.1)

##### Fixed

- Fix memory leak when using `to_vec` with `Bytes::from_owner`
([#&#8203;773](https://redirect.github.com/tokio-rs/bytes/issues/773))

</details>

---

### Configuration

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

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

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

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

---

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

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xODUuNCIsInVwZGF0ZWRJblZlciI6IjM5LjE4NS40IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-06 04:35:04 +00:00
Agus Zubiaga
352882af77 docs: Improve edit prediction tab conflict section (#25493)
To be merged when https://github.com/zed-industries/zed/pull/25491 is released

Release Notes:

- N/A

Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
2025-03-05 23:23:06 -05:00
Cole Miller
c5c4a6201b ci: Upload remote server assets to workflow run as well (#26153)
Closes #ISSUE

Release Notes:

- N/A
2025-03-06 04:20:38 +00:00
Devzeth
6327a5d665 docs: Improve documentation of ensure final new line on save (#25960)
The function ensure_final_newline in buffer.rs has this explanation:
Ensures that the buffer ends with a single newline character, no other
whitespace.

The documentation wasn't explaining well that we actually remove any
lines containing only whitespace and keep only 1 line at the end of a
buffer.

Release Notes:

- N/A

---------

Co-authored-by: Peter Tripp <peter@zed.dev>
Co-authored-by: Danilo Leal <danilo@zed.dev>
2025-03-05 23:14:20 -05:00
Devzeth
57438d30e8 docs: Add documentation for lsp_highlight_debounce (#25974)
Adds documentation for `lsp_highlight_debounce`. 

Release Notes:

- N/A
2025-03-05 23:09:04 -05:00
0x2CA
5c81dd7d39 git: Fix git commit font fallbacks (#26184)
Closes #ISSUE

Release Notes:

- Fixed git commit font_fallbacks
2025-03-06 04:06:00 +00:00
Cole Miller
aec4d5cb26 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
2025-03-06 03:21:40 +00:00
Peter Tripp
4c0750bd2f 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-05 21:59:58 -05:00
brian tan
22b1a02e23 vim: Implement <count>% motion (#25839)
Closes https://github.com/zed-industries/zed/discussions/25665

> Currently Zed is missing quite an useful Vim motion: <count>% (go to
{count} percentage in the file).
Description:
{count}% - Go to {count} percentage in the file, on the first non-blank
in the line linewise. To compute the new line number this formula is
used: ({count} * number-of-lines + 99) / 100 .
> [Link](https://neovim.io/doc/user/motion.html#N%25).

Release Notes:

- vim: Added `<count>%` motion

---------

Co-authored-by: Conrad Irwin <conrad@zed.dev>
2025-03-05 19:59:18 -07:00
Max Brunsfeld
314ad5dd5f 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-05 18:45:09 -08:00
Kirill Bulatov
d3c68650c0 Improve cmd-click in terminal to find more paths (#26174)
Closes https://github.com/zed-industries/zed/issues/25701

Reworks the way cmd-click is handled:

* first, all worktree entries are checked for existence

This allows more fine-grained lookup of entries that are in the
worktree, but their path in the terminal is not "full": in case neither
`cwd` no worktree's root + that temrinal paths form a valid path
(https://github.com/zed-industries/zed/issues/25701)

The worktrees are sorted by "the most close to cwd first" so such files
are attempted to resolved in the most specific worktree.

This also fixes no cmd-click working in the remote ssh.

* second, only if the client is local, do the FS checks to find
non-indexed files

Release Notes:

- Improved cmd-click in terminal to find more paths
2025-03-06 00:41:13 +00:00
Danilo Leal
43339c6869 assistant2: Improve clarity of loading state (#26178)
Follow up to https://github.com/zed-industries/zed/pull/23299.

Having the loading state on the button makes sense, but it's also too
subtle. If you're waiting on an LLM response that takes a while, like a
"thinking state", not having anything more clearly visible communicating
that the model is still in-progress can make you think something is
wrong.

<img
src="https://github.com/user-attachments/assets/da64516e-5540-4294-97a2-e4542ce704f3"
width="700px" />

Release Notes:

- N/A
2025-03-05 21:39:29 -03:00
Julia Ryan
e505d6bf5b 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-05 15:56:51 -08:00
Julia Ryan
0200dda83d 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-05 23:23:05 +00:00
Marshall Bowers
4db9ab15a7 elixir: Extract to zed-extensions/elixir repository (#26167)
This PR extracts the Elixir extension to the
[zed-extensions/elixir](https://github.com/zed-extensions/elixir)
repository.

Release Notes:

- N/A
2025-03-05 22:50:35 +00:00
Cole Miller
5daadc0d30 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
2025-03-05 22:31:45 +00:00
Marshall Bowers
431727fdd7 csharp: Extract to zed-extensions/csharp repository (#26166)
This PR extracts the C# extension to the
[zed-extensions/csharp](https://github.com/zed-extensions/csharp)
repository.

Release Notes:

- N/A
2025-03-05 22:23:49 +00:00
Marshall Bowers
cee98f872a git_ui: Fix typo in comment (#26162)
This PR fixes a typo in a comment.

Release Notes:

- N/A
2025-03-05 21:48:23 +00:00
Marshall Bowers
e99d68a66f 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-05 21:42:48 +00:00
renovate[bot]
6a3e8044b1 Update Rust crate anyhow to v1.0.97 (#26152)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [anyhow](https://redirect.github.com/dtolnay/anyhow) |
workspace.dependencies | patch | `1.0.96` -> `1.0.97` |

---

### Release Notes

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

###
[`v1.0.97`](https://redirect.github.com/dtolnay/anyhow/releases/tag/1.0.97)

[Compare
Source](https://redirect.github.com/dtolnay/anyhow/compare/1.0.96...1.0.97)

-   Documentation improvements

</details>

---

### Configuration

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

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

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

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

---

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

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xODUuNCIsInVwZGF0ZWRJblZlciI6IjM5LjE4NS40IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-05 16:32:07 -05:00
renovate[bot]
c2375a4164 Update Rust crate async-trait to v0.1.87 (#26158)
This PR contains the following updates:

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

---

### Release Notes

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

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

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

-   Documentation improvements

</details>

---

### Configuration

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

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

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

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

---

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

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xODUuNCIsInVwZGF0ZWRJblZlciI6IjM5LjE4NS40IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-05 16:31:40 -05:00
Mikayla Maki
9d54e63a11 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-05 21:16:46 +00:00
Conrad Irwin
2a919ad1d0 git: Make repo selector wider (#26149)
…m_item()

Closes #ISSUE

Release Notes:

- git: Fixed repository selector being too narrow
2025-03-05 13:02:29 -07:00
Julia Ryan
f13b2fd811 Fix left clicking the close button in the switcher (#25979)
The close button on each tab previously only worked when you right
clicked it, presumably because on macos people were using `ctrl+tab` to
open the picker, and clicking with `ctrl` held registers as a right
click. Now it should work with either mouse button.

Release Notes:

- N/A

Co-authored-by: Conrad <conrad@zed.dev>
2025-03-05 11:50:39 -08:00
Marshall Bowers
7c39153160 assistant_tools: Add list-worktrees and read-file tools (#26147)
This PR adds two new tools to Assistant 2:

- `list-worktrees` - Lists the worktrees in a project
- `read-file` - Reads a file at the given path in the project

I don't see `list-worktrees` sticking around long-term, as when we have
tools for listing files those will include the worktree IDs along with
the path, but making this tool available allows the model to utilize
`read-file` when it otherwise wouldn't be able to.

Release Notes:

- N/A
2025-03-05 19:41:42 +00:00
Marshall Bowers
d0c2bef8c3 anthropic: Use an empty object if no tool input is provided (#26144)
This PR changes the default value when no input is provided with a tool
use from `null` to `{}`.

This fixes an issue I was seeing where tools that didn't accept input
were not being called correctly.

Release Notes:

- N/A
2025-03-05 19:17:44 +00:00
Cole Miller
87b3fefdd1 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
2025-03-05 13:07:36 -05:00
Marshall Bowers
66784c0b3f 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:48:10 -05:00
Cole Miller
ad9c508a72 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>
2025-03-05 12:25:51 -05:00
Max Brunsfeld
aaa506c061 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 08:50:19 -08:00
Bennet Bo Fenner
a602c50a6c assistant2: Allow adding directories as context that contain non-UTF8 files (#26135)
We would previously return an error if there was at least one non-UTF8
file. Now we just ignore them and only add text files. If no text files
are found we show an error.

Release Notes:

- N/A
2025-03-05 16:47:43 +00:00
Marshall Bowers
728c161e8d 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 16:18:01 +00:00
Asqar Arslanov
3975d8ea93 vim: Rename wrapping keybindings + document cursor wrapping (#25694)
https://github.com/zed-industries/zed/pull/25663#issuecomment-2686095807

Renamed the `vim::Backspace` and `vim::Space` actions to
`vim::WrappingLeft` and `vim::WrappingRight` respectively. The old names
are still available, but they are marked as deprecated and users are
advised to use the new names.

Also added a paragraph to the docs describing how to enable wrapping
cursor navigation.
2025-03-05 08:54:30 -07:00
Peter Tripp
2d050a8130 Fix SSH remotes running Nushell (#25613)
- Closes: https://github.com/zed-industries/zed/issues/21005

Nushell does not support `uname -sm`
So invoke `sh -c "uname -sm"` instead which will also work under nushell.
See https://github.com/nushell/nushell/issues/12570 for the choice quote: "being posix/bash compliant is a non-goal"

Release Notes:

- Fixed ssh remotes running Nushell
2025-03-05 15:50:32 +00:00
Dino
e600e71c1c vim: Fix tab title when using !! and disable rerun button for terminal tasks (#26122)
These changes tackle two issues with running terminal commands via vim
mode:

- When using `!!` the tab's title was set to `!!` instead of the
previous command that was run and these changes fix that in order to
always display the previous command in the tab's title when re-running
the command with `!!`
- For a terminal command, pressing the rerun button would actually bring
up the task palette, so this has been updated in order to disable the
rerun button when the terminal tab was spawned via a vim command

Closes #25800 

Release Notes:

- Fixed the terminal tab title when using `!!` to rerun the last command
- Improved the terminal tab for when command is run via vim mode, in
order to disable the rerun button, seeing as Zed does not support it
2025-03-05 08:47:49 -07:00
Marshall Bowers
82d85fd2ed deno: Extract to zed-extensions/deno repository (#26129)
This PR extracts the Deno extension to the
[zed-extensions/deno](https://github.com/zed-extensions/deno)
repository.

Release Notes:

- N/A
2025-03-05 15:31:21 +00:00
smit
e061ebb46c editor: Fix cmd + click on a URL not working sometimes (#26128)
Closes #25647

This PR fixes two issues related to cmd + click on URL:

1. Normally cmd + click on URL, it opens browser. Now, alt + tab back to
Zed. If you cmd + click on link again it won't work, until you normal
click some where else in buffer. It won't even show underline.

2. Again, cmd + click on URL, it opens browser. Now, alt + tab back to
Zed. If you cmd + click, some where else in buffer like just normal
text, and now try to hover on URL it won't show up underline and cmd +
click on it won't work. Unless again, if you plain click somewhere else.

Problem:

Issue is when clicking we set pending anchor (for selection), and when
we mouse up we clear those. This works for normal case without pressing
any modifier.

But, in case of cmd modifier, we set pending anchor (set when
`SelectPhase::Begin`), but we don't clear it once we use that data.

Fix: 

Once we end up using selection, anchor, etc data to figure out where to
navigate either URL/defination etc, we clear selection just like how we
do it in normal click. This doesn't require to happen after navigate
task, so we do it right after our usage of it.

Before:


https://github.com/user-attachments/assets/b33d93fc-f490-4fa4-ae22-1da1fd6b77a9

After:


https://github.com/user-attachments/assets/028f039a-cd13-4651-b461-3ba52f2526de


Release Notes:

- Fixed an issue where cmd + click on a URL was not working sometimes.
2025-03-05 20:58:18 +05:30
smit
387ee46c46 project: Fix issue where Cmd+Click on an import opens the wrong file (#26120)
Closes #21974

`resolve_path_in_worktrees` function looks for provided path in each
worktree until valid file is found.

In this PR we priortize current buffer worktree before other worktrees,
because of edge case where, file with same name might exists in other
worktrees.

Updated tests to handle this case.

Release Notes:

- Fixed an issue where the wrong file from a different worktree would
open when using `Cmd + Click` on a file import.
2025-03-05 16:49:39 +05:30
Maksim Bondarenkov
89d89b8b2d docs: Update MSYS2 section to add information about CLI (#25882)
MSYS2 now provides CLI along with editor in Zed package:
https://packages.msys2.org/packages/mingw-w64-ucrt-x86_64-zed

Closes #ISSUE

Release Notes:

- N/A
2025-03-05 13:08:54 +08:00
AidanV
f07ae541ad vim: Add registers view (#25945)
Closes #18157

Release Notes:

- vim: Added `:reg[isters]` to show the current values of registers

---------

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-03-04 21:59:19 -07:00
brian tan
ff0bb1f389 vim: Fix insert before in visual modes (#25603)
Closes #22536

Changes:
- Visual and visual block: Cursor at start of selection.
- Visual line: Cursor at start on line.
- Uses different handling since the selection does not actually change
in vline.

Release Notes:

- vim: Fixed insert before (`shift-i`) in visual modes.
2025-03-04 21:58:01 -07:00
0x2CA
9c7eee24bc vim: Fix ignoring cursor_shape settings (#25439)
Closes #ISSUE

[Block cursor in insert mode
#25322](https://github.com/zed-industries/zed/discussions/25322)

Respect the `cursor_shape` setting in insert mode

Release Notes:

- Fixed vim ignoring `cursor_shape` settings
2025-03-04 21:48:43 -07:00
Conrad Irwin
ec4719146a Fix . repeat for remapping surrounds/exchange actions (#26101)
Closes #ISSUE

cc @thomasheartman

Release Notes:

- vim: Fixes `.` repeat for remapped surrounds/exchange actions
2025-03-04 21:47:12 -07:00
0x2CA
47f8f891c8 vim: Fix "seed_search_query_from_cursor" : "selection" (#26107)
Closes #9311
Closes #14843

Release Notes:

- Fixed vim `"seed_search_query_from_cursor" : "selection"`
2025-03-04 21:46:58 -07:00
maan2003
d9d3b8847b nix: Bump flake to get Rust 1.85 (#26076)
old nixpkgs versions didn't have rust 1.85 and nix develop failed (1.85
is specified in rust-toolchain.toml).

ran `nix flake update` to bump the flake dependencies. it now works

Release Notes:

- N/A
2025-03-04 19:18:40 -08:00
Conrad Irwin
d7b90f4204 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>
2025-03-04 20:07:19 -07:00
brian tan
3e64f38ba0 vim: Add support for toggling boolean values (#25997)
Closes #10400
Closes https://github.com/zed-industries/zed/issues/17947

Changes:
- Let vim::increment find boolean values in the line and toggle them. 

Release Notes:

- vim: Added support for toggling boolean values with `ctrl-a`/`ctrl-x`
2025-03-05 03:00:44 +00:00
Thomas Heartman
82338e2c47 vim: Fix clear exchange not working (#25804)
Fixes two issues with the Vim exchange implementation:

1. The clear exchange implementation **didn't** clear the exchange. This
was due to us asking the editor to clear normal highlights instead of
background highlights.
2. Calling clear exchange also wouldn't cause the operator to be
cleared, so you would be left in operator = "cx".

I've added tests for both of these cases.

Partially closes #25750. It doesn't address the problem with dot repeat
not working for my custom bindings, but I don't know what would cause
that. I'd love to hear some thoughts on why that is. That might be a
problem on my part or it might be something with the code. Input would
be appreciated.

Release Notes:

- Fixed: Vim exchange's "clear exchange" function didn't clear the
exchange and kept you in operator pending mode.
2025-03-04 19:34:52 -07:00
Nico Lehmann
229e853874 Make buffer search aware of search direction (#24974)
This solves a couple of issues with Vim search by making the search
buffer and `SearchableItem` aware of the direction of the search. If
`SearchOptions::BACKWARDS` is set, all operations will be reversed. By
making `SearchableItem` aware of the direction, the correct active match
can be selected when searching backward.

Fixes #22506. This PR does not fix the last problem in that issue, but
that one is also tracked in #8049.

Release Notes:

- Fixes incorrect behavior of backward search in Vim mode
2025-03-04 19:27:37 -07:00
Ben Kunkle
ed13e05855 project search: Fix text cutoff in options help text (#26098)
Closes #25495

Release Notes:

- N/A
2025-03-05 01:15:11 +00:00
Conrad Irwin
674fb7621f 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>
2025-03-05 00:50:26 +00:00
Max Brunsfeld
fe18c73a07 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:25:58 -08:00
Marshall Bowers
befacfe8c9 assistant2: Prevent concurrent thread saving tasks (#26089)
This PR makes it so only one thread-saving task will be in flight at a
time.

Release Notes:

- N/A
2025-03-05 00:18:13 +00:00
Danilo Leal
54f0a729c2 assistant2: Adjust edit message actions (#26081)
Fine-tuning the visuals (namely, reducing font and keybinding size) and
passing `on_click` handlers to the Cancel & Regenerate actions.

Release Notes:

- N/A
2025-03-04 20:48:29 -03:00
Marshall Bowers
67f9b2b87f markdown: Only change the copy code icon to a check temporarily (#26079)
This PR makes it so the copy code icon only changes to a check
temporarily.

It will now revert to the "copy" icon after 2 seconds.


https://github.com/user-attachments/assets/e8983268-9710-4519-97a0-b28dc237b109

Release Notes:

- N/A
2025-03-04 23:02:43 +00:00
Richard Feldman
a4ec0af681 Add initial scripting_tool (#26066)
Just a basic implementation so we can start trying it out.

Release Notes:

- N/A

---------

Co-authored-by: Marshall <marshall@zed.dev>
Co-authored-by: Michael <michael@zed.dev>
2025-03-04 17:59:19 -05:00
Marshall Bowers
886d8c1cab markdown: Ensure code block copy button stays in the right spot (#26074)
This PR makes it so the copy button on Markdown code blocks stays
absolutely positioned even when scrolled:

<img width="1297" alt="Screenshot 2025-03-04 at 5 28 48 PM"
src="https://github.com/user-attachments/assets/b0d0fae9-ccd6-43c1-bef3-44d8d3c3e669"
/>

We achieve this by inserting a new parent element around both the copy
button and the code block itself so we can position the copy button
absolutely within that element.

Release Notes:

- N/A
2025-03-04 22:44:29 +00:00
Mikayla Maki
ebc5c213a2 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.
2025-03-04 21:58:26 +00:00
Joseph T. Lyons
0a2d938ac5 Do not include recent issues in issue response script (#26064)
Do not report issues that were created yesterday or today.

Release Notes:

- N/A
2025-03-04 16:13:53 -05:00
Kirill Bulatov
fc01f496a9 Fix font sizes not reacting on settings change (#26060)
Proper version of https://github.com/zed-industries/zed/pull/25425
When https://github.com/zed-industries/zed/pull/24857 returned font
updates on settings changes, settings values, not in-memory ones should
be compared.

This PR returns back the logic finally, and changes it to explicitly
track the settings values, not the in-memory ones.
Also adds the same tracking for UI font changes, which had never been
tracked before.

Release Notes:

- Fixed font sizes not reacting on settings change
2025-03-04 20:57:37 +00:00
Isac Ljung
db28b9bbde Add typescript-language-server and vtsls to list of available language servers (#26046)
Add the typescript language severs as lsp adapters.
This would allow language extensions to use them.
For example using on vue files to be able to run the vue-language-server
in
[hybridMode](https://github.com/vuejs/language-tools?tab=readme-ov-file#hybrid-mode-configuration-requires-vuelanguage-server-version-200).

Release Notes:

- Added `vtsls` and `typescript-language-server` to the list of
available language servers.
2025-03-04 15:49:27 -05:00
Cole Miller
0453cb2b06 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
2025-03-04 12:37:11 -05:00
Conrad Irwin
85211889e5 git: Fix project diff shortcuts (#26045)
Release Notes:

- git: Fix keyboard shortcut display in project diff view
2025-03-04 10:32:20 -07:00
Marshall Bowers
ad94642e83 markdown: Fix code block wrapping when horizontal scrolling is disabled (#26048)
This PR fixes an issue where code block wrapping was broken when not
using horizontal scrolling after
https://github.com/zed-industries/zed/pull/25956.

Release Notes:

- N/A
2025-03-04 12:24:08 -05:00
Bennet Bo Fenner
f4899d92a4 assistant2: Add support for editing the last message sent by the user (#26037)
https://github.com/user-attachments/assets/df46632b-dfeb-4991-ab2e-86829b72be9b

Closes #ISSUE

Release Notes:

- N/A
2025-03-04 17:57:42 +01:00
0x2CA
6685d85f49 vim: Fix increment step error (#26023)
Closes #12887

Release Notes:

- Fixed `x g ctrl-a` step
2025-03-04 09:53:35 -07:00
Felix Packard
161f8a1dd2 Fix "Open a file or project to get started" placeholder text not always shown (#26044)
Check that there are no `visible_worktrees` rather than checking
`worktrees` when deciding whether to display the "Open a file or project
to get started" text

Closes #25395

Release Notes:

- Fixed the "Open a file or project to get started" message not always
showing after all buffers have been closed
2025-03-04 09:21:16 -07:00
Nate Butler
6cdd7b7390 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:10:39 -05:00
Alex Ozer
0ec15d6b02 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-04 15:55:27 +00:00
Bennet Bo Fenner
909de2ca6f assistant2: Use cmd-n to create a new prompt editor when already in a prompt editor (#25935)
This flips the keybindings that are used to create a new thread/prompt
editor (only when you're already in a prompt editor)

Release Notes:

- N/A
2025-03-04 16:44:32 +01:00
Agus Zubiaga
f31749c81b edit predictions: Improve UX when there's no keybinding for accepting predictions (#25815)
If the user already binds `tab`/`alt-tab`/`alt-l` to a different action
in a conflicting context and hasn't assigned a different keybinding for
`editor::AcceptEditPrediction`, we would show broken popovers with no
bindings:

![CleanShot 2025-02-28 at 12 46
13@2x](https://github.com/user-attachments/assets/a2c6a8ad-5e11-46ef-8031-62e1e6900244)

Instead, they will now see an error-variant of every popover which
includes a tooltip with a short description and buttons to open the
keymap, and open a new docs section explaining the issue in detail and
how to fix it.

![CleanShot 2025-02-28 at 12 48
11@2x](https://github.com/user-attachments/assets/36329b1f-6374-4735-9fbc-8fccab70e881)

Note: I included the docs change in this PR because it's ok to deploy
before the release, as it also applies to existing versions.

Release Notes:

- edit predictions: Improve UX when there's no keybinding for accepting
predictions

---------

Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
Co-authored-by: Danilo <danilo@zed.dev>
2025-03-04 11:28:36 -03:00
Joseph T. Lyons
76a81607de 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 13:50:53 +00:00
smit
7d22059a2f migration: Add for editor::GoToHunk and editor::GoToPrevHunk actions (#26017)
We modified few actions in
https://github.com/zed-industries/zed/pull/25846, which are:

`"editor::GoToHunk" -> ["editor::GoToHunk", { "center_cursor": true }]`
`"editor::GoToPrevHunk" -> ["editor::GoToPrevHunk", { "center_cursor":
true }]`

Also, recently we changed and added migration for:

`["editor::GoToPrevHunk", { "center_cursor": true }] ->
["editor::GoToPreviousHunk", { "center_cursor": true }] `

This means:

1. User that might still have `editor::GoToHunk` won't be automatically
migrated to `["editor::GoToHunk", { "center_cursor": true }]`. Note
value of `center_cursor` is false, in first case (default), and true in
second case.

2. User that might still have `editor::GoToPrevHunk` won't be
automatically migrated to `["editor::GoToPreviousHunk", {
"center_cursor": true }]`. Note, `editor::GoToPrevHunk` is renamed
since, it is now invalid action.

This PR adds those migrations.

cc: @marcospb19 

Release Notes:

- N/A
2025-03-04 18:39:29 +05:30
feeiyu
6b16a5555e Fix lost focus when navigating back in project search result (#22483)
Closes #22447

When navigate forward/back, the focus moves from the ProjectSearchView's
result editor to the Pane, and then move to the ProjectSearchView, but
the event `on_focus_in` not triggered for ProjectSearchView, causing the
result editor to lose focus eventually.


f6dabadaf7/crates/workspace/src/workspace.rs (L1372)


f6dabadaf7/crates/workspace/src/workspace.rs (L1385)

Considering that the navigation might be triggered again in the next
frame, so use `on_next_frame` in `on_focus` event to move focus to
result editor.

Next frame:
- the blur event triggered for result editor.
- focus move from ProjectSearchView to result editor in `on_focus` event
for ProjectSearchView
- navigate again, focus moves from result editor to Pane then move back
to ProjectSearchView
- the focus not change during this frame, so no focus event happened for
ProjectSearchView.

![fix lost
focus1229](https://github.com/user-attachments/assets/bfaac839-7bcf-40e7-b3b4-1423d0510594)

Release Notes:

- Fix lost focus when navigate back in project search result

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
2025-03-04 13:06:44 +00:00
Kirill Bulatov
7ba2b258de 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
2025-03-04 14:47:27 +02:00
Boris Vassilev
cbb535f5eb Fix completion details on new clangd versions (#25405)
Fixes #16057

In newer versions of clangd, the switch labelDetailsSupport in the json
passed to the language server modifies the format of the returned json.
Zed handles well the old format, but misses the function parameters in
the new one. For example:
The old format looks like this:
```json
...
"label": " Window(int width, int height, const char *name, bool vsync, bool resizable)",
...
```
and with labelDetailsSupport = true:
```json
...
 "label": " Window",
 "labelDetails": {
     "detail": "(int width, int height, const char *name, bool vsync, bool resizable)"
 },
...
```
A simple solution is to just to not tell the language server that label
details are supported and force it to use the old format. This is a
dirty fix, but makes the completions behave like in the old versions of
clangd.

I do not know if this will break another language server. From what I've
found out most lsp-s do not depend on that setting and provide all
completion data either way. If not, this switch will need to be exposed
in a config or be at least lsp-dependant.

Lastly, I do not know Rust, maybe will need help to make a better fix
for the issue.

Release Notes:

- Fixed broken C++ completion suggestions
2025-03-04 14:30:03 +02:00
Finn Evers
20fc753f2b editor: Ensure correct tab icon is shown for files outside of the current project (#25933)
Closes #25885 

This PR improves the matching for file icons to tabs. 
Previously, the tab icon would be resolved based upon the relative path
in the current project. However, this caused the default file icon being
assigned to all files outside of the project, as the relative path for
these files would be empty.

Instead, `path_for_buffer` is now used which always returns a proper
file name even for paths outside the current project (as also stated [in
this
comment](fee9c67707/crates/editor/src/items.rs (L1689))).
As the file name is sufficient for matching icons to files, this fixes
the linked issue whilst not changing anything for previously properly
matched icons.

| `main` | This PR |
| --- | --- | 
| <img width="296" alt="main"
src="https://github.com/user-attachments/assets/e72b8b5d-aa1c-4a8e-903f-14239f5b8764"
/> | <img width="296" alt="PR"
src="https://github.com/user-attachments/assets/a736974a-ce41-4861-be3f-95448cc7ffd0"
/> |

Release Notes:

- Fixed wrong file icons being shown for files outside of the current
project.
2025-03-04 13:57:26 +02:00
Finn Evers
042fc82e99 python: Fix and improve highlighting (#25813)
Closes #25803
Closes #25707 

This PR fixes the highlighting regression described in #25803 by fixing
the priorities of highlights as described in the [comment within the
file
itself](5b66ea1563/crates/languages/src/python/highlights.scm (L1)).
A nice side-effect of this is that scoped constants or other identifiers
are now also more accurately highlighted, as seen in the screenshots
below.

While I was at it, I also adressed the highlighting issue for default
typed idenfiers.

| This PR | <img width="575" alt="PR"
src="https://github.com/user-attachments/assets/aed5cdd0-c31a-4794-8128-376944fddd2d"
/> |
| --- | --- |
| Preview | <img width="575" alt="preview"
src="https://github.com/user-attachments/assets/ae3fad35-d436-472c-aff0-16508304ccf7"
/> |
| Stable | <img width="575" alt="stable"
src="https://github.com/user-attachments/assets/3836427c-f1cc-42ea-b1a7-8f5bbbadf210"
/> |

Release Notes:

- Fixed constants not being highlighted in Python-files.
- Improved Python-highlighting for default function arguments and scoped
identifiers.
2025-03-04 08:41:10 +01:00
Finn Evers
27781a8a60 html: Add injections for style attributes and event handler attributes (#23659)
Closes #23653 

Before:
<img width="921" alt="before"
src="https://github.com/user-attachments/assets/e993df15-77a7-4b5a-b6fb-3415047914c0"
/>

After:
<img width="922" alt="after"
src="https://github.com/user-attachments/assets/1b4bd695-2985-46e2-8b55-576d32af0583"
/>

Release Notes:

- N/A
2025-03-04 09:12:25 +02:00
Joseph T. Lyons
33af6bce55 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:01:52 -05:00
Max Brunsfeld
563baf682e 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
2025-03-03 22:18:27 -08:00
张小白
11b79d0ab9 workspace: Add trailing / to directories on completion when using OpenPathPrompt (#25430)
Closes #25045

With the setting `"use_system_path_prompts": false`, previously, if the
completion target was a directory, no separator would be added after it,
requiring us to manually append a `/` or `\`. Now, if the completion
target is a directory, a `/` or `\` will be automatically added. On
Windows, both `/` and `\` are considered valid path separators.



https://github.com/user-attachments/assets/0594ce27-9693-4a49-ae0e-3ed29f62526a



Release Notes:

- N/A
2025-03-04 14:01:08 +08:00
Joseph T. Lyons
8c4da9fba0 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.
2025-03-04 05:35:18 +00:00
Conrad Irwin
1f7fa80166 git: Fix race condition loading project diff (#25992)
Release Notes:

- git: Fixed a race condition where some files would be missing from
project diff
2025-03-03 21:40:37 -07:00
Conrad Irwin
2ac952ee6b 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
2025-03-03 21:40:20 -07:00
Cole Miller
495612be2e Revert "git: Use worktree paths in the panel (#25950)" (#25995)
This reverts commit e7b3b8bf03.

Release Notes:

- N/A
2025-03-04 04:20:41 +00:00
Conrad Irwin
1086b282b8 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.
2025-03-03 20:49:29 -07:00
Joseph T. Lyons
ffe2bed1e2 Refactor more code around commit button text (#25990)
Missed this when doing https://github.com/zed-industries/zed/pull/25988

Release Notes:

- N/A
2025-03-04 03:33:38 +00:00
Joseph T. Lyons
88940732ca Use same commit button text in panel and modal (#25988)
Release Notes:

- Fixed inconsistencies in commit button text between Git panel and modal.
2025-03-04 03:03:34 +00:00
Mikayla Maki
74fc52d5ce Git Beta: Fix a few cases of empty toasts showing up (#25985)
Improve parsing of git remote outputs

Release Notes:

- N/A
2025-03-04 02:16:50 +00:00
Conrad Irwin
2a7a4a80c6 Fix toggle fold in deleted hunk (#25967)
Updates #25835
Updates #25951

Closes #ISSUE

Release Notes:

- Fixed toggling folds from within deleted hunks
2025-03-03 18:51:09 -07:00
Finn Evers
c03bf1af36 gpui: Ensure hitbox is inserted when element has hover listener (#25981)
Currently, when an element has only a hover listener, the attached
listener will never trigger, because within the check for whether a
hitbox has to be inserted for the given element, this case it not
considered.
That leads to the behaviour as described in
https://github.com/zed-industries/zed/pull/25602#discussion_r1970720972,
where another event listener has to be attached to the element in order
for the hover listener to work.

This PR fixes the issue by ensuring that a hitbox is also inserted when
only a hover listener is attached to the element.

Release Notes:

- N/A
2025-03-04 01:46:18 +00:00
Max Brunsfeld
922aaa0534 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:36:13 -08:00
Marshall Bowers
fc5ff318e3 markdown: Change the copy icon to a check once copied (#25970)
This PR makes it so the copy icon on code blocks will change to a check
once the code block has been copied.

Release Notes:

- N/A
2025-03-04 00:14:26 +00:00
Cole Miller
e7b3b8bf03 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 18:32:03 -05:00
Conrad Irwin
6faa7cd722 Fix regex search colors (#25962)
In #25005 we added regex syntax highlighting to search; but the existing
regex grammar highlighted every character as a string which was hard to
read.

This flips so that characters are not highlighted, and brackets, etc.
are.
<img width="346" alt="Screenshot 2025-03-03 at 14 39 35"
src="https://github.com/user-attachments/assets/f7d3ae9c-fb5c-45eb-a5e9-41a330fbe940"
/>


Release Notes:

- Fixed regex search box being overly green
2025-03-03 15:55:07 -07:00
Marshall Bowers
0776fa8f31 markdown: Allow code blocks and tables to be horizontally scrollable (#25956)
This PR adds the ability for Markdown code blocks and tables to be made
horizontally scrollable.

This is a feature that the caller can opt in to.

Right now we're using it for the rendered Markdown in the Assistant 2
panel.

Release Notes:

- N/A
2025-03-03 22:52:59 +00:00
Marshall Bowers
7321c814ce gpui: Add restrict_scroll_to_axis to match web scrolling behavior (#25963)
This PR adds a new `restrict_scroll_to_axis` style to allow consumers to
opt-in to the scrolling behavior found on the web.

When this is enabled the behavior will be such that:

- Scrolling using the mouse wheel will only scroll the Y axis
- Scrolling using the mouse wheel with <kbd>Shift</kbd> held will only
scroll the X axis

This behavior is useful in scenarios where you have some
vertically-scrollable content that is interspersed with
horizontally-scrollable elements, as otherwise the scroll will be
constantly hijacked by the horizontally-scrollable elements while trying
to scroll up and down in the vertically-scrollable container.

I think that this behavior should be the default, but it's a bit of a
sweeping change to make all at once, so for now it remains opt-in.

Release Notes:

- N/A
2025-03-03 17:32:08 -05:00
Nate Butler
ac3cb3df05 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 22:00:32 +00:00
Conrad Irwin
0bd40da546 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>
2025-03-03 14:44:39 -07:00
Marshall Bowers
3bec4eb117 markdown: Add initial support for tables (#25954)
This PR adds initial support for displaying tables to the `markdown`
crate.

This allows us to render tables in Assistant 2:

| Before | After |
|
----------------------------------------------------------------------------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------------------------------------------------------------------------
|
| <img width="1309" alt="Screenshot 2025-03-03 at 1 39 39 PM"
src="https://github.com/user-attachments/assets/ad7ada01-f35d-4fcf-a20c-deb42b55b34e"
/> | <img width="1297" alt="Screenshot 2025-03-03 at 3 38 21 PM"
src="https://github.com/user-attachments/assets/9b771126-30a0-479b-8c29-f5f572936f56"
/> |

There are a few known issues that should be addressed as follow-ups:

- The horizontal scrolling within a table is linked with the scrolling
of the parent container (e.g., the Assistant 2 thread)
- Cells are currently cut off entirely when they are too wide, would be
nice to truncate them with an ellipsis

Release Notes:

- N/A
2025-03-03 21:01:26 +00:00
Kirill Bulatov
bf6cc2697a Do not detach reparse tasks (#25934)
Drop previous reparse task, if a new one is spawned.

Release Notes:

- N/A
2025-03-03 22:41:46 +02:00
Cole Miller
dc3158c8ce 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
2025-03-03 20:33:02 +00:00
Cole Miller
9e2b7bc5dc Fix missing hunks in project diff after revert (#25906)
Release Notes:

- N/A
2025-03-03 18:53:34 +00:00
Cole Miller
b774a4b8d1 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
2025-03-03 18:39:04 +00:00
Nate Butler
16ab8701a2 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 18:38:15 +00:00
Marshall Bowers
b2add8c803 assistant2: Restore tool uses when loading saved threads (#25942)
This PR makes it so tool uses are restored when loading saved threads in
Assistant 2.

Release Notes:

- N/A
2025-03-03 18:32:26 +00:00
Joseph T. Lyons
6635462f7b Bump Zed to v0.178 (#25939)
Release Notes:

-N/A
2025-03-03 12:48:51 -05:00
Marshall Bowers
81ff6f7a3c assistant2: Persist threads using serde_json instead of bincode (#25938)
This PR changes how we persist threads in Assistant2 to use `serde_json`
instead of `bincode` for the representation.

This makes the format more flexible to work with (and will allow for
using things like `#[serde(default)]`) if the schema changes over time.

Note: We have to bump the LMDB database version for this, so any threads
created before now will be gone.

Release Notes:

- N/A
2025-03-03 17:47:10 +00: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
920 changed files with 69217 additions and 22069 deletions

View File

@@ -26,3 +26,6 @@ rustflags = [
"-C",
"target-feature=+crt-static", # This fixes the linking issue when compiling livekit on Windows
]
[env]
MACOSX_DEPLOYMENT_TARGET = "10.15.7"

View File

@@ -23,9 +23,53 @@ 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 }}
run_license: ${{ steps.filter.outputs.run_license }}
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
# Specify anything which should skip full CI in this regex:
# - docs/
# - .github/ISSUE_TEMPLATE/
# - .github/workflows/ (except .github/workflows/ci.yml)
SKIP_REGEX='^(docs/|\.github/(ISSUE_TEMPLATE|workflows/(?!ci)))'
if [[ $(git diff --name-only $COMPARE_REV ${{ github.sha }} | grep -vP "$SKIP_REGEX") ]]; 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 +113,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 +121,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 +151,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 +186,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 +219,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 +271,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 +307,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 +349,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 +421,44 @@ 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.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 +466,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 +558,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 +577,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 +587,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 +619,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 +638,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 +648,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 +677,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

@@ -1,7 +1,7 @@
name: "Close Stale Issues"
on:
schedule:
- cron: "0 11 * * 2"
- cron: "0 7,9,11 * * 2"
workflow_dispatch:
jobs:

View File

@@ -13,11 +13,12 @@ jobs:
id: get-release-url
run: |
if [ "${{ github.event.release.prerelease }}" == "true" ]; then
URL="https://zed.dev/releases/preview/latest"
URL="https://zed.dev/releases/preview/latest"
else
URL="https://zed.dev/releases/stable/latest"
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 +34,35 @@ 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_promoted_from_preview=true" >> $GITHUB_OUTPUT
else
echo "was_promoted_from_preview=false" >> $GITHUB_OUTPUT
fi
- name: Send release notes email
if: steps.check-promotion-from-preview.outputs.was_promoted_from_preview == 'true'
run: |
TAG="${{ github.event.release.tag_name }}"
echo \"${{ toJSON(github.event.release.body) }}\" > release_body.txt
jq -n --arg tag "$TAG" --rawfile body release_body.txt '{version: $tag, markdown_body: $body}' \
> release_data.json
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 @release_data.json

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/

19
.zed/debug.json Normal file
View File

@@ -0,0 +1,19 @@
[
{
"label": "Debug Zed with LLDB",
"adapter": "lldb",
"program": "$ZED_WORKTREE_ROOT/target/debug/zed",
"request": "launch",
"cwd": "$ZED_WORKTREE_ROOT"
},
{
"label": "Debug Zed with GDB",
"adapter": "gdb",
"program": "$ZED_WORKTREE_ROOT/target/debug/zed",
"request": "launch",
"cwd": "$ZED_WORKTREE_ROOT",
"initialize_args": {
"stopAtBeginningOfMainSubprogram": true
}
}
]

1344
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -3,10 +3,12 @@ resolver = "2"
members = [
"crates/activity_indicator",
"crates/anthropic",
"crates/askpass",
"crates/assets",
"crates/assistant",
"crates/assistant2",
"crates/assistant_context_editor",
"crates/assistant_eval",
"crates/assistant_settings",
"crates/assistant_slash_command",
"crates/assistant_slash_commands",
@@ -35,6 +37,10 @@ members = [
"crates/context_server_settings",
"crates/copilot",
"crates/credentials_provider",
"crates/dap",
"crates/dap_adapters",
"crates/debugger_tools",
"crates/debugger_ui",
"crates/db",
"crates/deepseek",
"crates/diagnostics",
@@ -63,6 +69,7 @@ members = [
"crates/gpui_tokio",
"crates/html_to_markdown",
"crates/http_client",
"crates/http_client_tls",
"crates/image_viewer",
"crates/indexed_docs",
"crates/inline_completion",
@@ -103,6 +110,7 @@ members = [
"crates/project_panel",
"crates/project_symbols",
"crates/prompt_library",
"crates/prompt_store",
"crates/proto",
"crates/recent_projects",
"crates/refineable",
@@ -116,6 +124,7 @@ members = [
"crates/rope",
"crates/rpc",
"crates/schema_generator",
"crates/scripting_tool",
"crates/search",
"crates/semantic_index",
"crates/semantic_version",
@@ -151,6 +160,7 @@ members = [
"crates/ui",
"crates/ui_input",
"crates/ui_macros",
"crates/ui_prompt",
"crates/util",
"crates/util_macros",
"crates/vim",
@@ -166,26 +176,16 @@ members = [
# Extensions
#
"extensions/csharp",
"extensions/deno",
"extensions/elixir",
"extensions/emmet",
"extensions/erlang",
"extensions/glsl",
"extensions/haskell",
"extensions/html",
"extensions/lua",
"extensions/perplexity",
"extensions/proto",
"extensions/purescript",
"extensions/ruff",
"extensions/slash-commands-example",
"extensions/snippets",
"extensions/terraform",
"extensions/test-extension",
"extensions/toml",
"extensions/uiua",
"extensions/zig",
#
# Tooling
@@ -208,10 +208,12 @@ 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" }
assistant_context_editor = { path = "crates/assistant_context_editor" }
assistant_eval = { path = "crates/assistant_eval" }
assistant_settings = { path = "crates/assistant_settings" }
assistant_slash_command = { path = "crates/assistant_slash_command" }
assistant_slash_commands = { path = "crates/assistant_slash_commands" }
@@ -239,7 +241,11 @@ context_server = { path = "crates/context_server" }
context_server_settings = { path = "crates/context_server_settings" }
copilot = { path = "crates/copilot" }
credentials_provider = { path = "crates/credentials_provider" }
dap = { path = "crates/dap" }
dap_adapters = { path = "crates/dap_adapters" }
db = { path = "crates/db" }
debugger_ui = { path = "crates/debugger_ui" }
debugger_tools = { path = "crates/debugger_tools" }
deepseek = { path = "crates/deepseek" }
diagnostics = { path = "crates/diagnostics" }
buffer_diff = { path = "crates/buffer_diff" }
@@ -266,6 +272,7 @@ gpui_macros = { path = "crates/gpui_macros" }
gpui_tokio = { path = "crates/gpui_tokio" }
html_to_markdown = { path = "crates/html_to_markdown" }
http_client = { path = "crates/http_client" }
http_client_tls = { path = "crates/http_client_tls" }
image_viewer = { path = "crates/image_viewer" }
indexed_docs = { path = "crates/indexed_docs" }
inline_completion = { path = "crates/inline_completion" }
@@ -308,6 +315,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" }
@@ -319,6 +327,7 @@ reqwest_client = { path = "crates/reqwest_client" }
rich_text = { path = "crates/rich_text" }
rope = { path = "crates/rope" }
rpc = { path = "crates/rpc" }
scripting_tool = { path = "crates/scripting_tool" }
search = { path = "crates/search" }
semantic_index = { path = "crates/semantic_index" }
semantic_version = { path = "crates/semantic_version" }
@@ -354,6 +363,7 @@ toolchain_selector = { path = "crates/toolchain_selector" }
ui = { path = "crates/ui" }
ui_input = { path = "crates/ui_input" }
ui_macros = { path = "crates/ui_macros" }
ui_prompt = { path = "crates/ui_prompt" }
util = { path = "crates/util" }
util_macros = { path = "crates/util_macros" }
vim = { path = "crates/vim" }
@@ -370,7 +380,7 @@ zeta = { path = "crates/zeta" }
#
aho-corasick = "1.1"
alacritty_terminal = { git = "https://github.com/zed-industries/alacritty.git", rev = "03c2907b44b4189aac5fdeaea331f5aab5c7072e" }
alacritty_terminal = { git = "https://github.com/zed-industries/alacritty.git", branch = "add-hush-login-flag" }
any_vec = "0.14"
anyhow = "1.0.86"
arrayvec = { version = "0.7.4", features = ["serde"] }
@@ -402,6 +412,7 @@ bytes = "1.0"
cargo_metadata = "0.19"
cargo_toml = "0.21"
chrono = { version = "0.4", features = ["serde"] }
circular-buffer = "1.0"
clap = { version = "4.4", features = ["derive"] }
cocoa = "0.26"
cocoa-foundation = "0.2.0"
@@ -410,6 +421,7 @@ core-foundation = "0.9.3"
core-foundation-sys = "0.8.6"
ctor = "0.4.0"
dashmap = "6.0"
dap-types = { git = "https://github.com/zed-industries/dap-types", rev = "bfd4af0" }
derive_more = "0.99.17"
dirs = "4.0"
ec4rs = "1.1"
@@ -421,8 +433,7 @@ fork = "0.2.0"
futures = "0.3"
futures-batch = "0.6.1"
futures-lite = "1.13"
# TODO: get back to regular versions when https://github.com/rust-lang/git2-rs/pull/1120 is released
git2 = { git = "https://github.com/rust-lang/git2-rs", rev = "a3b90cb3756c1bb63e2317bf9cfa57838178de5c", default-features = false }
git2 = { version = "0.20.1", default-features = false }
globset = "0.4"
handlebars = "4.3"
heed = { version = "0.21.0", features = ["read-txn-no-tls"] }
@@ -451,6 +462,7 @@ livekit = { git = "https://github.com/zed-industries/livekit-rust-sdks", rev = "
], default-features = false }
log = { version = "0.4.16", features = ["kv_unstable_serde", "serde"] }
markup5ever_rcdom = "0.3.0"
mlua = { version = "0.10", features = ["lua54", "vendored", "async", "send"] }
nanoid = "0.4"
nbformat = { version = "0.10.0" }
nix = "0.29"
@@ -536,7 +548,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"
@@ -564,6 +576,7 @@ unindent = "0.2.0"
unicode-segmentation = "1.10"
unicode-script = "0.5.7"
url = "2.2"
urlencoding = "2.1.2"
uuid = { version = "1.1.2", features = ["v4", "v5", "v7", "serde"] }
wasmparser = "0.221"
wasm-encoder = "0.221"
@@ -596,12 +609,14 @@ features = [
]
[workspace.dependencies.windows]
version = "0.58"
version = "0.60"
features = [
"implement",
"Foundation_Collections",
"Foundation_Numerics",
"Storage",
"Storage_Search",
"Storage_Streams",
"System_Threading",
"UI_StartScreen",
"UI_ViewManagement",
"Wdk_System_SystemServices",
"Win32_Globalization",
@@ -620,9 +635,11 @@ features = [
"Win32_System_Com_StructuredStorage",
"Win32_System_Console",
"Win32_System_DataExchange",
"Win32_System_IO",
"Win32_System_LibraryLoader",
"Win32_System_Memory",
"Win32_System_Ole",
"Win32_System_Pipes",
"Win32_System_SystemInformation",
"Win32_System_SystemServices",
"Win32_System_Threading",
@@ -748,5 +765,9 @@ new_ret_no_self = { level = "allow" }
should_implement_trait = { level = "allow" }
let_underscore_future = "allow"
# in Rust it can be very tedious to reduce argument count without
# running afoul of the borrow checker.
too_many_arguments = "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

1
assets/icons/debug.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-bug"><path d="m8 2 1.88 1.88"/><path d="M14.12 3.88 16 2"/><path d="M9 7.13v-1a3.003 3.003 0 1 1 6 0v1"/><path d="M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v3c0 3.3-2.7 6-6 6"/><path d="M12 20v-9"/><path d="M6.53 9C4.6 8.8 3 7.1 3 5"/><path d="M6 13H2"/><path d="M3 21c0-2.1 1.7-3.9 3.8-4"/><path d="M20.97 5c0 2.1-1.6 3.8-3.5 4"/><path d="M22 13h-4"/><path d="M17.2 17c2.1.1 3.8 1.9 3.8 4"/></svg>

After

Width:  |  Height:  |  Size: 615 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-circle"><circle cx="12" cy="12" r="10"/></svg>

After

Width:  |  Height:  |  Size: 257 B

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-step-forward"><line x1="6" x2="6" y1="4" y2="20"/><polygon points="10,4 20,12 10,20"/></svg>

After

Width:  |  Height:  |  Size: 295 B

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-unplug"><path d="m19 5 3-3"/><path d="m2 22 3-3"/><path d="M6.3 20.3a2.4 2.4 0 0 0 3.4 0L12 18l-6-6-2.3 2.3a2.4 2.4 0 0 0 0 3.4Z"/><path d="M7.5 13.5 10 11"/><path d="M10.5 16.5 13 14"/><path d="m12 6 6 6 2.3-2.3a2.4 2.4 0 0 0 0-3.4l-2.6-2.6a2.4 2.4 0 0 0-3.4 0Z"/></svg>

After

Width:  |  Height:  |  Size: 474 B

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-circle-off"><path d="m2 2 20 20"/><path d="M8.35 2.69A10 10 0 0 1 21.3 15.65"/><path d="M19.08 19.08A10 10 0 1 1 4.92 4.92"/></svg>

After

Width:  |  Height:  |  Size: 334 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-message-circle"><path d="M7.9 20A9 9 0 1 0 4 16.1L2 22Z"/></svg>

After

Width:  |  Height:  |  Size: 275 B

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-pause"><rect x="14" y="4" width="4" height="16" rx="1"/><rect x="6" y="4" width="4" height="16" rx="1"/></svg>

After

Width:  |  Height:  |  Size: 313 B

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-rotate-ccw"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>

After

Width:  |  Height:  |  Size: 302 B

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-undo-dot"><path d="M21 17a9 9 0 0 0-15-6.7L3 13"/><path d="M3 7v6h6"/><circle cx="12" cy="17" r="1"/></svg>

After

Width:  |  Height:  |  Size: 310 B

View File

@@ -0,0 +1,5 @@
<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-arrow-up-from-dot">
<path d="m5 15 7 7 7-7"/>
<path d="M12 8v14"/>
<circle cx="12" cy="3" r="1"/>
</svg>

After

Width:  |  Height:  |  Size: 313 B

View File

@@ -0,0 +1,5 @@
<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-arrow-up-from-dot">
<path d="m3 10 9-8 9 8"/>
<path d="M12 17V2"/>
<circle cx="12" cy="21" r="1"/>
</svg>

After

Width:  |  Height:  |  Size: 314 B

View File

@@ -0,0 +1,5 @@
<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-redo-dot">
<circle cx="12" cy="17" r="1"/>
<path d="M21 7v6h-6"/>
<path d="M3 17a9 9 0 0 1 9-9 9 9 0 0 1 6 2.3l3 2.7"/>
</svg>

After

Width:  |  Height:  |  Size: 335 B

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-square"><rect width="18" height="18" x="3" y="3" rx="2"/></svg>

After

Width:  |  Height:  |  Size: 266 B

View File

@@ -0,0 +1,4 @@
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.5 8.5L7.5 11.5M7.5 11.5L4.5 8.5M7.5 11.5L7.5 5.5" stroke="black" stroke-linecap="square"/>
<path d="M5 3.5L10 3.5" stroke="black"/>
</svg>

After

Width:  |  Height:  |  Size: 248 B

View File

@@ -0,0 +1,4 @@
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.5 6.5L7.5 3.5M7.5 3.5L10.5 6.5M7.5 3.5V9.5" stroke="black" stroke-linecap="square"/>
<path d="M5 11.5H10" stroke="black"/>
</svg>

After

Width:  |  Height:  |  Size: 238 B

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.36197 1.67985C5.3748 1.41534 4.36011 2.00117 4.0956 2.98834L2.17985 10.138C1.91534 11.1252 2.50117 12.1399 3.48833 12.4044L10.638 14.3202C11.6252 14.5847 12.6399 13.9988 12.9044 13.0117L14.8202 5.86197C15.0847 4.8748 14.4988 3.86012 13.5117 3.59561L6.36197 1.67985ZM10.0457 4.58266C9.77896 4.51119 9.50479 4.66948 9.43332 4.93621L8.76235 7.44028C8.69088 7.70701 8.84917 7.98118 9.11591 8.05265L11.62 8.72362C11.8867 8.79509 12.1609 8.6368 12.2324 8.37006L12.9033 5.86599C12.9748 5.59926 12.8165 5.32509 12.5498 5.25362L10.0457 4.58266Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 707 B

View File

@@ -0,0 +1,7 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.5 13L1.5 5H11.5L6.5 13Z" fill="black"/>
<path d="M14 9H9L11.5 5L14 9Z" fill="black" fill-opacity="0.75"/>
<path d="M9 9L14 9L11.5 13L9 9Z" fill="black" fill-opacity="0.65"/>
<path d="M14 5L15.25 7L12.75 7L14 5Z" fill="black" fill-opacity="0.5"/>
<path d="M14 9L12.75 7H15.25L14 9Z" fill="black" fill-opacity="0.55"/>
</svg>

After

Width:  |  Height:  |  Size: 432 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

@@ -1,12 +1,5 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_2131_1193)">
<circle cx="7" cy="7" r="6" stroke="black" stroke-width="1.5"/>
<path d="M6 10H7M8 10H7M7 10V7.1C7 7.04477 6.95523 7 6.9 7H6" stroke="black" stroke-width="1.5" stroke-linecap="round"/>
<circle cx="7" cy="4.5" r="1" fill="black"/>
</g>
<defs>
<clipPath id="clip0_2131_1193">
<rect width="14" height="14" fill="white"/>
</clipPath>
</defs>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 14C11.3137 14 14 11.3137 14 8C14 4.68629 11.3137 2 8 2C4.68629 2 2 4.68629 2 8C2 11.3137 4.68629 14 8 14Z" stroke="black" stroke-width="1.5"/>
<path d="M7 11H8M8 11H9M8 11V8.1C8 8.04477 7.95523 8 7.9 8H7" stroke="black" stroke-width="1.5" stroke-linecap="round"/>
<path d="M8 6.5C8.55228 6.5 9 6.05228 9 5.5C9 4.94772 8.55228 4.5 8 4.5C7.44772 4.5 7 4.94772 7 5.5C7 6.05228 7.44772 6.5 8 6.5Z" fill="black"/>
</svg>

Before

Width:  |  Height:  |  Size: 479 B

After

Width:  |  Height:  |  Size: 524 B

View File

@@ -1,6 +1,6 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3 4H8" stroke="black" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6 10L11 10" stroke="black" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="4" cy="10" r="1.875" stroke="black" stroke-width="1.75"/>
<circle cx="10" cy="4" r="1.875" stroke="black" stroke-width="1.75"/>
<path d="M3 4H8" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6 10L11 10" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="4" cy="10" r="1.875" stroke="black" stroke-width="1.5"/>
<circle cx="10" cy="4" r="1.875" stroke="black" stroke-width="1.5"/>
</svg>

Before

Width:  |  Height:  |  Size: 450 B

After

Width:  |  Height:  |  Size: 446 B

View File

@@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.6" d="M7.5 8.9V11C5.43097 11 4.56903 11 2.5 11V10.4L7.5 5.6V5H2.5V7.1" stroke="black" stroke-width="1.5"/>
<path d="M14 8L10 12M14 12L10 8" stroke="black" stroke-width="1.5"/>
</svg>

After

Width:  |  Height:  |  Size: 296 B

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",
@@ -30,6 +30,13 @@
"ctrl-0": ["zed::ResetBufferFontSize", { "persist": false }],
"ctrl-,": "zed::OpenSettings",
"ctrl-q": "zed::Quit",
"f4": "debugger::Start",
"f5": "debugger::Continue",
"shift-f5": "debugger::Stop",
"f6": "debugger::Pause",
"f7": "debugger::StepOver",
"cmd-f11": "debugger::StepInto",
"shift-f11": "debugger::StepOut",
"f11": "zed::ToggleFullScreen",
"ctrl-alt-z": "edit_prediction::RateCompletions",
"ctrl-shift-i": "edit_prediction::ToggleMenu"
@@ -38,15 +45,17 @@
{
"context": "Picker || menu",
"bindings": {
"up": "menu::SelectPrev",
"up": "menu::SelectPrevious",
"down": "menu::SelectNext"
}
},
{
"context": "Prompt",
"bindings": {
"left": "menu::SelectPrev",
"right": "menu::SelectNext"
"left": "menu::SelectPrevious",
"right": "menu::SelectNext",
"h": "menu::SelectPrevious",
"l": "menu::SelectNext"
}
},
{
@@ -57,7 +66,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",
@@ -107,6 +116,7 @@
"ctrl-a": "editor::SelectAll",
"ctrl-l": "editor::SelectLine",
"ctrl-shift-i": "editor::Format",
"alt-shift-o": "editor::OrganizeImports",
// "cmd-shift-left": ["editor::SelectToBeginningOfLine", {"stop_at_soft_wraps": true, "stop_at_indent": true }],
// "ctrl-shift-a": ["editor::SelectToBeginningOfLine", { "stop_at_soft_wraps": true, "stop_at_indent": true }],
"shift-home": ["editor::SelectToBeginningOfLine", { "stop_at_soft_wraps": true, "stop_at_indent": true }],
@@ -123,7 +133,9 @@
"alt-g b": "editor::ToggleGitBlame",
"menu": "editor::OpenContextMenu",
"shift-f10": "editor::OpenContextMenu",
"ctrl-shift-e": "editor::ToggleEditPrediction"
"ctrl-shift-e": "editor::ToggleEditPrediction",
"f9": "editor::ToggleBreakpoint",
"shift-f9": "editor::EditLogBreakpoint"
}
},
{
@@ -180,7 +192,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 +215,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 +284,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 +302,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 +346,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",
@@ -362,6 +374,7 @@
"ctrl-k ctrl-0": "editor::FoldAll",
"ctrl-k ctrl-j": "editor::UnfoldAll",
"ctrl-space": "editor::ShowCompletions",
"ctrl-shift-space": "editor::ShowWordCompletions",
"ctrl-.": "editor::ToggleCodeActions",
"ctrl-k r": "editor::RevealInFileManager",
"ctrl-k p": "editor::CopyPath",
@@ -373,7 +386,7 @@
"alt-y": "git::StageAndNext",
"alt-shift-y": "git::UnstageAndNext",
"alt-.": "editor::GoToHunk",
"alt-,": "editor::GoToPrevHunk"
"alt-,": "editor::GoToPreviousHunk"
}
},
{
@@ -393,6 +406,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",
@@ -475,9 +489,7 @@
"ctrl-alt-delete": "editor::DeleteToNextSubwordEnd",
"ctrl-alt-d": "editor::DeleteToNextSubwordEnd",
"ctrl-alt-left": "editor::MoveToPreviousSubwordStart",
// "ctrl-alt-b": "editor::MoveToPreviousSubwordStart",
"ctrl-alt-right": "editor::MoveToNextSubwordEnd",
"ctrl-alt-f": "editor::MoveToNextSubwordEnd",
"ctrl-alt-shift-left": "editor::SelectToPreviousSubwordStart",
"ctrl-alt-shift-b": "editor::SelectToPreviousSubwordStart",
"ctrl-alt-shift-right": "editor::SelectToNextSubwordEnd",
@@ -536,8 +548,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 +577,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"
}
@@ -612,12 +624,29 @@
"ctrl-alt-e": "assistant2::RemoveAllContext"
}
},
{
"context": "AssistantPanel2 && prompt_editor",
"use_key_equivalents": true,
"bindings": {
"cmd-n": "assistant2::NewPromptEditor",
"cmd-alt-t": "assistant2::NewThread"
}
},
{
"context": "MessageEditor > Editor",
"bindings": {
"enter": "assistant2::Chat"
}
},
{
"context": "EditMessageEditor > Editor",
"use_key_equivalents": true,
"bindings": {
"escape": "menu::Cancel",
"enter": "menu::Confirm",
"alt-enter": "editor::Newline"
}
},
{
"context": "ContextStrip",
"bindings": {
@@ -662,7 +691,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 +729,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 +742,59 @@
{
"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",
"delete": "git::RestoreFile",
"shift-delete": "git::RestoreFile",
"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 +803,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 +831,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 +847,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 +857,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"
}
@@ -822,21 +877,22 @@
"alt-b": ["terminal::SendText", "\u001bb"],
"alt-f": ["terminal::SendText", "\u001bf"],
// Overrides for conflicting keybindings
"ctrl-b": ["terminal::SendKeystroke", "ctrl-b"],
"ctrl-c": ["terminal::SendKeystroke", "ctrl-c"],
"ctrl-e": ["terminal::SendKeystroke", "ctrl-e"],
"ctrl-o": ["terminal::SendKeystroke", "ctrl-o"],
"ctrl-w": ["terminal::SendKeystroke", "ctrl-w"],
"ctrl-shift-a": "editor::SelectAll",
"find": "buffer_search::Deploy",
"ctrl-shift-f": "buffer_search::Deploy",
"ctrl-shift-l": "terminal::Clear",
"ctrl-shift-w": "pane::CloseActiveItem",
"ctrl-e": ["terminal::SendKeystroke", "ctrl-e"],
"up": ["terminal::SendKeystroke", "up"],
"pageup": ["terminal::SendKeystroke", "pageup"],
"down": ["terminal::SendKeystroke", "down"],
"pagedown": ["terminal::SendKeystroke", "pagedown"],
"escape": ["terminal::SendKeystroke", "escape"],
"enter": ["terminal::SendKeystroke", "enter"],
"ctrl-b": ["terminal::SendKeystroke", "ctrl-b"],
"ctrl-c": ["terminal::SendKeystroke", "ctrl-c"],
"shift-pageup": "terminal::ScrollPageUp",
"shift-pagedown": "terminal::ScrollPageDown",
"shift-up": "terminal::ScrollLineUp",

View File

@@ -1,8 +1,26 @@
[
// 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,
"bindings": {
"f4": "debugger::Start",
"f5": "debugger::Continue",
"shift-f5": "debugger::Stop",
"f6": "debugger::Pause",
"f7": "debugger::StepOver",
"f11": "debugger::StepInto",
"shift-f11": "debugger::StepOut",
"home": "menu::SelectFirst",
"shift-pageup": "menu::SelectFirst",
"pageup": "menu::SelectFirst",
@@ -14,14 +32,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 +72,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 +115,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 +131,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 }],
@@ -136,6 +155,8 @@
"cmd-\"": "editor::ExpandAllDiffHunks",
"cmd-alt-g b": "editor::ToggleGitBlame",
"cmd-i": "editor::ShowSignatureHelp",
"f9": "editor::ToggleBreakpoint",
"shift-f9": "editor::EditLogBreakpoint",
"ctrl-f12": "editor::GoToDeclaration",
"alt-ctrl-f12": "editor::GoToDeclarationSplit",
"ctrl-cmd-e": "editor::ToggleEditPrediction"
@@ -160,6 +181,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 +238,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",
@@ -244,6 +275,14 @@
"cmd-alt-e": "assistant2::RemoveAllContext"
}
},
{
"context": "AssistantPanel2 && prompt_editor",
"use_key_equivalents": true,
"bindings": {
"cmd-n": "assistant2::NewPromptEditor",
"cmd-alt-t": "assistant2::NewThread"
}
},
{
"context": "MessageEditor > Editor",
"use_key_equivalents": true,
@@ -251,6 +290,15 @@
"enter": "assistant2::Chat"
}
},
{
"context": "EditMessageEditor > Editor",
"use_key_equivalents": true,
"bindings": {
"escape": "menu::Cancel",
"enter": "menu::Confirm",
"alt-enter": "editor::Newline"
}
},
{
"context": "ContextStrip",
"use_key_equivalents": true,
@@ -269,15 +317,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 +324,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 +391,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 +406,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 +446,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",
@@ -436,6 +475,7 @@
// Using `ctrl-space` in Zed requires disabling the macOS global shortcut.
// System Preferences->Keyboard->Keyboard Shortcuts->Input Sources->Select the previous input source (uncheck)
"ctrl-space": "editor::ShowCompletions",
"ctrl-shift-space": "editor::ShowWordCompletions",
"cmd-.": "editor::ToggleCodeActions",
"cmd-k r": "editor::RevealInFileManager",
"cmd-k p": "editor::CopyPath",
@@ -484,6 +524,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 +654,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 +681,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"
}
@@ -664,6 +705,16 @@
"ctrl-]": "assistant::CycleNextInlineAssist"
}
},
{
"context": "Prompt",
"use_key_equivalents": true,
"bindings": {
"left": "menu::SelectPrevious",
"right": "menu::SelectNext",
"h": "menu::SelectPrevious",
"l": "menu::SelectNext"
}
},
{
"context": "ProjectSearchBar && !in_replace",
"use_key_equivalents": true,
@@ -683,7 +734,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 +764,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"
}
},
@@ -724,30 +775,44 @@
"space": "project_panel::Open"
}
},
{
"context": "VariableList",
"use_key_equivalents": true,
"bindings": {
"left": "variable_list::CollapseSelectedEntry",
"right": "variable_list::ExpandSelectedEntry"
}
},
{
"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",
"delete": "git::RestoreFile",
"cmd-backspace": "git::RestoreFile",
"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 +823,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 +848,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 +879,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 +898,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 +909,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,8 +2,15 @@
{
"bindings": {
"ctrl-alt-s": "zed::OpenSettings",
"ctrl-{": "pane::ActivatePrevItem",
"ctrl-}": "pane::ActivateNextItem"
"ctrl-{": "pane::ActivatePreviousItem",
"ctrl-}": "pane::ActivateNextItem",
"ctrl-f2": "debugger::Stop",
"f6": "debugger::Pause",
"f7": "debugger::StepInto",
"f8": "debugger::StepOver",
"shift-f8": "debugger::StepOut",
"f9": "debugger::Continue",
"alt-shift-f9": "debugger::Start"
}
},
{
@@ -31,6 +38,7 @@
"shift-alt-up": "editor::MoveLineUp",
"shift-alt-down": "editor::MoveLineDown",
"ctrl-alt-l": "editor::Format",
"ctrl-alt-o": "editor::OrganizeImports",
"shift-f6": "editor::Rename",
"ctrl-alt-left": "pane::GoBack",
"ctrl-alt-right": "pane::GoForward",
@@ -41,14 +49,16 @@
"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",
"ctrl-shift-home": "editor::SelectToBeginning",
"ctrl-shift-end": "editor::SelectToEnd"
"ctrl-shift-end": "editor::SelectToEnd",
"ctrl-f8": "editor::ToggleBreakpoint",
"ctrl-shift-f8": "editor::EditLogBreakpoint"
}
},
{

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,8 +1,15 @@
[
{
"bindings": {
"cmd-{": "pane::ActivatePrevItem",
"cmd-}": "pane::ActivateNextItem"
"cmd-{": "pane::ActivatePreviousItem",
"cmd-}": "pane::ActivateNextItem",
"ctrl-f2": "debugger::Stop",
"f6": "debugger::Pause",
"f7": "debugger::StepInto",
"f8": "debugger::StepOver",
"shift-f8": "debugger::StepOut",
"f9": "debugger::Continue",
"alt-shift-f9": "debugger::Start"
}
},
{
@@ -29,6 +36,7 @@
"shift-alt-up": "editor::MoveLineUp",
"shift-alt-down": "editor::MoveLineDown",
"cmd-alt-l": "editor::Format",
"ctrl-alt-o": "editor::OrganizeImports",
"shift-f6": "editor::Rename",
"cmd-[": "pane::GoBack",
"cmd-]": "pane::GoForward",
@@ -39,13 +47,15 @@
"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",
"cmd-shift-end": "editor::SelectToEnd"
"cmd-shift-end": "editor::SelectToEnd",
"ctrl-f8": "editor::ToggleBreakpoint",
"ctrl-shift-f8": "editor::EditLogBreakpoint"
}
},
{
@@ -61,7 +71,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

@@ -6,7 +6,7 @@
"a": ["vim::PushObject", { "around": true }],
"left": "vim::Left",
"h": "vim::Left",
"backspace": "vim::Backspace",
"backspace": "vim::WrappingLeft",
"down": "vim::Down",
"ctrl-j": "vim::Down",
"j": "vim::Down",
@@ -20,7 +20,7 @@
"k": "vim::Up",
"right": "vim::Right",
"l": "vim::Right",
"space": "vim::Space",
"space": "vim::WrappingRight",
"end": "vim::EndOfLine",
"$": "vim::EndOfLine",
"^": "vim::FirstNonWhitespace",
@@ -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"
}
},
@@ -247,7 +247,8 @@
"context": "VimControl && VimCount",
"bindings": {
"0": ["vim::Number", 0],
":": "vim::CountCommand"
":": "vim::CountCommand",
"%": "vim::GoToPercentage"
}
},
{
@@ -272,7 +273,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 +449,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 +624,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 +668,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 +694,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 +703,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

@@ -0,0 +1,18 @@
You are an AI assistant integrated into a text editor. Your goal is to do one of the following two things:
1. Help users answer questions and perform tasks related to their codebase.
2. Answer general-purpose questions unrelated to their particular codebase.
It will be up to you to decide which of these you are doing based on what the user has told you. When unclear, ask clarifying questions to understand the user's intent before proceeding.
You should only perform actions that modify the users system if explicitly requested by the user:
- If the user asks a question about how to accomplish a task, provide guidance or information, and use read-only tools (e.g., search) to assist. You may suggest potential actions, but do not directly modify the users system without explicit instruction.
- If the user clearly requests that you perform an action, carry out the action directly without explaining why you are doing so.
Be concise and direct in your responses.
The user has opened a project that contains the following root directories/files:
{{#each worktrees}}
- {{root_name}} (absolute path: {{abs_path}})
{{/each}}

View File

@@ -136,6 +136,11 @@
// Whether to use the system provided dialogs for Open and Save As.
// When set to false, Zed will use the built-in keyboard-first pickers.
"use_system_path_prompts": true,
// Whether to use the system provided dialogs for prompts, such as confirmation
// prompts.
// When set to false, Zed will use its built-in prompts. Note that on Linux,
// this option is ignored and Zed will always use the built-in prompts.
"use_system_prompts": true,
// Whether the cursor blinks in the editor.
"cursor_blink": true,
// Cursor shape for the default editor.
@@ -324,6 +329,8 @@
"code_actions": true,
// Whether to show runnables buttons in the gutter.
"runnables": true,
// Whether to show breakpoints in the gutter.
"breakpoints": true,
// Whether to show fold buttons in the gutter.
"folds": true
},
@@ -336,14 +343,14 @@
"active_line_width": 1,
// Determines how indent guides are colored.
// This setting can take the following three values:
///
//
// 1. "disabled"
// 2. "fixed"
// 3. "indent_aware"
"coloring": "fixed",
// Determines how indent guide backgrounds are colored.
// This setting can take the following two values:
///
//
// 1. "disabled"
// 2. "indent_aware"
"background_coloring": "disabled"
@@ -402,8 +409,8 @@
// Time to wait after scrolling the buffer, before requesting the hints,
// set to 0 to disable debouncing.
"scroll_debounce_ms": 50,
/// A set of modifiers which, when pressed, will toggle the visibility of inlay hints.
/// If the set if empty or not all the modifiers specified are pressed, inlay hints will not be toggled.
// A set of modifiers which, when pressed, will toggle the visibility of inlay hints.
// If the set if empty or not all the modifiers specified are pressed, inlay hints will not be toggled.
"toggle_on_modifiers_press": {
"control": false,
"shift": false,
@@ -440,7 +447,7 @@
"scrollbar": {
// When to show the scrollbar in the project panel.
// This setting can take five values:
///
//
// 1. null (default): Inherit editor settings
// 2. Show the scrollbar if there's important information or
// follow the system's configured behavior (default):
@@ -455,7 +462,7 @@
},
// Which files containing diagnostic errors/warnings to mark in the project panel.
// This setting can take the following three values:
///
//
// 1. Do not mark any files:
// "off"
// 2. Only mark files with errors:
@@ -512,7 +519,7 @@
"scrollbar": {
// When to show the scrollbar in the project panel.
// This setting can take five values:
///
//
// 1. null (default): Inherit editor settings
// 2. Show the scrollbar if there's important information or
// follow the system's configured behavior (default):
@@ -547,7 +554,7 @@
"git_panel": {
// Whether to show the git panel button in the status bar.
"button": true,
// Where to the git panel. Can be 'left' or 'right'.
// Where to show the git panel. Can be 'left' or 'right'.
"dock": "left",
// Default width of the git panel.
"default_width": 360,
@@ -555,6 +562,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.
//
@@ -594,6 +607,13 @@
"provider": "zed.dev",
// The model to use.
"model": "claude-3-5-sonnet-latest"
},
// The model to use when applying edits from the assistant.
"editor_model": {
// The provider to use.
"provider": "zed.dev",
// The model to use.
"model": "claude-3-5-sonnet-latest"
}
},
// The settings for slash commands.
@@ -648,11 +668,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)
@@ -665,7 +693,7 @@
// Which files containing diagnostic errors/warnings to mark in the tabs.
// Diagnostics are only shown when file icons are also active.
// This setting only works when can take the following three values:
///
//
// 1. Do not mark any files:
// "off"
// 2. Only mark files with errors:
@@ -712,8 +740,8 @@
"remove_trailing_whitespace_on_save": true,
// Whether to start a new line with a comment when a previous line is a comment as well.
"extend_comment_on_newline": true,
// Whether or not to ensure there's a single newline at the end of a buffer
// when saving it.
// Removes any lines containing only whitespace at the end of the file and
// ensures just one newline at the end.
"ensure_final_newline_on_save": true,
// Whether or not to perform a buffer format before saving
//
@@ -829,8 +857,24 @@
//
// The minimum column number to show the inline blame information at
// "min_column": 0
}
},
// How git hunks are displayed visually in the editor.
// This setting can take two values:
//
// 1. Show unstaged hunks filled and staged hunks hollow:
// "hunk_style": "staged_hollow"
// 2. Show unstaged hunks hollow and staged hunks filled:
// "hunk_style": "unstaged_hollow"
"hunk_style": "staged_hollow"
},
// The list of custom Git hosting providers.
"git_hosting_providers": [
// {
// "provider": "github",
// "name": "BigCorp GitHub",
// "base_url": "https://code.big-corp.com"
// }
],
// Configuration for how direnv configuration should be loaded. May take 2 values:
// 1. Load direnv configuration using `direnv export json` directly.
// "load_direnv": "direct"
@@ -843,15 +887,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.
@@ -1001,7 +1037,7 @@
"scrollbar": {
// When to show the scrollbar in the terminal.
// This setting can take five values:
///
//
// 1. null (default): Inherit editor settings
// 2. Show the scrollbar if there's important information or
// follow the system's configured behavior (default):
@@ -1047,7 +1083,6 @@
// }
//
"file_types": {
"Plain Text": ["txt"],
"JSONC": ["**/.zed/**/*.json", "**/zed/**/*.json", "**/Zed/**/*.json", "**/.vscode/**/*.json"],
"Shell Script": [".env.*"]
},
@@ -1073,6 +1108,32 @@
"auto_install_extensions": {
"html": true
},
// Controls how completions are processed for this language.
"completions": {
// Controls how words are completed.
// For large documents, not all words may be fetched for completion.
//
// May take 3 values:
// 1. "enabled"
// Always fetch document's words for completions along with LSP completions.
// 2. "fallback"
// Only if LSP response errors or times out, use document's words to show completions.
// 3. "disabled"
// Never fetch or complete document's words for completions.
// (Word-based completions can still be queried via a separate action)
//
// Default: fallback
"words": "fallback",
// Whether to fetch LSP completions or not.
//
// Default: true
"lsp": true,
// When fetching LSP completions, determines how long to wait for a response of a particular server.
// When set to 0, waits indefinitely.
//
// Default: 0
"lsp_fetch_timeout_ms": 0
},
// Different settings for specific languages.
"languages": {
"Astro": {
@@ -1167,6 +1228,7 @@
"format_on_save": "off",
"use_on_type_format": false,
"allow_rewrap": "anywhere",
"soft_wrap": "bounded",
"prettier": {
"allowed": true
}
@@ -1290,6 +1352,10 @@
// "semi": false,
// "singleQuote": true
},
// Settings for auto-closing of JSX tags.
"jsx_tag_auto_close": {
"enabled": true
},
// LSP Specific settings.
"lsp": {
// Specify the LSP name as a key here.
@@ -1394,6 +1460,12 @@
// }
// ]
"ssh_connections": [],
// Configures context servers for use in the Assistant.
"context_servers": {}
"context_servers": {},
"debugger": {
"stepping_granularity": "line",
"save_breakpoints": true,
"button": true
}
}

View File

@@ -0,0 +1,32 @@
[
{
"label": "Debug active PHP file",
"adapter": "php",
"program": "$ZED_FILE",
"request": "launch",
"cwd": "$ZED_WORKTREE_ROOT"
},
{
"label": "Debug active Python file",
"adapter": "python",
"program": "$ZED_FILE",
"request": "launch",
"cwd": "$ZED_WORKTREE_ROOT"
},
{
"label": "Debug active JavaScript file",
"adapter": "javascript",
"program": "$ZED_FILE",
"request": "launch",
"cwd": "$ZED_WORKTREE_ROOT"
},
{
"label": "JavaScript debug terminal",
"adapter": "javascript",
"request": "launch",
"cwd": "$ZED_WORKTREE_ROOT",
"initialize_args": {
"console": "integratedTerminal"
}
}
]

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",
@@ -383,6 +375,11 @@
"font_style": null,
"font_weight": null
},
"variable.special": {
"color": "#83a598ff",
"font_style": null,
"font_weight": null
},
"variant": {
"color": "#83a598ff",
"font_style": null,
@@ -394,15 +391,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 +482,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",
@@ -771,6 +760,11 @@
"font_style": null,
"font_weight": null
},
"variable.special": {
"color": "#83a598ff",
"font_style": null,
"font_weight": null
},
"variant": {
"color": "#83a598ff",
"font_style": null,
@@ -782,15 +776,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 +867,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",
@@ -1159,6 +1145,11 @@
"font_style": null,
"font_weight": null
},
"variable.special": {
"color": "#83a598ff",
"font_style": null,
"font_weight": null
},
"variant": {
"color": "#83a598ff",
"font_style": null,
@@ -1170,15 +1161,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 +1252,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",
@@ -1547,6 +1530,11 @@
"font_style": null,
"font_weight": null
},
"variable.special": {
"color": "#066578ff",
"font_style": null,
"font_weight": null
},
"variant": {
"color": "#0b6678ff",
"font_style": null,
@@ -1558,15 +1546,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 +1637,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",
@@ -1935,6 +1915,11 @@
"font_style": null,
"font_weight": null
},
"variable.special": {
"color": "#066578ff",
"font_style": null,
"font_weight": null
},
"variant": {
"color": "#0b6678ff",
"font_style": null,
@@ -1946,15 +1931,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 +2022,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",
@@ -2323,6 +2300,11 @@
"font_style": null,
"font_weight": null
},
"variable.special": {
"color": "#066578ff",
"font_style": null,
"font_weight": null
},
"variant": {
"color": "#0b6678ff",
"font_style": null,

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

@@ -20,7 +20,6 @@ extension_host.workspace = true
futures.workspace = true
gpui.workspace = true
language.workspace = true
lsp.workspace = true
project.workspace = true
smallvec.workspace = true
ui.workspace = true

View File

@@ -7,9 +7,11 @@ use gpui::{
EventEmitter, InteractiveElement as _, ParentElement as _, Render, SharedString,
StatefulInteractiveElement, Styled, Transformation, Window,
};
use language::{LanguageRegistry, LanguageServerBinaryStatus, LanguageServerId};
use lsp::LanguageServerName;
use project::{EnvironmentErrorMessage, LanguageServerProgress, Project, WorktreeId};
use language::{BinaryStatus, LanguageRegistry, LanguageServerId};
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};
@@ -20,21 +22,21 @@ actions!(activity_indicator, [ShowErrorMessage]);
pub enum Event {
ShowError {
lsp_name: LanguageServerName,
server_name: SharedString,
error: String,
},
}
pub struct ActivityIndicator {
statuses: Vec<LspStatus>,
statuses: Vec<ServerStatus>,
project: Entity<Project>,
auto_updater: Option<Entity<AutoUpdater>>,
context_menu_handle: PopoverMenuHandle<ContextMenu>,
}
struct LspStatus {
name: LanguageServerName,
status: LanguageServerBinaryStatus,
struct ServerStatus {
name: SharedString,
status: BinaryStatus,
}
struct PendingWork<'a> {
@@ -61,11 +63,11 @@ impl ActivityIndicator {
let auto_updater = AutoUpdater::get(cx);
let this = cx.new(|cx| {
let mut status_events = languages.language_server_binary_statuses();
cx.spawn(|this, mut cx| async move {
cx.spawn(async move |this, cx| {
while let Some((name, status)) = status_events.next().await {
this.update(&mut cx, |this: &mut ActivityIndicator, cx| {
this.update(cx, |this: &mut ActivityIndicator, cx| {
this.statuses.retain(|s| s.name != name);
this.statuses.push(LspStatus { name, status });
this.statuses.push(ServerStatus { name, status });
cx.notify();
})?;
}
@@ -73,7 +75,35 @@ impl ActivityIndicator {
})
.detach();
cx.observe(&project, |_, _, cx| cx.notify()).detach();
let mut status_events = languages.dap_server_binary_statuses();
cx.spawn(async move |this, cx| {
while let Some((name, status)) = status_events.next().await {
this.update(cx, |this, cx| {
this.statuses.retain(|s| s.name != name);
this.statuses.push(ServerStatus { name, status });
cx.notify();
})?;
}
anyhow::Ok(())
})
.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();
@@ -88,25 +118,25 @@ impl ActivityIndicator {
});
cx.subscribe_in(&this, window, move |_, _, event, window, cx| match event {
Event::ShowError { lsp_name, error } => {
Event::ShowError { server_name, error } => {
let create_buffer = project.update(cx, |project, cx| project.create_buffer(cx));
let project = project.clone();
let error = error.clone();
let lsp_name = lsp_name.clone();
cx.spawn_in(window, |workspace, mut cx| async move {
let server_name = server_name.clone();
cx.spawn_in(window, async move |workspace, cx| {
let buffer = create_buffer.await?;
buffer.update(&mut cx, |buffer, cx| {
buffer.update(cx, |buffer, cx| {
buffer.edit(
[(
0..0,
format!("Language server error: {}\n\n{}", lsp_name, error),
format!("Language server error: {}\n\n{}", server_name, error),
)],
None,
cx,
);
buffer.set_capability(language::Capability::ReadOnly, cx);
})?;
workspace.update_in(&mut cx, |workspace, window, cx| {
workspace.update_in(cx, |workspace, window, cx| {
workspace.add_item_to_active_pane(
Box::new(cx.new(|cx| {
Editor::for_buffer(buffer, Some(project.clone()), window, cx)
@@ -129,9 +159,9 @@ impl ActivityIndicator {
fn show_error_message(&mut self, _: &ShowErrorMessage, _: &mut Window, cx: &mut Context<Self>) {
self.statuses.retain(|status| {
if let LanguageServerBinaryStatus::Failed { error } = &status.status {
if let BinaryStatus::Failed { error } = &status.status {
cx.emit(Event::ShowError {
lsp_name: status.name.clone(),
server_name: status.name.clone(),
error: error.clone(),
});
false
@@ -204,7 +234,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);
})),
@@ -260,12 +290,10 @@ impl ActivityIndicator {
let mut failed = SmallVec::<[_; 3]>::new();
for status in &self.statuses {
match status.status {
LanguageServerBinaryStatus::CheckingForUpdate => {
checking_for_update.push(status.name.clone())
}
LanguageServerBinaryStatus::Downloading => downloading.push(status.name.clone()),
LanguageServerBinaryStatus::Failed { .. } => failed.push(status.name.clone()),
LanguageServerBinaryStatus::None => {}
BinaryStatus::CheckingForUpdate => checking_for_update.push(status.name.clone()),
BinaryStatus::Downloading => downloading.push(status.name.clone()),
BinaryStatus::Failed { .. } => failed.push(status.name.clone()),
BinaryStatus::None => {}
}
}
@@ -278,7 +306,7 @@ impl ActivityIndicator {
),
message: format!(
"Downloading {}...",
downloading.iter().map(|name| name.0.as_ref()).fold(
downloading.iter().map(|name| name.as_ref()).fold(
String::new(),
|mut acc, s| {
if !acc.is_empty() {
@@ -306,7 +334,7 @@ impl ActivityIndicator {
),
message: format!(
"Checking for updates to {}...",
checking_for_update.iter().map(|name| name.0.as_ref()).fold(
checking_for_update.iter().map(|name| name.as_ref()).fold(
String::new(),
|mut acc, s| {
if !acc.is_empty() {
@@ -336,7 +364,7 @@ impl ActivityIndicator {
"Failed to run {}. Click to show error.",
failed
.iter()
.map(|name| name.0.as_ref())
.map(|name| name.as_ref())
.fold(String::new(), |mut acc, s| {
if !acc.is_empty() {
acc.push_str(", ");

View File

@@ -553,7 +553,7 @@ pub struct Metadata {
pub user_id: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct Usage {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub input_tokens: Option<u32>,

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,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(async move |cx: &mut AsyncApp| {
while let Some((prompt, channel)) = rx.next().await {
password_prompt(prompt, channel, 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(20))).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};
@@ -98,9 +98,9 @@ pub fn init(
AssistantSettings::register(cx);
SlashCommandSettings::register(cx);
cx.spawn(|mut cx| {
cx.spawn({
let client = client.clone();
async move {
async move |cx| {
let is_search_slash_command_enabled = cx
.update(|cx| cx.wait_for_flag::<SearchSlashCommandFeatureFlag>())?
.await;
@@ -116,7 +116,7 @@ pub fn init(
let semantic_index = SemanticDb::new(
paths::embeddings_dir().join("semantic-index-db.0.mdb"),
Arc::new(embedding_provider),
&mut cx,
cx,
)
.await?;
@@ -186,8 +186,12 @@ fn init_language_model_settings(cx: &mut App) {
fn update_active_language_model_from_settings(cx: &mut App) {
let settings = AssistantSettings::get_global(cx);
let provider_name = LanguageModelProviderId::from(settings.default_model.provider.clone());
let model_id = LanguageModelId::from(settings.default_model.model.clone());
let active_model_provider_name =
LanguageModelProviderId::from(settings.default_model.provider.clone());
let active_model_id = LanguageModelId::from(settings.default_model.model.clone());
let editor_provider_name =
LanguageModelProviderId::from(settings.editor_model.provider.clone());
let editor_model_id = LanguageModelId::from(settings.editor_model.model.clone());
let inline_alternatives = settings
.inline_alternatives
.iter()
@@ -199,7 +203,8 @@ fn update_active_language_model_from_settings(cx: &mut App) {
})
.collect::<Vec<_>>();
LanguageModelRegistry::global(cx).update(cx, |registry, cx| {
registry.select_active_model(&provider_name, &model_id, cx);
registry.select_active_model(&active_model_provider_name, &active_model_id, cx);
registry.select_editor_model(&editor_provider_name, &editor_model_id, cx);
registry.select_inline_alternative_models(inline_alternatives, cx);
});
}

View File

@@ -110,7 +110,7 @@ impl ConfigurationView {
.bg(cx.theme().colors().surface_background)
.border_1()
.border_color(cx.theme().colors().border_variant)
.rounded_md()
.rounded_sm()
.when(configuration_view.is_none(), |this| {
this.child(div().child(Label::new(format!(
"No configuration view for {}",

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;
@@ -97,16 +98,16 @@ impl AssistantPanel {
prompt_builder: Arc<PromptBuilder>,
cx: AsyncWindowContext,
) -> Task<Result<Entity<Self>>> {
cx.spawn(|mut cx| async move {
cx.spawn(async move |cx| {
let slash_commands = Arc::new(SlashCommandWorkingSet::default());
let context_store = workspace
.update(&mut cx, |workspace, cx| {
.update(cx, |workspace, cx| {
let project = workspace.project().clone();
ContextStore::new(project, prompt_builder.clone(), slash_commands, cx)
})?
.await?;
workspace.update_in(&mut cx, |workspace, window, cx| {
workspace.update_in(cx, |workspace, window, cx| {
// TODO: deserialize state.
cx.new(|cx| Self::new(workspace, context_store, window, cx))
})
@@ -296,7 +297,8 @@ impl AssistantPanel {
&LanguageModelRegistry::global(cx),
window,
|this, _, event: &language_model::Event, window, cx| match event {
language_model::Event::ActiveModelChanged => {
language_model::Event::ActiveModelChanged
| language_model::Event::EditorModelChanged => {
this.completion_provider_changed(window, cx);
}
language_model::Event::ProviderStateChanged => {
@@ -355,9 +357,9 @@ impl AssistantPanel {
) -> Task<()> {
let mut status_rx = client.status();
cx.spawn_in(window, |this, mut cx| async move {
cx.spawn_in(window, async move |this, cx| {
while let Some(status) = status_rx.next().await {
this.update(&mut cx, |this, cx| {
this.update(cx, |this, cx| {
if this.client_status.is_none()
|| this
.client_status
@@ -369,7 +371,7 @@ impl AssistantPanel {
})
.log_err();
}
this.update(&mut cx, |this, _cx| this.watch_client_status = None)
this.update(cx, |this, _cx| this.watch_client_status = None)
.log_err();
})
}
@@ -574,11 +576,11 @@ impl AssistantPanel {
if self.authenticate_provider_task.is_none() {
self.authenticate_provider_task = Some((
provider.id(),
cx.spawn_in(window, |this, mut cx| async move {
cx.spawn_in(window, async move |this, cx| {
if let Some(future) = load_credentials {
let _ = future.await;
}
this.update(&mut cx, |this, _cx| {
this.update(cx, |this, _cx| {
this.authenticate_provider_task = None;
})
.log_err();
@@ -639,9 +641,9 @@ impl AssistantPanel {
}
} else {
let assistant_panel = assistant_panel.downgrade();
cx.spawn_in(window, |workspace, mut cx| async move {
cx.spawn_in(window, async move |workspace, cx| {
let Some(task) =
assistant_panel.update(&mut cx, |assistant, cx| assistant.authenticate(cx))?
assistant_panel.update(cx, |assistant, cx| assistant.authenticate(cx))?
else {
let answer = cx
.prompt(
@@ -663,7 +665,7 @@ impl AssistantPanel {
return Ok(());
};
task.await?;
if assistant_panel.update(&mut cx, |panel, cx| panel.is_authenticated(cx))? {
if assistant_panel.update(cx, |panel, cx| panel.is_authenticated(cx))? {
cx.update(|window, cx| match inline_assist_target {
InlineAssistTarget::Editor(active_editor, include_context) => {
let assistant_panel = if include_context {
@@ -696,7 +698,7 @@ impl AssistantPanel {
}
})?
} else {
workspace.update_in(&mut cx, |workspace, window, cx| {
workspace.update_in(cx, |workspace, window, cx| {
workspace.focus_panel::<AssistantPanel>(window, cx)
})?;
}
@@ -789,10 +791,10 @@ impl AssistantPanel {
.context_store
.update(cx, |store, cx| store.create_remote_context(cx));
cx.spawn_in(window, |this, mut cx| async move {
cx.spawn_in(window, async move |this, cx| {
let context = task.await?;
this.update_in(&mut cx, |this, window, cx| {
this.update_in(cx, |this, window, cx| {
let workspace = this.workspace.clone();
let project = this.project.clone();
let lsp_adapter_delegate =
@@ -845,9 +847,9 @@ impl AssistantPanel {
self.show_context(editor.clone(), window, cx);
let workspace = self.workspace.clone();
cx.spawn_in(window, move |_, mut cx| async move {
cx.spawn_in(window, async move |_, cx| {
workspace
.update_in(&mut cx, |workspace, window, cx| {
.update_in(cx, |workspace, window, cx| {
workspace.focus_panel::<AssistantPanel>(window, cx);
})
.ok();
@@ -1067,8 +1069,8 @@ impl AssistantPanel {
.filter(|editor| editor.read(cx).context().read(cx).path() == Some(&path))
});
if let Some(existing_context) = existing_context {
return cx.spawn_in(window, |this, mut cx| async move {
this.update_in(&mut cx, |this, window, cx| {
return cx.spawn_in(window, async move |this, cx| {
this.update_in(cx, |this, window, cx| {
this.show_context(existing_context, window, cx)
})
});
@@ -1083,9 +1085,9 @@ impl AssistantPanel {
let lsp_adapter_delegate = make_lsp_adapter_delegate(&project, cx).log_err().flatten();
cx.spawn_in(window, |this, mut cx| async move {
cx.spawn_in(window, async move |this, cx| {
let context = context.await?;
this.update_in(&mut cx, |this, window, cx| {
this.update_in(cx, |this, window, cx| {
let editor = cx.new(|cx| {
ContextEditor::for_context(
context,
@@ -1115,8 +1117,8 @@ impl AssistantPanel {
.filter(|editor| *editor.read(cx).context().read(cx).id() == id)
});
if let Some(existing_context) = existing_context {
return cx.spawn_in(window, |this, mut cx| async move {
this.update_in(&mut cx, |this, window, cx| {
return cx.spawn_in(window, async move |this, cx| {
this.update_in(cx, |this, window, cx| {
this.show_context(existing_context.clone(), window, cx)
})?;
Ok(existing_context)
@@ -1132,9 +1134,9 @@ impl AssistantPanel {
.log_err()
.flatten();
cx.spawn_in(window, |this, mut cx| async move {
cx.spawn_in(window, async move |this, cx| {
let context = context.await?;
this.update_in(&mut cx, |this, window, cx| {
this.update_in(cx, |this, window, cx| {
let editor = cx.new(|cx| {
ContextEditor::for_context(
context,

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 project::{CodeAction, LspAction, ProjectTransaction};
use prompt_store::PromptBuilder;
use rope::Rope;
use settings::{update_settings_file, Settings, SettingsStore};
use smol::future::FutureExt;
@@ -386,7 +386,6 @@ impl InlineAssistant {
}
}
#[allow(clippy::too_many_arguments)]
pub fn suggest_assist(
&mut self,
editor: &Entity<Editor>,
@@ -1247,7 +1246,7 @@ impl InlineAssistant {
});
enum DeletedLines {}
let mut editor = Editor::for_multibuffer(multi_buffer, None, true, window, cx);
let mut editor = Editor::for_multibuffer(multi_buffer, None, window, cx);
editor.set_soft_wrap_mode(language::language_settings::SoftWrap::None, cx);
editor.set_show_wrap_guides(false, cx);
editor.set_show_gutter(false, cx);
@@ -1312,9 +1311,9 @@ impl EditorInlineAssists {
assist_ids: Vec::new(),
scroll_lock: None,
highlight_updates: highlight_updates_tx,
_update_highlights: cx.spawn(|cx| {
_update_highlights: cx.spawn({
let editor = editor.downgrade();
async move {
async move |cx| {
while let Ok(()) = highlight_updates_rx.changed().await {
let editor = editor.upgrade().context("editor was dropped")?;
cx.update_global(|assistant: &mut InlineAssistant, cx| {
@@ -1589,10 +1588,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;
@@ -1655,7 +1673,6 @@ impl Focusable for PromptEditor {
impl PromptEditor {
const MAX_LINES: u8 = 8;
#[allow(clippy::too_many_arguments)]
fn new(
id: InlineAssistId,
gutter_dimensions: Arc<Mutex<GutterDimensions>>,
@@ -1676,7 +1693,6 @@ impl PromptEditor {
},
prompt_buffer,
None,
false,
window,
cx,
);
@@ -1834,7 +1850,7 @@ impl PromptEditor {
fn count_tokens(&mut self, cx: &mut Context<Self>) {
let assist_id = self.id;
self.pending_token_count = cx.spawn(|this, mut cx| async move {
self.pending_token_count = cx.spawn(async move |this, cx| {
cx.background_executor().timer(Duration::from_secs(1)).await;
let token_count = cx
.update_global(|inline_assistant: &mut InlineAssistant, cx| {
@@ -1846,7 +1862,7 @@ impl PromptEditor {
})??
.await?;
this.update(&mut cx, |this, cx| {
this.update(cx, |this, cx| {
this.token_counts = Some(token_count);
cx.notify();
})
@@ -2314,7 +2330,6 @@ struct InlineAssist {
}
impl InlineAssist {
#[allow(clippy::too_many_arguments)]
fn new(
assist_id: InlineAssistId,
group_id: InlineAssistGroupId,
@@ -2867,7 +2882,7 @@ impl CodegenAlternative {
let request = self.build_request(user_prompt, assistant_panel_context, cx)?;
self.request = Some(request.clone());
cx.spawn(|_, cx| async move { model.stream_completion_text(request, &cx).await })
cx.spawn(async move |_, cx| model.stream_completion_text(request, &cx).await)
.boxed_local()
};
self.handle_stream(telemetry_id, provider_id.to_string(), api_key, stream, cx);
@@ -2984,213 +2999,207 @@ impl CodegenAlternative {
let completion = Arc::new(Mutex::new(String::new()));
let completion_clone = completion.clone();
self.generation = cx.spawn(|codegen, mut cx| {
async move {
let stream = stream.await;
let message_id = stream
.as_ref()
.ok()
.and_then(|stream| stream.message_id.clone());
let generate = async {
let (mut diff_tx, mut diff_rx) = mpsc::channel(1);
let executor = cx.background_executor().clone();
let message_id = message_id.clone();
let line_based_stream_diff: Task<anyhow::Result<()>> =
cx.background_spawn(async move {
let mut response_latency = None;
let request_start = Instant::now();
let diff = async {
let chunks = StripInvalidSpans::new(stream?.stream);
futures::pin_mut!(chunks);
let mut diff = StreamingDiff::new(selected_text.to_string());
let mut line_diff = LineDiff::default();
self.generation = cx.spawn(async move |codegen, cx| {
let stream = stream.await;
let message_id = stream
.as_ref()
.ok()
.and_then(|stream| stream.message_id.clone());
let generate = async {
let (mut diff_tx, mut diff_rx) = mpsc::channel(1);
let executor = cx.background_executor().clone();
let message_id = message_id.clone();
let line_based_stream_diff: Task<anyhow::Result<()>> =
cx.background_spawn(async move {
let mut response_latency = None;
let request_start = Instant::now();
let diff = async {
let chunks = StripInvalidSpans::new(stream?.stream);
futures::pin_mut!(chunks);
let mut diff = StreamingDiff::new(selected_text.to_string());
let mut line_diff = LineDiff::default();
let mut new_text = String::new();
let mut base_indent = None;
let mut line_indent = None;
let mut first_line = true;
let mut new_text = String::new();
let mut base_indent = None;
let mut line_indent = None;
let mut first_line = true;
while let Some(chunk) = chunks.next().await {
if response_latency.is_none() {
response_latency = Some(request_start.elapsed());
}
let chunk = chunk?;
completion_clone.lock().push_str(&chunk);
while let Some(chunk) = chunks.next().await {
if response_latency.is_none() {
response_latency = Some(request_start.elapsed());
}
let chunk = chunk?;
completion_clone.lock().push_str(&chunk);
let mut lines = chunk.split('\n').peekable();
while let Some(line) = lines.next() {
new_text.push_str(line);
if line_indent.is_none() {
if let Some(non_whitespace_ch_ix) =
new_text.find(|ch: char| !ch.is_whitespace())
{
line_indent = Some(non_whitespace_ch_ix);
base_indent = base_indent.or(line_indent);
let mut lines = chunk.split('\n').peekable();
while let Some(line) = lines.next() {
new_text.push_str(line);
if line_indent.is_none() {
if let Some(non_whitespace_ch_ix) =
new_text.find(|ch: char| !ch.is_whitespace())
{
line_indent = Some(non_whitespace_ch_ix);
base_indent = base_indent.or(line_indent);
let line_indent = line_indent.unwrap();
let base_indent = base_indent.unwrap();
let indent_delta =
line_indent as i32 - base_indent as i32;
let mut corrected_indent_len = cmp::max(
0,
suggested_line_indent.len as i32 + indent_delta,
)
as usize;
if first_line {
corrected_indent_len = corrected_indent_len
.saturating_sub(
selection_start.column as usize,
);
}
let indent_char = suggested_line_indent.char();
let mut indent_buffer = [0; 4];
let indent_str =
indent_char.encode_utf8(&mut indent_buffer);
new_text.replace_range(
..line_indent,
&indent_str.repeat(corrected_indent_len),
);
let line_indent = line_indent.unwrap();
let base_indent = base_indent.unwrap();
let indent_delta =
line_indent as i32 - base_indent as i32;
let mut corrected_indent_len = cmp::max(
0,
suggested_line_indent.len as i32 + indent_delta,
)
as usize;
if first_line {
corrected_indent_len = corrected_indent_len
.saturating_sub(
selection_start.column as usize,
);
}
}
if line_indent.is_some() {
let char_ops = diff.push_new(&new_text);
line_diff
.push_char_operations(&char_ops, &selected_text);
diff_tx
.send((char_ops, line_diff.line_operations()))
.await?;
let indent_char = suggested_line_indent.char();
let mut indent_buffer = [0; 4];
let indent_str =
indent_char.encode_utf8(&mut indent_buffer);
new_text.replace_range(
..line_indent,
&indent_str.repeat(corrected_indent_len),
);
}
}
if line_indent.is_some() {
let char_ops = diff.push_new(&new_text);
line_diff.push_char_operations(&char_ops, &selected_text);
diff_tx
.send((char_ops, line_diff.line_operations()))
.await?;
new_text.clear();
}
if lines.peek().is_some() {
let char_ops = diff.push_new("\n");
line_diff.push_char_operations(&char_ops, &selected_text);
diff_tx
.send((char_ops, line_diff.line_operations()))
.await?;
if line_indent.is_none() {
// Don't write out the leading indentation in empty lines on the next line
// This is the case where the above if statement didn't clear the buffer
new_text.clear();
}
if lines.peek().is_some() {
let char_ops = diff.push_new("\n");
line_diff
.push_char_operations(&char_ops, &selected_text);
diff_tx
.send((char_ops, line_diff.line_operations()))
.await?;
if line_indent.is_none() {
// Don't write out the leading indentation in empty lines on the next line
// This is the case where the above if statement didn't clear the buffer
new_text.clear();
}
line_indent = None;
first_line = false;
}
line_indent = None;
first_line = false;
}
}
let mut char_ops = diff.push_new(&new_text);
char_ops.extend(diff.finish());
line_diff.push_char_operations(&char_ops, &selected_text);
line_diff.finish(&selected_text);
diff_tx
.send((char_ops, line_diff.line_operations()))
.await?;
anyhow::Ok(())
};
let result = diff.await;
let error_message =
result.as_ref().err().map(|error| error.to_string());
report_assistant_event(
AssistantEvent {
conversation_id: None,
message_id,
kind: AssistantKind::Inline,
phase: AssistantPhase::Response,
model: model_telemetry_id,
model_provider: model_provider_id.to_string(),
response_latency,
error_message,
language_name: language_name.map(|name| name.to_proto()),
},
telemetry,
http_client,
model_api_key,
&executor,
);
result?;
Ok(())
});
while let Some((char_ops, line_ops)) = diff_rx.next().await {
codegen.update(&mut cx, |codegen, cx| {
codegen.last_equal_ranges.clear();
let edits = char_ops
.into_iter()
.filter_map(|operation| match operation {
CharOperation::Insert { text } => {
let edit_start = snapshot.anchor_after(edit_start);
Some((edit_start..edit_start, text))
}
CharOperation::Delete { bytes } => {
let edit_end = edit_start + bytes;
let edit_range = snapshot.anchor_after(edit_start)
..snapshot.anchor_before(edit_end);
edit_start = edit_end;
Some((edit_range, String::new()))
}
CharOperation::Keep { bytes } => {
let edit_end = edit_start + bytes;
let edit_range = snapshot.anchor_after(edit_start)
..snapshot.anchor_before(edit_end);
edit_start = edit_end;
codegen.last_equal_ranges.push(edit_range);
None
}
})
.collect::<Vec<_>>();
if codegen.active {
codegen.apply_edits(edits.iter().cloned(), cx);
codegen.reapply_line_based_diff(line_ops.iter().cloned(), cx);
}
codegen.edits.extend(edits);
codegen.line_operations = line_ops;
codegen.edit_position = Some(snapshot.anchor_after(edit_start));
cx.notify();
})?;
}
let mut char_ops = diff.push_new(&new_text);
char_ops.extend(diff.finish());
line_diff.push_char_operations(&char_ops, &selected_text);
line_diff.finish(&selected_text);
diff_tx
.send((char_ops, line_diff.line_operations()))
.await?;
// Streaming stopped and we have the new text in the buffer, and a line-based diff applied for the whole new buffer.
// That diff is not what a regular diff is and might look unexpected, ergo apply a regular diff.
// It's fine to apply even if the rest of the line diffing fails, as no more hunks are coming through `diff_rx`.
let batch_diff_task =
codegen.update(&mut cx, |codegen, cx| codegen.reapply_batch_diff(cx))?;
let (line_based_stream_diff, ()) =
join!(line_based_stream_diff, batch_diff_task);
line_based_stream_diff?;
anyhow::Ok(())
};
anyhow::Ok(())
};
let result = diff.await;
let result = generate.await;
let elapsed_time = start_time.elapsed().as_secs_f64();
let error_message = result.as_ref().err().map(|error| error.to_string());
report_assistant_event(
AssistantEvent {
conversation_id: None,
message_id,
kind: AssistantKind::Inline,
phase: AssistantPhase::Response,
model: model_telemetry_id,
model_provider: model_provider_id.to_string(),
response_latency,
error_message,
language_name: language_name.map(|name| name.to_proto()),
},
telemetry,
http_client,
model_api_key,
&executor,
);
codegen
.update(&mut cx, |this, cx| {
this.message_id = message_id;
this.last_equal_ranges.clear();
if let Err(error) = result {
this.status = CodegenStatus::Error(error);
} else {
this.status = CodegenStatus::Done;
result?;
Ok(())
});
while let Some((char_ops, line_ops)) = diff_rx.next().await {
codegen.update(cx, |codegen, cx| {
codegen.last_equal_ranges.clear();
let edits = char_ops
.into_iter()
.filter_map(|operation| match operation {
CharOperation::Insert { text } => {
let edit_start = snapshot.anchor_after(edit_start);
Some((edit_start..edit_start, text))
}
CharOperation::Delete { bytes } => {
let edit_end = edit_start + bytes;
let edit_range = snapshot.anchor_after(edit_start)
..snapshot.anchor_before(edit_end);
edit_start = edit_end;
Some((edit_range, String::new()))
}
CharOperation::Keep { bytes } => {
let edit_end = edit_start + bytes;
let edit_range = snapshot.anchor_after(edit_start)
..snapshot.anchor_before(edit_end);
edit_start = edit_end;
codegen.last_equal_ranges.push(edit_range);
None
}
})
.collect::<Vec<_>>();
if codegen.active {
codegen.apply_edits(edits.iter().cloned(), cx);
codegen.reapply_line_based_diff(line_ops.iter().cloned(), cx);
}
this.elapsed_time = Some(elapsed_time);
this.completion = Some(completion.lock().clone());
cx.emit(CodegenEvent::Finished);
codegen.edits.extend(edits);
codegen.line_operations = line_ops;
codegen.edit_position = Some(snapshot.anchor_after(edit_start));
cx.notify();
})
.ok();
}
})?;
}
// Streaming stopped and we have the new text in the buffer, and a line-based diff applied for the whole new buffer.
// That diff is not what a regular diff is and might look unexpected, ergo apply a regular diff.
// It's fine to apply even if the rest of the line diffing fails, as no more hunks are coming through `diff_rx`.
let batch_diff_task =
codegen.update(cx, |codegen, cx| codegen.reapply_batch_diff(cx))?;
let (line_based_stream_diff, ()) = join!(line_based_stream_diff, batch_diff_task);
line_based_stream_diff?;
anyhow::Ok(())
};
let result = generate.await;
let elapsed_time = start_time.elapsed().as_secs_f64();
codegen
.update(cx, |this, cx| {
this.message_id = message_id;
this.last_equal_ranges.clear();
if let Err(error) = result {
this.status = CodegenStatus::Error(error);
} else {
this.status = CodegenStatus::Done;
}
this.elapsed_time = Some(elapsed_time);
this.completion = Some(completion.lock().clone());
cx.emit(CodegenEvent::Finished);
cx.notify();
})
.ok();
});
cx.notify();
}
@@ -3308,7 +3317,7 @@ impl CodegenAlternative {
let new_snapshot = self.buffer.read(cx).snapshot(cx);
let new_range = self.range.to_point(&new_snapshot);
cx.spawn(|codegen, mut cx| async move {
cx.spawn(async move |codegen, cx| {
let (deleted_row_ranges, inserted_row_ranges) = cx
.background_spawn(async move {
let old_text = old_snapshot
@@ -3358,7 +3367,7 @@ impl CodegenAlternative {
.await;
codegen
.update(&mut cx, |codegen, cx| {
.update(cx, |codegen, cx| {
codegen.diff.deleted_row_ranges = deleted_row_ranges;
codegen.diff.inserted_row_ranges = inserted_row_ranges;
cx.notify();
@@ -3550,10 +3559,11 @@ impl CodeActionProvider for AssistantCodeActionProvider {
Task::ready(Ok(vec![CodeAction {
server_id: language::LanguageServerId(0),
range: snapshot.anchor_before(range.start)..snapshot.anchor_after(range.end),
lsp_action: lsp::CodeAction {
lsp_action: LspAction::Action(Box::new(lsp::CodeAction {
title: "Fix with Assistant".into(),
..Default::default()
},
})),
resolved: true,
}]))
} else {
Task::ready(Ok(Vec::new()))
@@ -3571,10 +3581,10 @@ impl CodeActionProvider for AssistantCodeActionProvider {
) -> Task<Result<ProjectTransaction>> {
let editor = self.editor.clone();
let workspace = self.workspace.clone();
window.spawn(cx, |mut cx| async move {
window.spawn(cx, async move |cx| {
let editor = editor.upgrade().context("editor was released")?;
let range = editor
.update(&mut cx, |editor, cx| {
.update(cx, |editor, cx| {
editor.buffer().update(cx, |multibuffer, cx| {
let buffer = buffer.read(cx);
let multibuffer_snapshot = multibuffer.read(cx);
@@ -3609,7 +3619,7 @@ impl CodeActionProvider for AssistantCodeActionProvider {
})
})?
.context("invalid range")?;
let assistant_panel = workspace.update(&mut cx, |workspace, cx| {
let assistant_panel = workspace.update(cx, |workspace, cx| {
workspace
.panel::<AssistantPanel>(cx)
.context("assistant panel was released")

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());
@@ -683,7 +702,6 @@ impl Focusable for PromptEditor {
impl PromptEditor {
const MAX_LINES: u8 = 8;
#[allow(clippy::too_many_arguments)]
fn new(
id: TerminalInlineAssistId,
prompt_history: VecDeque<String>,
@@ -702,7 +720,6 @@ impl PromptEditor {
},
prompt_buffer,
None,
false,
window,
cx,
);
@@ -808,7 +825,7 @@ impl PromptEditor {
let Some(model) = LanguageModelRegistry::read_global(cx).active_model() else {
return;
};
self.pending_token_count = cx.spawn(|this, mut cx| async move {
self.pending_token_count = cx.spawn(async move |this, cx| {
cx.background_executor().timer(Duration::from_secs(1)).await;
let request =
cx.update_global(|inline_assistant: &mut TerminalInlineAssistant, cx| {
@@ -816,7 +833,7 @@ impl PromptEditor {
})??;
let token_count = cx.update(|cx| model.count_tokens(request, cx))?.await?;
this.update(&mut cx, |this, cx| {
this.update(cx, |this, cx| {
this.token_count = Some(token_count);
cx.notify();
})
@@ -1123,7 +1140,7 @@ impl Codegen {
let telemetry = self.telemetry.clone();
self.status = CodegenStatus::Pending;
self.transaction = Some(TerminalTransaction::start(self.terminal.clone()));
self.generation = cx.spawn(|this, mut cx| async move {
self.generation = cx.spawn(async move |this, cx| {
let model_telemetry_id = model.telemetry_id();
let model_provider_id = model.provider_id();
let response = model.stream_completion_text(prompt, &cx).await;
@@ -1180,12 +1197,12 @@ impl Codegen {
}
});
this.update(&mut cx, |this, _| {
this.update(cx, |this, _| {
this.message_id = message_id;
})?;
while let Some(hunk) = hunks_rx.next().await {
this.update(&mut cx, |this, cx| {
this.update(cx, |this, cx| {
if let Some(transaction) = &mut this.transaction {
transaction.push(hunk, cx);
cx.notify();
@@ -1199,7 +1216,7 @@ impl Codegen {
let result = generate.await;
this.update(&mut cx, |this, cx| {
this.update(cx, |this, cx| {
if let Err(error) = result {
this.status = CodegenStatus::Error(error);
} else {

View File

@@ -38,6 +38,7 @@ file_icons.workspace = true
fs.workspace = true
futures.workspace = true
fuzzy.workspace = true
git.workspace = true
gpui.workspace = true
heed.workspace = true
html_to_markdown.workspace = true
@@ -56,13 +57,16 @@ paths.workspace = true
picker.workspace = true
project.workspace = true
prompt_library.workspace = true
prompt_store.workspace = true
proto.workspace = true
rope.workspace = true
scripting_tool.workspace = true
serde.workspace = true
serde_json.workspace = true
settings.workspace = true
smol.workspace = true
streaming_diff.workspace = true
telemetry.workspace = true
telemetry_events.workspace = true
terminal.workspace = true
terminal_view.workspace = true
@@ -80,8 +84,8 @@ zed_actions.workspace = true
[dev-dependencies]
editor = { workspace = true, features = ["test-support"] }
gpui = { workspace = true, "features" = ["test-support"] }
indoc.workspace = true
language = { workspace = true, "features" = ["test-support"] }
language_model = { workspace = true, "features" = ["test-support"] }
project = { workspace = true, features = ["test-support"] }
rand.workspace = true
indoc.workspace = true

View File

@@ -1,46 +1,55 @@
use std::sync::Arc;
use assistant_tool::ToolWorkingSet;
use collections::HashMap;
use gpui::{
list, AbsoluteLength, AnyElement, App, DefiniteLength, EdgesRefinement, Empty, Entity, Length,
ListAlignment, ListOffset, ListState, StyleRefinement, Subscription, TextStyleRefinement,
UnderlineStyle, WeakEntity,
};
use language::LanguageRegistry;
use language_model::{LanguageModelRegistry, LanguageModelToolUseId, Role};
use markdown::{Markdown, MarkdownStyle};
use settings::Settings as _;
use theme::ThemeSettings;
use ui::{prelude::*, Disclosure};
use workspace::Workspace;
use crate::thread::{MessageId, RequestKind, Thread, ThreadError, ThreadEvent};
use crate::thread_store::ThreadStore;
use crate::tool_use::{ToolUse, ToolUseStatus};
use crate::ui::ContextPill;
use collections::HashMap;
use editor::{Editor, MultiBuffer};
use gpui::{
list, percentage, AbsoluteLength, Animation, AnimationExt, AnyElement, App, ClickEvent,
DefiniteLength, EdgesRefinement, Empty, Entity, Focusable, Length, ListAlignment, ListOffset,
ListState, StyleRefinement, Subscription, Task, TextStyleRefinement, Transformation,
UnderlineStyle,
};
use language::{Buffer, LanguageRegistry};
use language_model::{LanguageModelRegistry, LanguageModelToolUseId, Role};
use markdown::{Markdown, MarkdownStyle};
use scripting_tool::{ScriptingTool, ScriptingToolInput};
use settings::Settings as _;
use std::sync::Arc;
use std::time::Duration;
use theme::ThemeSettings;
use ui::Color;
use ui::{prelude::*, Disclosure, KeyBinding};
use util::ResultExt as _;
use crate::context_store::{refresh_context_store_text, ContextStore};
pub struct ActiveThread {
workspace: WeakEntity<Workspace>,
language_registry: Arc<LanguageRegistry>,
tools: Arc<ToolWorkingSet>,
thread_store: Entity<ThreadStore>,
thread: Entity<Thread>,
context_store: Entity<ContextStore>,
save_thread_task: Option<Task<()>>,
messages: Vec<MessageId>,
list_state: ListState,
rendered_messages_by_id: HashMap<MessageId, Entity<Markdown>>,
rendered_scripting_tool_uses: HashMap<LanguageModelToolUseId, Entity<Markdown>>,
editing_message: Option<(MessageId, EditMessageState)>,
expanded_tool_uses: HashMap<LanguageModelToolUseId, bool>,
last_error: Option<ThreadError>,
_subscriptions: Vec<Subscription>,
}
struct EditMessageState {
editor: Entity<Editor>,
}
impl ActiveThread {
pub fn new(
thread: Entity<Thread>,
thread_store: Entity<ThreadStore>,
workspace: WeakEntity<Workspace>,
language_registry: Arc<LanguageRegistry>,
tools: Arc<ToolWorkingSet>,
context_store: Entity<ContextStore>,
window: &mut Window,
cx: &mut Context<Self>,
) -> Self {
@@ -50,27 +59,39 @@ impl ActiveThread {
];
let mut this = Self {
workspace,
language_registry,
tools,
thread_store,
thread: thread.clone(),
context_store,
save_thread_task: None,
messages: Vec::new(),
rendered_messages_by_id: HashMap::default(),
rendered_scripting_tool_uses: HashMap::default(),
expanded_tool_uses: HashMap::default(),
list_state: ListState::new(0, ListAlignment::Bottom, px(1024.), {
let this = cx.entity().downgrade();
move |ix, _: &mut Window, cx: &mut App| {
this.update(cx, |this, cx| this.render_message(ix, cx))
move |ix, window: &mut Window, cx: &mut App| {
this.update(cx, |this, cx| this.render_message(ix, window, cx))
.unwrap()
}
}),
editing_message: None,
last_error: None,
_subscriptions: subscriptions,
};
for message in thread.read(cx).messages().cloned().collect::<Vec<_>>() {
this.push_message(&message.id, message.text.clone(), window, cx);
for tool_use in thread.read(cx).scripting_tool_uses_for_message(message.id) {
this.render_scripting_tool_use_markdown(
tool_use.id.clone(),
tool_use.name.as_ref(),
tool_use.input.clone(),
window,
cx,
);
}
}
this
@@ -95,7 +116,7 @@ impl ActiveThread {
pub fn cancel_last_completion(&mut self, cx: &mut App) -> bool {
self.last_error.take();
self.thread
.update(cx, |thread, _cx| thread.cancel_last_completion())
.update(cx, |thread, cx| thread.cancel_last_completion(cx))
}
pub fn last_error(&self) -> Option<ThreadError> {
@@ -117,6 +138,44 @@ impl ActiveThread {
self.messages.push(*id);
self.list_state.splice(old_len..old_len, 1);
let markdown = self.render_markdown(text.into(), window, cx);
self.rendered_messages_by_id.insert(*id, markdown);
self.list_state.scroll_to(ListOffset {
item_ix: old_len,
offset_in_item: Pixels(0.0),
});
}
fn edited_message(
&mut self,
id: &MessageId,
text: String,
window: &mut Window,
cx: &mut Context<Self>,
) {
let Some(index) = self.messages.iter().position(|message_id| message_id == id) else {
return;
};
self.list_state.splice(index..index + 1, 1);
let markdown = self.render_markdown(text.into(), window, cx);
self.rendered_messages_by_id.insert(*id, markdown);
}
fn deleted_message(&mut self, id: &MessageId) {
let Some(index) = self.messages.iter().position(|message_id| message_id == id) else {
return;
};
self.messages.remove(index);
self.list_state.splice(index..index + 1, 0);
self.rendered_messages_by_id.remove(id);
}
fn render_markdown(
&self,
text: SharedString,
window: &Window,
cx: &mut Context<Self>,
) -> Entity<Markdown> {
let theme_settings = ThemeSettings::get_global(cx);
let colors = cx.theme().colors();
let ui_font_size = TextSize::Default.rems(cx);
@@ -125,6 +184,8 @@ impl ActiveThread {
text_style.refine(&TextStyleRefinement {
font_family: Some(theme_settings.ui_font.family.clone()),
font_fallbacks: theme_settings.ui_font.fallbacks.clone(),
font_features: Some(theme_settings.ui_font.features.clone()),
font_size: Some(ui_font_size.into()),
color: Some(cx.theme().colors().text),
..Default::default()
@@ -134,6 +195,8 @@ impl ActiveThread {
base_text_style: text_style,
syntax: cx.theme().syntax().clone(),
selection_background_color: cx.theme().players().local().selection,
code_block_overflow_x_scroll: true,
table_overflow_x_scroll: true,
code_block: StyleRefinement {
margin: EdgesRefinement {
top: Some(Length::Definite(rems(0.).into())),
@@ -157,6 +220,8 @@ impl ActiveThread {
},
text: Some(TextStyleRefinement {
font_family: Some(theme_settings.buffer_font.family.clone()),
font_fallbacks: theme_settings.buffer_font.fallbacks.clone(),
font_features: Some(theme_settings.buffer_font.features.clone()),
font_size: Some(buffer_font_size.into()),
..Default::default()
}),
@@ -164,6 +229,8 @@ impl ActiveThread {
},
inline_code: TextStyleRefinement {
font_family: Some(theme_settings.buffer_font.family.clone()),
font_fallbacks: theme_settings.buffer_font.fallbacks.clone(),
font_features: Some(theme_settings.buffer_font.features.clone()),
font_size: Some(buffer_font_size.into()),
background_color: Some(colors.editor_foreground.opacity(0.1)),
..Default::default()
@@ -180,25 +247,46 @@ impl ActiveThread {
..Default::default()
};
let markdown = cx.new(|cx| {
cx.new(|cx| {
Markdown::new(
text.into(),
text,
markdown_style,
Some(self.language_registry.clone()),
None,
cx,
)
});
self.rendered_messages_by_id.insert(*id, markdown);
self.list_state.scroll_to(ListOffset {
item_ix: old_len,
offset_in_item: Pixels(0.0),
});
})
}
/// Renders the input of a scripting tool use to Markdown.
///
/// Does nothing if the tool use does not correspond to the scripting tool.
fn render_scripting_tool_use_markdown(
&mut self,
tool_use_id: LanguageModelToolUseId,
tool_name: &str,
tool_input: serde_json::Value,
window: &mut Window,
cx: &mut Context<Self>,
) {
if tool_name != ScriptingTool::NAME {
return;
}
let lua_script = serde_json::from_value::<ScriptingToolInput>(tool_input)
.map(|input| input.lua_script)
.unwrap_or_default();
let lua_script =
self.render_markdown(format!("```lua\n{lua_script}\n```").into(), window, cx);
self.rendered_scripting_tool_uses
.insert(tool_use_id, lua_script);
}
fn handle_thread_event(
&mut self,
_: &Entity<Thread>,
_thread: &Entity<Thread>,
event: &ThreadEvent,
window: &mut Window,
cx: &mut Context<Self>,
@@ -208,12 +296,9 @@ impl ActiveThread {
self.last_error = Some(error.clone());
}
ThreadEvent::StreamedCompletion | ThreadEvent::SummaryChanged => {
self.thread_store
.update(cx, |thread_store, cx| {
thread_store.save_thread(&self.thread, cx)
})
.detach_and_log_err(cx);
self.save_thread(cx);
}
ThreadEvent::DoneStreaming => {}
ThreadEvent::StreamedAssistantText(message_id, text) => {
if let Some(markdown) = self.rendered_messages_by_id.get_mut(&message_id) {
markdown.update(cx, |markdown, cx| {
@@ -231,56 +316,229 @@ impl ActiveThread {
self.push_message(message_id, message_text, window, cx);
}
self.thread_store
.update(cx, |thread_store, cx| {
thread_store.save_thread(&self.thread, cx)
})
.detach_and_log_err(cx);
self.save_thread(cx);
cx.notify();
}
ThreadEvent::MessageEdited(message_id) => {
if let Some(message_text) = self
.thread
.read(cx)
.message(*message_id)
.map(|message| message.text.clone())
{
self.edited_message(message_id, message_text, window, cx);
}
self.save_thread(cx);
cx.notify();
}
ThreadEvent::MessageDeleted(message_id) => {
self.deleted_message(message_id);
self.save_thread(cx);
cx.notify();
}
ThreadEvent::UsePendingTools => {
let pending_tool_uses = self
.thread
.read(cx)
.pending_tool_uses()
.into_iter()
.filter(|tool_use| tool_use.status.is_idle())
.cloned()
.collect::<Vec<_>>();
for tool_use in pending_tool_uses {
if let Some(tool) = self.tools.tool(&tool_use.name, cx) {
let task = tool.run(tool_use.input, self.workspace.clone(), window, cx);
self.thread.update(cx, |thread, cx| {
thread.insert_tool_output(tool_use.id.clone(), task, cx);
});
}
}
self.thread.update(cx, |thread, cx| {
thread.use_pending_tools(cx);
});
}
ThreadEvent::ToolFinished { .. } => {
let all_tools_finished = self
.thread
.read(cx)
.pending_tool_uses()
.into_iter()
.all(|tool_use| tool_use.status.is_error());
if all_tools_finished {
ThreadEvent::ToolFinished {
pending_tool_use,
canceled,
..
} => {
let canceled = *canceled;
if let Some(tool_use) = pending_tool_use {
self.render_scripting_tool_use_markdown(
tool_use.id.clone(),
tool_use.name.as_ref(),
tool_use.input.clone(),
window,
cx,
);
}
if self.thread.read(cx).all_tools_finished() {
let pending_refresh_buffers = self.thread.update(cx, |thread, cx| {
thread.action_log().update(cx, |action_log, _cx| {
action_log.take_stale_buffers_in_context()
})
});
let context_update_task = if !pending_refresh_buffers.is_empty() {
let refresh_task = refresh_context_store_text(
self.context_store.clone(),
&pending_refresh_buffers,
cx,
);
cx.spawn(async move |this, cx| {
let updated_context_ids = refresh_task.await;
this.update(cx, |this, cx| {
this.context_store.read_with(cx, |context_store, cx| {
context_store
.context()
.iter()
.filter(|context| {
updated_context_ids.contains(&context.id())
})
.flat_map(|context| context.snapshot(cx))
.collect()
})
})
})
} else {
Task::ready(anyhow::Ok(Vec::new()))
};
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);
thread.send_to_model(model, RequestKind::Chat, true, cx);
});
cx.spawn(async move |this, cx| {
let updated_context = context_update_task.await?;
this.update(cx, |this, cx| {
this.thread.update(cx, |thread, cx| {
thread.attach_tool_results(updated_context, cx);
if !canceled {
thread.send_to_model(model, RequestKind::Chat, cx);
}
});
})
})
.detach();
}
}
}
}
}
fn render_message(&self, ix: usize, cx: &mut Context<Self>) -> AnyElement {
/// Spawns a task to save the active thread.
///
/// Only one task to save the thread will be in flight at a time.
fn save_thread(&mut self, cx: &mut Context<Self>) {
let thread = self.thread.clone();
self.save_thread_task = Some(cx.spawn(async move |this, cx| {
let task = this
.update(cx, |this, cx| {
this.thread_store
.update(cx, |thread_store, cx| thread_store.save_thread(&thread, cx))
})
.ok();
if let Some(task) = task {
task.await.log_err();
}
}));
}
fn start_editing_message(
&mut self,
message_id: MessageId,
message_text: String,
window: &mut Window,
cx: &mut Context<Self>,
) {
let buffer = cx.new(|cx| {
MultiBuffer::singleton(cx.new(|cx| Buffer::local(message_text.clone(), cx)), cx)
});
let editor = cx.new(|cx| {
let mut editor = Editor::new(
editor::EditorMode::AutoHeight { max_lines: 8 },
buffer,
None,
window,
cx,
);
editor.focus_handle(cx).focus(window);
editor.move_to_end(&editor::actions::MoveToEnd, window, cx);
editor
});
self.editing_message = Some((
message_id,
EditMessageState {
editor: editor.clone(),
},
));
cx.notify();
}
fn cancel_editing_message(&mut self, _: &menu::Cancel, _: &mut Window, cx: &mut Context<Self>) {
self.editing_message.take();
cx.notify();
}
fn confirm_editing_message(
&mut self,
_: &menu::Confirm,
_: &mut Window,
cx: &mut Context<Self>,
) {
let Some((message_id, state)) = self.editing_message.take() else {
return;
};
let edited_text = state.editor.read(cx).text(cx);
self.thread.update(cx, |thread, cx| {
thread.edit_message(message_id, Role::User, edited_text, cx);
for message_id in self.messages_after(message_id) {
thread.delete_message(*message_id, cx);
}
});
let provider = LanguageModelRegistry::read_global(cx).active_provider();
if provider
.as_ref()
.map_or(false, |provider| provider.must_accept_terms(cx))
{
cx.notify();
return;
}
let model_registry = LanguageModelRegistry::read_global(cx);
let Some(model) = model_registry.active_model() else {
return;
};
self.thread.update(cx, |thread, cx| {
thread.send_to_model(model, RequestKind::Chat, cx)
});
cx.notify();
}
fn last_user_message(&self, cx: &Context<Self>) -> Option<MessageId> {
self.messages
.iter()
.rev()
.find(|message_id| {
self.thread
.read(cx)
.message(**message_id)
.map_or(false, |message| message.role == Role::User)
})
.cloned()
}
fn messages_after(&self, message_id: MessageId) -> &[MessageId] {
self.messages
.iter()
.position(|id| *id == message_id)
.map(|index| &self.messages[index + 1..])
.unwrap_or(&[])
}
fn handle_cancel_click(&mut self, _: &ClickEvent, window: &mut Window, cx: &mut Context<Self>) {
self.cancel_editing_message(&menu::Cancel, window, cx);
}
fn handle_regenerate_click(
&mut self,
_: &ClickEvent,
window: &mut Window,
cx: &mut Context<Self>,
) {
self.confirm_editing_message(&menu::Confirm, window, cx);
}
fn render_message(&self, ix: usize, window: &mut Window, cx: &mut Context<Self>) -> AnyElement {
let message_id = self.messages[ix];
let Some(message) = self.thread.read(cx).message(message_id) else {
return Empty.into_any();
@@ -290,20 +548,44 @@ impl ActiveThread {
return Empty.into_any();
};
let context = self.thread.read(cx).context_for_message(message_id);
let tool_uses = self.thread.read(cx).tool_uses_for_message(message_id);
let colors = cx.theme().colors();
let thread = self.thread.read(cx);
// Get all the data we need from thread before we start using it in closures
let context = thread.context_for_message(message_id);
let tool_uses = thread.tool_uses_for_message(message_id);
let scripting_tool_uses = thread.scripting_tool_uses_for_message(message_id);
// 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)
&& (thread.message_has_tool_results(message_id)
|| thread.message_has_scripting_tool_results(message_id))
{
return Empty.into_any();
}
let allow_editing_message =
message.role == Role::User && self.last_user_message(cx) == Some(message_id);
let edit_message_editor = self
.editing_message
.as_ref()
.filter(|(id, _)| *id == message_id)
.map(|(_, state)| state.editor.clone());
let colors = cx.theme().colors();
let message_content = v_flex()
.child(div().p_2p5().text_ui(cx).child(markdown.clone()))
.child(
if let Some(edit_message_editor) = edit_message_editor.clone() {
div()
.key_context("EditMessageEditor")
.on_action(cx.listener(Self::cancel_editing_message))
.on_action(cx.listener(Self::confirm_editing_message))
.p_2p5()
.child(edit_message_editor)
} else {
div().text_ui(cx).child(markdown.clone())
},
)
.when_some(context, |parent, context| {
if !context.is_empty() {
parent.child(
@@ -321,19 +603,21 @@ impl ActiveThread {
let styled_message = match message.role {
Role::User => v_flex()
.id(("message-container", ix))
.pt_2p5()
.px_2p5()
.pt_2()
.pl_2()
.pr_2p5()
.child(
v_flex()
.bg(colors.editor_background)
.rounded_lg()
.border_1()
.border_color(colors.border)
.shadow_sm()
.shadow_md()
.child(
h_flex()
.py_1()
.px_2()
.pl_2()
.pr_1()
.bg(colors.editor_foreground.opacity(0.05))
.border_b_1()
.border_color(colors.border)
@@ -352,31 +636,101 @@ impl ActiveThread {
.size(LabelSize::Small)
.color(Color::Muted),
),
)
.when_some(
edit_message_editor.clone(),
|this, edit_message_editor| {
let focus_handle = edit_message_editor.focus_handle(cx);
this.child(
h_flex()
.gap_1()
.child(
Button::new("cancel-edit-message", "Cancel")
.label_size(LabelSize::Small)
.key_binding(
KeyBinding::for_action_in(
&menu::Cancel,
&focus_handle,
window,
cx,
)
.map(|kb| kb.size(rems_from_px(12.))),
)
.on_click(
cx.listener(Self::handle_cancel_click),
),
)
.child(
Button::new(
"confirm-edit-message",
"Regenerate",
)
.label_size(LabelSize::Small)
.key_binding(
KeyBinding::for_action_in(
&menu::Confirm,
&focus_handle,
window,
cx,
)
.map(|kb| kb.size(rems_from_px(12.))),
)
.on_click(
cx.listener(Self::handle_regenerate_click),
),
),
)
},
)
.when(
edit_message_editor.is_none() && allow_editing_message,
|this| {
this.child(
Button::new("edit-message", "Edit")
.label_size(LabelSize::Small)
.on_click(cx.listener({
let message_text = message.text.clone();
move |this, _, window, cx| {
this.start_editing_message(
message_id,
message_text.clone(),
window,
cx,
);
}
})),
)
},
),
)
.child(message_content),
.child(div().p_2().child(message_content)),
),
Role::Assistant => div()
.id(("message-container", ix))
.child(message_content)
.map(|parent| {
if tool_uses.is_empty() {
return parent;
}
parent.child(
v_flex().children(
tool_uses
.into_iter()
.map(|tool_use| self.render_tool_use(tool_use, cx)),
),
Role::Assistant => {
v_flex()
.id(("message-container", ix))
.child(div().py_3().px_4().child(message_content))
.when(
!tool_uses.is_empty() || !scripting_tool_uses.is_empty(),
|parent| {
parent.child(
v_flex()
.children(
tool_uses
.into_iter()
.map(|tool_use| self.render_tool_use(tool_use, cx)),
)
.children(scripting_tool_uses.into_iter().map(|tool_use| {
self.render_scripting_tool_use(tool_use, cx)
})),
)
},
)
}),
}
Role::System => div().id(("message-container", ix)).py_1().px_2().child(
v_flex()
.bg(colors.editor_background)
.rounded_md()
.child(message_content),
.rounded_sm()
.child(div().p_4().child(message_content)),
),
};
@@ -390,6 +744,184 @@ impl ActiveThread {
.copied()
.unwrap_or_default();
let lighter_border = cx.theme().colors().border.opacity(0.5);
div().px_4().child(
v_flex()
.rounded_lg()
.border_1()
.border_color(lighter_border)
.child(
h_flex()
.justify_between()
.py_1()
.pl_1()
.pr_2()
.bg(cx.theme().colors().editor_foreground.opacity(0.025))
.map(|element| {
if is_open {
element.border_b_1().rounded_t_md()
} else {
element.rounded_md()
}
})
.border_color(lighter_border)
.child(
h_flex()
.gap_1()
.child(Disclosure::new("tool-use-disclosure", is_open).on_click(
cx.listener({
let tool_use_id = tool_use.id.clone();
move |this, _event, _window, _cx| {
let is_open = this
.expanded_tool_uses
.entry(tool_use_id.clone())
.or_insert(false);
*is_open = !*is_open;
}
}),
))
.child(
Label::new(tool_use.name)
.size(LabelSize::Small)
.buffer_font(cx),
),
)
.child({
let (icon_name, color, animated) = match &tool_use.status {
ToolUseStatus::Pending => {
(IconName::Warning, Color::Warning, false)
}
ToolUseStatus::Running => {
(IconName::ArrowCircle, Color::Accent, true)
}
ToolUseStatus::Finished(_) => {
(IconName::Check, Color::Success, false)
}
ToolUseStatus::Error(_) => (IconName::Close, Color::Error, false),
};
let icon = Icon::new(icon_name).color(color).size(IconSize::Small);
if animated {
icon.with_animation(
"arrow-circle",
Animation::new(Duration::from_secs(2)).repeat(),
|icon, delta| {
icon.transform(Transformation::rotate(percentage(delta)))
},
)
.into_any_element()
} else {
icon.into_any_element()
}
}),
)
.map(|parent| {
if !is_open {
return parent;
}
let content_container = || v_flex().py_1().gap_0p5().px_2p5();
parent.child(
v_flex()
.gap_1()
.bg(cx.theme().colors().editor_background)
.rounded_b_lg()
.child(
content_container()
.border_b_1()
.border_color(lighter_border)
.child(
Label::new("Input")
.size(LabelSize::XSmall)
.color(Color::Muted)
.buffer_font(cx),
)
.child(
Label::new(
serde_json::to_string_pretty(&tool_use.input)
.unwrap_or_default(),
)
.size(LabelSize::Small)
.buffer_font(cx),
),
)
.map(|container| match tool_use.status {
ToolUseStatus::Finished(output) => container.child(
content_container()
.child(
Label::new("Result")
.size(LabelSize::XSmall)
.color(Color::Muted)
.buffer_font(cx),
)
.child(
Label::new(output)
.size(LabelSize::Small)
.buffer_font(cx),
),
),
ToolUseStatus::Running => container.child(
content_container().child(
h_flex()
.gap_1()
.pb_1()
.child(
Icon::new(IconName::ArrowCircle)
.size(IconSize::Small)
.color(Color::Accent)
.with_animation(
"arrow-circle",
Animation::new(Duration::from_secs(2))
.repeat(),
|icon, delta| {
icon.transform(Transformation::rotate(
percentage(delta),
))
},
),
)
.child(
Label::new("Running…")
.size(LabelSize::XSmall)
.color(Color::Muted)
.buffer_font(cx),
),
),
),
ToolUseStatus::Error(err) => container.child(
content_container()
.child(
Label::new("Error")
.size(LabelSize::XSmall)
.color(Color::Muted)
.buffer_font(cx),
)
.child(
Label::new(err).size(LabelSize::Small).buffer_font(cx),
),
),
ToolUseStatus::Pending => container,
}),
)
}),
)
}
fn render_scripting_tool_use(
&self,
tool_use: ToolUse,
cx: &mut Context<Self>,
) -> impl IntoElement {
let is_open = self
.expanded_tool_uses
.get(&tool_use.id)
.copied()
.unwrap_or_default();
div().px_2p5().child(
v_flex()
.gap_1()
@@ -403,8 +935,13 @@ impl ActiveThread {
.pl_1()
.pr_2()
.bg(cx.theme().colors().editor_foreground.opacity(0.02))
.when(is_open, |element| element.border_b_1().rounded_t(px(6.)))
.when(!is_open, |element| element.rounded(px(6.)))
.map(|element| {
if is_open {
element.border_b_1().rounded_t_md()
} else {
element.rounded_md()
}
})
.border_color(cx.theme().colors().border)
.child(
h_flex()
@@ -440,6 +977,9 @@ impl ActiveThread {
return parent;
}
let lua_script_markdown =
self.rendered_scripting_tool_uses.get(&tool_use.id).cloned();
parent.child(
v_flex()
.child(
@@ -450,10 +990,15 @@ impl ActiveThread {
.border_b_1()
.border_color(cx.theme().colors().border)
.child(Label::new("Input:"))
.child(Label::new(
serde_json::to_string_pretty(&tool_use.input)
.unwrap_or_default(),
)),
.map(|parent| {
if let Some(markdown) = lua_script_markdown {
parent.child(markdown)
} else {
parent.child(Label::new(
"Failed to render script input to Markdown",
))
}
}),
)
.map(|parent| match tool_use.status {
ToolUseStatus::Finished(output) => parent.child(

View File

@@ -16,6 +16,7 @@ mod terminal_inline_assistant;
mod thread;
mod thread_history;
mod thread_store;
mod tool_selector;
mod tool_use;
mod ui;
@@ -27,11 +28,14 @@ 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::active_thread::ActiveThread;
pub use crate::assistant_panel::{AssistantPanel, ConcreteAssistantPanelDelegate};
pub use crate::inline_assistant::InlineAssistant;
pub use crate::thread::{Message, RequestKind, Thread, ThreadEvent};
pub use crate::thread_store::ThreadStore;
actions!(
assistant2,
@@ -52,7 +56,8 @@ actions!(
FocusLeft,
FocusRight,
RemoveFocusedContext,
AcceptSuggestedContext
AcceptSuggestedContext,
OpenActiveThreadAsMarkdown
]
);

View File

@@ -1,19 +1,29 @@
use std::sync::Arc;
use assistant_tool::{ToolSource, ToolWorkingSet};
use collections::HashMap;
use gpui::{Action, AnyView, App, EventEmitter, FocusHandle, Focusable, Subscription};
use context_server::manager::ContextServerManager;
use gpui::{Action, AnyView, App, Entity, EventEmitter, FocusHandle, Focusable, Subscription};
use language_model::{LanguageModelProvider, LanguageModelProviderId, LanguageModelRegistry};
use ui::{prelude::*, Divider, DividerColor, ElevationIndex};
use ui::{prelude::*, Disclosure, Divider, DividerColor, ElevationIndex, Indicator};
use zed_actions::assistant::DeployPromptLibrary;
pub struct AssistantConfiguration {
focus_handle: FocusHandle,
configuration_views_by_provider: HashMap<LanguageModelProviderId, AnyView>,
context_server_manager: Entity<ContextServerManager>,
expanded_context_server_tools: HashMap<Arc<str>, bool>,
tools: Arc<ToolWorkingSet>,
_registry_subscription: Subscription,
}
impl AssistantConfiguration {
pub fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
pub fn new(
context_server_manager: Entity<ContextServerManager>,
tools: Arc<ToolWorkingSet>,
window: &mut Window,
cx: &mut Context<Self>,
) -> Self {
let focus_handle = cx.focus_handle();
let registry_subscription = cx.subscribe_in(
@@ -36,6 +46,9 @@ impl AssistantConfiguration {
let mut this = Self {
focus_handle,
configuration_views_by_provider: HashMap::default(),
context_server_manager,
expanded_context_server_tools: HashMap::default(),
tools,
_registry_subscription: registry_subscription,
};
this.build_provider_configuration_views(window, cx);
@@ -134,7 +147,7 @@ impl AssistantConfiguration {
.bg(cx.theme().colors().editor_background)
.border_1()
.border_color(cx.theme().colors().border_variant)
.rounded_md()
.rounded_sm()
.map(|parent| match configuration_view {
Some(configuration_view) => parent.child(configuration_view),
None => parent.child(div().child(Label::new(format!(
@@ -143,6 +156,98 @@ impl AssistantConfiguration {
}),
)
}
fn render_context_servers_section(&mut self, cx: &mut Context<Self>) -> impl IntoElement {
let context_servers = self.context_server_manager.read(cx).servers().clone();
let tools_by_source = self.tools.tools_by_source(cx);
let empty = Vec::new();
const SUBHEADING: &str = "Connect to context servers via the Model Context Protocol either via Zed extensions or directly.";
v_flex()
.p(DynamicSpacing::Base16.rems(cx))
.mt_1()
.gap_6()
.flex_1()
.child(
v_flex()
.gap_0p5()
.child(Headline::new("Context Servers (MCP)").size(HeadlineSize::Small))
.child(Label::new(SUBHEADING).color(Color::Muted)),
)
.children(context_servers.into_iter().map(|context_server| {
let is_running = context_server.client().is_some();
let are_tools_expanded = self
.expanded_context_server_tools
.get(&context_server.id())
.copied()
.unwrap_or_default();
let tools = tools_by_source
.get(&ToolSource::ContextServer {
id: context_server.id().into(),
})
.unwrap_or_else(|| &empty);
let tool_count = tools.len();
v_flex()
.border_1()
.rounded_sm()
.border_color(cx.theme().colors().border)
.bg(cx.theme().colors().editor_background)
.child(
h_flex()
.gap_2()
.px_2()
.py_1()
.when(are_tools_expanded, |element| {
element
.border_b_1()
.border_color(cx.theme().colors().border)
})
.child(
Disclosure::new("tool-list-disclosure", are_tools_expanded)
.on_click(cx.listener({
let context_server_id = context_server.id();
move |this, _event, _window, _cx| {
let is_open = this
.expanded_context_server_tools
.entry(context_server_id.clone())
.or_insert(false);
*is_open = !*is_open;
}
})),
)
.child(Indicator::dot().color(if is_running {
Color::Success
} else {
Color::Error
}))
.child(Label::new(context_server.id()))
.child(Label::new(format!("{tool_count} tools")).color(Color::Muted)),
)
.map(|parent| {
if !are_tools_expanded {
return parent;
}
parent.child(v_flex().children(tools.into_iter().enumerate().map(
|(ix, tool)| {
h_flex()
.px_2()
.py_1()
.when(ix < tool_count - 1, |element| {
element
.border_b_1()
.border_color(cx.theme().colors().border)
})
.child(Label::new(tool.name()))
},
)))
})
}))
}
}
impl Render for AssistantConfiguration {
@@ -182,6 +287,8 @@ impl Render for AssistantConfiguration {
),
)
.child(Divider::horizontal().color(DividerColor::Border))
.child(self.render_context_servers_section(cx))
.child(Divider::horizontal().color(DividerColor::Border))
.child(
v_flex()
.p(DynamicSpacing::Base16.rems(cx))

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

@@ -11,16 +11,18 @@ use assistant_slash_command::SlashCommandWorkingSet;
use assistant_tool::ToolWorkingSet;
use client::zed_urls;
use editor::Editor;
use editor::{Editor, MultiBuffer};
use fs::Fs;
use gpui::{
prelude::*, Action, AnyElement, App, AsyncWindowContext, Corner, Entity, EventEmitter,
FocusHandle, Focusable, FontWeight, Pixels, Subscription, Task, UpdateGlobal, WeakEntity,
FocusHandle, Focusable, FontWeight, KeyContext, Pixels, Subscription, Task, UpdateGlobal,
WeakEntity,
};
use language::LanguageRegistry;
use language_model::{LanguageModelProviderTosView, LanguageModelRegistry};
use project::Project;
use prompt_library::{open_prompt_library, PromptBuilder, PromptLibrary};
use prompt_library::{open_prompt_library, PromptLibrary};
use prompt_store::PromptBuilder;
use settings::{update_settings_file, Settings};
use time::UtcOffset;
use ui::{prelude::*, ContextMenu, KeyBinding, PopoverMenu, PopoverMenuHandle, Tab, Tooltip};
@@ -36,7 +38,10 @@ use crate::message_editor::MessageEditor;
use crate::thread::{Thread, ThreadError, ThreadId};
use crate::thread_history::{PastContext, PastThread, ThreadHistory};
use crate::thread_store::ThreadStore;
use crate::{InlineAssistant, NewPromptEditor, NewThread, OpenConfiguration, OpenHistory};
use crate::{
InlineAssistant, NewPromptEditor, NewThread, OpenActiveThreadAsMarkdown, OpenConfiguration,
OpenHistory,
};
pub fn init(cx: &mut App) {
cx.observe_new(
@@ -90,7 +95,6 @@ pub struct AssistantPanel {
context_editor: Option<Entity<ContextEditor>>,
configuration: Option<Entity<AssistantConfiguration>>,
configuration_subscription: Option<Subscription>,
tools: Arc<ToolWorkingSet>,
local_timezone: UtcOffset,
active_view: ActiveView,
history_store: Entity<HistoryStore>,
@@ -106,19 +110,16 @@ impl AssistantPanel {
prompt_builder: Arc<PromptBuilder>,
cx: AsyncWindowContext,
) -> Task<Result<Entity<Self>>> {
cx.spawn(|mut cx| async move {
cx.spawn(async move |cx| {
let tools = Arc::new(ToolWorkingSet::default());
log::info!("[assistant2-debug] initializing ThreadStore");
let thread_store = workspace.update(&mut cx, |workspace, cx| {
let thread_store = workspace.update(cx, |workspace, cx| {
let project = workspace.project().clone();
ThreadStore::new(project, tools.clone(), cx)
ThreadStore::new(project, tools.clone(), prompt_builder.clone(), cx)
})??;
log::info!("[assistant2-debug] finished initializing ThreadStore");
let slash_commands = Arc::new(SlashCommandWorkingSet::default());
log::info!("[assistant2-debug] initializing ContextStore");
let context_store = workspace
.update(&mut cx, |workspace, cx| {
.update(cx, |workspace, cx| {
let project = workspace.project().clone();
assistant_context_editor::ContextStore::new(
project,
@@ -128,10 +129,9 @@ impl AssistantPanel {
)
})?
.await?;
log::info!("[assistant2-debug] finished initializing ContextStore");
workspace.update_in(&mut cx, |workspace, window, cx| {
cx.new(|cx| Self::new(workspace, thread_store, context_store, tools, window, cx))
workspace.update_in(cx, |workspace, window, cx| {
cx.new(|cx| Self::new(workspace, thread_store, context_store, window, cx))
})
})
}
@@ -140,11 +140,9 @@ impl AssistantPanel {
workspace: &Workspace,
thread_store: Entity<ThreadStore>,
context_store: Entity<assistant_context_editor::ContextStore>,
tools: Arc<ToolWorkingSet>,
window: &mut Window,
cx: &mut Context<Self>,
) -> Self {
log::info!("[assistant2-debug] AssistantPanel::new");
let thread = thread_store.update(cx, |this, cx| this.create_thread(cx));
let fs = workspace.app_state().fs.clone();
let project = workspace.project().clone();
@@ -152,10 +150,14 @@ impl AssistantPanel {
let workspace = workspace.weak_handle();
let weak_self = cx.entity().downgrade();
let message_editor_context_store =
cx.new(|_cx| crate::context_store::ContextStore::new(workspace.clone()));
let message_editor = cx.new(|cx| {
MessageEditor::new(
fs.clone(),
workspace.clone(),
message_editor_context_store.clone(),
thread_store.downgrade(),
thread.clone(),
window,
@@ -166,30 +168,30 @@ impl AssistantPanel {
let history_store =
cx.new(|cx| HistoryStore::new(thread_store.clone(), context_store.clone(), cx));
let thread = cx.new(|cx| {
ActiveThread::new(
thread.clone(),
thread_store.clone(),
language_registry.clone(),
message_editor_context_store.clone(),
window,
cx,
)
});
Self {
active_view: ActiveView::Thread,
workspace: workspace.clone(),
project,
workspace,
project: project.clone(),
fs: fs.clone(),
language_registry: language_registry.clone(),
language_registry,
thread_store: thread_store.clone(),
thread: cx.new(|cx| {
ActiveThread::new(
thread.clone(),
thread_store.clone(),
workspace,
language_registry,
tools.clone(),
window,
cx,
)
}),
thread,
message_editor,
context_store,
context_editor: None,
configuration: None,
configuration_subscription: None,
tools,
local_timezone: UtcOffset::from_whole_seconds(
chrono::Local::now().offset().local_minus_utc(),
)
@@ -240,13 +242,16 @@ impl AssistantPanel {
.update(cx, |this, cx| this.create_thread(cx));
self.active_view = ActiveView::Thread;
let message_editor_context_store =
cx.new(|_cx| crate::context_store::ContextStore::new(self.workspace.clone()));
self.thread = cx.new(|cx| {
ActiveThread::new(
thread.clone(),
self.thread_store.clone(),
self.workspace.clone(),
self.language_registry.clone(),
self.tools.clone(),
message_editor_context_store.clone(),
window,
cx,
)
@@ -255,6 +260,7 @@ impl AssistantPanel {
MessageEditor::new(
self.fs.clone(),
self.workspace.clone(),
message_editor_context_store,
self.thread_store.downgrade(),
thread,
window,
@@ -338,9 +344,9 @@ impl AssistantPanel {
let lsp_adapter_delegate = make_lsp_adapter_delegate(&project, cx).log_err().flatten();
cx.spawn_in(window, |this, mut cx| async move {
cx.spawn_in(window, async move |this, cx| {
let context = context.await?;
this.update_in(&mut cx, |this, window, cx| {
this.update_in(cx, |this, window, cx| {
let editor = cx.new(|cx| {
ContextEditor::for_context(
context,
@@ -371,17 +377,18 @@ impl AssistantPanel {
.thread_store
.update(cx, |this, cx| this.open_thread(thread_id, cx));
cx.spawn_in(window, |this, mut cx| async move {
cx.spawn_in(window, async move |this, cx| {
let thread = open_thread_task.await?;
this.update_in(&mut cx, |this, window, cx| {
this.update_in(cx, |this, window, cx| {
this.active_view = ActiveView::Thread;
let message_editor_context_store =
cx.new(|_cx| crate::context_store::ContextStore::new(this.workspace.clone()));
this.thread = cx.new(|cx| {
ActiveThread::new(
thread.clone(),
this.thread_store.clone(),
this.workspace.clone(),
this.language_registry.clone(),
this.tools.clone(),
message_editor_context_store.clone(),
window,
cx,
)
@@ -390,6 +397,7 @@ impl AssistantPanel {
MessageEditor::new(
this.fs.clone(),
this.workspace.clone(),
message_editor_context_store,
this.thread_store.downgrade(),
thread,
window,
@@ -402,8 +410,13 @@ impl AssistantPanel {
}
pub(crate) fn open_configuration(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let context_server_manager = self.thread_store.read(cx).context_server_manager();
let tools = self.thread_store.read(cx).tools();
self.active_view = ActiveView::Configuration;
self.configuration = Some(cx.new(|cx| AssistantConfiguration::new(window, cx)));
self.configuration = Some(
cx.new(|cx| AssistantConfiguration::new(context_server_manager, tools, window, cx)),
);
if let Some(configuration) = self.configuration.as_ref() {
self.configuration_subscription = Some(cx.subscribe_in(
@@ -416,6 +429,65 @@ impl AssistantPanel {
}
}
pub(crate) fn open_active_thread_as_markdown(
&mut self,
_: &OpenActiveThreadAsMarkdown,
window: &mut Window,
cx: &mut Context<Self>,
) {
let Some(workspace) = self
.workspace
.upgrade()
.ok_or_else(|| anyhow!("workspace dropped"))
.log_err()
else {
return;
};
let markdown_language_task = workspace
.read(cx)
.app_state()
.languages
.language_for_name("Markdown");
let thread = self.active_thread(cx);
cx.spawn_in(window, async move |_this, cx| {
let markdown_language = markdown_language_task.await?;
workspace.update_in(cx, |workspace, window, cx| {
let thread = thread.read(cx);
let markdown = thread.to_markdown()?;
let thread_summary = thread
.summary()
.map(|summary| summary.to_string())
.unwrap_or_else(|| "Thread".to_string());
let project = workspace.project().clone();
let buffer = project.update(cx, |project, cx| {
project.create_local_buffer(&markdown, Some(markdown_language), cx)
});
let buffer = cx.new(|cx| {
MultiBuffer::singleton(buffer, cx).with_title(thread_summary.clone())
});
workspace.add_item_to_active_pane(
Box::new(cx.new(|cx| {
let mut editor =
Editor::for_multibuffer(buffer, Some(project.clone()), window, cx);
editor.set_breadcrumb_header(thread_summary);
editor
})),
None,
true,
window,
cx,
);
anyhow::Ok(())
})
})
.detach_and_log_err(cx);
}
fn handle_assistant_configuration_event(
&mut self,
_entity: &Entity<AssistantConfiguration>,
@@ -608,7 +680,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()
@@ -992,12 +1064,21 @@ impl AssistantPanel {
)
.into_any()
}
fn key_context(&self) -> KeyContext {
let mut key_context = KeyContext::new_with_defaults();
key_context.add("AssistantPanel2");
if matches!(self.active_view, ActiveView::PromptEditor) {
key_context.add("prompt_editor");
}
key_context
}
}
impl Render for AssistantPanel {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
v_flex()
.key_context("AssistantPanel2")
.key_context(self.key_context())
.justify_between()
.size_full()
.on_action(cx.listener(Self::cancel))
@@ -1007,17 +1088,13 @@ impl Render for AssistantPanel {
.on_action(cx.listener(|this, _: &OpenHistory, window, cx| {
this.open_history(window, cx);
}))
.on_action(cx.listener(Self::open_active_thread_as_markdown))
.on_action(cx.listener(Self::deploy_prompt_library))
.child(self.render_toolbar(cx))
.map(|parent| match self.active_view {
ActiveView::Thread => parent
.child(self.render_active_thread_or_empty_state(window, cx))
.child(
h_flex()
.border_t_1()
.border_color(cx.theme().colors().border)
.child(self.message_editor.clone()),
)
.child(h_flex().child(self.message_editor.clone()))
.children(self.render_last_error(cx)),
ActiveView::History => parent.child(self.history.clone()),
ActiveView::PromptEditor => parent.children(self.context_editor.clone()),

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::{
@@ -367,7 +367,7 @@ impl CodegenAlternative {
let request = self.build_request(user_prompt, cx)?;
self.request = Some(request.clone());
cx.spawn(|_, cx| async move { model.stream_completion_text(request, &cx).await })
cx.spawn(async move |_, cx| model.stream_completion_text(request, &cx).await)
.boxed_local()
};
self.handle_stream(telemetry_id, provider_id.to_string(), api_key, stream, cx);
@@ -480,213 +480,207 @@ impl CodegenAlternative {
let completion = Arc::new(Mutex::new(String::new()));
let completion_clone = completion.clone();
self.generation = cx.spawn(|codegen, mut cx| {
async move {
let stream = stream.await;
let message_id = stream
.as_ref()
.ok()
.and_then(|stream| stream.message_id.clone());
let generate = async {
let (mut diff_tx, mut diff_rx) = mpsc::channel(1);
let executor = cx.background_executor().clone();
let message_id = message_id.clone();
let line_based_stream_diff: Task<anyhow::Result<()>> =
cx.background_spawn(async move {
let mut response_latency = None;
let request_start = Instant::now();
let diff = async {
let chunks = StripInvalidSpans::new(stream?.stream);
futures::pin_mut!(chunks);
let mut diff = StreamingDiff::new(selected_text.to_string());
let mut line_diff = LineDiff::default();
self.generation = cx.spawn(async move |codegen, cx| {
let stream = stream.await;
let message_id = stream
.as_ref()
.ok()
.and_then(|stream| stream.message_id.clone());
let generate = async {
let (mut diff_tx, mut diff_rx) = mpsc::channel(1);
let executor = cx.background_executor().clone();
let message_id = message_id.clone();
let line_based_stream_diff: Task<anyhow::Result<()>> =
cx.background_spawn(async move {
let mut response_latency = None;
let request_start = Instant::now();
let diff = async {
let chunks = StripInvalidSpans::new(stream?.stream);
futures::pin_mut!(chunks);
let mut diff = StreamingDiff::new(selected_text.to_string());
let mut line_diff = LineDiff::default();
let mut new_text = String::new();
let mut base_indent = None;
let mut line_indent = None;
let mut first_line = true;
let mut new_text = String::new();
let mut base_indent = None;
let mut line_indent = None;
let mut first_line = true;
while let Some(chunk) = chunks.next().await {
if response_latency.is_none() {
response_latency = Some(request_start.elapsed());
}
let chunk = chunk?;
completion_clone.lock().push_str(&chunk);
while let Some(chunk) = chunks.next().await {
if response_latency.is_none() {
response_latency = Some(request_start.elapsed());
}
let chunk = chunk?;
completion_clone.lock().push_str(&chunk);
let mut lines = chunk.split('\n').peekable();
while let Some(line) = lines.next() {
new_text.push_str(line);
if line_indent.is_none() {
if let Some(non_whitespace_ch_ix) =
new_text.find(|ch: char| !ch.is_whitespace())
{
line_indent = Some(non_whitespace_ch_ix);
base_indent = base_indent.or(line_indent);
let mut lines = chunk.split('\n').peekable();
while let Some(line) = lines.next() {
new_text.push_str(line);
if line_indent.is_none() {
if let Some(non_whitespace_ch_ix) =
new_text.find(|ch: char| !ch.is_whitespace())
{
line_indent = Some(non_whitespace_ch_ix);
base_indent = base_indent.or(line_indent);
let line_indent = line_indent.unwrap();
let base_indent = base_indent.unwrap();
let indent_delta =
line_indent as i32 - base_indent as i32;
let mut corrected_indent_len = cmp::max(
0,
suggested_line_indent.len as i32 + indent_delta,
)
as usize;
if first_line {
corrected_indent_len = corrected_indent_len
.saturating_sub(
selection_start.column as usize,
);
}
let indent_char = suggested_line_indent.char();
let mut indent_buffer = [0; 4];
let indent_str =
indent_char.encode_utf8(&mut indent_buffer);
new_text.replace_range(
..line_indent,
&indent_str.repeat(corrected_indent_len),
);
let line_indent = line_indent.unwrap();
let base_indent = base_indent.unwrap();
let indent_delta =
line_indent as i32 - base_indent as i32;
let mut corrected_indent_len = cmp::max(
0,
suggested_line_indent.len as i32 + indent_delta,
)
as usize;
if first_line {
corrected_indent_len = corrected_indent_len
.saturating_sub(
selection_start.column as usize,
);
}
}
if line_indent.is_some() {
let char_ops = diff.push_new(&new_text);
line_diff
.push_char_operations(&char_ops, &selected_text);
diff_tx
.send((char_ops, line_diff.line_operations()))
.await?;
let indent_char = suggested_line_indent.char();
let mut indent_buffer = [0; 4];
let indent_str =
indent_char.encode_utf8(&mut indent_buffer);
new_text.replace_range(
..line_indent,
&indent_str.repeat(corrected_indent_len),
);
}
}
if line_indent.is_some() {
let char_ops = diff.push_new(&new_text);
line_diff.push_char_operations(&char_ops, &selected_text);
diff_tx
.send((char_ops, line_diff.line_operations()))
.await?;
new_text.clear();
}
if lines.peek().is_some() {
let char_ops = diff.push_new("\n");
line_diff.push_char_operations(&char_ops, &selected_text);
diff_tx
.send((char_ops, line_diff.line_operations()))
.await?;
if line_indent.is_none() {
// Don't write out the leading indentation in empty lines on the next line
// This is the case where the above if statement didn't clear the buffer
new_text.clear();
}
if lines.peek().is_some() {
let char_ops = diff.push_new("\n");
line_diff
.push_char_operations(&char_ops, &selected_text);
diff_tx
.send((char_ops, line_diff.line_operations()))
.await?;
if line_indent.is_none() {
// Don't write out the leading indentation in empty lines on the next line
// This is the case where the above if statement didn't clear the buffer
new_text.clear();
}
line_indent = None;
first_line = false;
}
line_indent = None;
first_line = false;
}
}
let mut char_ops = diff.push_new(&new_text);
char_ops.extend(diff.finish());
line_diff.push_char_operations(&char_ops, &selected_text);
line_diff.finish(&selected_text);
diff_tx
.send((char_ops, line_diff.line_operations()))
.await?;
anyhow::Ok(())
};
let result = diff.await;
let error_message =
result.as_ref().err().map(|error| error.to_string());
report_assistant_event(
AssistantEvent {
conversation_id: None,
message_id,
kind: AssistantKind::Inline,
phase: AssistantPhase::Response,
model: model_telemetry_id,
model_provider: model_provider_id.to_string(),
response_latency,
error_message,
language_name: language_name.map(|name| name.to_proto()),
},
telemetry,
http_client,
model_api_key,
&executor,
);
result?;
Ok(())
});
while let Some((char_ops, line_ops)) = diff_rx.next().await {
codegen.update(&mut cx, |codegen, cx| {
codegen.last_equal_ranges.clear();
let edits = char_ops
.into_iter()
.filter_map(|operation| match operation {
CharOperation::Insert { text } => {
let edit_start = snapshot.anchor_after(edit_start);
Some((edit_start..edit_start, text))
}
CharOperation::Delete { bytes } => {
let edit_end = edit_start + bytes;
let edit_range = snapshot.anchor_after(edit_start)
..snapshot.anchor_before(edit_end);
edit_start = edit_end;
Some((edit_range, String::new()))
}
CharOperation::Keep { bytes } => {
let edit_end = edit_start + bytes;
let edit_range = snapshot.anchor_after(edit_start)
..snapshot.anchor_before(edit_end);
edit_start = edit_end;
codegen.last_equal_ranges.push(edit_range);
None
}
})
.collect::<Vec<_>>();
if codegen.active {
codegen.apply_edits(edits.iter().cloned(), cx);
codegen.reapply_line_based_diff(line_ops.iter().cloned(), cx);
}
codegen.edits.extend(edits);
codegen.line_operations = line_ops;
codegen.edit_position = Some(snapshot.anchor_after(edit_start));
cx.notify();
})?;
}
let mut char_ops = diff.push_new(&new_text);
char_ops.extend(diff.finish());
line_diff.push_char_operations(&char_ops, &selected_text);
line_diff.finish(&selected_text);
diff_tx
.send((char_ops, line_diff.line_operations()))
.await?;
// Streaming stopped and we have the new text in the buffer, and a line-based diff applied for the whole new buffer.
// That diff is not what a regular diff is and might look unexpected, ergo apply a regular diff.
// It's fine to apply even if the rest of the line diffing fails, as no more hunks are coming through `diff_rx`.
let batch_diff_task =
codegen.update(&mut cx, |codegen, cx| codegen.reapply_batch_diff(cx))?;
let (line_based_stream_diff, ()) =
join!(line_based_stream_diff, batch_diff_task);
line_based_stream_diff?;
anyhow::Ok(())
};
anyhow::Ok(())
};
let result = diff.await;
let result = generate.await;
let elapsed_time = start_time.elapsed().as_secs_f64();
let error_message = result.as_ref().err().map(|error| error.to_string());
report_assistant_event(
AssistantEvent {
conversation_id: None,
message_id,
kind: AssistantKind::Inline,
phase: AssistantPhase::Response,
model: model_telemetry_id,
model_provider: model_provider_id.to_string(),
response_latency,
error_message,
language_name: language_name.map(|name| name.to_proto()),
},
telemetry,
http_client,
model_api_key,
&executor,
);
codegen
.update(&mut cx, |this, cx| {
this.message_id = message_id;
this.last_equal_ranges.clear();
if let Err(error) = result {
this.status = CodegenStatus::Error(error);
} else {
this.status = CodegenStatus::Done;
result?;
Ok(())
});
while let Some((char_ops, line_ops)) = diff_rx.next().await {
codegen.update(cx, |codegen, cx| {
codegen.last_equal_ranges.clear();
let edits = char_ops
.into_iter()
.filter_map(|operation| match operation {
CharOperation::Insert { text } => {
let edit_start = snapshot.anchor_after(edit_start);
Some((edit_start..edit_start, text))
}
CharOperation::Delete { bytes } => {
let edit_end = edit_start + bytes;
let edit_range = snapshot.anchor_after(edit_start)
..snapshot.anchor_before(edit_end);
edit_start = edit_end;
Some((edit_range, String::new()))
}
CharOperation::Keep { bytes } => {
let edit_end = edit_start + bytes;
let edit_range = snapshot.anchor_after(edit_start)
..snapshot.anchor_before(edit_end);
edit_start = edit_end;
codegen.last_equal_ranges.push(edit_range);
None
}
})
.collect::<Vec<_>>();
if codegen.active {
codegen.apply_edits(edits.iter().cloned(), cx);
codegen.reapply_line_based_diff(line_ops.iter().cloned(), cx);
}
this.elapsed_time = Some(elapsed_time);
this.completion = Some(completion.lock().clone());
cx.emit(CodegenEvent::Finished);
codegen.edits.extend(edits);
codegen.line_operations = line_ops;
codegen.edit_position = Some(snapshot.anchor_after(edit_start));
cx.notify();
})
.ok();
}
})?;
}
// Streaming stopped and we have the new text in the buffer, and a line-based diff applied for the whole new buffer.
// That diff is not what a regular diff is and might look unexpected, ergo apply a regular diff.
// It's fine to apply even if the rest of the line diffing fails, as no more hunks are coming through `diff_rx`.
let batch_diff_task =
codegen.update(cx, |codegen, cx| codegen.reapply_batch_diff(cx))?;
let (line_based_stream_diff, ()) = join!(line_based_stream_diff, batch_diff_task);
line_based_stream_diff?;
anyhow::Ok(())
};
let result = generate.await;
let elapsed_time = start_time.elapsed().as_secs_f64();
codegen
.update(cx, |this, cx| {
this.message_id = message_id;
this.last_equal_ranges.clear();
if let Err(error) = result {
this.status = CodegenStatus::Error(error);
} else {
this.status = CodegenStatus::Done;
}
this.elapsed_time = Some(elapsed_time);
this.completion = Some(completion.lock().clone());
cx.emit(CodegenEvent::Finished);
cx.notify();
})
.ok();
});
cx.notify();
}
@@ -804,7 +798,7 @@ impl CodegenAlternative {
let new_snapshot = self.buffer.read(cx).snapshot(cx);
let new_range = self.range.to_point(&new_snapshot);
cx.spawn(|codegen, mut cx| async move {
cx.spawn(async move |codegen, cx| {
let (deleted_row_ranges, inserted_row_ranges) = cx
.background_spawn(async move {
let old_text = old_snapshot
@@ -854,7 +848,7 @@ impl CodegenAlternative {
.await;
codegen
.update(&mut cx, |codegen, cx| {
.update(cx, |codegen, cx| {
codegen.diff.deleted_row_ranges = deleted_row_ranges;
codegen.diff.inserted_row_ranges = inserted_row_ranges;
cx.notify();

View File

@@ -43,15 +43,6 @@ pub enum ContextKind {
}
impl ContextKind {
pub fn label(&self) -> &'static str {
match self {
ContextKind::File => "File",
ContextKind::Directory => "Folder",
ContextKind::FetchedUrl => "Fetch",
ContextKind::Thread => "Thread",
}
}
pub fn icon(&self) -> IconName {
match self {
ContextKind::File => IconName::File,

View File

@@ -1,4 +1,3 @@
mod directory_context_picker;
mod fetch_context_picker;
mod file_context_picker;
mod thread_context_picker;
@@ -15,8 +14,6 @@ use thread_context_picker::{render_thread_context_entry, ThreadContextEntry};
use ui::{prelude::*, ContextMenu, ContextMenuEntry, ContextMenuItem};
use workspace::{notifications::NotifyResultExt, Workspace};
use crate::context::ContextKind;
use crate::context_picker::directory_context_picker::DirectoryContextPicker;
use crate::context_picker::fetch_context_picker::FetchContextPicker;
use crate::context_picker::file_context_picker::FileContextPicker;
use crate::context_picker::thread_context_picker::ThreadContextPicker;
@@ -30,17 +27,41 @@ pub enum ConfirmBehavior {
Close,
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ContextPickerMode {
File,
Fetch,
Thread,
}
impl ContextPickerMode {
pub fn label(&self) -> &'static str {
match self {
Self::File => "File/Directory",
Self::Fetch => "Fetch",
Self::Thread => "Thread",
}
}
pub fn icon(&self) -> IconName {
match self {
Self::File => IconName::File,
Self::Fetch => IconName::Globe,
Self::Thread => IconName::MessageCircle,
}
}
}
#[derive(Debug, Clone)]
enum ContextPickerState {
Default(Entity<ContextMenu>),
File(Entity<FileContextPicker>),
Directory(Entity<DirectoryContextPicker>),
Fetch(Entity<FetchContextPicker>),
Thread(Entity<ThreadContextPicker>),
}
pub(super) struct ContextPicker {
mode: ContextPickerMode,
mode: ContextPickerState,
workspace: WeakEntity<Workspace>,
editor: WeakEntity<Editor>,
context_store: WeakEntity<ContextStore>,
@@ -59,7 +80,7 @@ impl ContextPicker {
cx: &mut Context<Self>,
) -> Self {
ContextPicker {
mode: ContextPickerMode::Default(ContextMenu::build(
mode: ContextPickerState::Default(ContextMenu::build(
window,
cx,
|menu, _window, _cx| menu,
@@ -73,7 +94,7 @@ impl ContextPicker {
}
pub fn init(&mut self, window: &mut Window, cx: &mut Context<Self>) {
self.mode = ContextPickerMode::Default(self.build_menu(window, cx));
self.mode = ContextPickerState::Default(self.build_menu(window, cx));
cx.notify();
}
@@ -88,13 +109,9 @@ impl ContextPicker {
.enumerate()
.map(|(ix, entry)| self.recent_menu_item(context_picker.clone(), ix, entry));
let mut context_kinds = vec![
ContextKind::File,
ContextKind::Directory,
ContextKind::FetchedUrl,
];
let mut modes = vec![ContextPickerMode::File, ContextPickerMode::Fetch];
if self.allow_threads() {
context_kinds.push(ContextKind::Thread);
modes.push(ContextPickerMode::Thread);
}
let menu = menu
@@ -112,15 +129,15 @@ impl ContextPicker {
})
.extend(recent_entries)
.when(has_recent, |menu| menu.separator())
.extend(context_kinds.into_iter().map(|kind| {
.extend(modes.into_iter().map(|mode| {
let context_picker = context_picker.clone();
ContextMenuEntry::new(kind.label())
.icon(kind.icon())
ContextMenuEntry::new(mode.label())
.icon(mode.icon())
.icon_size(IconSize::XSmall)
.icon_color(Color::Muted)
.handler(move |window, cx| {
context_picker.update(cx, |this, cx| this.select_kind(kind, window, cx))
context_picker.update(cx, |this, cx| this.select_mode(mode, window, cx))
})
}));
@@ -143,12 +160,17 @@ impl ContextPicker {
self.thread_store.is_some()
}
fn select_kind(&mut self, kind: ContextKind, window: &mut Window, cx: &mut Context<Self>) {
fn select_mode(
&mut self,
mode: ContextPickerMode,
window: &mut Window,
cx: &mut Context<Self>,
) {
let context_picker = cx.entity().downgrade();
match kind {
ContextKind::File => {
self.mode = ContextPickerMode::File(cx.new(|cx| {
match mode {
ContextPickerMode::File => {
self.mode = ContextPickerState::File(cx.new(|cx| {
FileContextPicker::new(
context_picker.clone(),
self.workspace.clone(),
@@ -160,20 +182,8 @@ impl ContextPicker {
)
}));
}
ContextKind::Directory => {
self.mode = ContextPickerMode::Directory(cx.new(|cx| {
DirectoryContextPicker::new(
context_picker.clone(),
self.workspace.clone(),
self.context_store.clone(),
self.confirm_behavior,
window,
cx,
)
}));
}
ContextKind::FetchedUrl => {
self.mode = ContextPickerMode::Fetch(cx.new(|cx| {
ContextPickerMode::Fetch => {
self.mode = ContextPickerState::Fetch(cx.new(|cx| {
FetchContextPicker::new(
context_picker.clone(),
self.workspace.clone(),
@@ -184,9 +194,9 @@ impl ContextPicker {
)
}));
}
ContextKind::Thread => {
ContextPickerMode::Thread => {
if let Some(thread_store) = self.thread_store.as_ref() {
self.mode = ContextPickerMode::Thread(cx.new(|cx| {
self.mode = ContextPickerState::Thread(cx.new(|cx| {
ThreadContextPicker::new(
thread_store.clone(),
context_picker.clone(),
@@ -224,6 +234,7 @@ impl ContextPicker {
ElementId::NamedInteger("ctx-recent".into(), ix),
&path,
&path_prefix,
false,
context_store.clone(),
cx,
)
@@ -270,10 +281,8 @@ impl ContextPicker {
context_store.add_file_from_path(project_path.clone(), cx)
});
cx.spawn_in(window, |_, mut cx| async move {
task.await.notify_async_err(&mut cx)
})
.detach();
cx.spawn_in(window, async move |_, cx| task.await.notify_async_err(cx))
.detach();
cx.notify();
}
@@ -296,13 +305,13 @@ impl ContextPicker {
};
let open_thread_task = thread_store.update(cx, |this, cx| this.open_thread(&thread.id, cx));
cx.spawn(|this, mut cx| async move {
cx.spawn(async move |this, cx| {
let thread = open_thread_task.await?;
context_store.update(&mut cx, |context_store, cx| {
context_store.update(cx, |context_store, cx| {
context_store.add_thread(thread, cx);
})?;
this.update(&mut cx, |_this, cx| cx.notify())
this.update(cx, |_this, cx| cx.notify())
})
}
@@ -392,11 +401,10 @@ impl EventEmitter<DismissEvent> for ContextPicker {}
impl Focusable for ContextPicker {
fn focus_handle(&self, cx: &App) -> FocusHandle {
match &self.mode {
ContextPickerMode::Default(menu) => menu.focus_handle(cx),
ContextPickerMode::File(file_picker) => file_picker.focus_handle(cx),
ContextPickerMode::Directory(directory_picker) => directory_picker.focus_handle(cx),
ContextPickerMode::Fetch(fetch_picker) => fetch_picker.focus_handle(cx),
ContextPickerMode::Thread(thread_picker) => thread_picker.focus_handle(cx),
ContextPickerState::Default(menu) => menu.focus_handle(cx),
ContextPickerState::File(file_picker) => file_picker.focus_handle(cx),
ContextPickerState::Fetch(fetch_picker) => fetch_picker.focus_handle(cx),
ContextPickerState::Thread(thread_picker) => thread_picker.focus_handle(cx),
}
}
}
@@ -407,13 +415,10 @@ impl Render for ContextPicker {
.w(px(400.))
.min_w(px(400.))
.map(|parent| match &self.mode {
ContextPickerMode::Default(menu) => parent.child(menu.clone()),
ContextPickerMode::File(file_picker) => parent.child(file_picker.clone()),
ContextPickerMode::Directory(directory_picker) => {
parent.child(directory_picker.clone())
}
ContextPickerMode::Fetch(fetch_picker) => parent.child(fetch_picker.clone()),
ContextPickerMode::Thread(thread_picker) => parent.child(thread_picker.clone()),
ContextPickerState::Default(menu) => parent.child(menu.clone()),
ContextPickerState::File(file_picker) => parent.child(file_picker.clone()),
ContextPickerState::Fetch(fetch_picker) => parent.child(fetch_picker.clone()),
ContextPickerState::Thread(thread_picker) => parent.child(thread_picker.clone()),
})
}
}

View File

@@ -1,269 +0,0 @@
use std::path::Path;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use fuzzy::PathMatch;
use gpui::{App, DismissEvent, Entity, FocusHandle, Focusable, Task, WeakEntity};
use picker::{Picker, PickerDelegate};
use project::{PathMatchCandidateSet, ProjectPath, WorktreeId};
use ui::{prelude::*, ListItem};
use util::ResultExt as _;
use workspace::{notifications::NotifyResultExt, Workspace};
use crate::context_picker::{ConfirmBehavior, ContextPicker};
use crate::context_store::ContextStore;
pub struct DirectoryContextPicker {
picker: Entity<Picker<DirectoryContextPickerDelegate>>,
}
impl DirectoryContextPicker {
pub fn new(
context_picker: WeakEntity<ContextPicker>,
workspace: WeakEntity<Workspace>,
context_store: WeakEntity<ContextStore>,
confirm_behavior: ConfirmBehavior,
window: &mut Window,
cx: &mut Context<Self>,
) -> Self {
let delegate = DirectoryContextPickerDelegate::new(
context_picker,
workspace,
context_store,
confirm_behavior,
);
let picker = cx.new(|cx| Picker::uniform_list(delegate, window, cx));
Self { picker }
}
}
impl Focusable for DirectoryContextPicker {
fn focus_handle(&self, cx: &App) -> FocusHandle {
self.picker.focus_handle(cx)
}
}
impl Render for DirectoryContextPicker {
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
self.picker.clone()
}
}
pub struct DirectoryContextPickerDelegate {
context_picker: WeakEntity<ContextPicker>,
workspace: WeakEntity<Workspace>,
context_store: WeakEntity<ContextStore>,
confirm_behavior: ConfirmBehavior,
matches: Vec<PathMatch>,
selected_index: usize,
}
impl DirectoryContextPickerDelegate {
pub fn new(
context_picker: WeakEntity<ContextPicker>,
workspace: WeakEntity<Workspace>,
context_store: WeakEntity<ContextStore>,
confirm_behavior: ConfirmBehavior,
) -> Self {
Self {
context_picker,
workspace,
context_store,
confirm_behavior,
matches: Vec::new(),
selected_index: 0,
}
}
fn search(
&mut self,
query: String,
cancellation_flag: Arc<AtomicBool>,
workspace: &Entity<Workspace>,
cx: &mut Context<Picker<Self>>,
) -> Task<Vec<PathMatch>> {
if query.is_empty() {
let workspace = workspace.read(cx);
let project = workspace.project().read(cx);
let directory_matches = project.worktrees(cx).flat_map(|worktree| {
let worktree = worktree.read(cx);
let path_prefix: Arc<str> = worktree.root_name().into();
worktree.directories(false, 0).map(move |entry| PathMatch {
score: 0.,
positions: Vec::new(),
worktree_id: worktree.id().to_usize(),
path: entry.path.clone(),
path_prefix: path_prefix.clone(),
distance_to_relative_ancestor: 0,
is_dir: true,
})
});
Task::ready(directory_matches.collect())
} else {
let worktrees = workspace.read(cx).visible_worktrees(cx).collect::<Vec<_>>();
let candidate_sets = worktrees
.into_iter()
.map(|worktree| {
let worktree = worktree.read(cx);
PathMatchCandidateSet {
snapshot: worktree.snapshot(),
include_ignored: worktree
.root_entry()
.map_or(false, |entry| entry.is_ignored),
include_root_name: true,
candidates: project::Candidates::Directories,
}
})
.collect::<Vec<_>>();
let executor = cx.background_executor().clone();
cx.foreground_executor().spawn(async move {
fuzzy::match_path_sets(
candidate_sets.as_slice(),
query.as_str(),
None,
false,
100,
&cancellation_flag,
executor,
)
.await
})
}
}
}
impl PickerDelegate for DirectoryContextPickerDelegate {
type ListItem = ListItem;
fn match_count(&self) -> usize {
self.matches.len()
}
fn selected_index(&self) -> usize {
self.selected_index
}
fn set_selected_index(
&mut self,
ix: usize,
_window: &mut Window,
_cx: &mut Context<Picker<Self>>,
) {
self.selected_index = ix;
}
fn placeholder_text(&self, _window: &mut Window, _cx: &mut App) -> Arc<str> {
"Search folders…".into()
}
fn update_matches(
&mut self,
query: String,
_window: &mut Window,
cx: &mut Context<Picker<Self>>,
) -> Task<()> {
let Some(workspace) = self.workspace.upgrade() else {
return Task::ready(());
};
let search_task = self.search(query, Arc::<AtomicBool>::default(), &workspace, cx);
cx.spawn(|this, mut cx| async move {
let mut paths = search_task.await;
let empty_path = Path::new("");
paths.retain(|path_match| path_match.path.as_ref() != empty_path);
this.update(&mut cx, |this, _cx| {
this.delegate.matches = paths;
})
.log_err();
})
}
fn confirm(&mut self, _secondary: bool, window: &mut Window, cx: &mut Context<Picker<Self>>) {
let Some(mat) = self.matches.get(self.selected_index) else {
return;
};
let project_path = ProjectPath {
worktree_id: WorktreeId::from_usize(mat.worktree_id),
path: mat.path.clone(),
};
let Some(task) = self
.context_store
.update(cx, |context_store, cx| {
context_store.add_directory(project_path, cx)
})
.ok()
else {
return;
};
let confirm_behavior = self.confirm_behavior;
cx.spawn_in(window, |this, mut cx| async move {
match task.await.notify_async_err(&mut cx) {
None => anyhow::Ok(()),
Some(()) => this.update_in(&mut cx, |this, window, cx| match confirm_behavior {
ConfirmBehavior::KeepOpen => {}
ConfirmBehavior::Close => this.delegate.dismissed(window, cx),
}),
}
})
.detach_and_log_err(cx);
}
fn dismissed(&mut self, _window: &mut Window, cx: &mut Context<Picker<Self>>) {
self.context_picker
.update(cx, |_, cx| {
cx.emit(DismissEvent);
})
.ok();
}
fn render_match(
&self,
ix: usize,
selected: bool,
_window: &mut Window,
cx: &mut Context<Picker<Self>>,
) -> Option<Self::ListItem> {
let path_match = &self.matches[ix];
let directory_name = path_match.path.to_string_lossy().to_string();
let added = self.context_store.upgrade().map_or(false, |context_store| {
context_store
.read(cx)
.includes_directory(&path_match.path)
.is_some()
});
Some(
ListItem::new(ix)
.inset(true)
.toggle_state(selected)
.start_slot(
Icon::new(IconName::Folder)
.size(IconSize::XSmall)
.color(Color::Muted),
)
.child(Label::new(directory_name))
.when(added, |el| {
el.end_slot(
h_flex()
.gap_1()
.child(
Icon::new(IconName::Check)
.size(IconSize::Small)
.color(Color::Success),
)
.child(Label::new("Added").size(LabelSize::Small)),
)
}),
)
}
}

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 {
@@ -206,12 +206,12 @@ impl PickerDelegate for FetchContextPickerDelegate {
let http_client = workspace.read(cx).client().http_client().clone();
let url = self.url.clone();
let confirm_behavior = self.confirm_behavior;
cx.spawn_in(window, |this, mut cx| async move {
cx.spawn_in(window, async move |this, cx| {
let text = cx
.background_spawn(Self::build_message(http_client, url.clone()))
.await?;
this.update_in(&mut cx, |this, window, cx| {
this.update_in(cx, |this, window, cx| {
this.delegate
.context_store
.update(cx, |context_store, _cx| {

View File

@@ -99,7 +99,6 @@ impl FileContextPickerDelegate {
query: String,
cancellation_flag: Arc<AtomicBool>,
workspace: &Entity<Workspace>,
cx: &mut Context<Picker<Self>>,
) -> Task<Vec<PathMatch>> {
if query.is_empty() {
@@ -124,14 +123,14 @@ impl FileContextPickerDelegate {
let file_matches = project.worktrees(cx).flat_map(|worktree| {
let worktree = worktree.read(cx);
let path_prefix: Arc<str> = worktree.root_name().into();
worktree.files(false, 0).map(move |entry| PathMatch {
worktree.entries(false, 0).map(move |entry| PathMatch {
score: 0.,
positions: Vec::new(),
worktree_id: worktree.id().to_usize(),
path: entry.path.clone(),
path_prefix: path_prefix.clone(),
distance_to_relative_ancestor: 0,
is_dir: false,
is_dir: entry.is_dir(),
})
});
@@ -149,7 +148,7 @@ impl FileContextPickerDelegate {
.root_entry()
.map_or(false, |entry| entry.is_ignored),
include_root_name: true,
candidates: project::Candidates::Files,
candidates: project::Candidates::Entries,
}
})
.collect::<Vec<_>>();
@@ -192,7 +191,7 @@ impl PickerDelegate for FileContextPickerDelegate {
}
fn placeholder_text(&self, _window: &mut Window, _cx: &mut App) -> Arc<str> {
"Search files…".into()
"Search files & directories".into()
}
fn update_matches(
@@ -207,11 +206,11 @@ impl PickerDelegate for FileContextPickerDelegate {
let search_task = self.search(query, Arc::<AtomicBool>::default(), &workspace, cx);
cx.spawn_in(window, |this, mut cx| async move {
cx.spawn_in(window, async move |this, cx| {
// TODO: This should be probably be run in the background.
let paths = search_task.await;
this.update(&mut cx, |this, _cx| {
this.update(cx, |this, _cx| {
this.delegate.matches = paths;
})
.log_err();
@@ -223,13 +222,11 @@ impl PickerDelegate for FileContextPickerDelegate {
return;
};
let Some(file_name) = mat
let file_name = mat
.path
.file_name()
.map(|os_str| os_str.to_string_lossy().into_owned())
else {
return;
};
.unwrap_or(mat.path_prefix.to_string());
let full_path = mat.path.display().to_string();
@@ -238,6 +235,8 @@ impl PickerDelegate for FileContextPickerDelegate {
path: mat.path.clone(),
};
let is_directory = mat.is_dir;
let Some(editor_entity) = self.editor.upgrade() else {
return;
};
@@ -288,8 +287,12 @@ impl PickerDelegate for FileContextPickerDelegate {
editor.insert("\n", window, cx); // Needed to end the fold
let file_icon = FileIcons::get_icon(&Path::new(&full_path), cx)
.unwrap_or_else(|| SharedString::new(""));
let file_icon = if is_directory {
FileIcons::get_folder_icon(false, cx)
} else {
FileIcons::get_icon(&Path::new(&full_path), cx)
}
.unwrap_or_else(|| SharedString::new(""));
let placeholder = FoldPlaceholder {
render: render_fold_icon_button(
@@ -330,7 +333,11 @@ impl PickerDelegate for FileContextPickerDelegate {
let Some(task) = self
.context_store
.update(cx, |context_store, cx| {
context_store.add_file_from_path(project_path, cx)
if is_directory {
context_store.add_directory(project_path, cx)
} else {
context_store.add_file_from_path(project_path, cx)
}
})
.ok()
else {
@@ -338,10 +345,10 @@ impl PickerDelegate for FileContextPickerDelegate {
};
let confirm_behavior = self.confirm_behavior;
cx.spawn_in(window, |this, mut cx| async move {
match task.await.notify_async_err(&mut cx) {
cx.spawn_in(window, async move |this, cx| {
match task.await.notify_async_err(cx) {
None => anyhow::Ok(()),
Some(()) => this.update_in(&mut cx, |this, window, cx| match confirm_behavior {
Some(()) => this.update_in(cx, |this, window, cx| match confirm_behavior {
ConfirmBehavior::KeepOpen => {}
ConfirmBehavior::Close => this.delegate.dismissed(window, cx),
}),
@@ -375,6 +382,7 @@ impl PickerDelegate for FileContextPickerDelegate {
ElementId::NamedInteger("file-ctx-picker".into(), ix),
&path_match.path,
&path_match.path_prefix,
path_match.is_dir,
self.context_store.clone(),
cx,
)),
@@ -386,6 +394,7 @@ pub fn render_file_context_entry(
id: ElementId,
path: &Path,
path_prefix: &Arc<str>,
is_directory: bool,
context_store: WeakEntity<ContextStore>,
cx: &App,
) -> Stateful<Div> {
@@ -409,13 +418,24 @@ pub fn render_file_context_entry(
(file_name, Some(directory))
};
let added = context_store
.upgrade()
.and_then(|context_store| context_store.read(cx).will_include_file_path(path, cx));
let added = context_store.upgrade().and_then(|context_store| {
if is_directory {
context_store
.read(cx)
.includes_directory(path)
.map(FileInclusion::Direct)
} else {
context_store.read(cx).will_include_file_path(path, cx)
}
});
let file_icon = FileIcons::get_icon(&path, cx)
.map(Icon::from_path)
.unwrap_or_else(|| Icon::new(IconName::File));
let file_icon = if is_directory {
FileIcons::get_folder_icon(false, cx)
} else {
FileIcons::get_icon(&path, cx)
}
.map(Icon::from_path)
.unwrap_or_else(|| Icon::new(IconName::File));
h_flex()
.id(id)

View File

@@ -149,9 +149,9 @@ impl PickerDelegate for ThreadContextPickerDelegate {
}
});
cx.spawn_in(window, |this, mut cx| async move {
cx.spawn_in(window, async move |this, cx| {
let matches = search_task.await;
this.update(&mut cx, |this, cx| {
this.update(cx, |this, cx| {
this.delegate.matches = matches;
this.delegate.selected_index = 0;
cx.notify();
@@ -171,9 +171,9 @@ impl PickerDelegate for ThreadContextPickerDelegate {
let open_thread_task = thread_store.update(cx, |this, cx| this.open_thread(&entry.id, cx));
cx.spawn_in(window, |this, mut cx| async move {
cx.spawn_in(window, async move |this, cx| {
let thread = open_thread_task.await?;
this.update_in(&mut cx, |this, window, cx| {
this.update_in(cx, |this, window, cx| {
this.delegate
.context_store
.update(cx, |context_store, cx| context_store.add_thread(thread, cx))
@@ -223,13 +223,18 @@ pub fn render_thread_context_entry(
h_flex()
.gap_1p5()
.w_full()
.justify_between()
.child(
Icon::new(IconName::MessageCircle)
.size(IconSize::XSmall)
.color(Color::Muted),
h_flex()
.gap_1p5()
.max_w_72()
.child(
Icon::new(IconName::MessageCircle)
.size(IconSize::XSmall)
.color(Color::Muted),
)
.child(Label::new(thread.summary.clone()).truncate()),
)
.child(Label::new(thread.summary.clone()))
.child(div().w_full())
.when(added, |el| {
el.child(
h_flex()

View File

@@ -9,6 +9,7 @@ use language::Buffer;
use project::{ProjectPath, Worktree};
use rope::Rope;
use text::BufferId;
use util::maybe;
use workspace::Workspace;
use crate::context::{
@@ -74,15 +75,15 @@ impl ContextStore {
return Task::ready(Err(anyhow!("failed to read project")));
};
cx.spawn(|this, mut cx| async move {
let open_buffer_task = project.update(&mut cx, |project, cx| {
cx.spawn(async move |this, cx| {
let open_buffer_task = project.update(cx, |project, cx| {
project.open_buffer(project_path.clone(), cx)
})?;
let buffer_entity = open_buffer_task.await?;
let buffer_id = this.update(&mut cx, |_, cx| buffer_entity.read(cx).remote_id())?;
let buffer_id = this.update(cx, |_, cx| buffer_entity.read(cx).remote_id())?;
let already_included = this.update(&mut cx, |this, _cx| {
let already_included = this.update(cx, |this, _cx| {
match this.will_include_buffer(buffer_id, &project_path.path) {
Some(FileInclusion::Direct(context_id)) => {
this.remove_context(context_id);
@@ -97,7 +98,7 @@ impl ContextStore {
return anyhow::Ok(());
}
let (buffer_info, text_task) = this.update(&mut cx, |_, cx| {
let (buffer_info, text_task) = this.update(cx, |_, cx| {
let buffer = buffer_entity.read(cx);
collect_buffer_info_and_text(
project_path.path.clone(),
@@ -109,7 +110,7 @@ impl ContextStore {
let text = text_task.await;
this.update(&mut cx, |this, _cx| {
this.update(cx, |this, _cx| {
this.insert_file(make_context_buffer(buffer_info, text));
})?;
@@ -122,8 +123,8 @@ impl ContextStore {
buffer_entity: Entity<Buffer>,
cx: &mut Context<Self>,
) -> Task<Result<()>> {
cx.spawn(|this, mut cx| async move {
let (buffer_info, text_task) = this.update(&mut cx, |_, cx| {
cx.spawn(async move |this, cx| {
let (buffer_info, text_task) = this.update(cx, |_, cx| {
let buffer = buffer_entity.read(cx);
let Some(file) = buffer.file() else {
return Err(anyhow!("Buffer has no path."));
@@ -138,7 +139,7 @@ impl ContextStore {
let text = text_task.await;
this.update(&mut cx, |this, _cx| {
this.update(cx, |this, _cx| {
this.insert_file(make_context_buffer(buffer_info, text))
})?;
@@ -178,18 +179,18 @@ impl ContextStore {
}
let worktree_id = project_path.worktree_id;
cx.spawn(|this, mut cx| async move {
let worktree = project.update(&mut cx, |project, cx| {
cx.spawn(async move |this, cx| {
let worktree = project.update(cx, |project, cx| {
project
.worktree_for_id(worktree_id, cx)
.ok_or_else(|| anyhow!("no worktree found for {worktree_id:?}"))
})??;
let files = worktree.update(&mut cx, |worktree, _cx| {
let files = worktree.update(cx, |worktree, _cx| {
collect_files_in_path(worktree, &project_path.path)
})?;
let open_buffers_task = project.update(&mut cx, |project, cx| {
let open_buffers_task = project.update(cx, |project, cx| {
let tasks = files.iter().map(|file_path| {
project.open_buffer(
ProjectPath {
@@ -206,14 +207,20 @@ impl ContextStore {
let mut buffer_infos = Vec::new();
let mut text_tasks = Vec::new();
this.update(&mut cx, |_, cx| {
this.update(cx, |_, cx| {
for (path, buffer_entity) in files.into_iter().zip(buffers) {
let buffer_entity = buffer_entity?;
let buffer = buffer_entity.read(cx);
let (buffer_info, text_task) =
collect_buffer_info_and_text(path, buffer_entity, buffer, cx.to_async());
buffer_infos.push(buffer_info);
text_tasks.push(text_task);
// Skip all binary files and other non-UTF8 files
if let Ok(buffer_entity) = buffer_entity {
let buffer = buffer_entity.read(cx);
let (buffer_info, text_task) = collect_buffer_info_and_text(
path,
buffer_entity,
buffer,
cx.to_async(),
);
buffer_infos.push(buffer_info);
text_tasks.push(text_task);
}
}
anyhow::Ok(())
})??;
@@ -229,7 +236,7 @@ impl ContextStore {
bail!("No text files found in {}", &project_path.path.display());
}
this.update(&mut cx, |this, _| {
this.update(cx, |this, _| {
this.insert_directory(&project_path.path, context_buffers);
})?;
@@ -525,35 +532,59 @@ fn collect_files_in_path(worktree: &Worktree, path: &Path) -> Vec<Arc<Path>> {
pub fn refresh_context_store_text(
context_store: Entity<ContextStore>,
changed_buffers: &HashSet<Entity<Buffer>>,
cx: &App,
) -> impl Future<Output = ()> {
) -> impl Future<Output = Vec<ContextId>> {
let mut tasks = Vec::new();
for context in &context_store.read(cx).context {
match context {
AssistantContext::File(file_context) => {
let context_store = context_store.clone();
if let Some(task) = refresh_file_text(context_store, file_context, cx) {
tasks.push(task);
let id = context.id();
let task = maybe!({
match context {
AssistantContext::File(file_context) => {
if changed_buffers.is_empty()
|| changed_buffers.contains(&file_context.context_buffer.buffer)
{
let context_store = context_store.clone();
return refresh_file_text(context_store, file_context, cx);
}
}
}
AssistantContext::Directory(directory_context) => {
let context_store = context_store.clone();
if let Some(task) = refresh_directory_text(context_store, directory_context, cx) {
tasks.push(task);
AssistantContext::Directory(directory_context) => {
let should_refresh = changed_buffers.is_empty()
|| changed_buffers.iter().any(|buffer| {
let buffer = buffer.read(cx);
buffer_path_log_err(&buffer)
.map_or(false, |path| path.starts_with(&directory_context.path))
});
if should_refresh {
let context_store = context_store.clone();
return refresh_directory_text(context_store, directory_context, cx);
}
}
AssistantContext::Thread(thread_context) => {
if changed_buffers.is_empty() {
let context_store = context_store.clone();
return Some(refresh_thread_text(context_store, thread_context, cx));
}
}
// Intentionally omit refreshing fetched URLs as it doesn't seem all that useful,
// and doing the caching properly could be tricky (unless it's already handled by
// the HttpClient?).
AssistantContext::FetchedUrl(_) => {}
}
AssistantContext::Thread(thread_context) => {
let context_store = context_store.clone();
tasks.push(refresh_thread_text(context_store, thread_context, cx));
}
// Intentionally omit refreshing fetched URLs as it doesn't seem all that useful,
// and doing the caching properly could be tricky (unless it's already handled by
// the HttpClient?).
AssistantContext::FetchedUrl(_) => {}
None
});
if let Some(task) = task {
tasks.push(task.map(move |_| id));
}
}
future::join_all(tasks).map(|_| ())
future::join_all(tasks)
}
fn refresh_file_text(
@@ -564,10 +595,10 @@ fn refresh_file_text(
let id = file_context.id;
let task = refresh_context_buffer(&file_context.context_buffer, cx);
if let Some(task) = task {
Some(cx.spawn(|mut cx| async move {
Some(cx.spawn(async move |cx| {
let context_buffer = task.await;
context_store
.update(&mut cx, |context_store, _| {
.update(cx, |context_store, _| {
let new_file_context = FileContext { id, context_buffer };
context_store.replace_context(AssistantContext::File(new_file_context));
})
@@ -605,10 +636,10 @@ fn refresh_directory_text(
let id = directory_context.snapshot.id;
let path = directory_context.path.clone();
Some(cx.spawn(|mut cx| async move {
Some(cx.spawn(async move |cx| {
let context_buffers = context_buffers.await;
context_store
.update(&mut cx, |context_store, _| {
.update(cx, |context_store, _| {
let new_directory_context = DirectoryContext::new(id, &path, context_buffers);
context_store.replace_context(AssistantContext::Directory(new_directory_context));
})
@@ -623,9 +654,9 @@ fn refresh_thread_text(
) -> Task<()> {
let id = thread_context.id;
let thread = thread_context.thread.clone();
cx.spawn(move |mut cx| async move {
cx.spawn(async move |cx| {
context_store
.update(&mut cx, |context_store, cx| {
.update(cx, |context_store, cx| {
let text = thread.read(cx).text().into();
context_store.replace_context(AssistantContext::Thread(ThreadContext {
id,

View File

@@ -25,7 +25,7 @@ use crate::{
pub struct ContextStrip {
context_store: Entity<ContextStore>,
pub context_picker: Entity<ContextPicker>,
context_picker: Entity<ContextPicker>,
context_picker_menu_handle: PopoverMenuHandle<ContextPicker>,
focus_handle: FocusHandle,
suggest_context_kind: SuggestContextKind,
@@ -36,7 +36,6 @@ pub struct ContextStrip {
}
impl ContextStrip {
#[allow(clippy::too_many_arguments)]
pub fn new(
context_store: Entity<ContextStore>,
workspace: WeakEntity<Workspace>,
@@ -336,12 +335,12 @@ impl ContextStrip {
context_store.accept_suggested_context(&suggested, cx)
});
cx.spawn_in(window, |this, mut cx| async move {
match task.await.notify_async_err(&mut cx) {
cx.spawn_in(window, async move |this, cx| {
match task.await.notify_async_err(cx) {
None => {}
Some(()) => {
if let Some(this) = this.upgrade() {
this.update(&mut cx, |_, cx| cx.notify())?;
this.update(cx, |_, cx| cx.notify())?;
}
}
}

View File

@@ -2,10 +2,10 @@ use assistant_context_editor::SavedContextMetadata;
use chrono::{DateTime, Utc};
use gpui::{prelude::*, Entity};
use crate::thread_store::{SavedThreadMetadata, ThreadStore};
use crate::thread_store::{SerializedThreadMetadata, ThreadStore};
pub enum HistoryEntry {
Thread(SavedThreadMetadata),
Thread(SerializedThreadMetadata),
Context(SavedContextMetadata),
}

View File

@@ -27,8 +27,9 @@ use language::{Buffer, Point, Selection, TransactionId};
use language_model::{report_assistant_event, LanguageModelRegistry};
use multi_buffer::MultiBufferRow;
use parking_lot::Mutex;
use project::LspAction;
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};
@@ -275,7 +276,7 @@ impl InlineAssistant {
if is_authenticated() {
handle_assist(window, cx);
} else {
cx.spawn_in(window, |_workspace, mut cx| async move {
cx.spawn_in(window, async move |_workspace, cx| {
let Some(task) = cx.update(|_, cx| {
LanguageModelRegistry::read_global(cx)
.active_provider()
@@ -479,7 +480,6 @@ impl InlineAssistant {
}
}
#[allow(clippy::too_many_arguments)]
pub fn suggest_assist(
&mut self,
editor: &Entity<Editor>,
@@ -1341,7 +1341,7 @@ impl InlineAssistant {
});
enum DeletedLines {}
let mut editor = Editor::for_multibuffer(multi_buffer, None, true, window, cx);
let mut editor = Editor::for_multibuffer(multi_buffer, None, window, cx);
editor.set_soft_wrap_mode(language::language_settings::SoftWrap::None, cx);
editor.set_show_wrap_guides(false, cx);
editor.set_show_gutter(false, cx);
@@ -1450,16 +1450,15 @@ struct InlineAssistScrollLock {
}
impl EditorInlineAssists {
#[allow(clippy::too_many_arguments)]
fn new(editor: &Entity<Editor>, window: &mut Window, cx: &mut App) -> Self {
let (highlight_updates_tx, mut highlight_updates_rx) = async_watch::channel(());
Self {
assist_ids: Vec::new(),
scroll_lock: None,
highlight_updates: highlight_updates_tx,
_update_highlights: cx.spawn(|cx| {
_update_highlights: cx.spawn({
let editor = editor.downgrade();
async move {
async move |cx| {
while let Ok(()) = highlight_updates_rx.changed().await {
let editor = editor.upgrade().context("editor was dropped")?;
cx.update_global(|assistant: &mut InlineAssistant, cx| {
@@ -1562,7 +1561,6 @@ pub struct InlineAssist {
}
impl InlineAssist {
#[allow(clippy::too_many_arguments)]
fn new(
assist_id: InlineAssistId,
group_id: InlineAssistGroupId,
@@ -1727,10 +1725,11 @@ impl CodeActionProvider for AssistantCodeActionProvider {
Task::ready(Ok(vec![CodeAction {
server_id: language::LanguageServerId(0),
range: snapshot.anchor_before(range.start)..snapshot.anchor_after(range.end),
lsp_action: lsp::CodeAction {
lsp_action: LspAction::Action(Box::new(lsp::CodeAction {
title: "Fix with Assistant".into(),
..Default::default()
},
})),
resolved: true,
}]))
} else {
Task::ready(Ok(Vec::new()))
@@ -1749,10 +1748,10 @@ impl CodeActionProvider for AssistantCodeActionProvider {
let editor = self.editor.clone();
let workspace = self.workspace.clone();
let thread_store = self.thread_store.clone();
window.spawn(cx, |mut cx| async move {
window.spawn(cx, async move |cx| {
let editor = editor.upgrade().context("editor was released")?;
let range = editor
.update(&mut cx, |editor, cx| {
.update(cx, |editor, cx| {
editor.buffer().update(cx, |multibuffer, cx| {
let buffer = buffer.read(cx);
let multibuffer_snapshot = multibuffer.read(cx);

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))
@@ -817,7 +816,6 @@ impl InlineAssistId {
}
impl PromptEditor<BufferCodegen> {
#[allow(clippy::too_many_arguments)]
pub fn new_buffer(
id: InlineAssistId,
gutter_dimensions: Arc<Mutex<GutterDimensions>>,
@@ -845,7 +843,6 @@ impl PromptEditor<BufferCodegen> {
},
prompt_buffer,
None,
false,
window,
cx,
);
@@ -858,6 +855,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 +879,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,
@@ -970,7 +974,6 @@ impl TerminalInlineAssistId {
}
impl PromptEditor<TerminalCodegen> {
#[allow(clippy::too_many_arguments)]
pub fn new_terminal(
id: TerminalInlineAssistId,
prompt_history: VecDeque<String>,
@@ -997,7 +1000,6 @@ impl PromptEditor<TerminalCodegen> {
},
prompt_buffer,
None,
false,
window,
cx,
);
@@ -1006,6 +1008,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 +1032,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

@@ -1,24 +1,28 @@
use std::sync::Arc;
use collections::HashSet;
use editor::actions::MoveUp;
use editor::{Editor, EditorElement, EditorEvent, EditorStyle};
use file_icons::FileIcons;
use fs::Fs;
use gpui::{
pulsating_between, Animation, AnimationExt, App, DismissEvent, Entity, Focusable, Subscription,
TextStyle, WeakEntity,
Animation, AnimationExt, App, DismissEvent, Entity, Focusable, Subscription, TextStyle,
WeakEntity,
};
use language_model::LanguageModelRegistry;
use language_model_selector::ToggleModelSelector;
use rope::Point;
use settings::Settings;
use std::time::Duration;
use text::Bias;
use theme::ThemeSettings;
use ui::{
prelude::*, ButtonLike, KeyBinding, PlatformStyle, PopoverMenu, PopoverMenuHandle, Switch,
TintColor, Tooltip,
prelude::*, ButtonLike, Disclosure, KeyBinding, PlatformStyle, PopoverMenu, PopoverMenuHandle,
Tooltip,
};
use vim_mode_setting::VimModeSetting;
use workspace::Workspace;
use workspace::notifications::{NotificationId, NotifyTaskExt};
use workspace::{Toast, Workspace};
use crate::assistant_model_selector::AssistantModelSelector;
use crate::context_picker::{ConfirmBehavior, ContextPicker};
@@ -26,18 +30,21 @@ use crate::context_store::{refresh_context_store_text, ContextStore};
use crate::context_strip::{ContextStrip, ContextStripEvent, SuggestContextKind};
use crate::thread::{RequestKind, Thread};
use crate::thread_store::ThreadStore;
use crate::tool_selector::ToolSelector;
use crate::{Chat, ChatMode, RemoveAllContext, ToggleContextPicker};
pub struct MessageEditor {
thread: Entity<Thread>,
editor: Entity<Editor>,
workspace: WeakEntity<Workspace>,
context_store: Entity<ContextStore>,
context_strip: Entity<ContextStrip>,
context_picker_menu_handle: PopoverMenuHandle<ContextPicker>,
inline_context_picker: Entity<ContextPicker>,
inline_context_picker_menu_handle: PopoverMenuHandle<ContextPicker>,
model_selector: Entity<AssistantModelSelector>,
use_tools: bool,
tool_selector: Entity<ToolSelector>,
edits_expanded: bool,
_subscriptions: Vec<Subscription>,
}
@@ -45,14 +52,16 @@ impl MessageEditor {
pub fn new(
fs: Arc<dyn Fs>,
workspace: WeakEntity<Workspace>,
context_store: Entity<ContextStore>,
thread_store: WeakEntity<ThreadStore>,
thread: Entity<Thread>,
window: &mut Window,
cx: &mut Context<Self>,
) -> Self {
let context_store = cx.new(|_cx| ContextStore::new(workspace.clone()));
let tools = thread.read(cx).tools().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);
@@ -100,20 +109,28 @@ impl MessageEditor {
Self {
thread,
editor: editor.clone(),
workspace,
context_store,
context_strip,
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)),
use_tools: false,
model_selector: cx.new(|cx| {
AssistantModelSelector::new(
fs,
model_selector_menu_handle,
editor.focus_handle(cx),
window,
cx,
)
}),
tool_selector: cx.new(|cx| ToolSelector::new(tools, cx)),
edits_expanded: false,
_subscriptions: subscriptions,
}
}
fn toggle_chat_mode(&mut self, _: &ChatMode, _window: &mut Window, cx: &mut Context<Self>) {
self.use_tools = !self.use_tools;
cx.notify();
}
@@ -137,6 +154,14 @@ impl MessageEditor {
}
fn chat(&mut self, _: &Chat, window: &mut Window, cx: &mut Context<Self>) {
if self.is_editor_empty(cx) {
return;
}
if self.thread.read(cx).is_generating() {
return;
}
self.send_to_model(RequestKind::Chat, window, cx);
}
@@ -176,18 +201,18 @@ impl MessageEditor {
text
});
let refresh_task = refresh_context_store_text(self.context_store.clone(), cx);
let refresh_task =
refresh_context_store_text(self.context_store.clone(), &HashSet::default(), cx);
let thread = self.thread.clone();
let context_store = self.context_store.clone();
let use_tools = self.use_tools;
cx.spawn(move |_, mut cx| async move {
cx.spawn(async move |_, cx| {
refresh_task.await;
thread
.update(&mut cx, |thread, cx| {
.update(cx, |thread, cx| {
let context = context_store.read(cx).snapshot(cx).collect::<Vec<_>>();
thread.insert_user_message(user_message, context, cx);
thread.send_to_model(model, request_kind, use_tools, cx);
thread.send_to_model(model, request_kind, cx);
})
.ok();
})
@@ -260,6 +285,34 @@ impl MessageEditor {
self.context_strip.focus_handle(cx).focus(window);
}
}
fn handle_feedback_click(
&mut self,
is_positive: bool,
window: &mut Window,
cx: &mut Context<Self>,
) {
let workspace = self.workspace.clone();
let report = self
.thread
.update(cx, |thread, cx| thread.report_feedback(is_positive, cx));
cx.spawn(async move |_, cx| {
report.await?;
workspace.update(cx, |workspace, cx| {
let message = if is_positive {
"Positive feedback recorded. Thank you!"
} else {
"Negative feedback recorded. Thank you for helping us improve!"
};
struct ThreadFeedback;
let id = NotificationId::unique::<ThreadFeedback>();
workspace.show_toast(Toast::new(id, message).autohide(), cx)
})
})
.detach_and_notify_err(window, cx);
}
}
impl Focusable for MessageEditor {
@@ -275,7 +328,7 @@ impl Render for MessageEditor {
let focus_handle = self.editor.focus_handle(cx);
let inline_context_picker = self.inline_context_picker.clone();
let bg_color = cx.theme().colors().editor_background;
let is_streaming_completion = self.thread.read(cx).is_streaming();
let is_generating = self.thread.read(cx).is_generating();
let is_model_selected = self.is_model_selected(cx);
let is_editor_empty = self.is_editor_empty(cx);
let submit_label_color = if is_editor_empty {
@@ -289,168 +342,337 @@ impl Render for MessageEditor {
let linux = platform == PlatformStyle::Linux;
let windows = platform == PlatformStyle::Windows;
let button_width = if linux || windows || vim_mode_enabled {
px(92.)
px(82.)
} else {
px(64.)
};
let changed_buffers = self.thread.read(cx).scripting_changed_buffers(cx);
let changed_buffers_count = changed_buffers.len();
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(Self::toggle_context_picker))
.on_action(cx.listener(Self::remove_all_context))
.on_action(cx.listener(Self::move_up))
.on_action(cx.listener(Self::toggle_chat_mode))
.size_full()
.gap_2()
.p_2()
.bg(bg_color)
.child(self.context_strip.clone())
.when(is_generating, |parent| {
let focus_handle = self.editor.focus_handle(cx).clone();
parent.child(
h_flex().py_3().w_full().justify_center().child(
h_flex()
.flex_none()
.pl_2()
.pr_1()
.py_1()
.bg(cx.theme().colors().editor_background)
.border_1()
.border_color(cx.theme().colors().border_variant)
.rounded_lg()
.shadow_md()
.gap_1()
.child(
Icon::new(IconName::ArrowCircle)
.size(IconSize::XSmall)
.color(Color::Muted)
.with_animation(
"arrow-circle",
Animation::new(Duration::from_secs(2)).repeat(),
|icon, delta| {
icon.transform(gpui::Transformation::rotate(
gpui::percentage(delta),
))
},
),
)
.child(
Label::new("Generating…")
.size(LabelSize::XSmall)
.color(Color::Muted),
)
.child(ui::Divider::vertical())
.child(
Button::new("cancel-generation", "Cancel")
.label_size(LabelSize::XSmall)
.key_binding(
KeyBinding::for_action_in(
&editor::actions::Cancel,
&focus_handle,
window,
cx,
)
.map(|kb| kb.size(rems_from_px(10.))),
)
.on_click(move |_event, window, cx| {
focus_handle.dispatch_action(
&editor::actions::Cancel,
window,
cx,
);
}),
),
),
)
})
.when(changed_buffers_count > 0, |parent| {
parent.child(
v_flex()
.mx_2()
.bg(cx.theme().colors().element_background)
.border_1()
.border_b_0()
.border_color(cx.theme().colors().border)
.rounded_t_md()
.child(
h_flex()
.gap_2()
.p_2()
.child(
Disclosure::new("edits-disclosure", self.edits_expanded)
.on_click(cx.listener(|this, _ev, _window, cx| {
this.edits_expanded = !this.edits_expanded;
cx.notify();
})),
)
.child(
Label::new("Edits")
.size(LabelSize::XSmall)
.color(Color::Muted),
)
.child(Label::new("").size(LabelSize::XSmall).color(Color::Muted))
.child(
Label::new(format!(
"{} {}",
changed_buffers_count,
if changed_buffers_count == 1 {
"file"
} else {
"files"
}
))
.size(LabelSize::XSmall)
.color(Color::Muted),
),
)
.when(self.edits_expanded, |parent| {
parent.child(
v_flex().bg(cx.theme().colors().editor_background).children(
changed_buffers.enumerate().flat_map(|(index, buffer)| {
let file = buffer.read(cx).file()?;
let path = file.path();
let parent_label = path.parent().and_then(|parent| {
let parent_str = parent.to_string_lossy();
if parent_str.is_empty() {
None
} else {
Some(
Label::new(format!(
"{}{}",
parent_str,
std::path::MAIN_SEPARATOR_STR
))
.color(Color::Muted)
.size(LabelSize::Small),
)
}
});
let name_label = path.file_name().map(|name| {
Label::new(name.to_string_lossy().to_string())
.size(LabelSize::Small)
});
let file_icon = FileIcons::get_icon(&path, cx)
.map(Icon::from_path)
.unwrap_or_else(|| Icon::new(IconName::File));
let element = div()
.p_2()
.when(index + 1 < changed_buffers_count, |parent| {
parent
.border_color(cx.theme().colors().border)
.border_b_1()
})
.child(
h_flex()
.gap_2()
.child(file_icon)
.child(
// TODO: handle overflow
h_flex()
.children(parent_label)
.children(name_label),
)
// TODO: show lines changed
.child(Label::new("+").color(Color::Created))
.child(Label::new("-").color(Color::Deleted)),
);
Some(element)
}),
),
)
}),
)
})
.child(
v_flex()
.gap_5()
.child({
let settings = ThemeSettings::get_global(cx);
let text_style = TextStyle {
color: cx.theme().colors().text,
font_family: settings.ui_font.family.clone(),
font_features: settings.ui_font.features.clone(),
font_size: font_size.into(),
font_weight: settings.ui_font.weight,
line_height: line_height.into(),
..Default::default()
};
EditorElement::new(
&self.editor,
EditorStyle {
background: bg_color,
local_player: cx.theme().players().local(),
text: text_style,
..Default::default()
},
)
})
.child(
PopoverMenu::new("inline-context-picker")
.menu(move |window, cx| {
inline_context_picker.update(cx, |this, cx| {
this.init(window, cx);
});
Some(inline_context_picker.clone())
})
.attach(gpui::Corner::TopLeft)
.anchor(gpui::Corner::BottomLeft)
.offset(gpui::Point {
x: px(0.0),
y: (-ThemeSettings::get_global(cx).ui_font_size(cx) * 2) - px(4.0),
})
.with_handle(self.inline_context_picker_menu_handle.clone()),
)
.key_context("MessageEditor")
.on_action(cx.listener(Self::chat))
.on_action(cx.listener(|this, _: &ToggleModelSelector, window, cx| {
this.model_selector
.update(cx, |model_selector, cx| model_selector.toggle(window, cx));
}))
.on_action(cx.listener(Self::toggle_context_picker))
.on_action(cx.listener(Self::remove_all_context))
.on_action(cx.listener(Self::move_up))
.on_action(cx.listener(Self::toggle_chat_mode))
.gap_2()
.p_2()
.bg(bg_color)
.border_t_1()
.border_color(cx.theme().colors().border)
.child(
h_flex()
.justify_between()
.child(
Switch::new("use-tools", self.use_tools.into())
.label("Tools")
.on_click(cx.listener(|this, selection, _window, _cx| {
this.use_tools = match selection {
ToggleState::Selected => true,
ToggleState::Unselected
| ToggleState::Indeterminate => false,
};
}))
.key_binding(KeyBinding::for_action_in(
&ChatMode,
&focus_handle,
window,
cx,
)),
)
.child(h_flex().gap_1().child(self.model_selector.clone()).child(
if is_streaming_completion {
ButtonLike::new("cancel-generation")
.width(button_width.into())
.style(ButtonStyle::Tinted(TintColor::Accent))
.child(self.context_strip.clone())
.when(!self.thread.read(cx).is_empty(), |this| {
this.child(
h_flex()
.gap_2()
.child(
h_flex()
.w_full()
.justify_between()
IconButton::new(
"feedback-thumbs-up",
IconName::ThumbsUp,
)
.style(ButtonStyle::Subtle)
.icon_size(IconSize::Small)
.tooltip(Tooltip::text("Helpful"))
.on_click(
cx.listener(|this, _, window, cx| {
this.handle_feedback_click(true, window, cx);
}),
),
)
.child(
IconButton::new(
"feedback-thumbs-down",
IconName::ThumbsDown,
)
.style(ButtonStyle::Subtle)
.icon_size(IconSize::Small)
.tooltip(Tooltip::text("Not Helpful"))
.on_click(
cx.listener(|this, _, window, cx| {
this.handle_feedback_click(false, window, cx);
}),
),
),
)
}),
)
.child(
v_flex()
.gap_5()
.child({
let settings = ThemeSettings::get_global(cx);
let text_style = TextStyle {
color: cx.theme().colors().text,
font_family: settings.ui_font.family.clone(),
font_fallbacks: settings.ui_font.fallbacks.clone(),
font_features: settings.ui_font.features.clone(),
font_size: font_size.into(),
font_weight: settings.ui_font.weight,
line_height: line_height.into(),
..Default::default()
};
EditorElement::new(
&self.editor,
EditorStyle {
background: bg_color,
local_player: cx.theme().players().local(),
text: text_style,
..Default::default()
},
)
})
.child(
PopoverMenu::new("inline-context-picker")
.menu(move |window, cx| {
inline_context_picker.update(cx, |this, cx| {
this.init(window, cx);
});
Some(inline_context_picker.clone())
})
.attach(gpui::Corner::TopLeft)
.anchor(gpui::Corner::BottomLeft)
.offset(gpui::Point {
x: px(0.0),
y: (-ThemeSettings::get_global(cx).ui_font_size(cx) * 2)
- px(4.0),
})
.with_handle(self.inline_context_picker_menu_handle.clone()),
)
.child(
h_flex()
.justify_between()
.child(h_flex().gap_2().child(self.tool_selector.clone()))
.child(
h_flex().gap_1().child(self.model_selector.clone()).child(
ButtonLike::new("submit-message")
.width(button_width.into())
.style(ButtonStyle::Filled)
.disabled(
is_editor_empty
|| !is_model_selected
|| is_generating,
)
.child(
Label::new("Cancel")
.size(LabelSize::Small)
.with_animation(
"pulsating-label",
Animation::new(Duration::from_secs(2))
.repeat()
.with_easing(pulsating_between(
0.4, 0.8,
)),
|label, delta| label.alpha(delta),
h_flex()
.w_full()
.justify_between()
.child(
Label::new("Submit")
.size(LabelSize::Small)
.color(submit_label_color),
)
.children(
KeyBinding::for_action_in(
&Chat,
&focus_handle,
window,
cx,
)
.map(|binding| {
binding
.when(vim_mode_enabled, |kb| {
kb.size(rems_from_px(12.))
})
.into_any_element()
}),
),
)
.children(
KeyBinding::for_action_in(
&editor::actions::Cancel,
&focus_handle,
window,
cx,
)
.map(|binding| binding.into_any_element()),
),
)
.on_click(move |_event, window, cx| {
focus_handle.dispatch_action(
&editor::actions::Cancel,
window,
cx,
);
})
} else {
ButtonLike::new("submit-message")
.width(button_width.into())
.style(ButtonStyle::Filled)
.disabled(is_editor_empty || !is_model_selected)
.child(
h_flex()
.w_full()
.justify_between()
.child(
Label::new("Submit")
.size(LabelSize::Small)
.color(submit_label_color),
)
.children(
KeyBinding::for_action_in(
&Chat,
&focus_handle,
window,
cx,
)
.map(|binding| binding.into_any_element()),
),
)
.on_click(move |_event, window, cx| {
focus_handle.dispatch_action(&Chat, window, cx);
})
.when(is_editor_empty, |button| {
button
.tooltip(Tooltip::text("Type a message to submit"))
})
.when(!is_model_selected, |button| {
button.tooltip(Tooltip::text(
"Select a model to continue",
))
})
},
)),
.on_click(move |_event, window, cx| {
focus_handle.dispatch_action(&Chat, window, cx);
})
.when(is_editor_empty, |button| {
button.tooltip(Tooltip::text(
"Type a message to submit",
))
})
.when(is_generating, |button| {
button.tooltip(Tooltip::text(
"Cancel to submit a new message",
))
})
.when(!is_model_selected, |button| {
button.tooltip(Tooltip::text(
"Select a model to continue",
))
}),
),
),
),
),
)
}

View File

@@ -40,7 +40,7 @@ impl TerminalCodegen {
let telemetry = self.telemetry.clone();
self.status = CodegenStatus::Pending;
self.transaction = Some(TerminalTransaction::start(self.terminal.clone()));
self.generation = cx.spawn(|this, mut cx| async move {
self.generation = cx.spawn(async move |this, cx| {
let model_telemetry_id = model.telemetry_id();
let model_provider_id = model.provider_id();
let response = model.stream_completion_text(prompt, &cx).await;
@@ -97,12 +97,12 @@ impl TerminalCodegen {
}
});
this.update(&mut cx, |this, _| {
this.update(cx, |this, _| {
this.message_id = message_id;
})?;
while let Some(hunk) = hunks_rx.next().await {
this.update(&mut cx, |this, cx| {
this.update(cx, |this, cx| {
if let Some(transaction) = &mut this.transaction {
transaction.push(hunk, cx);
cx.notify();
@@ -116,7 +116,7 @@ impl TerminalCodegen {
let result = generate.await;
this.update(&mut cx, |this, cx| {
this.update(cx, |this, cx| {
if let Err(error) = result {
this.status = CodegenStatus::Error(error);
} else {

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;

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ use time::{OffsetDateTime, UtcOffset};
use ui::{prelude::*, IconButtonShape, ListItem, ListItemSpacing, Tooltip};
use crate::history_store::{HistoryEntry, HistoryStore};
use crate::thread_store::SavedThreadMetadata;
use crate::thread_store::SerializedThreadMetadata;
use crate::{AssistantPanel, RemoveSelectedThread};
pub struct ThreadHistory {
@@ -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))
@@ -221,14 +221,14 @@ impl Render for ThreadHistory {
#[derive(IntoElement)]
pub struct PastThread {
thread: SavedThreadMetadata,
thread: SerializedThreadMetadata,
assistant_panel: WeakEntity<AssistantPanel>,
selected: bool,
}
impl PastThread {
pub fn new(
thread: SavedThreadMetadata,
thread: SerializedThreadMetadata,
assistant_panel: WeakEntity<AssistantPanel>,
selected: bool,
) -> Self {
@@ -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

@@ -12,32 +12,34 @@ use futures::FutureExt as _;
use gpui::{
prelude::*, App, BackgroundExecutor, Context, Entity, Global, ReadGlobal, SharedString, Task,
};
use heed::types::SerdeBincode;
use heed::types::{SerdeBincode, SerdeJson};
use heed::Database;
use language_model::Role;
use language_model::{LanguageModelToolUseId, Role};
use project::Project;
use prompt_store::PromptBuilder;
use serde::{Deserialize, Serialize};
use util::ResultExt as _;
use crate::thread::{MessageId, Thread, ThreadId};
use crate::thread::{MessageId, ProjectSnapshot, Thread, ThreadId};
pub fn init(cx: &mut App) {
ThreadsDatabase::init(cx);
}
pub struct ThreadStore {
#[allow(unused)]
project: Entity<Project>,
tools: Arc<ToolWorkingSet>,
prompt_builder: Arc<PromptBuilder>,
context_server_manager: Entity<ContextServerManager>,
context_server_tool_ids: HashMap<Arc<str>, Vec<ToolId>>,
threads: Vec<SavedThreadMetadata>,
threads: Vec<SerializedThreadMetadata>,
}
impl ThreadStore {
pub fn new(
project: Entity<Project>,
tools: Arc<ToolWorkingSet>,
prompt_builder: Arc<PromptBuilder>,
cx: &mut App,
) -> Result<Entity<Self>> {
let this = cx.new(|cx| {
@@ -49,6 +51,7 @@ impl ThreadStore {
let this = Self {
project,
tools,
prompt_builder,
context_server_manager,
context_server_tool_ids: HashMap::default(),
threads: Vec::new(),
@@ -62,23 +65,38 @@ impl ThreadStore {
Ok(this)
}
pub fn context_server_manager(&self) -> Entity<ContextServerManager> {
self.context_server_manager.clone()
}
pub fn tools(&self) -> Arc<ToolWorkingSet> {
self.tools.clone()
}
/// Returns the number of threads.
pub fn thread_count(&self) -> usize {
self.threads.len()
}
pub fn threads(&self) -> Vec<SavedThreadMetadata> {
pub fn threads(&self) -> Vec<SerializedThreadMetadata> {
let mut threads = self.threads.iter().cloned().collect::<Vec<_>>();
threads.sort_unstable_by_key(|thread| std::cmp::Reverse(thread.updated_at));
threads
}
pub fn recent_threads(&self, limit: usize) -> Vec<SavedThreadMetadata> {
pub fn recent_threads(&self, limit: usize) -> Vec<SerializedThreadMetadata> {
self.threads().into_iter().take(limit).collect()
}
pub fn create_thread(&mut self, cx: &mut Context<Self>) -> Entity<Thread> {
cx.new(|cx| Thread::new(self.tools.clone(), cx))
cx.new(|cx| {
Thread::new(
self.project.clone(),
self.tools.clone(),
self.prompt_builder.clone(),
cx,
)
})
}
pub fn open_thread(
@@ -88,55 +106,50 @@ impl ThreadStore {
) -> Task<Result<Entity<Thread>>> {
let id = id.clone();
let database_future = ThreadsDatabase::global_future(cx);
cx.spawn(|this, mut cx| async move {
cx.spawn(async move |this, cx| {
let database = database_future.await.map_err(|err| anyhow!(err))?;
let thread = database
.try_find_thread(id.clone())
.await?
.ok_or_else(|| anyhow!("no thread found with ID: {id:?}"))?;
this.update(&mut cx, |this, cx| {
cx.new(|cx| Thread::from_saved(id.clone(), thread, this.tools.clone(), cx))
this.update(cx, |this, cx| {
cx.new(|cx| {
Thread::deserialize(
id.clone(),
thread,
this.project.clone(),
this.tools.clone(),
this.prompt_builder.clone(),
cx,
)
})
})
})
}
pub fn save_thread(&self, thread: &Entity<Thread>, cx: &mut Context<Self>) -> Task<Result<()>> {
let (metadata, thread) = thread.update(cx, |thread, _cx| {
let id = thread.id().clone();
let thread = SavedThread {
summary: thread.summary_or_default(),
updated_at: thread.updated_at(),
messages: thread
.messages()
.map(|message| SavedMessage {
id: message.id,
role: message.role,
text: message.text.clone(),
})
.collect(),
};
(id, thread)
});
let (metadata, serialized_thread) =
thread.update(cx, |thread, cx| (thread.id().clone(), thread.serialize(cx)));
let database_future = ThreadsDatabase::global_future(cx);
cx.spawn(|this, mut cx| async move {
cx.spawn(async move |this, cx| {
let serialized_thread = serialized_thread.await?;
let database = database_future.await.map_err(|err| anyhow!(err))?;
database.save_thread(metadata, thread).await?;
database.save_thread(metadata, serialized_thread).await?;
this.update(&mut cx, |this, cx| this.reload(cx))?.await
this.update(cx, |this, cx| this.reload(cx))?.await
})
}
pub fn delete_thread(&mut self, id: &ThreadId, cx: &mut Context<Self>) -> Task<Result<()>> {
let id = id.clone();
let database_future = ThreadsDatabase::global_future(cx);
cx.spawn(|this, mut cx| async move {
cx.spawn(async move |this, cx| {
let database = database_future.await.map_err(|err| anyhow!(err))?;
database.delete_thread(id.clone()).await?;
this.update(&mut cx, |this, _cx| {
this.update(cx, |this, _cx| {
this.threads.retain(|thread| thread.id != id)
})
})
@@ -144,14 +157,14 @@ impl ThreadStore {
pub fn reload(&self, cx: &mut Context<Self>) -> Task<Result<()>> {
let database_future = ThreadsDatabase::global_future(cx);
cx.spawn(|this, mut cx| async move {
cx.spawn(async move |this, cx| {
let threads = database_future
.await
.map_err(|err| anyhow!(err))?
.list_threads()
.await?;
this.update(&mut cx, |this, cx| {
this.update(cx, |this, cx| {
this.threads = threads;
cx.notify();
})
@@ -180,7 +193,7 @@ impl ThreadStore {
cx.spawn({
let server = server.clone();
let server_id = server_id.clone();
|this, mut cx| async move {
async move |this, cx| {
let Some(protocol) = server.client() else {
return;
};
@@ -205,7 +218,7 @@ impl ThreadStore {
})
.collect::<Vec<_>>();
this.update(&mut cx, |this, _cx| {
this.update(cx, |this, _cx| {
this.context_server_tool_ids.insert(server_id, tool_ids);
})
.log_err();
@@ -226,24 +239,44 @@ impl ThreadStore {
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SavedThreadMetadata {
pub struct SerializedThreadMetadata {
pub id: ThreadId,
pub summary: SharedString,
pub updated_at: DateTime<Utc>,
}
#[derive(Serialize, Deserialize)]
pub struct SavedThread {
pub struct SerializedThread {
pub summary: SharedString,
pub updated_at: DateTime<Utc>,
pub messages: Vec<SavedMessage>,
pub messages: Vec<SerializedMessage>,
#[serde(default)]
pub initial_project_snapshot: Option<Arc<ProjectSnapshot>>,
}
#[derive(Serialize, Deserialize)]
pub struct SavedMessage {
#[derive(Debug, Serialize, Deserialize)]
pub struct SerializedMessage {
pub id: MessageId,
pub role: Role,
pub text: String,
#[serde(default)]
pub tool_uses: Vec<SerializedToolUse>,
#[serde(default)]
pub tool_results: Vec<SerializedToolResult>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct SerializedToolUse {
pub id: LanguageModelToolUseId,
pub name: SharedString,
pub input: serde_json::Value,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct SerializedToolResult {
pub tool_use_id: LanguageModelToolUseId,
pub is_error: bool,
pub content: Arc<str>,
}
struct GlobalThreadsDatabase(
@@ -255,7 +288,7 @@ impl Global for GlobalThreadsDatabase {}
pub(crate) struct ThreadsDatabase {
executor: BackgroundExecutor,
env: heed::Env,
threads: Database<SerdeBincode<ThreadId>, SerdeBincode<SavedThread>>,
threads: Database<SerdeBincode<ThreadId>, SerdeJson<SerializedThread>>,
}
impl ThreadsDatabase {
@@ -270,7 +303,7 @@ impl ThreadsDatabase {
let database_future = executor
.spawn({
let executor = executor.clone();
let database_path = paths::support_dir().join("threads/threads-db.0.mdb");
let database_path = paths::support_dir().join("threads/threads-db.1.mdb");
async move { ThreadsDatabase::new(database_path, executor) }
})
.then(|result| future::ready(result.map(Arc::new).map_err(Arc::new)))
@@ -302,7 +335,7 @@ impl ThreadsDatabase {
})
}
pub fn list_threads(&self) -> Task<Result<Vec<SavedThreadMetadata>>> {
pub fn list_threads(&self) -> Task<Result<Vec<SerializedThreadMetadata>>> {
let env = self.env.clone();
let threads = self.threads;
@@ -311,7 +344,7 @@ impl ThreadsDatabase {
let mut iter = threads.iter(&txn)?;
let mut threads = Vec::new();
while let Some((key, value)) = iter.next().transpose()? {
threads.push(SavedThreadMetadata {
threads.push(SerializedThreadMetadata {
id: key,
summary: value.summary,
updated_at: value.updated_at,
@@ -322,7 +355,7 @@ impl ThreadsDatabase {
})
}
pub fn try_find_thread(&self, id: ThreadId) -> Task<Result<Option<SavedThread>>> {
pub fn try_find_thread(&self, id: ThreadId) -> Task<Result<Option<SerializedThread>>> {
let env = self.env.clone();
let threads = self.threads;
@@ -333,7 +366,7 @@ impl ThreadsDatabase {
})
}
pub fn save_thread(&self, id: ThreadId, thread: SavedThread) -> Task<Result<()>> {
pub fn save_thread(&self, id: ThreadId, thread: SerializedThread) -> Task<Result<()>> {
let env = self.env.clone();
let threads = self.threads;

View File

@@ -0,0 +1,128 @@
use std::sync::Arc;
use assistant_tool::{ToolSource, ToolWorkingSet};
use gpui::Entity;
use scripting_tool::ScriptingTool;
use ui::{prelude::*, ContextMenu, PopoverMenu, Tooltip};
pub struct ToolSelector {
tools: Arc<ToolWorkingSet>,
}
impl ToolSelector {
pub fn new(tools: Arc<ToolWorkingSet>, _cx: &mut Context<Self>) -> Self {
Self { tools }
}
fn build_context_menu(
&self,
window: &mut Window,
cx: &mut Context<Self>,
) -> Entity<ContextMenu> {
let tool_set = self.tools.clone();
ContextMenu::build_persistent(window, cx, move |mut menu, _window, cx| {
let icon_position = IconPosition::End;
let tools_by_source = tool_set.tools_by_source(cx);
let all_tools_enabled = tool_set.are_all_tools_enabled();
menu = menu.toggleable_entry("All Tools", all_tools_enabled, icon_position, None, {
let tools = tool_set.clone();
move |_window, cx| {
if all_tools_enabled {
tools.disable_all_tools(cx);
} else {
tools.enable_all_tools();
}
}
});
for (source, tools) in tools_by_source {
let mut tools = tools
.into_iter()
.map(|tool| {
let source = tool.source();
let name = tool.name().into();
let is_enabled = tool_set.is_enabled(&source, &name);
(source, name, is_enabled)
})
.collect::<Vec<_>>();
if ToolSource::Native == source {
tools.push((
ToolSource::Native,
ScriptingTool::NAME.into(),
tool_set.is_scripting_tool_enabled(),
));
tools.sort_by(|(_, name_a, _), (_, name_b, _)| name_a.cmp(name_b));
}
menu = match &source {
ToolSource::Native => menu.separator().header("Zed Tools"),
ToolSource::ContextServer { id } => {
let all_tools_from_source_enabled =
tool_set.are_all_tools_from_source_enabled(&source);
menu.separator().header(id).toggleable_entry(
"All Tools",
all_tools_from_source_enabled,
icon_position,
None,
{
let tools = tool_set.clone();
let source = source.clone();
move |_window, cx| {
if all_tools_from_source_enabled {
tools.disable_source(source.clone(), cx);
} else {
tools.enable_source(&source);
}
}
},
)
}
};
for (source, name, is_enabled) in tools {
menu = menu.toggleable_entry(name.clone(), is_enabled, icon_position, None, {
let tools = tool_set.clone();
move |_window, _cx| {
if name.as_ref() == ScriptingTool::NAME {
if is_enabled {
tools.disable_scripting_tool();
} else {
tools.enable_scripting_tool();
}
} else {
if is_enabled {
tools.disable(source.clone(), &[name.clone()]);
} else {
tools.enable(source.clone(), &[name.clone()]);
}
}
}
});
}
}
menu
})
}
}
impl Render for ToolSelector {
fn render(&mut self, _window: &mut Window, cx: &mut Context<'_, Self>) -> impl IntoElement {
let this = cx.entity().clone();
PopoverMenu::new("tool-selector")
.menu(move |window, cx| {
Some(this.update(cx, |this, cx| this.build_context_menu(window, cx)))
})
.trigger_with_tooltip(
IconButton::new("tool-selector-button", IconName::SettingsAlt)
.icon_size(IconSize::Small)
.icon_color(Color::Muted),
Tooltip::text("Customize Tools"),
)
.anchor(gpui::Corner::BottomLeft)
}
}

View File

@@ -7,10 +7,11 @@ use futures::FutureExt as _;
use gpui::{SharedString, Task};
use language_model::{
LanguageModelRequestMessage, LanguageModelToolResult, LanguageModelToolUse,
LanguageModelToolUseId, MessageContent,
LanguageModelToolUseId, MessageContent, Role,
};
use crate::thread::MessageId;
use crate::thread_store::SerializedMessage;
#[derive(Debug)]
pub struct ToolUse {
@@ -28,7 +29,6 @@ pub enum ToolUseStatus {
Error(SharedString),
}
#[derive(Default)]
pub struct ToolUseState {
tool_uses_by_assistant_message: HashMap<MessageId, Vec<LanguageModelToolUse>>,
tool_uses_by_user_message: HashMap<MessageId, Vec<LanguageModelToolUseId>>,
@@ -37,6 +37,103 @@ pub struct ToolUseState {
}
impl ToolUseState {
pub fn new() -> Self {
Self {
tool_uses_by_assistant_message: HashMap::default(),
tool_uses_by_user_message: HashMap::default(),
tool_results: HashMap::default(),
pending_tool_uses_by_id: HashMap::default(),
}
}
/// Constructs a [`ToolUseState`] from the given list of [`SerializedMessage`]s.
///
/// Accepts a function to filter the tools that should be used to populate the state.
pub fn from_serialized_messages(
messages: &[SerializedMessage],
mut filter_by_tool_name: impl FnMut(&str) -> bool,
) -> Self {
let mut this = Self::new();
let mut tool_names_by_id = HashMap::default();
for message in messages {
match message.role {
Role::Assistant => {
if !message.tool_uses.is_empty() {
let tool_uses = message
.tool_uses
.iter()
.filter(|tool_use| (filter_by_tool_name)(tool_use.name.as_ref()))
.map(|tool_use| LanguageModelToolUse {
id: tool_use.id.clone(),
name: tool_use.name.clone().into(),
input: tool_use.input.clone(),
})
.collect::<Vec<_>>();
tool_names_by_id.extend(
tool_uses
.iter()
.map(|tool_use| (tool_use.id.clone(), tool_use.name.clone())),
);
this.tool_uses_by_assistant_message
.insert(message.id, tool_uses);
}
}
Role::User => {
if !message.tool_results.is_empty() {
let tool_uses_by_user_message = this
.tool_uses_by_user_message
.entry(message.id)
.or_default();
for tool_result in &message.tool_results {
let tool_use_id = tool_result.tool_use_id.clone();
let Some(tool_use) = tool_names_by_id.get(&tool_use_id) else {
log::warn!("no tool name found for tool use: {tool_use_id:?}");
continue;
};
if !(filter_by_tool_name)(tool_use.as_ref()) {
continue;
}
tool_uses_by_user_message.push(tool_use_id.clone());
this.tool_results.insert(
tool_use_id.clone(),
LanguageModelToolResult {
tool_use_id,
is_error: tool_result.is_error,
content: tool_result.content.clone(),
},
);
}
}
}
Role::System => {}
}
}
this
}
pub fn cancel_pending(&mut self) -> Vec<PendingToolUse> {
let mut pending_tools = Vec::new();
for (tool_use_id, tool_use) in self.pending_tool_uses_by_id.drain() {
self.tool_results.insert(
tool_use_id.clone(),
LanguageModelToolResult {
tool_use_id,
content: "Tool canceled by user".into(),
is_error: true,
},
);
pending_tools.push(tool_use.clone());
}
pending_tools
}
pub fn pending_tool_uses(&self) -> Vec<&PendingToolUse> {
self.pending_tool_uses_by_id.values().collect()
}
@@ -84,12 +181,30 @@ impl ToolUseState {
tool_uses
}
pub fn tool_results_for_message(&self, message_id: MessageId) -> Vec<&LanguageModelToolResult> {
let empty = Vec::new();
self.tool_uses_by_user_message
.get(&message_id)
.unwrap_or(&empty)
.iter()
.filter_map(|tool_use_id| self.tool_results.get(&tool_use_id))
.collect()
}
pub fn message_has_tool_results(&self, message_id: MessageId) -> bool {
self.tool_uses_by_user_message
.get(&message_id)
.map_or(false, |results| !results.is_empty())
}
pub fn tool_result(
&self,
tool_use_id: &LanguageModelToolUseId,
) -> Option<&LanguageModelToolResult> {
self.tool_results.get(tool_use_id)
}
pub fn request_tool_use(
&mut self,
assistant_message_id: MessageId,
@@ -132,18 +247,18 @@ impl ToolUseState {
&mut self,
tool_use_id: LanguageModelToolUseId,
output: Result<String>,
) {
) -> Option<PendingToolUse> {
match output {
Ok(output) => {
Ok(tool_result) => {
self.tool_results.insert(
tool_use_id.clone(),
LanguageModelToolResult {
tool_use_id: tool_use_id.clone(),
content: output.into(),
content: tool_result.into(),
is_error: false,
},
);
self.pending_tool_uses_by_id.remove(&tool_use_id);
self.pending_tool_uses_by_id.remove(&tool_use_id)
}
Err(err) => {
self.tool_results.insert(
@@ -158,6 +273,8 @@ impl ToolUseState {
if let Some(tool_use) = self.pending_tool_uses_by_id.get_mut(&tool_use_id) {
tool_use.status = PendingToolUseStatus::Error(err.to_string().into());
}
self.pending_tool_uses_by_id.get(&tool_use_id).cloned()
}
}
}
@@ -197,6 +314,7 @@ impl ToolUseState {
pub struct PendingToolUse {
pub id: LanguageModelToolUseId,
/// The ID of the Assistant message in which the tool use was requested.
#[allow(unused)]
pub assistant_message_id: MessageId,
pub name: Arc<str>,
pub input: serde_json::Value,

View File

@@ -103,7 +103,7 @@ impl RenderOnce for ContextPill {
.pl_1()
.pb(px(1.))
.border_1()
.rounded_md()
.rounded_sm()
.gap_1()
.child(self.icon().size(IconSize::XSmall).color(Color::Muted));
@@ -126,7 +126,13 @@ impl RenderOnce for ContextPill {
h_flex()
.id("context-data")
.gap_1()
.child(Label::new(context.name.clone()).size(LabelSize::Small))
.child(
div().max_w_64().child(
Label::new(context.name.clone())
.size(LabelSize::Small)
.truncate(),
),
)
.when_some(context.parent.as_ref(), |element, parent_name| {
if *dupe_name {
element.child(
@@ -174,21 +180,22 @@ impl RenderOnce for ContextPill {
})
.hover(|style| style.bg(color.element_hover.opacity(0.5)))
.child(
Label::new(name.clone())
.size(LabelSize::Small)
.color(Color::Muted),
div().px_0p5().max_w_64().child(
Label::new(name.clone())
.size(LabelSize::Small)
.color(Color::Muted)
.truncate(),
),
)
.child(
div().px_0p5().child(
Label::new(match kind {
ContextKind::File => "Active Tab",
ContextKind::Thread
| ContextKind::Directory
| ContextKind::FetchedUrl => "Active",
})
.size(LabelSize::XSmall)
.color(Color::Muted),
),
Label::new(match kind {
ContextKind::File => "Active Tab",
ContextKind::Thread | ContextKind::Directory | ContextKind::FetchedUrl => {
"Active"
}
})
.size(LabelSize::XSmall)
.color(Color::Muted),
)
.child(
Icon::new(IconName::Plus)

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::{
@@ -647,7 +647,6 @@ impl AssistantContext {
)
}
#[allow(clippy::too_many_arguments)]
pub fn new(
id: ContextId,
replica_id: ReplicaId,
@@ -768,7 +767,6 @@ impl AssistantContext {
}
}
#[allow(clippy::too_many_arguments)]
pub fn deserialize(
saved_context: SavedContext,
path: PathBuf,
@@ -1146,9 +1144,9 @@ impl AssistantContext {
fn set_language(&mut self, cx: &mut Context<Self>) {
let markdown = self.language_registry.language_for_name("Markdown");
cx.spawn(|this, mut cx| async move {
cx.spawn(async move |this, cx| {
let markdown = markdown.await?;
this.update(&mut cx, |this, cx| {
this.update(cx, |this, cx| {
this.buffer
.update(cx, |buffer, cx| buffer.set_language(Some(markdown), cx));
})
@@ -1190,7 +1188,7 @@ impl AssistantContext {
return;
};
let debounce = self.token_count.is_some();
self.pending_token_count = cx.spawn(|this, mut cx| {
self.pending_token_count = cx.spawn(async move |this, cx| {
async move {
if debounce {
cx.background_executor()
@@ -1199,13 +1197,14 @@ impl AssistantContext {
}
let token_count = cx.update(|cx| model.count_tokens(request, cx))?.await?;
this.update(&mut cx, |this, cx| {
this.update(cx, |this, cx| {
this.token_count = Some(token_count);
this.start_cache_warming(&model, cx);
cx.notify()
})
}
.log_err()
.await
});
}
@@ -1344,7 +1343,7 @@ impl AssistantContext {
};
let model = Arc::clone(model);
self.pending_cache_warming_task = cx.spawn(|this, mut cx| {
self.pending_cache_warming_task = cx.spawn(async move |this, cx| {
async move {
match model.stream_completion(request, &cx).await {
Ok(mut stream) => {
@@ -1355,13 +1354,14 @@ impl AssistantContext {
log::warn!("Cache warming failed: {}", e);
}
};
this.update(&mut cx, |this, cx| {
this.update(cx, |this, cx| {
this.update_cache_status_for_completion(cx);
})
.ok();
anyhow::Ok(())
}
.log_err()
.await
});
}
@@ -1918,7 +1918,7 @@ impl AssistantContext {
});
self.reparse(cx);
let insert_output_task = cx.spawn(|this, mut cx| async move {
let insert_output_task = cx.spawn(async move |this, cx| {
let run_command = async {
let mut stream = output.await?;
@@ -1935,7 +1935,7 @@ impl AssistantContext {
while let Some(event) = stream.next().await {
let event = event?;
this.update(&mut cx, |this, cx| {
this.update(cx, |this, cx| {
this.buffer.update(cx, |buffer, _cx| {
buffer.finalize_last_transaction();
buffer.start_transaction()
@@ -2036,7 +2036,7 @@ impl AssistantContext {
})?;
}
this.update(&mut cx, |this, cx| {
this.update(cx, |this, cx| {
this.buffer.update(cx, |buffer, cx| {
buffer.finalize_last_transaction();
buffer.start_transaction();
@@ -2082,7 +2082,7 @@ impl AssistantContext {
let command_result = run_command.await;
this.update(&mut cx, |this, cx| {
this.update(cx, |this, cx| {
let version = this.version.clone();
let timestamp = this.next_timestamp();
let Some(invoked_slash_command) = this.invoked_slash_commands.get_mut(&command_id)
@@ -2212,7 +2212,7 @@ impl AssistantContext {
let pending_completion_id = post_inc(&mut self.completion_count);
let task = cx.spawn({
|this, mut cx| async move {
async move |this, cx| {
let stream = model.stream_completion(request, &cx);
let assistant_message_id = assistant_message.id;
let mut response_latency = None;
@@ -2227,7 +2227,7 @@ impl AssistantContext {
}
let event = event?;
this.update(&mut cx, |this, cx| {
this.update(cx, |this, cx| {
let message_ix = this
.message_anchors
.iter()
@@ -2256,6 +2256,7 @@ impl AssistantContext {
);
}
LanguageModelCompletionEvent::ToolUse(_) => {}
LanguageModelCompletionEvent::UsageUpdate(_) => {}
}
});
@@ -2265,7 +2266,7 @@ impl AssistantContext {
})?;
smol::future::yield_now().await;
}
this.update(&mut cx, |this, cx| {
this.update(cx, |this, cx| {
this.pending_completions
.retain(|completion| completion.id != pending_completion_id);
this.summarize(false, cx);
@@ -2277,7 +2278,7 @@ impl AssistantContext {
let result = stream_completion.await;
this.update(&mut cx, |this, cx| {
this.update(cx, |this, cx| {
let error_message = if let Some(error) = result.as_ref().err() {
if error.is::<PaymentRequiredError>() {
cx.emit(ContextEvent::ShowPaymentRequiredError);
@@ -2787,7 +2788,7 @@ impl AssistantContext {
cache: false,
});
self.pending_summary = cx.spawn(|this, mut cx| {
self.pending_summary = cx.spawn(async move |this, cx| {
async move {
let stream = model.stream_completion_text(request, &cx);
let mut messages = stream.await?;
@@ -2796,7 +2797,7 @@ impl AssistantContext {
while let Some(message) = messages.stream.next().await {
let text = message?;
let mut lines = text.lines();
this.update(&mut cx, |this, cx| {
this.update(cx, |this, cx| {
let version = this.version.clone();
let timestamp = this.next_timestamp();
let summary = this.summary.get_or_insert(ContextSummary::default());
@@ -2820,7 +2821,7 @@ impl AssistantContext {
}
}
this.update(&mut cx, |this, cx| {
this.update(cx, |this, cx| {
let version = this.version.clone();
let timestamp = this.next_timestamp();
if let Some(summary) = this.summary.as_mut() {
@@ -2838,6 +2839,7 @@ impl AssistantContext {
anyhow::Ok(())
}
.log_err()
.await
});
}
}
@@ -2944,12 +2946,12 @@ impl AssistantContext {
return;
}
self.pending_save = cx.spawn(|this, mut cx| async move {
self.pending_save = cx.spawn(async move |this, cx| {
if let Some(debounce) = debounce {
cx.background_executor().timer(debounce).await;
}
let (old_path, summary) = this.read_with(&cx, |this, _| {
let (old_path, summary) = this.read_with(cx, |this, _| {
let path = this.path.clone();
let summary = if let Some(summary) = this.summary.as_ref() {
if summary.done {
@@ -2964,7 +2966,7 @@ impl AssistantContext {
})?;
if let Some(summary) = summary {
let context = this.read_with(&cx, |this, cx| this.serialize(cx))?;
let context = this.read_with(cx, |this, cx| this.serialize(cx))?;
let mut discriminant = 1;
let mut new_path;
loop {
@@ -2996,7 +2998,7 @@ impl AssistantContext {
}
}
this.update(&mut cx, |this, _| this.path = Some(new_path))?;
this.update(cx, |this, _| this.path = Some(new_path))?;
}
Ok(())

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;
@@ -52,7 +54,7 @@ use ui::{
Tooltip,
};
use util::{maybe, ResultExt};
use workspace::searchable::SearchableItemHandle;
use workspace::searchable::{Direction, SearchableItemHandle};
use workspace::{
item::{self, FollowableItem, Item, ItemHandle},
notifications::NotificationId,
@@ -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";
@@ -226,6 +229,7 @@ impl ContextEditor {
editor.set_show_git_diff_gutter(false, cx);
editor.set_show_code_actions(false, cx);
editor.set_show_runnables(false, cx);
editor.set_show_breakpoints(false, cx);
editor.set_show_wrap_guides(false, cx);
editor.set_show_indent_guides(false, cx);
editor.set_completion_provider(Some(Box::new(completion_provider)));
@@ -249,21 +253,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 +265,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 +277,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);
@@ -534,7 +536,6 @@ impl ContextEditor {
}
}
#[allow(clippy::too_many_arguments)]
pub fn run_command(
&mut self,
command_range: Range<language::Anchor>,
@@ -906,7 +907,7 @@ impl ContextEditor {
if editor_state.opened_patch != patch {
state.update_task = Some({
let this = this.clone();
cx.spawn_in(window, |_, cx| async move {
cx.spawn_in(window, async move |_, cx| {
Self::update_patch_editor(this.clone(), patch, cx)
.await
.log_err();
@@ -1069,10 +1070,9 @@ impl ContextEditor {
})
.ok();
} else {
patch_state.update_task =
Some(cx.spawn_in(window, move |this, cx| async move {
Self::open_patch_editor(this, new_patch, cx).await.log_err();
}));
patch_state.update_task = Some(cx.spawn_in(window, async move |this, cx| {
Self::open_patch_editor(this, new_patch, cx).await.log_err();
}));
}
}
}
@@ -1102,10 +1102,10 @@ impl ContextEditor {
async fn open_patch_editor(
this: WeakEntity<Self>,
patch: AssistantPatch,
mut cx: AsyncWindowContext,
cx: &mut AsyncWindowContext,
) -> Result<()> {
let project = this.read_with(&cx, |this, _| this.project.clone())?;
let resolved_patch = patch.resolve(project.clone(), &mut cx).await;
let project = this.read_with(cx, |this, _| this.project.clone())?;
let resolved_patch = patch.resolve(project.clone(), cx).await;
let editor = cx.new_window_entity(|window, cx| {
let editor = ProposedChangesEditor::new(
@@ -1129,7 +1129,7 @@ impl ContextEditor {
editor
})?;
this.update(&mut cx, |this, _| {
this.update(cx, |this, _| {
if let Some(patch_state) = this.patches.get_mut(&patch.range) {
patch_state.editor = Some(PatchEditorState {
editor: editor.downgrade(),
@@ -1138,8 +1138,8 @@ impl ContextEditor {
patch_state.update_task.take();
}
})?;
this.read_with(&cx, |this, _| this.workspace.clone())?
.update_in(&mut cx, |workspace, window, cx| {
this.read_with(cx, |this, _| this.workspace.clone())?
.update_in(cx, |workspace, window, cx| {
workspace.add_item_to_active_pane(Box::new(editor.clone()), None, false, window, cx)
})
.log_err();
@@ -1150,11 +1150,11 @@ impl ContextEditor {
async fn update_patch_editor(
this: WeakEntity<Self>,
patch: AssistantPatch,
mut cx: AsyncWindowContext,
cx: &mut AsyncWindowContext,
) -> Result<()> {
let project = this.update(&mut cx, |this, _| this.project.clone())?;
let resolved_patch = patch.resolve(project.clone(), &mut cx).await;
this.update_in(&mut cx, |this, window, cx| {
let project = this.update(cx, |this, _| this.project.clone())?;
let resolved_patch = patch.resolve(project.clone(), cx).await;
this.update_in(cx, |this, window, cx| {
let patch_state = this.patches.get_mut(&patch.range)?;
let locations = resolved_patch
@@ -1240,7 +1240,7 @@ impl ContextEditor {
.child("Press")
.child(
h_flex()
.rounded_md()
.rounded_sm()
.px_1()
.mr_0p5()
.border_1()
@@ -1624,14 +1624,14 @@ impl ContextEditor {
.map(|path| Workspace::project_path_for_path(project.clone(), &path, false, cx))
.collect::<Vec<_>>();
cx.spawn(move |_, cx| async move {
cx.spawn(async move |_, cx| {
let mut paths = vec![];
let mut worktrees = vec![];
let opened_paths = futures::future::join_all(tasks).await;
for (worktree, project_path) in opened_paths.into_iter().flatten() {
let Ok(worktree_root_name) =
worktree.read_with(&cx, |worktree, _| worktree.root_name().to_string())
worktree.read_with(cx, |worktree, _| worktree.root_name().to_string())
else {
continue;
};
@@ -1648,12 +1648,12 @@ impl ContextEditor {
};
window
.spawn(cx, |mut cx| async move {
.spawn(cx, async move |cx| {
let (paths, dragged_file_worktrees) = paths.await;
let cmd_name = FileSlashCommand.name();
context_editor_view
.update_in(&mut cx, |context_editor, window, cx| {
.update_in(cx, |context_editor, window, cx| {
let file_argument = paths
.into_iter()
.map(|path| path.to_string_lossy().to_string())
@@ -2056,7 +2056,6 @@ impl ContextEditor {
.unwrap_or_else(|| Cow::Borrowed(DEFAULT_TAB_TITLE))
}
#[allow(clippy::too_many_arguments)]
fn render_patch_block(
&mut self,
range: Range<text::Anchor>,
@@ -2091,7 +2090,7 @@ impl ContextEditor {
.ml(gutter_width)
.pb_1()
.w(max_width - gutter_width)
.rounded_md()
.rounded_sm()
.border_1()
.border_color(theme.colors().border_variant)
.overflow_hidden()
@@ -2200,9 +2199,9 @@ impl ContextEditor {
.log_err();
if let Some(client) = client {
cx.spawn(|this, mut cx| async move {
client.authenticate_and_connect(true, &mut cx).await?;
this.update(&mut cx, |_, cx| cx.notify())
cx.spawn(async move |this, cx| {
client.authenticate_and_connect(true, cx).await?;
this.update(cx, |_, cx| cx.notify())
})
.detach_and_log_err(cx)
}
@@ -2388,6 +2387,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 +2871,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 +2884,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 +2924,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()
@@ -3070,12 +3104,13 @@ impl SearchableItem for ContextEditor {
fn active_match_index(
&mut self,
direction: Direction,
matches: &[Self::Match],
window: &mut Window,
cx: &mut Context<Self>,
) -> Option<usize> {
self.editor.update(cx, |editor, cx| {
editor.active_match_index(matches, window, cx)
editor.active_match_index(direction, matches, window, cx)
})
}
}
@@ -3125,10 +3160,10 @@ impl FollowableItem for ContextEditor {
assistant_panel_delegate.open_remote_context(workspace, context_id, window, cx)
});
Some(window.spawn(cx, |mut cx| async move {
Some(window.spawn(cx, async move |cx| {
let context_editor = context_editor_task.await?;
context_editor
.update_in(&mut cx, |context_editor, window, cx| {
.update_in(cx, |context_editor, window, cx| {
context_editor.remote_id = Some(id);
context_editor.editor.update(cx, |editor, cx| {
editor.apply_update_proto(
@@ -3385,7 +3420,7 @@ fn invoked_slash_command_fold_placeholder(
.ml_6()
.gap_2()
.bg(cx.theme().colors().surface_background)
.rounded_md()
.rounded_sm()
.child(Label::new(format!("/{}", command.name.clone())))
.map(|parent| match &command.status {
InvokedSlashCommandStatus::Running(_) => {

View File

@@ -164,9 +164,9 @@ impl PickerDelegate for SavedContextPickerDelegate {
cx: &mut Context<Picker<Self>>,
) -> Task<()> {
let search = self.store.read(cx).search(query, cx);
cx.spawn(|this, mut cx| async move {
cx.spawn(async move |this, cx| {
let matches = search.await;
this.update(&mut cx, |this, cx| {
this.update(cx, |this, cx| {
let host_contexts = this.delegate.store.read(cx).host_contexts();
this.delegate.matches = host_contexts
.iter()

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;
@@ -100,53 +100,56 @@ impl ContextStore {
let fs = project.read(cx).fs().clone();
let languages = project.read(cx).languages().clone();
let telemetry = project.read(cx).client().telemetry().clone();
cx.spawn(|mut cx| async move {
cx.spawn(async move |cx| {
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(async move |this, cx| {
async move {
while events.next().await.is_some() {
this.update(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()
.await
}),
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 +291,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 +321,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);
}
@@ -388,7 +394,7 @@ impl ContextStore {
let prompt_builder = self.prompt_builder.clone();
let slash_commands = self.slash_commands.clone();
let request = self.client.request(proto::CreateContext { project_id });
cx.spawn(|this, mut cx| async move {
cx.spawn(async move |this, cx| {
let response = request.await?;
let context_id = ContextId::from_proto(response.context_id);
let context_proto = response.context.context("invalid context")?;
@@ -414,8 +420,8 @@ impl ContextStore {
.collect::<Result<Vec<_>>>()
})
.await?;
context.update(&mut cx, |context, cx| context.apply_ops(operations, cx))?;
this.update(&mut cx, |this, cx| {
context.update(cx, |context, cx| context.apply_ops(operations, cx))?;
this.update(cx, |this, cx| {
if let Some(existing_context) = this.loaded_context_for_id(&context_id, cx) {
existing_context
} else {
@@ -450,7 +456,7 @@ impl ContextStore {
let prompt_builder = self.prompt_builder.clone();
let slash_commands = self.slash_commands.clone();
cx.spawn(|this, mut cx| async move {
cx.spawn(async move |this, cx| {
let saved_context = load.await?;
let context = cx.new(|cx| {
AssistantContext::deserialize(
@@ -464,7 +470,7 @@ impl ContextStore {
cx,
)
})?;
this.update(&mut cx, |this, cx| {
this.update(cx, |this, cx| {
if let Some(existing_context) = this.loaded_context_for_path(&path, cx) {
existing_context
} else {
@@ -482,7 +488,7 @@ impl ContextStore {
) -> Task<Result<()>> {
let fs = self.fs.clone();
cx.spawn(|this, mut cx| async move {
cx.spawn(async move |this, cx| {
fs.remove_file(
&path,
RemoveOptions {
@@ -492,7 +498,7 @@ impl ContextStore {
)
.await?;
this.update(&mut cx, |this, cx| {
this.update(cx, |this, cx| {
this.contexts.retain(|context| {
context
.upgrade()
@@ -558,7 +564,7 @@ impl ContextStore {
});
let prompt_builder = self.prompt_builder.clone();
let slash_commands = self.slash_commands.clone();
cx.spawn(|this, mut cx| async move {
cx.spawn(async move |this, cx| {
let response = request.await?;
let context_proto = response.context.context("invalid context")?;
let context = cx.new(|cx| {
@@ -583,8 +589,8 @@ impl ContextStore {
.collect::<Result<Vec<_>>>()
})
.await?;
context.update(&mut cx, |context, cx| context.apply_ops(operations, cx))?;
this.update(&mut cx, |this, cx| {
context.update(cx, |context, cx| context.apply_ops(operations, cx))?;
this.update(cx, |this, cx| {
if let Some(existing_context) = this.loaded_context_for_id(&context_id, cx) {
existing_context
} else {
@@ -693,12 +699,12 @@ impl ContextStore {
project_id,
contexts,
});
cx.spawn(|this, cx| async move {
cx.spawn(async move |this, cx| {
let response = request.await?;
let mut context_ids = Vec::new();
let mut operations = Vec::new();
this.read_with(&cx, |this, cx| {
this.read_with(cx, |this, cx| {
for context_version_proto in response.contexts {
let context_version = ContextVersion::from_proto(&context_version_proto);
let context_id = ContextId::from_proto(context_version_proto.context_id);
@@ -761,7 +767,7 @@ impl ContextStore {
fn reload(&mut self, cx: &mut Context<Self>) -> Task<Result<()>> {
let fs = self.fs.clone();
cx.spawn(|this, mut cx| async move {
cx.spawn(async move |this, cx| {
fs.create_dir(contexts_dir()).await?;
let mut paths = fs.read_dir(contexts_dir()).await?;
@@ -801,7 +807,7 @@ impl ContextStore {
}
contexts.sort_unstable_by_key(|context| Reverse(context.mtime));
this.update(&mut cx, |this, cx| {
this.update(cx, |this, cx| {
this.contexts_metadata = contexts;
cx.notify();
})
@@ -843,7 +849,7 @@ impl ContextStore {
cx.spawn({
let server = server.clone();
let server_id = server_id.clone();
|this, mut cx| async move {
async move |this, cx| {
let Some(protocol) = server.client() else {
return;
};
@@ -868,7 +874,7 @@ impl ContextStore {
})
.collect::<Vec<_>>();
this.update(&mut cx, |this, _cx| {
this.update( cx, |this, _cx| {
this.context_server_slash_command_ids
.insert(server_id.clone(), slash_command_ids);
})

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

@@ -5,9 +5,9 @@ use assistant_slash_command::{AfterCompletion, SlashCommandLine, SlashCommandWor
use editor::{CompletionProvider, Editor};
use fuzzy::{match_strings, StringMatchCandidate};
use gpui::{App, AppContext as _, Context, Entity, Task, WeakEntity, Window};
use language::{Anchor, Buffer, LanguageServerId, ToPoint};
use language::{Anchor, Buffer, ToPoint};
use parking_lot::Mutex;
use project::{lsp_store::CompletionDocumentation, CompletionIntent};
use project::{lsp_store::CompletionDocumentation, CompletionIntent, CompletionSource};
use rope::Point;
use std::{
cell::RefCell,
@@ -48,7 +48,7 @@ impl SlashCommandCompletionProvider {
name_range: Range<Anchor>,
window: &mut Window,
cx: &mut App,
) -> Task<Result<Vec<project::Completion>>> {
) -> Task<Result<Option<Vec<project::Completion>>>> {
let slash_commands = self.slash_commands.clone();
let candidates = slash_commands
.command_names(cx)
@@ -59,7 +59,7 @@ impl SlashCommandCompletionProvider {
let command_name = command_name.to_string();
let editor = self.editor.clone();
let workspace = self.workspace.clone();
window.spawn(cx, |mut cx| async move {
window.spawn(cx, async move |cx| {
let matches = match_strings(
&candidates,
&command_name,
@@ -71,72 +71,71 @@ impl SlashCommandCompletionProvider {
.await;
cx.update(|_, cx| {
matches
.into_iter()
.filter_map(|mat| {
let command = slash_commands.command(&mat.string, cx)?;
let mut new_text = mat.string.clone();
let requires_argument = command.requires_argument();
let accepts_arguments = command.accepts_arguments();
if requires_argument || accepts_arguments {
new_text.push(' ');
}
Some(
matches
.into_iter()
.filter_map(|mat| {
let command = slash_commands.command(&mat.string, cx)?;
let mut new_text = mat.string.clone();
let requires_argument = command.requires_argument();
let accepts_arguments = command.accepts_arguments();
if requires_argument || accepts_arguments {
new_text.push(' ');
}
let confirm =
editor
.clone()
.zip(workspace.clone())
.map(|(editor, workspace)| {
let command_name = mat.string.clone();
let command_range = command_range.clone();
let editor = editor.clone();
let workspace = workspace.clone();
Arc::new(
move |intent: CompletionIntent,
window: &mut Window,
cx: &mut App| {
if !requires_argument
&& (!accepts_arguments || intent.is_complete())
{
editor
.update(cx, |editor, cx| {
editor.run_command(
command_range.clone(),
&command_name,
&[],
true,
workspace.clone(),
window,
cx,
);
})
.ok();
false
} else {
requires_argument || accepts_arguments
}
},
) as Arc<_>
});
Some(project::Completion {
old_range: name_range.clone(),
documentation: Some(CompletionDocumentation::SingleLine(
command.description().into(),
)),
new_text,
label: command.label(cx),
server_id: LanguageServerId(0),
lsp_completion: Default::default(),
confirm,
resolved: true,
let confirm =
editor
.clone()
.zip(workspace.clone())
.map(|(editor, workspace)| {
let command_name = mat.string.clone();
let command_range = command_range.clone();
let editor = editor.clone();
let workspace = workspace.clone();
Arc::new(
move |intent: CompletionIntent,
window: &mut Window,
cx: &mut App| {
if !requires_argument
&& (!accepts_arguments || intent.is_complete())
{
editor
.update(cx, |editor, cx| {
editor.run_command(
command_range.clone(),
&command_name,
&[],
true,
workspace.clone(),
window,
cx,
);
})
.ok();
false
} else {
requires_argument || accepts_arguments
}
},
) as Arc<_>
});
Some(project::Completion {
old_range: name_range.clone(),
documentation: Some(CompletionDocumentation::SingleLine(
command.description().into(),
)),
new_text,
label: command.label(cx),
confirm,
source: CompletionSource::Custom,
})
})
})
.collect()
.collect(),
)
})
})
}
#[allow(clippy::too_many_arguments)]
fn complete_command_argument(
&self,
command_name: &str,
@@ -146,7 +145,7 @@ impl SlashCommandCompletionProvider {
last_argument_range: Range<Anchor>,
window: &mut Window,
cx: &mut App,
) -> Task<Result<Vec<project::Completion>>> {
) -> Task<Result<Option<Vec<project::Completion>>>> {
let new_cancel_flag = Arc::new(AtomicBool::new(false));
let mut flag = self.cancel_flag.lock();
flag.store(true, SeqCst);
@@ -164,27 +163,28 @@ impl SlashCommandCompletionProvider {
let workspace = self.workspace.clone();
let arguments = arguments.to_vec();
cx.background_spawn(async move {
Ok(completions
.await?
.into_iter()
.map(|new_argument| {
let confirm =
editor
.clone()
.zip(workspace.clone())
.map(|(editor, workspace)| {
Arc::new({
let mut completed_arguments = arguments.clone();
if new_argument.replace_previous_arguments {
completed_arguments.clear();
} else {
completed_arguments.pop();
}
completed_arguments.push(new_argument.new_text.clone());
Ok(Some(
completions
.await?
.into_iter()
.map(|new_argument| {
let confirm =
editor
.clone()
.zip(workspace.clone())
.map(|(editor, workspace)| {
Arc::new({
let mut completed_arguments = arguments.clone();
if new_argument.replace_previous_arguments {
completed_arguments.clear();
} else {
completed_arguments.pop();
}
completed_arguments.push(new_argument.new_text.clone());
let command_range = command_range.clone();
let command_name = command_name.clone();
move |intent: CompletionIntent,
let command_range = command_range.clone();
let command_name = command_name.clone();
move |intent: CompletionIntent,
window: &mut Window,
cx: &mut App| {
if new_argument.after_completion.run()
@@ -208,33 +208,32 @@ impl SlashCommandCompletionProvider {
!new_argument.after_completion.run()
}
}
}) as Arc<_>
});
}) as Arc<_>
});
let mut new_text = new_argument.new_text.clone();
if new_argument.after_completion == AfterCompletion::Continue {
new_text.push(' ');
}
let mut new_text = new_argument.new_text.clone();
if new_argument.after_completion == AfterCompletion::Continue {
new_text.push(' ');
}
project::Completion {
old_range: if new_argument.replace_previous_arguments {
argument_range.clone()
} else {
last_argument_range.clone()
},
label: new_argument.label,
new_text,
documentation: None,
server_id: LanguageServerId(0),
lsp_completion: Default::default(),
confirm,
resolved: true,
}
})
.collect())
project::Completion {
old_range: if new_argument.replace_previous_arguments {
argument_range.clone()
} else {
last_argument_range.clone()
},
label: new_argument.label,
new_text,
documentation: None,
confirm,
source: CompletionSource::Custom,
}
})
.collect(),
))
})
} else {
Task::ready(Ok(Vec::new()))
Task::ready(Ok(Some(Vec::new())))
}
}
}
@@ -247,7 +246,7 @@ impl CompletionProvider for SlashCommandCompletionProvider {
_: editor::CompletionContext,
window: &mut Window,
cx: &mut Context<Editor>,
) -> Task<Result<Vec<project::Completion>>> {
) -> Task<Result<Option<Vec<project::Completion>>>> {
let Some((name, arguments, command_range, last_argument_range)) =
buffer.update(cx, |buffer, _cx| {
let position = buffer_position.to_point(buffer);
@@ -291,7 +290,7 @@ impl CompletionProvider for SlashCommandCompletionProvider {
Some((name, arguments, command_range, last_argument_range))
})
else {
return Task::ready(Ok(Vec::new()));
return Task::ready(Ok(Some(Vec::new())));
};
if let Some((arguments, argument_range)) = arguments {

View File

@@ -100,7 +100,7 @@ impl PickerDelegate for SlashCommandDelegate {
cx: &mut Context<Picker<Self>>,
) -> Task<()> {
let all_commands = self.all_commands.clone();
cx.spawn_in(window, |this, mut cx| async move {
cx.spawn_in(window, async move |this, cx| {
let filtered_commands = cx
.background_spawn(async move {
if query.is_empty() {
@@ -119,7 +119,7 @@ impl PickerDelegate for SlashCommandDelegate {
})
.await;
this.update_in(&mut cx, |this, window, cx| {
this.update_in(cx, |this, window, cx| {
this.delegate.filtered_commands = filtered_commands;
this.delegate.set_selected_index(0, window, cx);
cx.notify();
@@ -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

@@ -0,0 +1,44 @@
[package]
name = "assistant_eval"
version = "0.1.0"
edition.workspace = true
publish.workspace = true
license = "GPL-3.0-or-later"
[lints]
workspace = true
[[bin]]
name = "assistant_eval"
path = "src/main.rs"
[dependencies]
anyhow.workspace = true
assistant2.workspace = true
assistant_tool.workspace = true
assistant_tools.workspace = true
clap.workspace = true
client.workspace = true
collections.workspace = true
context_server.workspace = true
env_logger.workspace = true
fs.workspace = true
futures.workspace = true
gpui.workspace = true
gpui_tokio.workspace = true
itertools.workspace = true
language.workspace = true
language_model.workspace = true
language_models.workspace = true
node_runtime.workspace = true
project.workspace = true
prompt_store.workspace = true
regex.workspace = true
release_channel.workspace = true
reqwest_client.workspace = true
serde.workspace = true
serde_json.workspace = true
serde_json_lenient.workspace = true
settings.workspace = true
smol.workspace = true
util.workspace = true

View File

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

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