Compare commits

...

517 Commits

Author SHA1 Message Date
Max Brunsfeld
c20204d269 collab 0.3.4 2022-12-13 11:17:37 -08:00
Max Brunsfeld
45bfcfc3b8 Fix excessive delay before clearing stale room data
Co-authored-by: Antonio Scandurra <antonio@zed.dev>
2022-12-13 11:17:20 -08:00
Max Brunsfeld
5218a2f966 collab 0.3.3 2022-12-13 10:17:01 -08:00
Max Brunsfeld
95748123b5 Merge remote-tracking branch 'origin/collab-0.3.x' 2022-12-13 10:16:25 -08:00
Max Brunsfeld
6ad326ac58 Wait longer before deleting outdated rooms from the database
Co-authored-by: Antonio Scandurra <antonio@zed.dev>
2022-12-13 10:14:43 -08:00
Mikayla Maki
b0652c55c6 Merge pull request #1968 from zed-industries/fix-text-size-in-updates
Fix text size in notifications
2022-12-13 10:00:24 -08:00
Mikayla Maki
790ef19a48 Fix mis-set variables 2022-12-13 09:58:04 -08:00
Antonio Scandurra
99c5f8c713 collab 0.3.2 2022-12-13 15:16:41 +01:00
Antonio Scandurra
461c2400ad Merge pull request #1965 from zed-industries/preserve-calls-during-server-restarts
Automatically re-join call when server is restarted
2022-12-13 14:12:32 +01:00
Antonio Scandurra
073a2988e6 Move creation of room_id index into its own migration 2022-12-13 13:57:41 +01:00
Antonio Scandurra
70aac75dd5 Run until parked before asserting about participants in restart test 2022-12-13 13:53:51 +01:00
Antonio Scandurra
4dc838fbb7 Reset connection pool when tearing down the server in tests 2022-12-13 13:51:25 +01:00
Antonio Scandurra
d4c8fa3090 Use a synchronous mutex for ConnectionPool 2022-12-13 13:50:51 +01:00
Antonio Scandurra
a594ba8f8a Simulate server restarts in randomized test 2022-12-13 12:18:38 +01:00
Antonio Scandurra
f1884d608b Allow server to see client disconnection before giving up on reconnecting 2022-12-13 12:17:21 +01:00
Antonio Scandurra
417db95693 Fix typo in index name 2022-12-13 11:44:48 +01:00
Antonio Scandurra
0220d7ba5d Include room_id in CallCanceled message
This ensures we don't accidentally cancel old calls.
2022-12-13 11:43:09 +01:00
Antonio Scandurra
e2b132ef23 💄 2022-12-13 11:37:39 +01:00
Antonio Scandurra
7e8d9d52d3 Delete stray debug statement 2022-12-13 11:36:40 +01:00
Antonio Scandurra
6a6a032f1f Delete stale rooms/participants after RECONNECT_TIMEOUT 2022-12-13 11:32:37 +01:00
Mikayla Maki
fcea254e8e Merge pull request #1963 from zed-industries/fix-workspace-corner-cases
Fix small workspace deserialization corner cases
2022-12-12 17:56:43 -08:00
Mikayla Maki
9bf0a02eae Allow an empty center group to successfully deserialize into an empty pane.
Fix error when deserializing pane axis which caused it's members.len() > 1 invariant to be violated
Fix failure to gain center pane focus when failing to deserialize a center pane entirely

Co-authored-by: Max <max@zed.dev>
2022-12-12 17:51:16 -08:00
Max Brunsfeld
2affbcc495 Merge pull request #1962 from zed-industries/scrolling-breaks-follow
Avoid breaking follow when syncing leader's scroll position
2022-12-12 16:37:58 -08:00
Mikayla Maki
8012e9fcbd Merge pull request #1961 from zed-industries/fix-next-screen-bug
Fixed issue where the NextScreen action would never have an effect
2022-12-12 15:47:16 -08:00
Mikayla Maki
cd2d593a6c Fixed issue where the NextScreen action would never have an effect 2022-12-12 15:36:51 -08:00
Max Brunsfeld
9ef00ea44c Avoid breaking follow when syncing leader's scroll position
Co-authored-by: Mikayla Maki <mikayla@zed.dev>
Co-authored-by: Kay Simmons <kay@zed.dev>
2022-12-12 15:36:30 -08:00
Mikayla Maki
91d6b66fc4 Merge pull request #1959 from zed-industries/serializing-bug-fixes
Add check for if the user wants a blanks workspace when deserializing
2022-12-12 13:37:43 -08:00
Mikayla Maki
5a29a74956 Fetch last workspace explicitly when starting Zed
co-authored-by: Max <max@zed.dev>
2022-12-12 13:29:18 -08:00
Mikayla Maki
db3119b553 Add check for if the user wants a blanks workspace when deserializing 2022-12-12 12:25:52 -08:00
Antonio Scandurra
beea9b68ff Allow re-joining room after server restarts 2022-12-12 16:03:21 +01:00
Antonio Scandurra
82397f34d1 Merge pull request #1950 from zed-industries/reconnect-to-room
Automatically re-join call when client connection drops
2022-12-12 13:40:21 +01:00
Antonio Scandurra
3cd77bfcc4 Always cast connection ids to i32
Postgres doesn't support unsigned types. This also adds indices to
support querying `project_collaborators` and `room_participants`
by connection id.
2022-12-12 11:43:08 +01:00
Antonio Scandurra
456396ca6e Rename connection_lost to answering_connection_lost 2022-12-12 11:43:08 +01:00
Antonio Scandurra
26b5653427 Delete hosted projects from database when connection is lost 2022-12-12 11:43:08 +01:00
Antonio Scandurra
895c365485 Introduce random reconnections in the randomized test 2022-12-12 11:43:08 +01:00
Antonio Scandurra
8fa26bfe18 Fix test_calls_on_multiple_connections after adding room reconnection 2022-12-12 11:43:08 +01:00
Antonio Scandurra
aca3f02590 Re-join room when client temporarily loses connection 2022-12-12 11:43:08 +01:00
Antonio Scandurra
d74fb97158 Remove Executor trait from collab and use an enum instead
This will let us save off the executor and avoid using generics.
2022-12-12 11:43:08 +01:00
Mikayla Maki
5879dcc4e9 Merge pull request #1951 from zed-industries/dock-bugfix
Fix infinite loop in dock position when deserializing
2022-12-09 13:19:44 -08:00
Mikayla Maki
34388a1d31 Updated is_child() to omit self 2022-12-09 12:07:49 -08:00
Mikayla Maki
3a4f8d267a Fix infinite loop in dock position when deserializing 2022-12-09 11:50:24 -08:00
Antonio Scandurra
0366d725ea collab 0.3.1 2022-12-09 08:19:41 +01:00
Antonio Scandurra
8bd7b28056 Merge pull request #1949 from zed-industries/do-not-drop-unregistered
Don't drop `unregistered` column in reconnection support migration
2022-12-09 08:15:53 +01:00
Antonio Scandurra
2697112a8a Don't drop unregistered column in reconnection support migration
We don't use this column anymore because, when a project is unshared, we
simply remove it from the `projects` table. However, this column is expected
in the stable version of the server and the database is shared between stable
and preview. If we dropped it, stable would start throwing errors.
2022-12-09 08:11:18 +01:00
Mikayla Maki
9bd4bc8813 Merge pull request #1940 from zed-industries/terminal-collab-kickoff
WIP - move terminal to project as pre-prep for collaboration
2022-12-08 20:30:32 -08:00
Mikayla Maki
925c9e13bb Remove terminal container view, switch to notify errors 2022-12-08 20:21:00 -08:00
Mikayla Maki
da100a09fb WIP 2022-12-08 20:21:00 -08:00
Mikayla Maki
c42da5c9b9 WIP 2022-12-08 20:21:00 -08:00
Mikayla Maki
2733f91d8c Fix bugs resulting from refactoring the terminal into project and workspace halves 2022-12-08 20:21:00 -08:00
Mikayla Maki
83aefffa38 Rearrange the terminal code to not have a cyclic dependency with the project 2022-12-08 20:21:00 -08:00
Mikayla Maki
1b8763d0cf WIP - move terminal to project as pre-prep for collaboration 2022-12-08 20:21:00 -08:00
Max Brunsfeld
7dde54b052 v0.68.x dev 2022-12-08 15:33:02 -08:00
Kay Simmons
b1e37378dc Merge pull request #1944 from zed-industries/vim-page-movement
Add scroll commands to vim mode
2022-12-08 14:58:19 -08:00
Kay Simmons
e61a38b3a9 remove printline 2022-12-08 14:45:22 -08:00
Kay Simmons
2cf48c03f9 fix final failing tests 2022-12-08 14:39:48 -08:00
Joseph Lyons
ab978ff1a3 collab 0.3.0 2022-12-08 16:35:13 -05:00
Joseph T. Lyons
dcd4b8f7db Merge pull request #1941 from zed-industries/Allow-overwriting-signup-data
Allow overwriting signup data if a user signs up more than once with the same email address
2022-12-08 16:11:28 -05:00
Kay Simmons
2eb335158b Merge pull request #1946 from zed-industries/fix-zombie-tooltips
notify views when hover finishes in tooltip wrapper
2022-12-08 11:37:12 -08:00
Kay Simmons
10aecc310e notify views when hover finishes in tooltip wrapper 2022-12-08 11:26:46 -08:00
Kay Simmons
750e7eb833 Merge pull request #1945 from zed-industries/drag-and-drop-deadzones
Add deadzones to drag and drop
2022-12-08 11:15:42 -08:00
Kay Simmons
36bc90b2b8 Add deadzones to drag and drop 2022-12-07 17:46:00 -08:00
Kay Simmons
f6f41510d2 fix failing tests from incorrect follow behavior 2022-12-07 17:25:48 -08:00
Kay Simmons
cffb064c16 Refactor editor scrolling and implement scroll commands from vim mode 2022-12-07 16:39:32 -08:00
Antonio Scandurra
3313387b28 Merge pull request #1943 from zed-industries/fix-inviting-existing-users-via-different-mail
Fix inviting existing users via a different email address
2022-12-07 14:19:17 +01:00
Joseph Lyons
d71d543337 Ensure that subsequent signup happens after initial
We can't rely on the fact that the test won't run fast enough such that both `created_at`s are the same time.  This ensures the subsequent signup happens after the initial one and that the database doesn't overwrite the initial one.
2022-12-07 08:15:01 -05:00
Antonio Scandurra
665219fb00 Fix inviting user that had already signed up via a different email 2022-12-07 14:07:01 +01:00
Antonio Scandurra
1b8f23eeed Add failing test showcasing inviting existing user via different email 2022-12-07 14:06:59 +01:00
Joseph Lyons
5f31907127 Clean up test 2022-12-07 07:12:27 -05:00
Joseph Lyons
97989b04a0 Remove comment 2022-12-06 17:18:54 -05:00
Joseph Lyons
694840cdd6 Allow overwriting signup data if a user signs up more than once with the same email address 2022-12-06 17:12:12 -05:00
Antonio Scandurra
1920de81d9 Merge pull request #1938 from zed-industries/fix-metrics
Query project count as `i64` instead of `i32` when gathering metrics
2022-12-06 15:04:27 +01:00
Antonio Scandurra
3b5b48c043 Query project count as i64 instead of i32 when gathering metrics
Using the latter will cause a type mismatch when performing the query.
2022-12-06 15:00:32 +01:00
Antonio Scandurra
2080d3efff Merge pull request #1937 from zed-industries/fix-accepted-contact-busy-status
Fix busy status when accepting a contact request
2022-12-06 10:29:58 +01:00
Antonio Scandurra
fc7b01b74e Fix busy status when accepting a contact request
Previously, we would send an contact update when accepting a request
using the same `busy` status for both the requester and the responder.
This was obviously wrong and caused the requester to see their own
busy status as the newly-added responder contact's status.
2022-12-06 10:19:34 +01:00
Antonio Scandurra
f1b35981c2 Merge pull request #1935 from zed-industries/reconnections-2
Move in-memory server state to the database
2022-12-06 09:22:59 +01:00
Antonio Scandurra
744714b478 Remove unused UserId import from seed script 2022-12-06 09:07:25 +01:00
Max Brunsfeld
35549ffabe Merge pull request #1936 from zed-industries/c-outline-pointers
Include outline items for c/c++ functions returning pointers
2022-12-05 14:03:49 -08:00
Max Brunsfeld
855f17c378 Include outline items for c/c++ functions returning pointers-to-pointers, references
Co-authored-by: Julia Risley <julia@zed.dev>
2022-12-05 13:56:21 -08:00
Mikayla Maki
f23f294b86 Merge pull request #1858 from zed-industries/add-lisp
Added tree sitter support for scheme and racket
2022-12-05 11:40:52 -08:00
Mikayla Maki
0921178b42 Got tree sitter integration to a shippable place 2022-12-05 11:31:52 -08:00
Mikayla Maki
30872d3992 Added experimental support for scheme, racket, and commonlisp 2022-12-05 11:31:49 -08:00
Antonio Scandurra
cd08d289aa Fix warnings 2022-12-05 19:45:56 +01:00
Antonio Scandurra
9a62150dce Merge branch 'main' into reconnections-2 2022-12-05 19:18:40 +01:00
Antonio Scandurra
7bbd97cfb9 Send diagnostic summaries synchronously 2022-12-05 19:07:06 +01:00
Antonio Scandurra
5443d9cffe Return project collaborators and connection IDs in a RoomGuard 2022-12-05 18:37:01 +01:00
Antonio Scandurra
be3fb1e985 Update sea-orm to fix bug on failure to commit transactions
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
2022-12-05 18:36:25 +01:00
Antonio Scandurra
b97c35a468 Remove project_id foreign key from room_participants 2022-12-05 15:16:06 +01:00
Antonio Scandurra
eec3df09be Upgrade sea-orm 2022-12-05 14:56:01 +01:00
Antonio Scandurra
d3c411677a Remove random pauses to prevent the database from deadlocking 2022-12-05 12:03:45 +01:00
Antonio Scandurra
d97a8364ad Retry transactions if there's a serialization failure during commit 2022-12-05 10:49:53 +01:00
Antonio Scandurra
0ed731780a Remove duplication between transaction and room_transaction 2022-12-05 09:46:03 +01:00
Julia
11c1254e71 Merge pull request #1924 from zed-industries/simon-says-dont-move
Do not reorder tab opened by follower to end of item list
2022-12-04 13:00:07 -05:00
Mikayla Maki
6ba225f3a5 Merge pull request #1798 from zed-industries/serializing-workspaces
Serializing workspaces
2022-12-03 16:56:02 -08:00
Mikayla Maki
55eb0a3742 Fixed and error message and properly initialized the DB 2022-12-03 16:46:35 -08:00
Mikayla Maki
1ce0863158 Removed old code 2022-12-03 16:27:45 -08:00
Mikayla Maki
d609237c32 Found db parallelism problem :( 2022-12-03 16:26:37 -08:00
Mikayla Maki
4288f10873 And library change 2022-12-03 16:13:02 -08:00
Mikayla Maki
80e035cc2c Fixed bad rebase 2022-12-03 16:12:07 -08:00
Mikayla Maki
a1f273278b Added user notifications 2022-12-03 16:06:02 -08:00
Mikayla Maki
ffcad4e4e2 WIP fixing dock problems 2022-12-03 16:06:02 -08:00
Mikayla Maki
5262e8c77e CHANGE LOCK TO NOT BE DROPPED INSTANTLY. DANG U RUST
co-authored-by: kay@zed.dev
2022-12-03 16:06:02 -08:00
Mikayla Maki
5e240f98f0 Reworked thread safe connection be threadsafer,,,, again
Co-Authored-By: kay@zed.dev
2022-12-03 16:06:02 -08:00
Mikayla Maki
189a820113 First draft of graceful corruption restoration 2022-12-03 16:06:02 -08:00
Mikayla Maki
b8d423555b Added side bar restoration 2022-12-03 16:06:02 -08:00
Kay Simmons
8a48567857 Reactivate the correct item in each pane when deserializing 2022-12-03 16:06:01 -08:00
Kay Simmons
f68e8d4664 Address some issues with the sqlez_macros 2022-12-03 16:06:01 -08:00
Kay Simmons
1b225fa37c fix test failures 2022-12-03 16:06:01 -08:00
Kay Simmons
a29ccb4ff8 make thread safe connection more thread safe
Co-Authored-By: Mikayla Maki <mikayla@zed.dev>
2022-12-03 16:06:01 -08:00
Mikayla Maki
9cd6894dc5 Added multi-threading problem test 2022-12-03 16:06:01 -08:00
Kay Simmons
dd9d20be25 Added sql! proc macro which checks syntax errors on sql code and displays them with reasonable underline locations
Co-Authored-By: Mikayla Maki <mikayla@zed.dev>
2022-12-03 16:06:01 -08:00
Mikayla Maki
260164a711 Added basic syntax checker to sqlez 2022-12-03 16:06:01 -08:00
Kay Simmons
359b8aaf47 rename sql_method to query and adjust the syntax to more closely match function definitions 2022-12-03 16:06:01 -08:00
Kay Simmons
1cc3e4820a working serialized writes with panics on failure. Everything seems to be working 2022-12-03 16:06:01 -08:00
Mikayla Maki
b01243109e Removed database test files 2022-12-03 16:06:01 -08:00
Mikayla Maki
3e0f9d27a7 Made dev tools not break everything about the db
Also improved multi statements to allow out of order parameter binding in statements
Ensured that all statements are run for maybe_row and single, and that of all statements only 1 of them returns only 1 row
Made bind and column calls add useful context to errors

Co-authored-by: kay@zed.dev
2022-12-03 16:06:01 -08:00
Mikayla Maki
2dc1130902 Added extra sql methods 2022-12-03 16:06:01 -08:00
Mikayla Maki
37174f45f0 Touched up sql macro 2022-12-03 16:06:01 -08:00
Mikayla Maki
76c42af62a Finished terminal working directory restoration 2022-12-03 16:06:01 -08:00
Mikayla Maki
cf4c103660 Fixed workspace tests 2022-12-03 16:06:01 -08:00
Mikayla Maki
e1eff3f4cd WIP: Some bugs switching to database provided IDs, terminal titles don't reload when restored from serialized, workspace tests are no longer passing but should be easy to fix when it isn't 11:44 2022-12-03 16:06:01 -08:00
Mikayla Maki
a47f2ca445 Added UUID based, stable workspace ID for caching on item startup. Completed first sketch of terminal persistence. Still need to debug it though.... 2022-12-03 16:06:01 -08:00
Mikayla Maki
e659823e6c WIP termial implementation. need some way of getting the currently valid workspace ID 2022-12-03 16:06:01 -08:00
Mikayla Maki
a8ed95e1dc Implementing persistence for the terminal working directory, found an issue with my current data model. :( 2022-12-03 16:06:01 -08:00
Kay Simmons
cb1d2cd1f2 WIP serializing and deserializing editors 2022-12-03 16:06:01 -08:00
Mikayla Maki
9077b058a2 removed test file 2022-12-03 16:06:01 -08:00
Mikayla Maki
7ceb5e815e workspace level integration of serialization complete! Time for item level integration....
Co-Authored-By: kay@zed.dev
2022-12-03 16:06:01 -08:00
Mikayla Maki
992b94eef3 Rebased to main 2022-12-03 16:06:01 -08:00
Mikayla Maki
a0cb6542ba Polishing workspace data structures
Co-authored-by: kay@zed.dev
2022-12-03 16:06:01 -08:00
Mikayla Maki
6530658c3e Added center group deserialization 2022-12-03 16:06:01 -08:00
Kay Simmons
75d3d46b1b wip serialize editor 2022-12-03 16:06:01 -08:00
Kay Simmons
d20d21c6a2 Dock persistence working!
Co-Authored-By: Mikayla Maki <mikayla@zed.dev>
2022-12-03 16:06:01 -08:00
Kay Simmons
c1f7902309 wip 2022-12-03 16:06:01 -08:00
Mikayla Maki
4798161118 Distributed database pattern built.
Co-Authored-By: kay@zed.dev
2022-12-03 16:06:01 -08:00
Mikayla Maki
2a5565ca93 WIP 2022-12-03 16:06:00 -08:00
Mikayla Maki
a5edac312e Moved to workspaces crate... don't feel great about it 2022-12-03 16:05:26 -08:00
Mikayla Maki
e578f2530e WIP commit, migrating workspace serialization code into the workspace 2022-12-03 16:05:25 -08:00
Mikayla Maki
c84201fc9f Done first draft of strongly typed migrations 2022-12-03 16:05:25 -08:00
Kay Simmons
4a00f0b062 Add typed statements 2022-12-03 16:05:25 -08:00
Mikayla Maki
64ac84fdf4 Re-use big union statement for get_center_pane 2022-12-03 16:05:25 -08:00
Mikayla Maki
f27a9d77d1 Finished the bulk of workspace serialization. Just items and wiring it all through.
Co-Authored-By: kay@zed.dev
2022-12-03 16:05:25 -08:00
Mikayla Maki
0186289420 Refined sqlez, implemented 60% of workspace serialization sql 2022-12-03 16:05:25 -08:00
Mikayla Maki
6b214acbc4 Got Zed compiling again 🥰 2022-12-03 16:05:25 -08:00
Kay Simmons
d419f27d75 replace worktree roots table with serialized worktree roots list 2022-12-03 16:05:25 -08:00
Kay Simmons
eb0598dac2 more refactoring and slightly better api 2022-12-03 16:05:25 -08:00
Mikayla Maki
aa7b909b7b WIP3 2022-12-03 16:05:25 -08:00
Mikayla Maki
b552f1788c WIP2 2022-12-03 16:05:25 -08:00
Mikayla Maki
d492cbced9 WIP 2022-12-03 16:05:25 -08:00
Mikayla Maki
19aac6a57f Moved docks to a better position 2022-12-03 16:05:25 -08:00
Kay Simmons
685bc9fed3 impl bind and column and adjust pane tables 2022-12-03 16:05:25 -08:00
Mikayla Maki
406663c75e Converted to sqlez, so much nicer 2022-12-03 16:05:25 -08:00
Mikayla Maki
c8face33fa WIP, incorporating type parsing using new sqlez patterns 2022-12-03 16:05:25 -08:00
Mikayla Maki
3c1b747f64 WIP almost compiling with sqlez 2022-12-03 16:05:25 -08:00
Mikayla Maki
777f05eb76 Finished implementing the workspace stuff 2022-12-03 16:05:25 -08:00
Mikayla Maki
395070cb92 remove submodule 2022-12-03 16:05:25 -08:00
Mikayla Maki
a4a1859dfc Added sqlez api 2022-12-03 16:05:25 -08:00
Kay Simmons
e3fdfe02e5 WIP switching to sqlez 2022-12-03 16:05:24 -08:00
Mikayla Maki
7744c9ba45 Abandoning rusqlite, the API is miserable 2022-12-03 16:04:10 -08:00
Mikayla Maki
e6ca0adbcb Fixed failing serialization issues 2022-12-03 16:04:10 -08:00
Mikayla Maki
c105f41487 Started working on dock panes
co-authored-by: kay@zed.dev
2022-12-03 16:04:10 -08:00
Mikayla Maki
ddecba143f Refactored workspaces API and corrected method headers + fixed bug caused by migration failures
co-authored-by: kay@zed.dev
2022-12-03 16:04:10 -08:00
Mikayla Maki
3451a3c7fe Rebase - Got Zed compiling and fixed a build error due to conflicting dependencies that cargo didn't catch :(
Co-Authored-By: kay@zed.dev
2022-12-03 16:04:10 -08:00
Mikayla Maki
b9cbd4084e WIP: fixing up behavior of workspace initialization 2022-12-03 16:04:10 -08:00
Mikayla Maki
5505a776e6 Figured out a good schema for the pane serialization stuff 2022-12-03 16:04:10 -08:00
Mikayla Maki
46ff0885f0 WIP: Writing tests 2022-12-03 16:04:10 -08:00
Mikayla Maki
a9dc46c950 added stubs for more tests 2022-12-03 16:04:10 -08:00
Mikayla Maki
7d33520b2c Tidied up code, managed errors, etc. 2022-12-03 16:04:10 -08:00
Mikayla Maki
e9ea751f3d All workspace tests passing :D 2022-12-03 16:04:10 -08:00
Mikayla Maki
d7bbfb82a3 Rebase - Successfully detecting workplace IDs :D 2022-12-03 16:04:10 -08:00
Mikayla Maki
500ecbf915 Rebase fix + Started writing the real SQL we're going to need 2022-12-03 16:04:10 -08:00
K Simmons
e5c6393f85 rebase fix - almost have serialize_workspace piped to the workspace constructor. Just a few compile errors left 2022-12-03 16:04:10 -08:00
K Simmons
73f0459a0f wip 2022-12-03 16:04:10 -08:00
K Simmons
0c466f806c WIP 2022-12-03 16:04:10 -08:00
Mikayla Maki
b48e28b555 Built first draft of workspace serialization schemas, started writing DB tests
Co-Authored-By: kay@zed.dev
2022-12-03 16:04:10 -08:00
Mikayla Maki
60ebe33518 Rebase fix - Reworking approach to sql for take 2022-12-03 16:04:10 -08:00
Mikayla Maki
72c1ee904b Fix rebase - Broken tab 2022-12-03 16:04:10 -08:00
Julia
57e10b7dd5 Cleanup dbg 2022-12-02 16:42:49 -05:00
Julia
4bc1d77535 Fix tab following order test to wait for file open to propagate
Now it can actually repro the original bug

Co-Authored-By: Max Brunsfeld <max@zed.dev>
2022-12-02 16:09:37 -05:00
Antonio Scandurra
d96f524fb6 WIP: Manually rollback transactions to avoid spurious savepoint failure
TODO:
- Avoid unwrapping transaction after f(tx)
- Remove duplication between `transaction` and `room_transaction`
- Introduce random delay before and after committing a transaction
- Run lots of randomized tests
- Investigate diverging diagnostic summaries

Co-Authored-By: Max Brunsfeld <max@zed.dev>
2022-12-02 20:36:50 +01:00
Antonio Scandurra
1c30767592 Remove stale Error variant
Co-Authored-By: Max Brunsfeld <max@zed.dev>
2022-12-02 19:20:51 +01:00
Antonio Scandurra
969c314315 Merge branch 'main' into reconnections-2 2022-12-02 19:09:33 +01:00
Antonio Scandurra
568de814aa Delete empty rooms 2022-12-02 16:56:41 +01:00
Antonio Scandurra
27f6ae945d Clear stale data on startup
This is a stopgap measure until we introduce reconnection support.
2022-12-02 16:30:00 +01:00
Antonio Scandurra
1b46b7a7d6 Move modules into collab library as opposed to using the binary
This ensures that we can use collab's modules from the seed script
as well.
2022-12-02 14:37:52 +01:00
Antonio Scandurra
7502558631 Make all tests pass again after migration to sea-orm 2022-12-02 14:22:36 +01:00
Antonio Scandurra
48b6ee313f Use i32 to represent Postgres INTEGER types in Rust 2022-12-02 13:58:54 +01:00
Antonio Scandurra
dec5f37e4e Finish porting remaining db methods to sea-orm 2022-12-02 13:58:23 +01:00
Julia
239a04ea5b Add test that should have exercised tab reordering while following
Except it doesn't, it passes both with and without the prior commit.
Investigate further
2022-12-02 00:31:16 -05:00
Joseph T. Lyons
ea03b48243 Merge pull request #1876 from zed-industries/update-release-urls-to-match-new-zed.dev-url-format
Update release urls to match new zed.dev url format
2022-12-01 20:32:14 -05:00
Antonio Scandurra
585ac3e1be WIP 2022-12-01 18:39:24 +01:00
Antonio Scandurra
29a4baf346 Replace i32 with u32 for database columns
We never expect to return signed integers and so we shouldn't use
a signed type. I think this was a limitation of sqlx.
2022-12-01 17:47:51 +01:00
Antonio Scandurra
cfdf0a57b8 Implement Database::update_project 2022-12-01 17:36:36 +01:00
Antonio Scandurra
944d6554de Implement Database::unshare_project 2022-12-01 16:26:13 +01:00
Antonio Scandurra
e3ac67784a Implement Database::project_guest_connection_ids 2022-12-01 16:23:29 +01:00
Antonio Scandurra
62624b81d8 Avoid using col_expr whenever possible
...and use the more type-safe `::set`.
2022-12-01 16:17:27 +01:00
Antonio Scandurra
256e3e8e0f Get basic calls working again with sea-orm 2022-12-01 16:17:24 +01:00
Antonio Scandurra
aebc6326a9 Implement Database::create_room 2022-12-01 15:22:20 +01:00
Antonio Scandurra
db1d93576f Go back to a compiling state, panicking on unimplemented db methods 2022-12-01 15:13:57 +01:00
Antonio Scandurra
d2385bd6a0 Start using the new sea-orm backed database 2022-12-01 14:41:59 +01:00
Antonio Scandurra
19d14737bf Implement signups using sea-orm 2022-12-01 11:58:07 +01:00
Antonio Scandurra
4f864a20a7 Implement invite codes using sea-orm 2022-12-01 11:10:51 +01:00
Antonio Scandurra
2375741bdf Implement db2::Database::fuzzy_search_users 2022-12-01 10:09:53 +01:00
Julia
46f1d5f5c2 Avoid moving tab when leader item updates 2022-12-01 00:29:58 -05:00
Max Brunsfeld
d70996bb99 collab 0.2.5 2022-11-30 14:10:10 -08:00
Julia
5a0c39cbed Merge pull request #1922 from zed-industries/dont-panic-clip-instead
Dont panic in point conversion, clip instead
2022-11-30 13:28:10 -05:00
Julia
41b2fde10d Style
Co-Authored-By: Max Brunsfeld <max@zed.dev>
2022-11-30 13:11:08 -05:00
Julia
023ecd595b Change verify macro to debug panic
Co-Authored-By: Max Brunsfeld <max@zed.dev>
2022-11-30 13:03:15 -05:00
Julia
2b979d3b88 Don't panic rope point conversions 2022-11-30 12:43:43 -05:00
Julia
5965113fc8 Add verify macros & use in one location for point conversion 2022-11-30 12:43:43 -05:00
Antonio Scandurra
4c04d512db Implement db2::Database::remove_contact 2022-11-30 17:39:17 +01:00
Antonio Scandurra
d1a44b889e Implement contacts using sea-orm
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
2022-11-30 17:36:25 +01:00
Antonio Scandurra
04d553d4d3 Implement db2::Database::get_user_metrics_id 2022-11-30 15:06:04 +01:00
Antonio Scandurra
2e24d128db Implement access tokens using sea-orm 2022-11-30 14:47:03 +01:00
Antonio Scandurra
9e59056e7f Implement db2::Database::get_user_by_github_account 2022-11-30 14:18:46 +01:00
Antonio Scandurra
d9a892a423 Make some db tests pass against the new sea-orm implementation 2022-11-30 12:13:16 +01:00
Joseph T. Lyons
3a1cd6ed3a Merge pull request #1913 from zed-industries/Add-column-to-signups-for-added-to-mailing-list
Add "added_to_mailing_list" column on signups table
2022-11-29 19:30:11 -05:00
Joseph T. Lyons
9f9398476d Merge pull request #1920 from zed-industries/order-invites-by-creation-time
Order invites by creation time
2022-11-29 14:28:53 -05:00
Antonio Scandurra
b7294887c7 WIP: move to a non-generic test database struct
Co-Authored-By: Mikayla Maki <mikayla@zed.dev>
Co-Authored-By: Julia Risley <julia@zed.dev>
2022-11-29 19:20:11 +01:00
Joseph Lyons
049c0f8ba4 Order invites by creation time 2022-11-29 12:57:51 -05:00
Antonio Scandurra
11a39226e8 Start on a new db2 module that uses SeaORM 2022-11-29 16:49:04 +01:00
Antonio Scandurra
ac24600a40 Start moving towards using sea-query to construct queries 2022-11-29 13:55:08 +01:00
Antonio Scandurra
d525cfd697 Increase probability of creating new files in randomized test 2022-11-29 11:02:14 +01:00
Joseph Lyons
4436ec48eb Add "added_to_mailing_list" column on signups table 2022-11-29 02:13:13 -05:00
Joseph T. Lyons
5a9a0f9fa5 Merge pull request #1918 from zed-industries/remove-sign-in-telemetry-event
Remove sign in telemetry event
2022-11-29 01:59:33 -05:00
Joseph Lyons
d2cd9c94f7 Remove sign in telemetry event 2022-11-28 18:56:27 -05:00
Max Brunsfeld
3adc0b947f Merge pull request #1917 from zed-industries/integer-excerpt-ids
Use integers for excerpt ids, map them to locators internally
2022-11-28 14:27:35 -08:00
Max Brunsfeld
718f802157 Implement Copy for multibuffer anchors 2022-11-28 14:18:49 -08:00
Max Brunsfeld
f71145bb32 Add a layer of indirection between excerpt ids and locators 2022-11-28 14:18:49 -08:00
Antonio Scandurra
cd2a8579b9 Capture runnable backtraces only when detecting nondeterminism 2022-11-28 19:35:33 +01:00
Antonio Scandurra
d0709e7bfa Error if project is disconnected after getting completions response 2022-11-28 19:19:24 +01:00
Antonio Scandurra
fa3f100eff Introduce a new detect_nondeterminism = true attribute to gpui::test 2022-11-28 19:01:28 +01:00
Antonio Scandurra
f0a721032d Remove non-determinism caused by random entropy when reconnecting 2022-11-28 18:56:11 +01:00
Antonio Scandurra
0a565c6bae 💄 2022-11-28 17:44:18 +01:00
Antonio Scandurra
af2a2d2494 Return error when waiting on a worktree snapshot after disconnecting 2022-11-28 17:43:40 +01:00
Antonio Scandurra
cd0b663f62 Introduce per-room lock acquired before committing a transaction 2022-11-28 17:00:47 +01:00
Antonio Scandurra
2a0ddd99d2 Error if project is disconnected after getting code actions response 2022-11-28 15:05:34 +01:00
Antonio Scandurra
5581674f8f After completing LSP request, return an error if guest is disconnected 2022-11-28 14:39:27 +01:00
Antonio Scandurra
b0e1d6bc7f Fix integration test incorrectly assuming a certain ordering 2022-11-28 13:57:15 +01:00
Antonio Scandurra
ae11e4f798 Check the correct serialization failure code when retrying transaction 2022-11-28 13:56:03 +01:00
Max Brunsfeld
0b0fe91545 Merge pull request #1912 from zed-industries/matching-brackets-must-contain-range
Fix enclosing-bracket bug that appeared in JS for loops
2022-11-23 13:44:48 -08:00
Max Brunsfeld
aeea47323a Fix enclosing-bracket bug that appeared in JS for loops
Previously, we were relying on the tree-sitter query's range restriction to
avoid returning brackets that did not contain the given range. But the
query's range restriction only guarantees that we don't descend into parent
nodes unless they intersect the range.
2022-11-23 13:37:22 -08:00
Julia
e4185f38cf Merge pull request #1910 from zed-industries/lsp-coordinate-clamp
Don't trust LSP coordinates to be within document bounds
2022-11-23 14:07:37 -05:00
Julia
09e6d44873 Move Unclipped into separate file 2022-11-23 14:02:11 -05:00
Julia
525d84e5bf Remove spurious lifetimes
Co-Authored-By: Max Brunsfeld <max@zed.dev>
2022-11-23 13:52:39 -05:00
Julia
55ca085d7d Consistency in prefix/suffix/signature of UTF16 point to point conversion
Co-Authored-By: Max Brunsfeld <max@zed.dev>
2022-11-23 13:52:18 -05:00
Julia
03cfd23ac5 Bump protocol version back down as proto changes are non-breaking 2022-11-23 13:40:49 -05:00
Julia
a666ca3e40 Collapse proto Point into the one kind of use case, utf-16 coords
Co-Authored-By: Max Brunsfeld <max@zed.dev>
2022-11-23 13:28:44 -05:00
Julia
b58ae8bdd7 Clip diagnostic range before and during empty range expansion
Co-Authored-By: Max Brunsfeld <max@zed.dev>
2022-11-23 13:21:05 -05:00
Max Brunsfeld
5e7652698d v0.67.x dev 2022-11-23 09:56:06 -08:00
Julia
e51cbf67ab Fixup compile errors 2022-11-22 02:49:47 -05:00
Julia
8c75df30cb Wrap a bunch of traits for Unclipped<T> 2022-11-21 15:58:44 -05:00
Julia
1c84e77c37 Start adding concept of Unclipped text coordinates
Co-Authored-By: Max Brunsfeld <max@zed.dev>
2022-11-21 15:48:25 -05:00
Max Brunsfeld
b3a92979a3 Merge pull request #1911 from zed-industries/single-file-worktree-event-extension
Fix file extension retrieval for single-file worktrees
2022-11-21 12:41:35 -08:00
Max Brunsfeld
55d3c09b6b Fix file extension retrieval for single-file worktrees
Previously, we used the file's 'path' method, which only returns the relative
path from the worktree root.
2022-11-21 12:34:36 -08:00
Julia
436c89650a Rename clamped -> clipped 2022-11-21 15:23:00 -05:00
Julia
4ead1ecbbf Simply logic of this method
Co-Authored-By: Max Brunsfeld <max@zed.dev>
2022-11-21 14:25:01 -05:00
Julia
074e3cfbd6 Clamp UTF-16 to point conversions 2022-11-21 14:25:01 -05:00
Julia
bb32599ded Clamp for all UTF-16 to offset conversions which used to use ToOffset 2022-11-21 14:25:01 -05:00
Julia
f9cbed5a1f Clamp UTF-16 coordinate while performing LSP edits rather than panicing 2022-11-21 11:48:13 -05:00
Kay Simmons
0078bea877 change bump-version to install jq if its not already installed 2022-11-18 13:42:46 -08:00
Kay Simmons
bb80cee19e Merge pull request #1814 from zed-industries/golden-ratio
Active Pane Magnification
2022-11-18 13:14:03 -08:00
Kay Simmons
0c50c0959d Merge pull request #1906 from zed-industries/mouse-down-capture-on-click-fix
Fix mouse down falling through popovers
2022-11-18 13:10:50 -08:00
Kay Simmons
75b8a12ab3 address issue where mouse down events weren't getting captured after the multiple handlers change 2022-11-18 13:04:27 -08:00
Antonio Scandurra
4c1b4953c1 Remove version from Room
We won't need it once we add the per-room lock.
2022-11-18 20:18:48 +01:00
Antonio Scandurra
c3d556d9bd Don't take an Arc<Server> in message handlers 2022-11-18 11:45:42 +01:00
Max Brunsfeld
d090d230e2 Merge pull request #1903 from zed-industries/override-pyright-completion-sorting
Add LspAdapter hook for processing completions, fix completion sorting from Pyright
2022-11-17 15:30:07 -08:00
Max Brunsfeld
bca635e5d3 Add LspAdapter hook for processing completions, fix completion sorting from Pyright 2022-11-17 15:26:46 -08:00
Julia
3938adf60a Merge pull request #1902 from zed-industries/event-handlers-are-multitude
Allow having multiple mouse event handlers of the same kind
2022-11-17 17:19:32 -05:00
Julia
6537def97e Allow having multiple mouse event handlers of the same kind
Co-Authored-By: Kay Simmons <kay@zed.dev>
2022-11-17 17:01:34 -05:00
Max Brunsfeld
5020c70a04 collab 0.2.4 2022-11-17 11:44:29 -08:00
Mikayla Maki
0a63d2e3e1 Merge pull request #1900 from zed-industries/fix-terminal-performance
Check for wakeups correctly
2022-11-17 11:17:13 -08:00
Mikayla Maki
ce0dfde8ee Check for wakeups correctly 2022-11-17 11:14:31 -08:00
Antonio Scandurra
44bb2ce024 Rename Store to ConnectionPool 2022-11-17 19:03:59 +01:00
Antonio Scandurra
6c83be3f89 Remove obsolete code from Store 2022-11-17 18:46:39 +01:00
Antonio Scandurra
0a4517f97e WIP: Introduce a db field to Session
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
2022-11-17 17:30:26 +01:00
Antonio Scandurra
c34a5f3177 Introduce a new Session struct to server message handlers
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
2022-11-17 17:11:06 +01:00
Antonio Scandurra
4f39181c4c Revert "Don't replace newer diagnostics with older ones"
This reverts commit 71eeeedc05.
2022-11-17 16:57:40 +01:00
Antonio Scandurra
e7e45be6e1 Revert "Wait for previous UpdateFollowers message ack before sending new ones"
This reverts commit fe93263ad4.
2022-11-17 16:57:32 +01:00
Antonio Scandurra
8621c88a3c Use int8 for scan_id and inode in Postgres 2022-11-17 16:56:43 +01:00
Antonio Scandurra
7dae21cb36 🎨 2022-11-17 15:35:18 +01:00
Antonio Scandurra
0f4598a243 Fix seed script 2022-11-17 15:34:35 +01:00
Antonio Scandurra
6415809b61 Fix errors in Postgres schema 2022-11-17 15:34:12 +01:00
Antonio Scandurra
fe93263ad4 Wait for previous UpdateFollowers message ack before sending new ones 2022-11-17 14:12:00 +01:00
Antonio Scandurra
3b34d858b5 Remove unwrap from Server::share_project 2022-11-17 13:33:26 +01:00
Antonio Scandurra
71eeeedc05 Don't replace newer diagnostics with older ones 2022-11-17 12:21:51 +01:00
Antonio Scandurra
532a599239 Use Db::get_guest_connection_ids in other db methods 2022-11-17 11:38:00 +01:00
Nathan Sobo
9eee22ff0a Fix column name in query 2022-11-16 19:40:53 -07:00
Nathan Sobo
94fe93c6ee Move unshare_project to db module 2022-11-16 18:28:45 -07:00
Joseph Lyons
93824dd239 Fix top-level header in discord webhook action 2022-11-16 20:02:15 -05:00
Nathan Sobo
e5f05c9f3b Move leave_project from Store to db module 2022-11-16 17:45:47 -07:00
Nathan Sobo
bdb521cb6b Fix typo in query 2022-11-16 16:52:05 -07:00
Joseph Lyons
c613c98e37 Move comment to correct location 2022-11-16 17:28:50 -05:00
Max Brunsfeld
4e4299d500 v0.66.x dev 2022-11-16 14:22:18 -08:00
Antonio Scandurra
c1291a093b WIP: Allow subscribing to remote entity before creating a model
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
Co-Authored-By: Max Brunsfeld <max@zed.dev>
2022-11-16 19:51:24 +01:00
Mikayla Maki
ccc8c247a1 Merge pull request #1894 from zed-industries/opt-as-meta-fix
Fix small terminal bugs
2022-11-16 10:50:02 -08:00
Mikayla Maki
8e6c5dbc3b Fix unscaled scrolling when using an imprecise mouse wheel 2022-11-16 10:44:13 -08:00
Mikayla Maki
3c53fcdb43 Added alt-left: move word left and alt-right: move word right in the terminal for for antonio 2022-11-16 09:59:23 -08:00
Antonio Scandurra
adf43c87dd Batch some of the new queries in Db
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
2022-11-16 17:19:06 +01:00
Antonio Scandurra
faf265328e Wait for acknowledgment before sending the next diagnostic summary 2022-11-16 16:03:01 +01:00
Antonio Scandurra
9bc57c0c61 Move Store::start_language_server to Db 2022-11-16 15:48:26 +01:00
Antonio Scandurra
95369f92eb Move Store::update_diagnostic_summary to Db 2022-11-16 15:41:33 +01:00
Antonio Scandurra
117458f4f6 Send worktree updates after project metadata has been sent 2022-11-16 14:58:11 +01:00
Antonio Scandurra
eeb32fa888 Improve queries for composite primary keys 2022-11-16 11:07:39 +01:00
Antonio Scandurra
f9567ae116 Cascade deletes when project is deleted 2022-11-16 10:41:36 +01:00
Antonio Scandurra
c151c87e12 Correctly leave projects when leaving room 2022-11-16 10:36:48 +01:00
Antonio Scandurra
3190236396 Update worktree entry instead of erroring when it already exists 2022-11-16 08:57:19 +01:00
Joseph T. Lyons
17dfbb91ba Merge pull request #1897 from zed-industries/allow-users-to-sign-up-multiple-times 2022-11-15 20:13:43 -05:00
Joseph Lyons
c3cf056fc5 allow users to sign up multiple times without throwing a 500 2022-11-15 20:04:56 -05:00
Nathan Sobo
275f0ae492 collab 0.2.3 2022-11-15 15:45:04 -07:00
Nathan Sobo
f4e9759f26 Merge pull request #1896 from zed-industries/fix-invites
Once we email someone an invite, honor the invitation
2022-11-15 15:43:30 -07:00
Nathan Sobo
fdf758e050 Once we email someone an invite, honor the invitation
Previously, we were waiting to decrement the invite_count until a user
confirmed their email address, which created weird situations where we would
email people only to have them get a 500 when trying to sign up. Now, we
decrement the invite_count upon sending the email and always honor the
invitation.

Co-Authored-By: Joseph Lyons <joseph@zed.dev>
Co-Authored-By: Max Brunsfeld <max@zed.dev>
2022-11-15 15:36:59 -07:00
Max Brunsfeld
0dfacd7ffa Merge pull request #1895 from zed-industries/ruby-solargraph
Add ruby LSP support via SolarGraph
2022-11-15 12:45:54 -08:00
Max Brunsfeld
36c07f940c Add ruby LSP support via SolarGraph 2022-11-15 12:34:43 -08:00
Mikayla Maki
01929037f1 fixed clear problem 2022-11-15 12:02:09 -08:00
Antonio Scandurra
0817f905a2 Fix syntax error in schema 2022-11-15 18:02:07 +01:00
Antonio Scandurra
ad67f5e4de Always use the database to retrieve collaborators for a project 2022-11-15 17:49:37 +01:00
Antonio Scandurra
e9eadcaa6a Move Store::update_worktree to Db::update_worktree 2022-11-15 17:18:28 +01:00
Antonio Scandurra
4b1dcf2d55 Always use strings to represent paths over the wire
Previously, the protocol used a mix of strings and bytes without any consistency.

When we go to multiple platforms, we won't be able to mix encodings of paths anyway.
We don't know this is the right approach, but it at least makes things consistent
and easy to read in the database, on the wire, etc. Really, we should be using entry
ids etc to refer to entries on the wire anyway, but there's a chance this is the
wrong decision.

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
2022-11-15 16:46:17 +01:00
Antonio Scandurra
974ef967a3 Move Store::join_project to Db::join_project
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
2022-11-15 16:37:51 +01:00
Antonio Scandurra
be523617c9 Start reworking join_project to use the database 2022-11-15 11:44:26 +01:00
Antonio Scandurra
6cbf197226 Determine whether a contact is busy via the database 2022-11-15 10:41:21 +01:00
Antonio Scandurra
3e8fcb04f7 Finish implementing Db::update_project 2022-11-15 09:01:51 +01:00
Antonio Scandurra
42bb5f0e9f Add random delay after returning results from the database 2022-11-15 08:48:16 +01:00
Max Brunsfeld
e401caff7c Merge pull request #1863 from zed-industries/erb
Add support for ERB
2022-11-14 16:59:51 -08:00
Max Brunsfeld
b222e8eb5a Use a longer example text in random combined injections test 2022-11-14 16:56:21 -08:00
Max Brunsfeld
fb35631337 Bump tree-sitter after merging included-ranges PR 2022-11-14 16:56:09 -08:00
Max Brunsfeld
6659dac2e5 Fix compile errors in seed script, ensure it is compiled on CI
Co-authored-by: Nate Butler <nate@zed.dev>
2022-11-14 11:12:25 -08:00
Antonio Scandurra
b9af2ae66e Switch to serializable isolation
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
2022-11-14 19:39:12 +01:00
Mikayla Maki
0dcdd6ea39 Merge pull request #1889 from zed-industries/terminal-bugs
Refactored rendering to squash all wakeups into 1
2022-11-14 10:29:00 -08:00
Mikayla Maki
a66aa9c09c Refactored rendering to squash all wakeups into 1 2022-11-14 10:20:55 -08:00
Kay Simmons
e6c5079a49 Merge pull request #1873 from zed-industries/drag-project-entry-to-pane
Drag and Drop Project Entries Between Folders
2022-11-14 09:55:56 -08:00
Antonio Scandurra
d7369ace6a Skip applying room updates if they're older than the local room state 2022-11-14 15:35:39 +01:00
Antonio Scandurra
40073f6100 Wait for acknowledgment before sending the next project update 2022-11-14 15:32:49 +01:00
Antonio Scandurra
65c5adff05 Automatically decline call when user drops their last connection 2022-11-14 11:32:26 +01:00
Antonio Scandurra
59e8600e4c Implement Db::cancel_call 2022-11-14 11:12:23 +01:00
Antonio Scandurra
0310e27347 Fix query errors in Db::share_project 2022-11-14 10:53:11 +01:00
Antonio Scandurra
9902211af1 Leave room when connection is dropped 2022-11-14 10:13:36 +01:00
Joseph Lyons
1da5be6e8f Update release urls to match new zed.dev url format 2022-11-12 21:39:08 -05:00
Max Brunsfeld
ee66adbb49 SyntaxMap - Don't ignore deletions at the boundaries of layers 2022-11-11 16:43:57 -08:00
Max Brunsfeld
3612c46d6d Bump tree-sitter for included range bugfix 2022-11-11 16:36:04 -08:00
Julia
bf9c9b0103 Merge pull request #1875 from zed-industries/fix-code-actions-regression
Use `EMPTY` code action kind to get more RA actions without breaking TS
2022-11-11 15:34:40 -05:00
Julia
ea8778921b Use EMPTY code action kind to get more RA actions without breaking TS 2022-11-11 15:26:12 -05:00
Julia
2ef2b5a053 Merge pull request #1874 from zed-industries/propagate-mouse-up-through-drop-receiver
Propagate mouse up event through drop receiver in early return
2022-11-11 14:05:07 -05:00
Julia
5bb7701de7 Propagate mouse up event through drop receiver in early return 2022-11-11 14:00:01 -05:00
Antonio Scandurra
2145965749 WIP 2022-11-11 19:36:20 +01:00
Antonio Scandurra
11caba4a4c Remove stray log statement 2022-11-11 18:54:08 +01:00
Antonio Scandurra
9f39dcf7cf Get basic calls test passing again 2022-11-11 18:53:23 +01:00
Antonio Scandurra
1135aeecb8 WIP: Move Store::leave_room to Db::leave_room 2022-11-11 16:59:54 +01:00
Julia
b6f78cd5dc Merge pull request #1871 from zed-industries/skip-additional-edit-within-primary
Skip LSP additional completion edits which fall within primary edit
2022-11-11 10:31:41 -05:00
Antonio Scandurra
a6198c9a1a Merge pull request #1870 from zed-industries/fix-remote-abs-paths
Fix bug where absolute paths of worktrees were not being stored on the server
2022-11-11 15:28:17 +00:00
Julia
ad698fd110 Test for filtering out of faulty LSP completion additional edits 2022-11-11 10:28:07 -05:00
Antonio Scandurra
0d1d267213 Move Store::decline_call to Db::decline_call 2022-11-11 15:41:56 +01:00
Antonio Scandurra
c213c98ea4 Remove calls table and use just room_participants 2022-11-11 15:22:04 +01:00
Antonio Scandurra
cc58607c3b Move Store::join_room into Db::join_room 2022-11-11 14:43:40 +01:00
Antonio Scandurra
58947c5c72 Move incoming calls into Db 2022-11-11 14:28:26 +01:00
Antonio Scandurra
6871bbbc71 Start moving Store state into the database 2022-11-11 12:06:43 +01:00
Antonio Scandurra
28aa1567ce Include sender_user_id when handling a server message/request 2022-11-11 11:45:58 +01:00
Antonio Scandurra
f639c4c3d1 Add schema for reconnection support 2022-11-11 10:41:44 +01:00
Kay Simmons
d61c0fb24c Allow dragging and dropping project entries 2022-11-10 20:43:55 -08:00
Kay Simmons
3d5a3634cf Merge pull request #1867 from zed-industries/drag-project-entry-to-pane
Drag project entry to pane
2022-11-10 17:25:22 -08:00
Max Brunsfeld
9ad8731897 Fix boundary condition where injection was not found after an edit 2022-11-10 17:04:40 -08:00
Julia
44c3cedc48 Skip additional completions on any kind of overlap with primary edit 2022-11-10 18:53:37 -05:00
Max Brunsfeld
eeeaf6d9a2 Merge pull request #1872 from zed-industries/tests-use-real-db
Run integration tests with an in-memory sqlite database instead of a hand-coded fake database
2022-11-10 15:15:52 -08:00
Max Brunsfeld
2d4deaafcd Use upstream sqlx git repository 2022-11-10 15:13:32 -08:00
Max Brunsfeld
c839ab2028 Add missing cfg(test) attribute to sqlite RowsAffected 2022-11-10 15:04:57 -08:00
Max Brunsfeld
5d17347a45 Use our fork of sqlx, for now 2022-11-10 14:58:05 -08:00
Max Brunsfeld
9ce3524eb8 Run db tests against both postgres and sqlite 2022-11-10 14:29:03 -08:00
Julia
03115c8d71 Skip LSP additional completion edits which fall within primary edit 2022-11-10 15:28:11 -05:00
Max Brunsfeld
dafdc4b4a5 Run tests with an in-memory sqlite database 2022-11-10 12:18:35 -08:00
Max Brunsfeld
05a6bd914d Get integration tests passing with sqlite
Co-authored-by: Antonio Scandurra <antonio@zed.dev>
2022-11-10 11:03:52 -08:00
Nathan Sobo
fb03eb7a3c Store absolute path on server when sharing worktree
Co-Authored-By: Antonio Scandurra <me@as-cii.com>
2022-11-10 09:34:16 -07:00
Nathan Sobo
8e70e1934a Avoid unwrapping when computing tab description
A bug caused the assumptions of this method to be violated. We will fix that in the next commit, but we want to be more conservative in our assumptions here going forward.

Co-Authored-By: Antonio Scandurra <me@as-cii.com>
2022-11-10 09:33:57 -07:00
Antonio Scandurra
1bb41b6f54 Go back to a compiling state and start running tests again 2022-11-10 15:24:49 +01:00
Antonio Scandurra
90d1d9ac82 WIP: add more trait bounds 2022-11-10 12:24:56 +01:00
Max Brunsfeld
bed06346d1 Total WIP - try making Db a generic struct instead of a trait 2022-11-09 19:28:06 -08:00
Max Brunsfeld
7e02ac772a Start work on using sqlite in tests 2022-11-09 19:26:29 -08:00
Nate Butler
c0d67d9522 Merge pull request #1868 from zed-industries/readd-search-match-highlight
Update search match highlight and occurrence style
2022-11-09 18:37:17 -05:00
Max Brunsfeld
d14dd27cdc Use a real database in tests, but block on db calls
Co-authored-by: Nathan Sobo <nathan@zed.dev>
2022-11-09 15:22:50 -08:00
Nate Butler
6b4dd2a5de Update search match highlight and occurrence style 2022-11-09 18:17:00 -05:00
Max Brunsfeld
9355d501bc Fetch release branches before bumping zed minor versions 2022-11-09 14:02:46 -08:00
Max Brunsfeld
335db5d03d v0.65.x dev 2022-11-09 13:18:23 -08:00
Julia
98461ea0cd Merge pull request #1865 from zed-industries/do-not-restrict-code-action-kinds
Don't restrict which kind of code actions we ask the LSP server for
2022-11-09 09:49:47 -05:00
Kay Simmons
5707bae9b9 Merge pull request #1866 from zed-industries/tweak-restart-zed-message
Remove restart to update zed icon
2022-11-08 14:38:10 -08:00
Kay Simmons
bbeb685769 remove unused comment 2022-11-08 14:26:55 -08:00
Kay Simmons
cea103e47c remove dead comment 2022-11-08 14:24:51 -08:00
Kay Simmons
ad31c284c7 remove restart to update zed icon because it clashes with the no diagnostics icon 2022-11-08 14:22:11 -08:00
Kay Simmons
738893c527 Split and move to pane working 2022-11-08 14:19:31 -08:00
Max Brunsfeld
6da04d0eee Fix failure to load .env.toml in bootstrap script 2022-11-08 14:09:17 -08:00
Julia
7482660456 Don't restrict which kind of code actions we ask the LSP server for 2022-11-08 16:23:31 -05:00
Mikayla Maki
00123ffe2b Merge pull request #1864 from zed-industries/add-more-move-cursor
Added more autoscroll behaviors
2022-11-08 11:57:09 -08:00
Mikayla Maki
53f8744794 Tried alternate stratergy 2022-11-08 11:54:26 -08:00
Mikayla Maki
537d4762f6 Added more autoscroll behaviors 2022-11-08 11:35:12 -08:00
Max Brunsfeld
2f5004c238 Add highlight query for ERB 2022-11-08 11:29:57 -08:00
Max Brunsfeld
7dcd6c920f Add randomized test for syntax map with combined injections 2022-11-08 11:29:23 -08:00
Max Brunsfeld
ea42bc3c9b Rename some sum_tree seek targets in SyntaxMap 2022-11-08 10:36:44 -08:00
Antonio Scandurra
d3ba769291 Merge pull request #1862 from zed-industries/fix-catalina
Weakly link ReplayKit to ensure this library can be used on macOS 10.15
2022-11-08 15:07:09 +00:00
Antonio Scandurra
3f1b95927f Move weak linking into zed's build.rs 2022-11-08 16:04:55 +01:00
Antonio Scandurra
c183e854d7 Weakly link ReplayKit to ensure this library can be used on macOS 10.15 2022-11-08 13:44:31 +01:00
Max Brunsfeld
86f51ade60 Fix panic in handling edits to combined injections 2022-11-07 17:32:15 -08:00
Max Brunsfeld
c838a7d973 Get combined injections basically working
Co-authored-by: Nathan Sobo <nathan@zed.dev>
Co-authored-by: Mikayla Maki <mikayla@zed.dev>
2022-11-07 16:58:12 -08:00
Julia
9abfa037fd Handle project entry drop render & start fixing drag cancel issues
Co-Authored-By: Kay Simmons <kay@zed.dev>
2022-11-07 18:17:36 -05:00
Max Brunsfeld
5efe2ed6d3 Start work on handling combined injections in SyntaxMap 2022-11-07 14:45:17 -08:00
Julia
847376a4f5 Start dragging project panel entries
Co-Authored-By: Kay Simmons <kay@zed.dev>
2022-11-07 17:00:01 -05:00
Kay Simmons
1d6af4cf20 Merge pull request #1857 from zed-industries/fix-unicode-vim-left
fixes issue with left motion in vim mode clipping incorrectly
2022-11-04 15:24:17 -07:00
Kay Simmons
b6c5c7871e Addresses issue where left motion in vim mode would clip in the wrong direction 2022-11-04 15:21:29 -07:00
Nate Butler
5acae094bd Swap the color of diagnostic underlines to fix low contrast issue. 2022-11-04 18:02:10 -04:00
Kay Simmons
4d7425f4bf Merge pull request #1845 from zed-industries/vim-dd-fix
Vim dd fix
2022-11-04 14:57:21 -07:00
Joseph T. Lyons
2497e7c008 Merge pull request #1855 from zed-industries/make-app-a-user-property-in-mixpanel
Make `App` a user property in Mixpanel
2022-11-04 14:43:46 -04:00
Joseph T Lyons
474a5dd4f2 Make App a user property in Mixpanel
Currently, we cannot take advantage of Mixpanel's virtual session end events because they are associated with users, not events; this change moves the property onto users.

Co-Authored-By: Max Brunsfeld <maxbrunsfeld@gmail.com>
2022-11-04 14:16:12 -04:00
Max Brunsfeld
18ff459014 collab 0.2.2 2022-11-04 10:04:14 -07:00
Max Brunsfeld
927cfa44db Use Rust 1.65 in collab docker image 2022-11-04 10:03:47 -07:00
Max Brunsfeld
be6ee3cbff Start work on ERB language support 2022-11-04 09:33:59 -07:00
Antonio Scandurra
7301ab4f44 Merge pull request #1854 from zed-industries/command-palette-improvements
Improve styling of command palettes
2022-11-04 14:09:55 +00:00
Antonio Scandurra
0b231e58fd Show placeholder text for pickers 2022-11-04 10:18:47 +01:00
Antonio Scandurra
08b84416d2 Avoid showing "No matches" when query is empty if there are no matches 2022-11-04 10:18:47 +01:00
Antonio Scandurra
aec8aec800 Show the cursor right away when opening opening/focusing editors 2022-11-04 10:18:47 +01:00
Max Brunsfeld
5bcf9916c9 Merge pull request #1853 from zed-industries/diagnostics-focus-loop
Fix infinite focus transfer loop in project diagnostics
2022-11-03 18:01:14 -07:00
Max Brunsfeld
6076a3fc61 Fix infinite focus transfer loop in project diagnostics
Co-authored-by: Kay Simmons <kay@zed.dev>
2022-11-03 17:53:36 -07:00
Max Brunsfeld
05389dc239 Merge pull request #1844 from zed-industries/ruby
Add support for Ruby
2022-11-03 15:59:11 -07:00
Max Brunsfeld
d222904471 Add basic support for ruby
Co-authored-by: Kay Simmons <kay@zed.dev>
2022-11-03 15:52:33 -07:00
Max Brunsfeld
9f3ea0c87f Merge pull request #1851 from zed-industries/rust-let-else
Bump tree-sitter-rust for let-else, let-chains
2022-11-03 12:39:37 -07:00
Max Brunsfeld
601ec40ddc Bump tree-sitter-rust for let-else, let-chains 2022-11-03 12:35:12 -07:00
Joseph T. Lyons
adc4a5984e Merge pull request #1850 from zed-industries/add-automatic-annotations-for-mixpanel
Add automatic annotations for mixpanel
2022-11-03 13:26:15 -04:00
Joseph T Lyons
0f78174d78 Use folded style to make arguments easier to read 2022-11-03 13:06:19 -04:00
Joseph T Lyons
ad67a1b744 Add automatic annotations for mixpanel 2022-11-03 01:48:49 -04:00
Nate Butler
edc2966651 Merge pull request #1847 from zed-industries/readd-abruzzo-theme
Re-add Abruzzo theme to experimental themes
2022-11-02 22:34:04 -04:00
Joseph T. Lyons
eacfa856cf Merge pull request #1848 from zed-industries/fix-markdown-rendering-of-discord-release-notes-webhook
Fix markdown rendering of discord release notes webhook
2022-11-02 16:12:29 -04:00
Max Brunsfeld
fe4862d756 Fix error in bump-zed-patch-version script 2022-11-02 12:18:14 -07:00
Max Brunsfeld
8312d974ac Fix release channel on stable 2022-11-02 12:18:07 -07:00
Max Brunsfeld
6d3bd495fc Fix error case in what-is-deployed script 2022-11-02 12:05:37 -07:00
Joseph T Lyons
576e350bea Fix markdown rendering of discord release notes webhook 2022-11-02 14:55:27 -04:00
Max Brunsfeld
cc1325d6f9 Adjust script for getting changes to put in release notes
Now, this script is only useful for the preview channel's releases. The
stable channel's release notes can be mostly copied from the existing
preview releases notes.

Co-authored-by: Joseph Lyons <joseph@zed.dev>
2022-11-02 10:55:48 -07:00
Max Brunsfeld
c411cb7eef collab 0.2.1 2022-11-02 10:27:26 -07:00
Max Brunsfeld
c9ba41d002 Fix errors in bump-zed-minor-versions script
Co-authored-by: Joseph Lyons <joseph@zed.dev>
2022-11-02 10:25:20 -07:00
Joseph T Lyons
3caa7a4916 v0.64.x dev 2022-11-02 12:57:53 -04:00
Joseph T. Lyons
370a6f3dbd Merge pull request #1842 from zed-industries/telemetry-corrections
Telemetry corrections
2022-11-02 12:36:48 -04:00
Joseph T Lyons
d8685baa47 Revert "Differentiate between first time app starts and subsequent ones" 2022-11-02 12:22:46 -04:00
Nate Butler
4f344f1ac1 Re-add Abruzzo theme to experimental themes 2022-11-02 11:28:43 -04:00
Nate Butler
6a07f59d34 Merge pull request #1831 from zed-industries/theme-tweaks
Theme tweaks
2022-11-02 10:04:55 -04:00
Nate Butler
7981cd45ed Increase scrollbar width 2022-11-02 09:58:15 -04:00
Antonio Scandurra
66b1283c95 Merge pull request #1846 from zed-industries/dont-focus-notification-windows
Don't focus incoming call and project shared notification windows
2022-11-02 13:21:18 +00:00
Antonio Scandurra
d275474b23 Don't focus incoming call and project shared notification windows 2022-11-02 14:17:16 +01:00
Antonio Scandurra
86057ab071 Merge pull request #1843 from zed-industries/call-randomized-test
Model calls in randomized collaboration test
2022-11-02 13:03:34 +00:00
Kay Simmons
4977acf6a5 fix some vim mode bugs around deletions and failed motions 2022-11-02 01:20:11 -07:00
Joseph T Lyons
aafc3a9584 Make event name casing consistent with other event names 2022-11-01 23:19:55 -04:00
Joseph T Lyons
dc657a647e Remove Amplitude event tracking 2022-11-01 20:49:49 -04:00
Joseph T Lyons
e5f0965138 Differentiate between first time app starts and subsequent ones 2022-11-01 20:36:18 -04:00
Kay Simmons
0cd2d9a9c8 added new supported feature 2022-11-01 13:15:14 -07:00
Julia
b2b25acc4c Merge pull request #1841 from zed-industries/tab-activation-history
Avoid reordering items by adding an activation history to panes, and remove tab reordering hack
2022-11-01 14:46:45 -04:00
Antonio Scandurra
0b79950510 Don't hold the lock while yielding back to the executor in Client 2022-11-01 19:16:02 +01:00
Antonio Scandurra
d6d1e20f07 Ensure declining call doesn't accidentally leave a room 2022-11-01 18:48:08 +01:00
Julia
c58abf1b0b Add test for new tab order history behavior 2022-11-01 13:29:21 -04:00
Antonio Scandurra
88d2e2e277 Introduce calls to randomized collaboration test 2022-11-01 15:44:00 +01:00
Antonio Scandurra
946c92667f Don't drop fake LSP adapter's receiver before simulate ends 2022-11-01 14:28:01 +01:00
Antonio Scandurra
f54f653d42 Don't return an error when failing to send AddProjectCollaborator
This can happen when a peer has disconnected but we haven't yet been
able to acquire a lock to the store to clean up the state associated
with it.
2022-11-01 11:21:40 +01:00
Antonio Scandurra
ef72c75fab Honor MAX_PEERS env variable in randomized test 2022-11-01 10:24:26 +01:00
Antonio Scandurra
c6e52dbef7 Fix hang due to acquiring rng lock twice 2022-11-01 09:35:53 +01:00
Antonio Scandurra
62547e87dd Prevent randomized test from failing if another guest disconnects 2022-11-01 09:27:51 +01:00
Antonio Scandurra
eb6b545eeb Fix outstanding compiler errors in randomized collaboration test 2022-11-01 08:40:31 +01:00
Antonio Scandurra
4c4ebbfa19 Start removing distinction between host and guest in random collab test 2022-11-01 08:40:08 +01:00
Joseph T Lyons
61f31bf010 Fill in missing "app" field names on Mixpanel events 2022-10-31 19:18:35 -04:00
Joseph T Lyons
495fd151f5 Revert Amplitude's "app" name back to "platform"
This was unintentional.  We only want to rename the Mixpanel telemetry "platform" field to "app."  We want to keep it as "platform" on Amplitude because we want to keep using Amplitude for a bit, and the event fields should be the same.
2022-10-31 19:18:03 -04:00
Max Brunsfeld
482a5bb02a Merge pull request #1840 from zed-industries/build-themes-in-assets-crate
Generate themes before compiling the 'assets' crate
2022-10-31 14:18:28 -07:00
Kay Simmons
4e35b26365 Avoid reordering items by adding an activation history to panes, and remove tab reordering hack
Co-Authored-By: Julia Risley <julia@zed.dev>
2022-10-31 14:10:34 -07:00
Joseph T. Lyons
c180137e02 Merge pull request #1829 from zed-industries/add-release-channel-information-to-telemetry-events
Add release channel information to telemetry events
2022-10-31 16:42:28 -04:00
Max Brunsfeld
ef837232bc Generate themes before compiling the 'assets' crate 2022-10-31 13:25:12 -07:00
Max Brunsfeld
d0aa9f1c57 Merge pull request #1839 from zed-industries/contact-list-project-color
Don't use 'on' background color for projects in the contact list
2022-10-31 12:39:17 -07:00
Max Brunsfeld
aa549d1da7 Don't use 'on' color for projects in the contact list 2022-10-31 12:28:25 -07:00
Julia
259a758849 Merge pull request #1800 from zed-industries/go-to-diff-hunk
Add action to go to next/previous git diff in editor
2022-10-31 14:38:52 -04:00
Julia
7ac45379eb Layout git gutters inclusively 2022-10-31 14:35:42 -04:00
Max Brunsfeld
0940482c62 Merge pull request #1838 from zed-industries/tab-panic
Fix panic when hitting tab at the beginning of a line with mixed tab/…
2022-10-31 10:55:48 -07:00
Max Brunsfeld
9cbb698b96 Fix panic when hitting tab at the beginning of a line with mixed tab/space indent 2022-10-31 10:51:20 -07:00
Mikayla Maki
1820be4990 Adds a little spacing between the share button and the screenshare icon 2022-10-31 10:19:06 -07:00
Mikayla Maki
37ca232548 Remove annoyoing debug 2022-10-31 10:02:17 -07:00
Mikayla Maki
ea9b009a22 Fixed bug with cut entry active states 2022-10-31 09:55:52 -07:00
Nate Butler
dbc804669c Update ignored, cut entry styles in the project panel 2022-10-31 10:30:58 -04:00
Julia
c8fbc0d348 Slightly expand region hunk layout checks for folds 2022-10-28 19:05:29 -04:00
Julia
8361b4d47a Add test for go-to hunk and fix discovered bugs 2022-10-28 15:08:13 -04:00
Julia
ae2021e073 WIP start setting up test infrastructure for editor diff actions
Co-Authored-By: Kay Simmons <kay@zed.dev>
2022-10-28 15:08:13 -04:00
Julia
c4b21a0ab5 Add action to go to next/previous git diff in editor
Co-Authored-By: Kay Simmons <kay@zed.dev>
2022-10-28 15:08:13 -04:00
Mikayla Maki
8a095d0a55 Merge pull request #1833 from zed-industries/add-channel-to-db
Added channel info to database directories
2022-10-28 11:54:46 -07:00
Mikayla Maki
c0bf8fd6a8 Added channel to database directories 2022-10-28 11:50:26 -07:00
Mikayla Maki
14329980e1 Merge pull request #1832 from zed-industries/upgrade-migration-lib
Upgraded migration library to remove panic
2022-10-28 11:41:31 -07:00
Mikayla Maki
950626fe9e Upgraded migration library to remove panic 2022-10-28 11:36:41 -07:00
Mikayla Maki
8b7e587467 Removed stray test file 2022-10-28 10:48:54 -07:00
Mikayla Maki
552ebc0f29 Implemented direct styling for ignored and cut project panel entries 2022-10-28 10:45:45 -07:00
Nate Butler
9148e1d30a Update icons
- `x_mark_thin` combined into `x_mark`
- updated many icons
- remove unused icons
2022-10-28 12:59:05 -04:00
Max Brunsfeld
9156d488ca Merge pull request #1830 from zed-industries/auto-update-filename
Make auto-update handle an app bundle name other than 'Zed.app'
2022-10-27 16:47:34 -07:00
Max Brunsfeld
e1ac1675ea Avoid hard-coding app bundle filename in auto-updater 2022-10-27 16:44:07 -07:00
Max Brunsfeld
863250904b Avoid posting in Discord about preview releases (for now)
Co-authored-by: Joseph Lyons <joseph@zed.dev>
2022-10-27 15:43:00 -07:00
Joseph T Lyons
8a926c4a23 Make release_channel optional to fix tests
Co-Authored-By: Max Brunsfeld <maxbrunsfeld@gmail.com>
2022-10-27 18:06:34 -04:00
Kay Simmons
760cceb378 Merge pull request #1827 from zed-industries/fix-keymap-resolution-fallback
Keymap resolution fallbacks
2022-10-27 13:50:38 -07:00
K Simmons
c5650f9334 remove unnecessary comment 2022-10-27 13:29:57 -07:00
K Simmons
bf968707df upgrade existing test to match new expected behavior 2022-10-27 13:28:49 -07:00
Max Brunsfeld
31fa7ca90c Add livekit to the Procfile, update the README 2022-10-27 13:24:35 -07:00
Joseph T Lyons
309f401015 Rename all keys, in telemetry events, to be consistent with Mixpanels conventions 2022-10-27 16:19:21 -04:00
Max Brunsfeld
33d02cedd7 Run CI when pushing to release branches (e.g. 'v0.62.x') 2022-10-27 13:03:35 -07:00
Joseph T Lyons
daa75b5282 Add missing struct field
This must've gotten lost on the merging of main into this branch
2022-10-27 15:59:22 -04:00
Joseph T Lyons
36c64045ae Merge branch 'main' into add-release-channel-information-to-telemetry-events 2022-10-27 15:57:17 -04:00
Joseph T Lyons
93e1e30323 Add release channel information to telemetry events 2022-10-27 15:53:14 -04:00
Max Brunsfeld
9b69f9a3ff Merge pull request #1828 from zed-industries/following-scrollbar
Show scrollbar when scrolling while following
2022-10-27 12:46:14 -07:00
Max Brunsfeld
d5fbb59656 Show scrollbar when scrolling while following 2022-10-27 12:42:34 -07:00
Max Brunsfeld
7ba95d5d6c 🔥 stray dbg 2022-10-27 12:42:20 -07:00
Max Brunsfeld
d79aeba2c1 Avoid spurious log messages in development builds 2022-10-27 12:42:03 -07:00
K Simmons
672b445676 minor tweak to keymap code 2022-10-27 12:36:53 -07:00
K Simmons
e02199fa2a fixed binding fallback 2022-10-27 12:33:51 -07:00
Max Brunsfeld
9e55051811 Tweak version-bumping scripts 2022-10-27 12:10:09 -07:00
Max Brunsfeld
7db176a763 Remove stale docs folder 2022-10-27 12:08:55 -07:00
Nate Butler
92886236a2 Refine editor styles
- Update active line backgrounds and line numbers
- Add a higher contrast border between the dock and panes
2022-10-27 14:59:50 -04:00
Mikayla Maki
8d94de8eb2 WIP: Change to matches to vec 2022-10-27 11:27:26 -07:00
Max Brunsfeld
eaebec88c0 Merge pull request #1825 from zed-industries/update-notification-release-channel
Indicate release channel in auto-update notification
2022-10-27 11:00:16 -07:00
Max Brunsfeld
22fa6c07dd Indicate release channel in auto-update notification 2022-10-27 10:57:59 -07:00
Joseph T. Lyons
afe9ab9d8c Merge pull request #1824 from zed-industries/change-telemetry-event-field-name-to-app
Change telemetry event field name to app
2022-10-27 13:16:45 -04:00
Max Brunsfeld
16139cc6b6 Merge pull request #1822 from zed-industries/dont-bundle-app-on-prs
Don't bundle the app on CI for PRs
2022-10-27 10:10:29 -07:00
Joseph T Lyons
31a904d370 Change telemetry event field name to app 2022-10-27 12:35:35 -04:00
Max Brunsfeld
02cf7679a3 0.63.x dev 2022-10-26 23:04:36 -07:00
Max Brunsfeld
d85d4de218 Don't bundle the app on CI for PRs
Just run that job on main and for release tags
2022-10-26 17:26:16 -07:00
K Simmons
e2ba8d6df7 Add active pane magnification setting which grows the active pane making it easier to see it's contents 2022-10-25 17:24:19 -07:00
347 changed files with 24334 additions and 16474 deletions

View File

@@ -4,6 +4,7 @@ on:
push:
branches:
- main
- "v*"
tags:
- "v*"
pull_request:
@@ -44,20 +45,24 @@ jobs:
- name: Run tests
run: cargo test --workspace --no-fail-fast
- name: Build collab binaries
run: cargo build --bins --all-features
- name: Build collab
run: cargo build -p collab
- name: Build other binaries
run: cargo build --workspace --bins --all-features
bundle:
name: Bundle app
runs-on:
- self-hosted
- bundle
if: ${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') }}
needs: tests
env:
MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
APPLE_NOTARIZATION_USERNAME: ${{ secrets.APPLE_NOTARIZATION_USERNAME }}
APPLE_NOTARIZATION_PASSWORD: ${{ secrets.APPLE_NOTARIZATION_PASSWORD }}
ZED_AMPLITUDE_API_KEY: ${{ secrets.ZED_AMPLITUDE_API_KEY }}
ZED_MIXPANEL_TOKEN: ${{ secrets.ZED_MIXPANEL_TOKEN }}
steps:
- name: Install Rust

View File

@@ -8,19 +8,20 @@ jobs:
steps:
- name: Discord Webhook Action
uses: tsickert/discord-webhook@v5.3.0
if: ${{ ! github.event.release.prerelease }}
with:
webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
content: |
📣 Zed ${{ github.event.release.tag_name }} was just released!
Restart your Zed or head to https://zed.dev/releases to grab it.
Restart your Zed or head to https://zed.dev/releases/latest to grab it.
```md
### Changelog
# Changelog
${{ github.event.release.body }}
```
amplitude_release:
mixpanel_release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
@@ -29,5 +30,10 @@ jobs:
python-version: "3.10.5"
architecture: "x64"
cache: "pip"
- run: pip install -r script/amplitude_release/requirements.txt
- run: python script/amplitude_release/main.py ${{ github.event.release.tag_name }} ${{ secrets.ZED_AMPLITUDE_API_KEY }} ${{ secrets.ZED_AMPLITUDE_SECRET_KEY }}
- run: pip install -r script/mixpanel_release/requirements.txt
- run: >
python script/mixpanel_release/main.py
${{ github.event.release.tag_name }}
${{ secrets.MIXPANEL_PROJECT_ID }}
${{ secrets.MIXPANEL_SERVICE_ACCOUNT_USERNAME }}
${{ secrets.MIXPANEL_SERVICE_ACCOUNT_SECRET }}

1
.gitignore vendored
View File

@@ -18,3 +18,4 @@ DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
**/*.db

1247
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -45,6 +45,8 @@ members = [
"crates/search",
"crates/settings",
"crates/snippet",
"crates/sqlez",
"crates/sqlez_macros",
"crates/sum_tree",
"crates/terminal",
"crates/text",
@@ -65,7 +67,7 @@ serde_json = { version = "1.0", features = ["preserve_order", "raw_value"] }
rand = { version = "0.8" }
[patch.crates-io]
tree-sitter = { git = "https://github.com/tree-sitter/tree-sitter", rev = "366210ae925d7ea0891bc7a0c738f60c77c04d7b" }
tree-sitter = { git = "https://github.com/tree-sitter/tree-sitter", rev = "36b5b6c89e55ad1a502f8b3234bb3e12ec83a5da" }
async-task = { git = "https://github.com/zed-industries/async-task", rev = "341b57d6de98cdfd7b418567b8de2022ca993a6e" }
# TODO - Remove when a version is released with this PR: https://github.com/servo/core-foundation-rs/pull/457
@@ -81,3 +83,4 @@ split-debuginfo = "unpacked"
[profile.release]
debug = true

View File

@@ -1,6 +1,6 @@
# syntax = docker/dockerfile:1.2
FROM rust:1.64-bullseye as builder
FROM rust:1.65-bullseye as builder
WORKDIR app
COPY . .

View File

@@ -1,2 +1,3 @@
web: cd ../zed.dev && PORT=3000 npx vercel dev
collab: cd crates/collab && cargo run serve
livekit: livekit-server --dev

View File

@@ -6,36 +6,43 @@ Welcome to Zed, a lightning-fast, collaborative code editor that makes your drea
## Development tips
### Dependencies
* Install [Postgres.app](https://postgresapp.com) and start it.
* Install the `LiveKit` server and the `foreman` process supervisor:
```
brew install livekit
brew install foreman
```
* Ensure the Zed.dev website is checked out in a sibling directory:
```
cd ..
git clone https://github.com/zed-industries/zed.dev
```
* Set up a local `zed` database and seed it with some initial users:
```
script/bootstrap
```
### Testing against locally-running servers
Make sure you have `zed.dev` cloned as a sibling to this repo.
Start the web and collab servers:
```
cd ..
git clone https://github.com/zed-industries/zed.dev
```
Make sure your local database is created, migrated, and seeded with initial data. Install [Postgres](https://postgresapp.com), then from the `zed` repository root, run:
```
script/sqlx database create
script/sqlx migrate run
script/seed-db
```
Run the web frontend and the collaboration server.
```
brew install foreman
foreman start
```
If you want to run Zed pointed at the local servers, you can run:
```
script/zed_with_local_servers
script/zed-with-local-servers
# or...
script/zed_with_local_servers --release
script/zed-with-local-servers --release
```
### Dump element JSON

View File

@@ -1,3 +1,10 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_430_1271)">
<path d="M10.9007 7.45347L6.60649 11.7477C6.44009 11.9168 6.22001 12 5.99993 12C5.77985 12 5.56031 11.9161 5.39283 11.7484L1.09859 7.45414C0.763098 7.11865 0.763098 6.57516 1.09859 6.23967C1.43407 5.90419 1.97756 5.90419 2.31305 6.23967L5.14108 9.06904V0.834694C5.14108 0.359912 5.52568 0 5.97577 0C6.42587 0 6.85878 0.359912 6.85878 0.834694V9.06891L9.68761 6.24008C10.0231 5.90459 10.5666 5.90459 10.9021 6.24008C11.2376 6.57556 11.2362 7.11771 10.9007 7.4532V7.45347Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1271">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 590 B

After

Width:  |  Height:  |  Size: 734 B

View File

@@ -1,3 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.0538 9.45347L8.75952 13.7477C8.59312 13.9168 8.37304 14 8.15296 14C7.93288 14 7.71334 13.9161 7.54586 13.7484L3.25162 9.45414C2.91613 9.11865 2.91613 8.57516 3.25162 8.23967C3.5871 7.90419 4.13059 7.90419 4.46608 8.23967L7.29411 11.069V2.83469C7.29411 2.35991 7.67871 2 8.1288 2C8.5789 2 9.01181 2.35991 9.01181 2.83469V11.0689L11.8406 8.24008C12.1761 7.90459 12.7196 7.90459 13.0551 8.24008C13.3906 8.57556 13.3893 9.11771 13.0538 9.4532V9.45347Z" fill="white"/>
<path d="M13.0538 9.45347L8.75952 13.7477C8.59312 13.9168 8.37304 14 8.15296 14C7.93288 14 7.71334 13.9161 7.54586 13.7484L3.25162 9.45414C2.91613 9.11865 2.91613 8.57516 3.25162 8.23967C3.5871 7.90418 4.13059 7.90418 4.46608 8.23967L7.29411 11.069V2.83469C7.29411 2.35991 7.67871 2 8.12881 2C8.5789 2 9.01181 2.35991 9.01181 2.83469V11.0689L11.8406 8.24008C12.1761 7.90459 12.7196 7.90459 13.0551 8.24008C13.3906 8.57556 13.3893 9.11771 13.0538 9.4532V9.45347Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 580 B

After

Width:  |  Height:  |  Size: 581 B

View File

@@ -1,3 +1,10 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_430_1354)">
<path d="M7.26716 4.96898L4.40433 7.83181C4.2934 7.94453 4.14668 8 3.99996 8C3.85324 8 3.70688 7.94409 3.59523 7.83226L0.732395 4.96943C0.508737 4.74577 0.508737 4.38344 0.732395 4.15978C0.956054 3.93612 1.31838 3.93612 1.54204 4.15978L3.42739 6.04603V0.556463C3.42739 0.239941 3.68379 0 3.98385 0C4.28392 0 4.57252 0.239941 4.57252 0.556463V6.04594L6.45841 4.16005C6.68207 3.93639 7.0444 3.93639 7.26806 4.16005C7.49172 4.38371 7.49082 4.74514 7.26716 4.9688V4.96898Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1354">
<rect width="8" height="8" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 584 B

After

Width:  |  Height:  |  Size: 726 B

View File

@@ -1,3 +1,10 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_430_1272)">
<path d="M12 6.00001C12 6.47507 11.6403 6.85889 11.1653 6.85889H2.93347L5.7624 9.68781C6.0979 10.0233 6.0979 10.5668 5.7624 10.9023C5.59331 11.0701 5.37322 11.1533 5.15313 11.1533C4.93305 11.1533 4.71349 11.0694 4.54601 10.9017L0.251624 6.60726C-0.0838748 6.27176 -0.0838748 5.72825 0.251624 5.39275L4.54601 1.09837C4.88151 0.762866 5.42502 0.762866 5.76052 1.09837C6.09602 1.43386 6.09602 1.97737 5.76052 2.31287L2.93347 5.14113H11.1653C11.6403 5.14113 12 5.52494 12 6.00001Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1272">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 596 B

After

Width:  |  Height:  |  Size: 740 B

View File

@@ -1,3 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 8.15327C14 8.62833 13.6403 9.01214 13.1653 9.01214H4.93347L7.7624 11.8411C8.0979 12.1766 8.0979 12.7201 7.7624 13.0556C7.59331 13.2233 7.37322 13.3065 7.15313 13.3065C6.93305 13.3065 6.71349 13.2227 6.54601 13.0549L2.25162 8.76052C1.91613 8.42502 1.91613 7.88151 2.25162 7.54601L6.54601 3.25162C6.88151 2.91613 7.42502 2.91613 7.76052 3.25162C8.09602 3.58712 8.09602 4.13063 7.76052 4.46613L4.93347 7.29439H13.1653C13.6403 7.29439 14 7.6782 14 8.15327Z" fill="white"/>
<path d="M14 8.15327C14 8.62833 13.6403 9.01215 13.1653 9.01215H4.93347L7.7624 11.8411C8.0979 12.1766 8.0979 12.7201 7.7624 13.0556C7.59331 13.2233 7.37322 13.3065 7.15313 13.3065C6.93305 13.3065 6.71349 13.2227 6.54601 13.0549L2.25162 8.76052C1.91613 8.42502 1.91613 7.88151 2.25162 7.54601L6.54601 3.25162C6.88151 2.91613 7.42502 2.91613 7.76052 3.25162C8.09602 3.58712 8.09602 4.13063 7.76052 4.46613L4.93347 7.29439H13.1653C13.6403 7.29439 14 7.6782 14 8.15327Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 585 B

After

Width:  |  Height:  |  Size: 585 B

View File

@@ -1,3 +1,10 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_430_1355)">
<path d="M8 4.00003C8 4.31674 7.76023 4.57261 7.44352 4.57261H1.95565L3.8416 6.45856C4.06527 6.68223 4.06527 7.04457 3.8416 7.26823C3.72887 7.38007 3.58215 7.43554 3.43542 7.43554C3.2887 7.43554 3.14233 7.37962 3.03068 7.26779L0.16775 4.40486C-0.0559165 4.1812 -0.0559165 3.81886 0.16775 3.59519L3.03068 0.732264C3.25434 0.508598 3.61668 0.508598 3.84035 0.732264C4.06401 0.95593 4.06401 1.31827 3.84035 1.54194L1.95565 3.42744H7.44352C7.76023 3.42744 8 3.68331 8 4.00003Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1355">
<rect width="8" height="8" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 588 B

After

Width:  |  Height:  |  Size: 730 B

View File

@@ -1,3 +1,10 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_430_1273)">
<path d="M11.749 6.60576L7.46298 10.8917C7.2969 11.0605 7.07724 11.1436 6.85758 11.1436C6.63793 11.1436 6.41881 11.0598 6.25165 10.8924C5.91681 10.5576 5.91681 10.0151 6.25165 9.68029L9.07558 6.85756H0.857198C0.383864 6.85756 0 6.4745 0 6.00036C0 5.52623 0.383596 5.14317 0.85693 5.14317H9.07531L6.25192 2.31977C5.91708 1.98493 5.91708 1.44248 6.25192 1.10764C6.58676 0.772796 7.12921 0.772796 7.46405 1.10764L11.75 5.39363C12.0835 5.72981 12.0835 6.27092 11.7487 6.60576H11.749Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1273">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 599 B

After

Width:  |  Height:  |  Size: 743 B

View File

@@ -1,3 +1,10 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_430_1356)">
<path d="M7.83265 4.40382L4.97532 7.26115C4.8646 7.37365 4.71816 7.42901 4.57172 7.42901C4.42528 7.42901 4.2792 7.37321 4.16777 7.26159C3.94454 7.03836 3.94454 6.67673 4.16777 6.4535L6.05039 4.57169H0.571465C0.255909 4.57169 0 4.31631 0 4.00022C0 3.68413 0.255731 3.42876 0.571287 3.42876H6.05021L4.16795 1.54649C3.94472 1.32326 3.94472 0.961634 4.16795 0.738405C4.39117 0.515177 4.75281 0.515177 4.97603 0.738405L7.83336 3.59573C8.0557 3.81985 8.0557 4.18059 7.83247 4.40382H7.83265Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1356">
<rect width="8" height="8" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 600 B

After

Width:  |  Height:  |  Size: 742 B

View File

@@ -1,3 +1,10 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_430_1274)">
<path d="M10.9009 5.7604C10.7345 5.92948 10.5144 6.01268 10.2943 6.01268C10.0742 6.01268 9.85471 5.92881 9.68724 5.76107L6.85903 2.93408V11.1653C6.85903 11.6401 6.47444 12 6.02437 12C5.57429 12 5.14139 11.6404 5.14139 11.1653V2.93408L2.31346 5.76013C1.97798 6.09561 1.43451 6.09561 1.09903 5.76013C0.763558 5.42466 0.763558 4.88119 1.09903 4.54571L5.39314 0.251607C5.72861 -0.0838692 6.27209 -0.0838692 6.60756 0.251607L10.9017 4.54571C11.2363 4.88253 11.2363 5.42466 10.9009 5.76013V5.7604Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1274">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 611 B

After

Width:  |  Height:  |  Size: 755 B

View File

@@ -1,3 +1,10 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_430_1357)">
<path d="M7.26724 3.84027C7.15631 3.95299 7.0096 4.00845 6.86288 4.00845C6.71617 4.00845 6.56981 3.95254 6.45816 3.84072L4.57269 1.95605V7.44356C4.57269 7.76007 4.3163 8 4.01625 8C3.7162 8 3.4276 7.76025 3.4276 7.44356V1.95605L1.54231 3.84009C1.31866 4.06374 0.956346 4.06374 0.732695 3.84009C0.509044 3.61644 0.509044 3.25412 0.732695 3.03047L3.59543 0.167738C3.81908 -0.0559128 4.1814 -0.0559128 4.40505 0.167738L7.26778 3.03047C7.49089 3.25502 7.49089 3.61644 7.26724 3.84009V3.84027Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1357">
<rect width="8" height="8" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 603 B

After

Width:  |  Height:  |  Size: 745 B

View File

@@ -1,3 +1,3 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.17314 8L5.89399 3.29329L6.20495 7.94346L8 6.14841L7.67491 0.339222L1.85159 0L0.0565371 1.79505L4.70671 2.12014L0 6.82685L1.17314 8Z" fill="white"/>
<path d="M6 2H6.5C6.5 1.86739 6.44732 1.74021 6.35355 1.64645C6.25979 1.55268 6.13261 1.5 6 1.5V2ZM2 1.5C1.72386 1.5 1.5 1.72386 1.5 2C1.5 2.27614 1.72386 2.5 2 2.5L2 1.5ZM5.5 6C5.5 6.27614 5.72386 6.5 6 6.5C6.27614 6.5 6.5 6.27614 6.5 6H5.5ZM1.64645 5.64645C1.45118 5.84171 1.45118 6.15829 1.64645 6.35355C1.84171 6.54882 2.15829 6.54882 2.35355 6.35355L1.64645 5.64645ZM6 1.5H2L2 2.5H6V1.5ZM5.5 2V6H6.5V2H5.5ZM5.64645 1.64645L1.64645 5.64645L2.35355 6.35355L6.35355 2.35355L5.64645 1.64645Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 259 B

After

Width:  |  Height:  |  Size: 608 B

View File

@@ -1,3 +1,3 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.14029 5.25005H9.75348C10.0652 5.25005 10.3464 5.44457 10.4355 5.73518C10.5644 6.02814 10.4824 6.3586 10.248 6.56484L4.24822 11.8146C3.98338 12.0443 3.59598 12.0631 3.31286 11.8568C3.02951 11.6506 2.92639 11.2756 3.06443 10.9545L4.86694 6.74999H2.23267C1.94135 6.74999 1.66152 6.55546 1.5516 6.26485C1.44171 5.97189 1.52465 5.64144 1.75986 5.43519L7.75893 0.185629C8.02376 -0.0449871 8.41046 -0.0625645 8.69405 0.143209C8.97763 0.349123 9.08075 0.723265 8.94248 1.04542L7.1402 5.24972L7.14029 5.25005Z" fill="white"/>
<path d="M7.01442 5.33285H9.33914C9.61643 5.33285 9.86663 5.5059 9.94586 5.76443C10.0605 6.02505 9.98756 6.31903 9.77906 6.50251L4.4416 11.1728C4.206 11.3771 3.86136 11.3938 3.6095 11.2103C3.35743 11.0268 3.26569 10.6932 3.38849 10.4076L4.99202 6.66722H2.64855C2.38939 6.66722 2.14044 6.49417 2.04266 6.23563C1.9449 5.97501 2.01868 5.68104 2.22793 5.49756L7.56476 0.827491C7.80036 0.622333 8.14438 0.606695 8.39666 0.789754C8.64894 0.972937 8.74067 1.30578 8.61766 1.59237L7.01434 5.33256L7.01442 5.33285Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 632 B

After

Width:  |  Height:  |  Size: 625 B

View File

@@ -1,3 +1,3 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.76019 3.50003H6.50231C6.71012 3.50003 6.89761 3.62971 6.95698 3.82346C7.04292 4.01876 6.98823 4.23906 6.83199 4.37656L2.83214 7.87643C2.65558 8.02954 2.39731 8.04204 2.20857 7.90455C2.01967 7.76705 1.95092 7.51706 2.04295 7.30301L3.24462 4.49999H1.48844C1.29423 4.49999 1.10767 4.37031 1.0344 4.17657C0.961132 3.98126 1.01643 3.76096 1.17323 3.62346L5.17261 0.123753C5.34917 -0.0299914 5.60697 -0.0417097 5.79603 0.0954726C5.98508 0.232749 6.05383 0.482177 5.96164 0.69695L4.76013 3.49981L4.76019 3.50003Z" fill="white"/>
<path d="M4.76019 3.50003H6.50231C6.71012 3.50003 6.89761 3.62971 6.95698 3.82346C7.04292 4.01876 6.98823 4.23906 6.83199 4.37656L2.83214 7.87643C2.65558 8.02954 2.39731 8.04204 2.20857 7.90455C2.01967 7.76705 1.95092 7.51706 2.04295 7.30301L3.24462 4.49999H1.48844C1.29423 4.49999 1.10767 4.37031 1.0344 4.17657C0.961132 3.98126 1.01643 3.76096 1.17323 3.62346L5.17261 0.123753C5.34917 -0.0299914 5.60697 -0.0417097 5.79603 0.0954726C5.98508 0.232749 6.05383 0.482177 5.96165 0.69695L4.76013 3.49981L4.76019 3.50003Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 633 B

After

Width:  |  Height:  |  Size: 633 B

View File

@@ -1,3 +1,10 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.00788 3.83701L7.62903 0.754503C7.87479 0.546451 8.23364 0.530593 8.4968 0.716233C8.75996 0.901999 8.85565 1.23953 8.72734 1.53017L7.05487 5.3231H9.47984C9.7691 5.3231 10.0301 5.49859 10.1127 5.76077C10.2323 6.02506 10.1562 6.32318 9.93874 6.50925L8.79258 7.48396L11.7998 9.86631C12.026 10.0397 12.0673 10.3589 11.889 10.5788C11.7106 10.7987 11.3822 10.8389 11.156 10.6655L0.200158 2.51988C-0.0268974 2.34693 -0.0666975 2.02808 0.111206 1.80735C0.28911 1.58661 0.616862 1.54792 0.843918 1.72108L4.00788 3.83701ZM2.06138 5.49043L2.40718 5.17751L4.34064 6.67658H2.52027C2.23102 6.67658 1.97003 6.50109 1.86782 6.23891C1.76777 5.97461 1.84389 5.67649 2.06138 5.49043ZM3.27278 10.4697L4.79301 7.02333L7.18318 8.83533L4.37108 11.2457C4.12532 11.4529 3.76647 11.4698 3.50331 11.2837C3.24015 11.0977 3.14446 10.7594 3.27278 10.4697Z" fill="white"/>
<g clip-path="url(#clip0_430_1336)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.01443 5.33285H9.33914C9.61644 5.33285 9.86663 5.5059 9.94586 5.76443C10.0605 6.02505 9.98756 6.31903 9.77906 6.50251L9.11489 7.08366L11.4605 8.90799C11.7874 9.16229 11.8463 9.6335 11.592 9.96045C11.3377 10.2874 10.8665 10.3463 10.5395 10.092L1.53955 3.09201C1.21259 2.83771 1.15369 2.3665 1.40799 2.03954C1.66229 1.71258 2.1335 1.65368 2.46046 1.90799L4.50911 3.50138L7.56477 0.827491C7.80037 0.622333 8.14438 0.606695 8.39666 0.789754C8.64894 0.972937 8.74068 1.30578 8.61767 1.59237L7.01434 5.33256L7.01443 5.33285ZM2.88883 4.91923L7.49455 8.50146L4.4416 11.1728C4.206 11.3771 3.86136 11.3938 3.6095 11.2103C3.35743 11.0268 3.26569 10.6932 3.3885 10.4076L4.99203 6.66722H2.64855C2.38939 6.66722 2.14045 6.49416 2.04266 6.23563C1.9449 5.97501 2.01869 5.68104 2.22793 5.49756L2.88883 4.91923Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1336">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 956 B

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,9 +1,9 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_430_1350)">
<path d="M2.8102 2.0687L5.08603 0.503002C5.24987 0.364301 5.4891 0.353729 5.66454 0.477489C5.83998 0.601333 5.90377 0.826356 5.81823 1.02011L4.70325 3.54873H6.3199C6.51274 3.54873 6.68673 3.66573 6.74182 3.84051C6.82157 4.01671 6.77082 4.21546 6.62583 4.3395L6.22432 4.68222L8.0048 6.08823C8.15559 6.20381 8.18314 6.41666 8.06425 6.56325C7.94536 6.70985 7.72642 6.73663 7.57563 6.62104L0.271717 1.19061C0.120346 1.07531 0.093813 0.862748 0.212416 0.715589C0.331018 0.56843 0.54952 0.542635 0.70089 0.658079L2.8102 2.0687ZM1.37426 3.66029L1.60479 3.45167L2.89376 4.45105H1.68019C1.48735 4.45105 1.31336 4.33406 1.24521 4.15927C1.17852 3.98308 1.22927 3.78433 1.37426 3.66029ZM2.18186 6.97981L3.19534 4.68222L4.78879 5.89022L2.91406 7.49712C2.75022 7.63526 2.51099 7.64653 2.33555 7.52249C2.16011 7.39845 2.09631 7.17292 2.18186 6.97981Z" fill="white"/>
<g clip-path="url(#clip0_702_132)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.67628 3.55525H6.22609C6.41096 3.55525 6.57775 3.67062 6.63057 3.84298C6.70702 4.01672 6.65837 4.21271 6.51937 4.33502L6.07659 4.72246L7.6403 5.93868C7.85828 6.10821 7.89754 6.42235 7.72801 6.64032C7.55847 6.8583 7.24434 6.89756 7.02636 6.72803L1.02636 2.06136C0.808388 1.89183 0.769121 1.57769 0.938656 1.35972C1.10819 1.14174 1.42233 1.10248 1.6403 1.27201L3.00607 2.33428L5.04318 0.551681C5.20024 0.414909 5.42959 0.404484 5.59777 0.526523C5.76596 0.648645 5.82712 0.870539 5.74511 1.0616L4.67622 3.55506L4.67628 3.55525ZM3.25023 4.62627L4.80474 5.83533L2.96106 7.44854C2.804 7.58476 2.57424 7.59588 2.40633 7.47356C2.23828 7.35125 2.17713 7.12885 2.25899 6.93843L3.25023 4.62627ZM1.73426 3.44719L3.01695 4.44483H1.7657C1.59292 4.44483 1.42696 4.32946 1.36177 4.15711C1.2966 3.98336 1.34579 3.78738 1.48528 3.66506L1.73426 3.44719Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1350">
<clipPath id="clip0_702_132">
<rect width="8" height="8" fill="white"/>
</clipPath>
</defs>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,3 +1,10 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.78057 2.96296L4.59642 6.16966C4.41855 6.32749 4.21312 6.40515 4.00769 6.40515C3.80226 6.40515 3.59733 6.32686 3.44075 6.17028L0.256599 2.96358C0.00482339 2.73498 -0.06382 2.38913 0.0601891 2.09088C0.184298 1.79276 0.47686 1.59485 0.800787 1.59485H7.19164C7.51582 1.59485 7.80843 1.78976 7.93269 2.08963C8.05695 2.38926 8.01085 2.73473 7.78037 2.96271L7.78057 2.96296Z" fill="white"/>
<g clip-path="url(#clip0_430_1359)">
<path d="M6.36286 3.35324L4.37276 5.35315C4.26159 5.45158 4.1332 5.50002 4.0048 5.50002C3.87641 5.50002 3.74833 5.45119 3.65047 5.35354L1.66037 3.35363C1.50301 3.21106 1.46011 2.99537 1.53762 2.80936C1.61519 2.62343 1.79804 2.5 2.00049 2.5H5.99478C6.19739 2.5 6.38027 2.62156 6.45793 2.80858C6.53559 2.99545 6.50678 3.2109 6.36273 3.35309L6.36286 3.35324Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1359">
<rect width="8" height="8" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 495 B

After

Width:  |  Height:  |  Size: 613 B

View File

@@ -1,3 +1,10 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.03717 7.78065L1.83086 4.59689C1.67355 4.41904 1.5954 4.21363 1.5954 3.98568C1.5954 3.75774 1.67368 3.57538 1.83011 3.41882L5.03641 0.235058C5.26562 0.00560697 5.61029 -0.0630281 5.91013 0.0609657C6.20997 0.18496 6.40461 0.478537 6.40461 0.801672V7.19174C6.40461 7.51588 6.20947 7.80845 5.90988 7.9327C5.61004 8.05694 5.26486 8.01085 5.03692 7.7804L5.03717 7.78065Z" fill="white"/>
<g clip-path="url(#clip0_430_1360)">
<path d="M4.64677 6.36286L2.64687 4.37276C2.54843 4.26159 2.5 4.1332 2.5 4.0048C2.5 3.87641 2.54882 3.74833 2.64648 3.65047L4.64638 1.66037C4.78895 1.50301 5.00465 1.46011 5.19065 1.53762C5.37658 1.61519 5.50002 1.79804 5.50002 2.00049L5.50002 5.99478C5.50002 6.19739 5.37846 6.38027 5.19144 6.45793C5.00457 6.53559 4.78911 6.50678 4.64693 6.36273L4.64677 6.36286Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1360">
<rect width="8" height="8" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 492 B

After

Width:  |  Height:  |  Size: 622 B

View File

@@ -1,3 +1,10 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.95931 0.236879L6.17709 3.43204C6.33546 3.61052 6.4134 3.81666 6.4134 4.00018C6.4134 4.18369 6.33484 4.41195 6.17772 4.56907L2.95993 7.76423C2.72966 7.99425 2.384 8.06338 2.08309 7.93869C1.78217 7.81401 1.58659 7.56463 1.58659 7.21771V0.804768C1.58659 0.47947 1.78217 0.185847 2.08309 0.0611582C2.38375 -0.0635309 2.73042 0.0061038 2.95918 0.236628L2.95931 0.236879Z" fill="white"/>
<g clip-path="url(#clip0_430_1361)">
<path d="M3.35323 1.63714L5.35313 3.62724C5.45157 3.73841 5.5 3.8668 5.5 3.9952C5.5 4.12359 5.45118 4.25167 5.35352 4.34953L3.35362 6.33963C3.21105 6.49699 2.99535 6.53989 2.80935 6.46238C2.62342 6.38481 2.49998 6.20196 2.49998 5.99951L2.49998 2.00522C2.49998 1.80261 2.62154 1.61973 2.80856 1.54207C2.99543 1.46441 3.21089 1.49322 3.35307 1.63727L3.35323 1.63714Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1361">
<rect width="8" height="8" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 493 B

After

Width:  |  Height:  |  Size: 622 B

View File

@@ -1,3 +1,10 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.235788 5.03793L3.42201 1.82915C3.60024 1.67122 3.80581 1.59351 4.01137 1.59351C4.21693 1.59351 4.42199 1.67185 4.57867 1.82852L7.76489 5.0373C7.99427 5.26668 8.06321 5.61163 7.93887 5.9117C7.81453 6.21177 7.54328 6.40655 7.19734 6.40655H0.802589C0.478202 6.40655 0.1854 6.21127 0.0610601 5.91145C-0.0632802 5.61137 0.00590919 5.26593 0.235538 5.03781L0.235788 5.03793Z" fill="white"/>
<g clip-path="url(#clip0_430_1362)">
<path d="M1.63714 4.64676L3.62724 2.64685C3.73841 2.54842 3.8668 2.49998 3.9952 2.49998C4.12359 2.49998 4.25167 2.54881 4.34953 2.64646L6.33963 4.64637C6.49699 4.78894 6.53989 5.00463 6.46238 5.19064C6.38481 5.37657 6.20196 5.5 5.99951 5.5L2.00522 5.5C1.80261 5.5 1.61973 5.37844 1.54207 5.19142C1.46441 5.00455 1.49322 4.7891 1.63727 4.64691L1.63714 4.64676Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1362">
<rect width="8" height="8" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 496 B

After

Width:  |  Height:  |  Size: 617 B

View File

@@ -1,3 +1,3 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.28561 8C2.13936 8 1.99311 7.9442 1.88168 7.83259C1.65846 7.60937 1.65846 7.24776 1.88168 7.02454L4.90707 3.99996L1.88168 0.975457C1.65846 0.75224 1.65846 0.390629 1.88168 0.167413C2.10489 -0.0558042 2.4665 -0.0558042 2.68972 0.167413L6.11833 3.59602C6.34155 3.81924 6.34155 4.18085 6.11833 4.40407L2.68972 7.83268C2.57847 7.94464 2.43204 8 2.28561 8Z" fill="white"/>
<path d="M2.28561 8C2.13936 8 1.99311 7.9442 1.88168 7.83259C1.65846 7.60937 1.65846 7.24776 1.88168 7.02454L4.90707 3.99996L1.88168 0.975457C1.65846 0.752241 1.65846 0.390629 1.88168 0.167413C2.10489 -0.0558042 2.4665 -0.0558042 2.68972 0.167413L6.11833 3.59602C6.34155 3.81924 6.34155 4.18085 6.11833 4.40407L2.68972 7.83268C2.57847 7.94464 2.43204 8 2.28561 8Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 478 B

After

Width:  |  Height:  |  Size: 479 B

View File

@@ -1,3 +1,10 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_430_1285)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M6 12C9.31371 12 12 9.31371 12 6C12 2.68629 9.31371 0 6 0C2.68629 0 0 2.68629 0 6C0 9.31371 2.68629 12 6 12ZM9.53033 4.28033L8.46967 3.21967L4.875 6.81434L3.53033 5.46967L2.46967 6.53033L4.875 8.93566L9.53033 4.28033Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1285">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 386 B

After

Width:  |  Height:  |  Size: 530 B

View File

@@ -1,3 +1,10 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_430_1370)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 8C6.20914 8 8 6.20914 8 4C8 1.79086 6.20914 0 4 0C1.79086 0 0 1.79086 0 4C0 6.20914 1.79086 8 4 8ZM6.35355 2.85355L5.64645 2.14645L3.25 4.54289L2.35355 3.64645L1.64645 4.35355L3.25 5.95711L6.35355 2.85355Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1370">
<rect width="8" height="8" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 373 B

After

Width:  |  Height:  |  Size: 515 B

View File

@@ -1,3 +1,10 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_430_1294)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 6C12 9.31371 9.31371 12 6 12C2.68629 12 0 9.31371 0 6C0 2.68629 2.68629 0 6 0C9.31371 0 12 2.68629 12 6ZM5.25 6H4.5V4.5H6.75V8.25H7.5V9.75H5.25V6ZM6.75 3.75V2.25H5.25V3.75H6.75Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1294">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 350 B

After

Width:  |  Height:  |  Size: 494 B

View File

@@ -1,3 +1,10 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_430_1372)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 4C8 6.20914 6.20914 8 4 8C1.79086 8 0 6.20914 0 4C0 1.79086 1.79086 0 4 0C6.20914 0 8 1.79086 8 4ZM3.5 4H3V3H4.5V5.5H5V6.5H3.5V4ZM4.5 2.5V1.5H3.5V2.5H4.5Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1372">
<rect width="8" height="8" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 322 B

After

Width:  |  Height:  |  Size: 464 B

View File

@@ -1,3 +1,10 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_430_1287)">
<path d="M6 0C2.68594 0 0 2.68594 0 6C0 9.31406 2.68594 12 6 12C9.31406 12 12 9.31406 12 6C12 2.68594 9.31406 0 6 0ZM8.97187 5.76797C8.91328 5.90859 8.77734 6 8.625 6H7.125V8.25C7.125 8.66414 6.78914 9 6.375 9H5.625C5.21086 9 4.875 8.66414 4.875 8.25V6H3.375C3.22266 6 3.08672 5.90859 3.02812 5.76797C2.96953 5.62734 3.00234 5.46797 3.11016 5.36016L5.73516 2.73516C5.88141 2.58867 6.11906 2.58867 6.26531 2.73516L8.89031 5.36016C8.99766 5.46797 9.03047 5.62734 8.97187 5.76797Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1287">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 597 B

After

Width:  |  Height:  |  Size: 741 B

View File

@@ -1,3 +1,10 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_430_1376)">
<path d="M4 0C1.79063 0 0 1.79063 0 4C0 6.20937 1.79063 8 4 8C6.20937 8 8 6.20937 8 4C8 1.79063 6.20937 0 4 0ZM5.98125 3.84531C5.94219 3.93906 5.85156 4 5.75 4H4.75V5.5C4.75 5.77609 4.52609 6 4.25 6H3.75C3.47391 6 3.25 5.77609 3.25 5.5V4H2.25C2.14844 4 2.05781 3.93906 2.01875 3.84531C1.97969 3.75156 2.00156 3.64531 2.07344 3.57344L3.82344 1.82344C3.92094 1.72578 4.07938 1.72578 4.17688 1.82344L5.92688 3.57344C5.99844 3.64531 6.02031 3.75156 5.98125 3.84531Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1376">
<rect width="8" height="8" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 577 B

After

Width:  |  Height:  |  Size: 719 B

View File

@@ -1,3 +1,10 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_430_1292)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M6 12C9.31371 12 12 9.31371 12 6C12 2.68629 9.31371 0 6 0C2.68629 0 0 2.68629 0 6C0 9.31371 2.68629 12 6 12ZM3.21967 4.28033L4.93934 6L3.21967 7.71967L4.28033 8.78033L6 7.06066L7.71967 8.78033L8.78033 7.71967L7.06066 6L8.78033 4.28033L7.71967 3.21967L6 4.93934L4.28033 3.21967L3.21967 4.28033Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1292">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 462 B

After

Width:  |  Height:  |  Size: 606 B

View File

@@ -1,3 +1,10 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_430_1365)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M4 8C6.20914 8 8 6.20914 8 4C8 1.79086 6.20914 0 4 0C1.79086 0 0 1.79086 0 4C0 6.20914 1.79086 8 4 8ZM2.14645 2.85355L3.29289 4L2.14645 5.14645L2.85355 5.85355L4 4.70711L5.14645 5.85355L5.85355 5.14645L4.70711 4L5.85355 2.85355L5.14645 2.14645L4 3.29289L2.85355 2.14645L2.14645 2.85355Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1365">
<rect width="8" height="8" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 451 B

After

Width:  |  Height:  |  Size: 593 B

View File

@@ -1,3 +1,3 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.59892 2.76222C3.14641 2.17067 3.93013 1.80018 4.80011 1.80018C5.91195 1.80018 6.8813 2.40485 7.40066 3.30389C7.68565 3.09577 8.03064 3.00015 8.4 3.00015C9.39372 3.00015 10.1999 3.7895 10.1999 4.80009C10.1999 5.02884 10.1568 5.24633 10.08 5.44882C11.1749 5.67007 11.9999 6.63941 11.9999 7.8C11.9999 8.48623 11.7112 9.10497 11.233 9.52683L11.8274 9.99557C12.0224 10.1493 12.058 10.4324 11.9043 10.6274C11.7505 10.8224 11.4674 10.858 11.2724 10.7043L0.172556 2.00436C-0.0231882 1.85099 -0.0574997 1.56825 0.0958708 1.37251C0.249241 1.17676 0.531796 1.14245 0.727671 1.29582L2.59868 2.76184L2.59892 2.76222ZM1.82213 4.43635L9.13873 10.1999H2.70017C1.20903 10.1999 0.000248596 8.99059 0.000248596 7.50001C0.000248596 6.32255 0.753414 5.32133 1.80395 4.95196C1.80151 4.90134 1.8002 4.85072 1.8002 4.80009C1.8002 4.67635 1.8077 4.55448 1.82213 4.43635Z" fill="white"/>
<path d="M2.59892 2.76222C3.14641 2.17067 3.93013 1.80018 4.80011 1.80018C5.91195 1.80018 6.8813 2.40485 7.40066 3.30389C7.68565 3.09577 8.03064 3.00015 8.4 3.00015C9.39372 3.00015 10.1999 3.7895 10.1999 4.80009C10.1999 5.02884 10.1568 5.24633 10.08 5.44882C11.1749 5.67007 11.9999 6.63941 11.9999 7.80001C11.9999 8.48623 11.7112 9.10497 11.233 9.52683L11.8274 9.99557C12.0224 10.1493 12.058 10.4324 11.9043 10.6274C11.7505 10.8224 11.4674 10.858 11.2724 10.7043L0.172556 2.00436C-0.0231882 1.85099 -0.0574997 1.56825 0.0958708 1.37251C0.249241 1.17676 0.531795 1.14245 0.727671 1.29582L2.59868 2.76184L2.59892 2.76222ZM1.82213 4.43635L9.13873 10.1999H2.70017C1.20903 10.1999 0.000248596 8.99059 0.000248596 7.50001C0.000248596 6.32255 0.753414 5.32133 1.80395 4.95196C1.80151 4.90134 1.8002 4.85072 1.8002 4.80009C1.8002 4.67635 1.8077 4.55448 1.82213 4.43635Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 977 B

After

Width:  |  Height:  |  Size: 981 B

View File

@@ -1,3 +1,10 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.73261 1.8415C2.0976 1.44713 2.62009 1.20014 3.20007 1.20014C3.9413 1.20014 4.58753 1.60325 4.93377 2.20261C5.12376 2.06387 5.35376 2.00012 5.6 2.00012C6.26248 2.00012 6.79996 2.52635 6.79996 3.20008C6.79996 3.35258 6.77122 3.49757 6.71997 3.63257C7.44995 3.78007 7.99993 4.4263 7.99993 5.20002C7.99993 5.65751 7.80744 6.07 7.48869 6.35124L7.88493 6.66373C8.01493 6.76623 8.03868 6.95497 7.93618 7.08497C7.83368 7.21496 7.64494 7.23871 7.51494 7.13622L0.115037 1.33626C-0.0154588 1.23402 -0.0383331 1.04552 0.0639139 0.915025C0.166161 0.784529 0.35453 0.761655 0.485114 0.863902L1.73245 1.84125L1.73261 1.8415ZM1.21475 2.95759L6.09249 6.79998H1.80011C0.806017 6.79998 0.000165731 5.99375 0.000165731 5.00003C0.000165731 4.21505 0.502276 3.54757 1.20263 3.30133C1.20101 3.26758 1.20013 3.23383 1.20013 3.20008C1.20013 3.11759 1.20513 3.03634 1.21475 2.95759Z" fill="white"/>
<g clip-path="url(#clip0_430_1352)">
<path d="M1.73261 1.8415C2.0976 1.44713 2.62009 1.20014 3.20007 1.20014C3.9413 1.20014 4.58753 1.60325 4.93377 2.20261C5.12376 2.06387 5.35376 2.00012 5.6 2.00012C6.26248 2.00012 6.79997 2.52635 6.79997 3.20008C6.79997 3.35258 6.77122 3.49757 6.71997 3.63257C7.44995 3.78007 7.99993 4.4263 7.99993 5.20002C7.99993 5.65751 7.80744 6.07 7.48869 6.35124L7.88493 6.66373C8.01493 6.76623 8.03868 6.95497 7.93618 7.08497C7.83368 7.21496 7.64494 7.23871 7.51494 7.13622L0.115037 1.33626C-0.0154588 1.23402 -0.0383331 1.04552 0.0639139 0.915025C0.166161 0.784529 0.35453 0.761655 0.485114 0.863902L1.73245 1.84125L1.73261 1.8415ZM1.21475 2.95759L6.09249 6.79998H1.80011C0.806017 6.79998 0.000165731 5.99375 0.000165731 5.00003C0.000165731 4.21505 0.502276 3.54757 1.20263 3.30133C1.20101 3.26758 1.20013 3.23383 1.20013 3.20008C1.20013 3.11759 1.20513 3.03634 1.21475 2.95759Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1352">
<rect width="8" height="8" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 984 B

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,11 +1,10 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_616_81)">
<path opacity="0.6" d="M11 11L11 7L1 7L1 11L11 11Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.1818 1C1.51237 1 1.04544 1.48778 1.04544 2V10C1.04544 10.5122 1.51237 11 2.1818 11H9.81817C10.4876 11 10.9545 10.5122 10.9545 10V2C10.9545 1.48778 10.4876 1 9.81817 1H2.1818ZM0.0454407 2C0.0454407 0.855367 1.04377 0 2.1818 0H9.81817C10.9562 0 11.9545 0.855367 11.9545 2V10C11.9545 11.1446 10.9562 12 9.81817 12H2.1818C1.04377 12 0.0454407 11.1446 0.0454407 10V2Z" fill="white"/>
<path d="M11 8L11 7L1 7L1 8L11 8Z" fill="white"/>
<g clip-path="url(#clip0_702_214)">
<rect x="0.5" y="0.5" width="11" height="11" rx="1" stroke="white" stroke-opacity="0.4"/>
<path d="M12 7.5L12 10.5C12 11.3284 11.3284 12 10.5 12L1.5 12C0.671573 12 -1.67346e-07 11.3284 -1.31134e-07 10.5L0 7.5L12 7.5Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_616_81">
<clipPath id="clip0_702_214">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>

Before

Width:  |  Height:  |  Size: 791 B

After

Width:  |  Height:  |  Size: 478 B

View File

@@ -1,7 +1,7 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_610_112)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 1H1V7H7V1ZM1 0C0.447715 0 4.37114e-08 0.447715 4.37114e-08 1V7C4.37114e-08 7.55228 0.447715 8 1 8H7C7.55228 8 8 7.55228 8 7V1C8 0.447715 7.55228 0 7 0H1Z" fill="white"/>
<path d="M7 4C7.55228 4 8 4.44772 8 5V7C8 7.55228 7.55228 8 7 8H1C0.447715 8 4.37114e-08 7.55228 4.37114e-08 7L0 5C2.41411e-08 4.44771 0.447715 4 1 4L7 4Z" fill="white"/>
<rect x="0.5" y="0.5" width="7" height="7" rx="0.5" stroke="white" stroke-opacity="0.4"/>
<path d="M8 5L8 7C8 7.55228 7.55228 8 7 8L1 8C0.447715 8 -1.11564e-07 7.55228 -8.74228e-08 7L0 5L8 5Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_610_112">

Before

Width:  |  Height:  |  Size: 632 B

After

Width:  |  Height:  |  Size: 447 B

View File

@@ -1,11 +0,0 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_616_82)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.1818 1C1.51237 1 1.04544 1.48778 1.04544 2V10C1.04544 10.5122 1.51237 11 2.1818 11H9.81817C10.4876 11 10.9545 10.5122 10.9545 10V2C10.9545 1.48778 10.4876 1 9.81817 1H2.1818ZM0.0454407 2C0.0454407 0.855367 1.04377 0 2.1818 0H9.81817C10.9562 0 11.9545 0.855367 11.9545 2V10C11.9545 11.1446 10.9562 12 9.81817 12H2.1818C1.04377 12 0.0454407 11.1446 0.0454407 10V2Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.5 4C5.5 3.72386 5.72386 3.5 6 3.5H8C8.27614 3.5 8.5 3.72386 8.5 4V6C8.5 6.27614 8.27614 6.5 8 6.5C7.72386 6.5 7.5 6.27614 7.5 6V5.20711L5.20711 7.5H6C6.27614 7.5 6.5 7.72386 6.5 8C6.5 8.27614 6.27614 8.5 6 8.5H4C3.72386 8.5 3.5 8.27614 3.5 8V6C3.5 5.72386 3.72386 5.5 4 5.5C4.27614 5.5 4.5 5.72386 4.5 6V6.79289L6.79289 4.5H6C5.72386 4.5 5.5 4.27614 5.5 4Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_616_82">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,13 +0,0 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_610_113)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 1H1V7H7V1ZM1 0C0.447715 0 0 0.447715 0 1V7C0 7.55228 0.447715 8 1 8H7C7.55228 8 8 7.55228 8 7V1C8 0.447715 7.55228 0 7 0H1Z" fill="white"/>
<path d="M6 2H3L6 5V2Z" fill="white"/>
<path d="M2 6L5 6L2 3L2 6Z" fill="white"/>
<path d="M5.5 2.5L2.5 5.5" stroke="white"/>
</g>
<defs>
<clipPath id="clip0_610_113">
<rect width="8" height="8" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 557 B

View File

@@ -1,11 +1,10 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_620_198)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.1818 1C1.51237 1 1.04544 1.48778 1.04544 2V10C1.04544 10.5122 1.51237 11 2.1818 11H9.81817C10.4876 11 10.9545 10.5122 10.9545 10V2C10.9545 1.48778 10.4876 1 9.81817 1H2.1818ZM0.0454407 2C0.0454407 0.855367 1.04377 0 2.1818 0H9.81817C10.9562 0 11.9545 0.855367 11.9545 2V10C11.9545 11.1446 10.9562 12 9.81817 12H2.1818C1.04377 12 0.0454407 11.1446 0.0454407 10V2Z" fill="white"/>
<rect opacity="0.6" x="4" y="4" width="4" height="4" fill="white"/>
<rect x="3.5" y="3.5" width="5" height="5" rx="0.5" stroke="white"/>
<g clip-path="url(#clip0_702_213)">
<rect x="2" y="3" width="8" height="6" rx="1" fill="white"/>
<rect x="0.5" y="0.5" width="11" height="11" rx="1" stroke="white" stroke-opacity="0.4"/>
</g>
<defs>
<clipPath id="clip0_620_198">
<clipPath id="clip0_702_213">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>

Before

Width:  |  Height:  |  Size: 813 B

After

Width:  |  Height:  |  Size: 396 B

View File

@@ -1,6 +1,6 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_620_186)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 1H1V7H7V1ZM1 0C0.447715 0 0 0.447715 0 1V7C0 7.55228 0.447715 8 1 8H7C7.55228 8 8 7.55228 8 7V1C8 0.447715 7.55228 0 7 0H1Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 1H1V7H7V1ZM1 0C0.447715 0 0 0.447715 0 1V7C0 7.55228 0.447715 8 1 8H7C7.55228 8 8 7.55228 8 7V1C8 0.447715 7.55228 0 7 0H1Z" fill="white" fill-opacity="0.4"/>
<rect x="2" y="2" width="4" height="4" fill="white"/>
</g>
<defs>

Before

Width:  |  Height:  |  Size: 485 B

After

Width:  |  Height:  |  Size: 504 B

View File

@@ -1,11 +1,10 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_616_83)">
<path opacity="0.6" d="M11 1H7V11H11V1Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.1818 1C1.51237 1 1.04544 1.48778 1.04544 2V10C1.04544 10.5122 1.51237 11 2.1818 11H9.81817C10.4876 11 10.9545 10.5122 10.9545 10V2C10.9545 1.48778 10.4876 1 9.81817 1H2.1818ZM0.0454407 2C0.0454407 0.855367 1.04377 0 2.1818 0H9.81817C10.9562 0 11.9545 0.855367 11.9545 2V10C11.9545 11.1446 10.9562 12 9.81817 12H2.1818C1.04377 12 0.0454407 11.1446 0.0454407 10V2Z" fill="white"/>
<path d="M8 1H7V11H8V1Z" fill="white"/>
<g clip-path="url(#clip0_702_215)">
<rect x="0.5" y="0.5" width="11" height="11" rx="1" stroke="white" stroke-opacity="0.4"/>
<path d="M7.5 0H10.5C11.3284 0 12 0.671573 12 1.5V10.5C12 11.3284 11.3284 12 10.5 12H7.5V0Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_616_83">
<clipPath id="clip0_702_215">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>

Before

Width:  |  Height:  |  Size: 770 B

After

Width:  |  Height:  |  Size: 443 B

View File

@@ -1,7 +1,7 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_610_114)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 1H1V7H7V1ZM1 0C0.447715 0 0 0.447715 0 1V7C0 7.55228 0.447715 8 1 8H7C7.55228 8 8 7.55228 8 7V1C8 0.447715 7.55228 0 7 0H1Z" fill="white"/>
<path d="M4 1C4 0.447715 4.44772 0 5 0H7C7.55228 0 8 0.447715 8 1V7C8 7.55228 7.55228 8 7 8H5C4.44772 8 4 7.55228 4 7V1Z" fill="white"/>
<rect x="0.5" y="0.5" width="7" height="7" rx="0.5" stroke="white" stroke-opacity="0.4"/>
<path d="M5 0H7C7.55228 0 8 0.447715 8 1V7C8 7.55228 7.55228 8 7 8H5V0Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_610_114">

Before

Width:  |  Height:  |  Size: 568 B

After

Width:  |  Height:  |  Size: 417 B

View File

@@ -1,3 +1,10 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_430_1286)">
<path d="M11.3333 1.33335H9L8.33333 0.666687H6.66667C6.29958 0.666687 6 0.96627 6 1.33335V4.66669C6 5.03377 6.29958 5.33335 6.66667 5.33335H11.3333C11.7004 5.33335 12 5.03377 12 4.66669V2.00002C12 1.63294 11.7 1.33335 11.3333 1.33335ZM11.3333 7.33335H9L8.33333 6.66669H6.66667C6.29958 6.66669 6 6.96627 6 7.33335V10.6667C6 11.0338 6.29958 11.3334 6.66667 11.3334H11.3333C11.7004 11.3334 12 11.0338 12 10.6667V8.00002C12 7.63335 11.7 7.33335 11.3333 7.33335ZM1.33333 1.00002C1.33333 0.815125 1.185 0.666687 1 0.666687H0.333333C0.148438 0.666687 0 0.81502 0 1.00002V9.33335C0 9.70044 0.299583 10 0.666667 10H5.33333V8.66669H1.33333V4.00002H5.33333V2.66669H1.33333V1.00002Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1286">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 790 B

After

Width:  |  Height:  |  Size: 934 B

View File

@@ -1,3 +1,10 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_430_1367)">
<path d="M7.55556 0.888902H6L5.55556 0.444458H4.44444C4.19972 0.444458 4 0.64418 4 0.888902V3.11112C4 3.35585 4.19972 3.55557 4.44444 3.55557H7.55556C7.80028 3.55557 8 3.35585 8 3.11112V1.33335C8 1.08862 7.8 0.888902 7.55556 0.888902ZM7.55556 4.8889H6L5.55556 4.44446H4.44444C4.19972 4.44446 4 4.64418 4 4.8889V7.11112C4 7.35585 4.19972 7.55557 4.44444 7.55557H7.55556C7.80028 7.55557 8 7.35585 8 7.11112V5.33335C8 5.0889 7.8 4.8889 7.55556 4.8889ZM0.888889 0.66668C0.888889 0.543416 0.79 0.444458 0.666667 0.444458H0.222222C0.0989583 0.444458 0 0.543347 0 0.66668V6.22224C0 6.46696 0.199722 6.66668 0.444444 6.66668H3.55556V5.77779H0.888889V2.66668H3.55556V1.77779H0.888889V0.66668Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1367">
<rect width="8" height="8" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 799 B

After

Width:  |  Height:  |  Size: 941 B

View File

@@ -1,6 +1,6 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_614_97)">
<path d="M5 7.62515C5 7.77359 4.9125 7.90796 4.77812 7.96734C4.64219 8.02828 4.47031 8.00327 4.37344 7.90328L3.12344 6.77828C3.04531 6.70796 3 6.6064 3 6.50015C3 6.3939 3.04531 6.29234 3.12344 6.22203L4.37344 5.09703C4.47031 4.99703 4.64219 4.97203 4.77812 5.03296C4.9125 5.09234 5 5.22671 5 5.37515V6.00015H5.25C5.80156 6.00015 6.25 5.55171 6.25 5.00015V2.39546C5.80781 2.18921 5.5 1.76265 5.5 1.25015C5.5 0.559838 6.05937 0.000150232 6.75 0.000150232C7.44063 0.000134607 8 0.559838 8 1.25015C8 1.76265 7.69219 2.18921 7.25 2.39546V5.00015C7.25 6.10484 6.35469 7.00015 5.25 7.00015H5V7.62515ZM7.125 1.23609C7.125 1.04296 6.95781 0.861088 6.75 0.861088C6.54219 0.861088 6.375 1.04296 6.375 1.23609C6.375 1.45718 6.54219 1.61109 6.75 1.61109C6.95781 1.61109 7.125 1.45718 7.125 1.23609ZM3 0.37515C3 0.227025 3.0875 0.0928065 3.22187 0.032494C3.35781 -0.0278185 3.51562 -0.00281852 3.62656 0.096244L4.87656 1.22123C4.95469 1.29232 5 1.39373 5 1.49998C5 1.60623 4.95469 1.70779 4.87656 1.7781L3.62656 2.9031C3.51562 3.0031 3.35781 3.0281 3.22187 2.96717C3.0875 2.90779 3 2.77342 3 2.62498V1.99998H2.75C2.19844 1.99998 1.75 2.44842 1.75 2.99998V5.60467C2.19219 5.79685 2.5 6.23748 2.5 6.74998C2.5 7.4406 1.94062 7.99998 1.25 7.99998C0.559687 7.99998 0 7.4406 0 6.74998C0 6.23748 0.308594 5.79685 0.75 5.60467V2.99998C0.75 1.89529 1.64531 0.999978 2.75 0.999978H3V0.374978V0.37515ZM0.875 6.75015C0.875 6.95796 1.04297 7.12515 1.25 7.12515C1.45703 7.12515 1.625 6.95796 1.625 6.75015C1.625 6.54234 1.45703 6.37515 1.25 6.37515C1.04297 6.37515 0.875 6.54234 0.875 6.75015Z" fill="white"/>
<path d="M5 7.62515C5 7.77359 4.9125 7.90796 4.77812 7.96734C4.64219 8.02828 4.47031 8.00328 4.37344 7.90328L3.12344 6.77828C3.04531 6.70796 3 6.6064 3 6.50015C3 6.3939 3.04531 6.29234 3.12344 6.22203L4.37344 5.09703C4.47031 4.99703 4.64219 4.97203 4.77812 5.03296C4.9125 5.09234 5 5.22671 5 5.37515V6.00015H5.25C5.80156 6.00015 6.25 5.55171 6.25 5.00015V2.39546C5.80781 2.18921 5.5 1.76265 5.5 1.25015C5.5 0.559838 6.05937 0.000150232 6.75 0.000150232C7.44063 0.000134607 8 0.559838 8 1.25015C8 1.76265 7.69219 2.18921 7.25 2.39546V5.00015C7.25 6.10484 6.35469 7.00015 5.25 7.00015H5V7.62515ZM7.125 1.23609C7.125 1.04296 6.95781 0.861088 6.75 0.861088C6.54219 0.861088 6.375 1.04296 6.375 1.23609C6.375 1.45718 6.54219 1.61109 6.75 1.61109C6.95781 1.61109 7.125 1.45718 7.125 1.23609ZM3 0.37515C3 0.227025 3.0875 0.0928065 3.22187 0.032494C3.35781 -0.0278185 3.51563 -0.00281852 3.62656 0.096244L4.87656 1.22123C4.95469 1.29232 5 1.39373 5 1.49998C5 1.60623 4.95469 1.70779 4.87656 1.7781L3.62656 2.9031C3.51563 3.0031 3.35781 3.0281 3.22187 2.96717C3.0875 2.90779 3 2.77342 3 2.62498V1.99998H2.75C2.19844 1.99998 1.75 2.44842 1.75 2.99998V5.60467C2.19219 5.79685 2.5 6.23748 2.5 6.74998C2.5 7.4406 1.94063 7.99998 1.25 7.99998C0.559687 7.99998 0 7.4406 0 6.74998C0 6.23748 0.308594 5.79685 0.75 5.60467V2.99998C0.75 1.89529 1.64531 0.999978 2.75 0.999978H3V0.374978V0.37515ZM0.875 6.75015C0.875 6.95796 1.04297 7.12515 1.25 7.12515C1.45703 7.12515 1.625 6.95796 1.625 6.75015C1.625 6.54234 1.45703 6.37515 1.25 6.37515C1.04297 6.37515 0.875 6.54234 0.875 6.75015Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_614_97">

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -1,3 +1,10 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.8167 11.0391L8.67607 7.89844C9.35576 7.06641 9.73076 6.01875 9.73076 4.875C9.73076 2.18203 7.54802 0 4.85576 0C2.16349 0 0.00161743 2.18273 0.00161743 4.875C0.00161743 7.56727 2.18412 9.75 4.85552 9.75C5.99904 9.75 7.0481 9.35367 7.87896 8.69438L11.0196 11.835C11.1508 11.9461 11.2961 12 11.4391 12C11.5821 12 11.7269 11.9449 11.8369 11.835C12.0555 11.6154 12.0555 11.2591 11.8165 11.0388L11.8167 11.0391ZM1.12685 4.875C1.12685 2.80734 2.8092 1.125 4.87685 1.125C6.94451 1.125 8.62685 2.80734 8.62685 4.875C8.62685 6.94266 6.94451 8.625 4.87685 8.625C2.8092 8.625 1.12685 6.94219 1.12685 4.875Z" fill="white"/>
<g clip-path="url(#clip0_430_1288)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.40624 7.54167C6.77901 8.13568 5.93205 8.5 5 8.5C3.067 8.5 1.5 6.933 1.5 5C1.5 3.067 3.067 1.5 5 1.5C6.933 1.5 8.5 3.067 8.5 5C8.5 5.93205 8.13568 6.77901 7.54167 7.40624C7.51667 7.42558 7.49261 7.44673 7.46967 7.46967C7.44673 7.49261 7.42558 7.51667 7.40624 7.54167ZM7.96544 9.0261C7.13578 9.63821 6.11014 10 5 10C2.23858 10 0 7.76142 0 5C0 2.23858 2.23858 0 5 0C7.76142 0 10 2.23858 10 5C10 6.11014 9.63821 7.13578 9.0261 7.96544L11.5303 10.4697C11.8232 10.7626 11.8232 11.2374 11.5303 11.5303C11.2374 11.8232 10.7626 11.8232 10.4697 11.5303L7.96544 9.0261Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1288">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 727 B

After

Width:  |  Height:  |  Size: 874 B

View File

@@ -1,3 +1,10 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.87779 7.35938L5.78404 5.26562C6.23716 4.71094 6.48716 4.0125 6.48716 3.25C6.48716 1.45469 5.03201 0 3.23716 0C1.44232 0 0.00106812 1.45516 0.00106812 3.25C0.00106812 5.04484 1.45607 6.5 3.23701 6.5C3.99935 6.5 4.69873 6.23578 5.25263 5.79625L7.34638 7.89C7.43388 7.96406 7.53076 8 7.62607 8C7.72138 8 7.81794 7.96328 7.89123 7.89C8.03701 7.74359 8.03701 7.50609 7.87763 7.35922L7.87779 7.35938ZM0.751224 3.25C0.751224 1.87156 1.87279 0.75 3.25122 0.75C4.62966 0.75 5.75122 1.87156 5.75122 3.25C5.75122 4.62844 4.62966 5.75 3.25122 5.75C1.87279 5.75 0.751224 4.62813 0.751224 3.25Z" fill="white"/>
<g clip-path="url(#clip0_430_1369)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.16734 5.87445C4.62987 6.26778 3.96705 6.5 3.25 6.5C1.45507 6.5 0 5.04493 0 3.25C0 1.45507 1.45507 0 3.25 0C5.04493 0 6.5 1.45507 6.5 3.25C6.5 3.96705 6.26778 4.62987 5.87445 5.16734L7.85355 7.14645C8.04882 7.34171 8.04882 7.65829 7.85355 7.85355C7.65829 8.04882 7.34171 8.04882 7.14645 7.85355L5.16734 5.87445ZM5.5 3.25C5.5 4.49264 4.49264 5.5 3.25 5.5C2.00736 5.5 1 4.49264 1 3.25C1 2.00736 2.00736 1 3.25 1C4.49264 1 5.5 2.00736 5.5 3.25Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1369">
<rect width="8" height="8" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 708 B

After

Width:  |  Height:  |  Size: 750 B

View File

@@ -1,6 +1,6 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_609_69)">
<path d="M2.77187 4.52188L0.999998 6.29375V5.50001C0.999998 5.2236 0.776405 5.00001 0.499999 5.00001C0.223593 5.00001 0 5.2236 0 5.50001V7.5C0 7.565 0.013125 7.62985 0.0385155 7.69094C0.0891405 7.81328 0.186484 7.91078 0.308984 7.96141C0.370077 7.9875 0.434921 8 0.499921 8H2.49992C2.77632 8 2.99992 7.77641 2.99992 7.5C2.99992 7.2236 2.77632 7 2.49992 7H1.70773L3.4796 5.22813C3.67492 5.03282 3.67492 4.71641 3.4796 4.5211C3.28429 4.32579 2.9671 4.32657 2.77179 4.52188H2.77187ZM7.96092 0.309078C7.91014 0.186578 7.8128 0.089078 7.6903 0.038453C7.62967 0.0131406 7.56561 0 7.49999 0H5.49999C5.22358 0 4.99999 0.223593 4.99999 0.499999C4.99999 0.776405 5.22358 0.999998 5.49999 0.999998H6.29296L4.52109 2.77187C4.32577 2.96718 4.32577 3.28359 4.52109 3.4789C4.71624 3.67406 5.03265 3.67437 5.22812 3.4789L6.99999 1.70782V2.50001C6.99999 2.77642 7.22358 3.00001 7.49999 3.00001C7.77639 3.00001 7.99998 2.77642 7.99998 2.50001V0.500015C7.99998 0.435015 7.98748 0.370171 7.96092 0.309078Z" fill="white"/>
<path d="M2.77188 4.52188L1.00001 6.29375V5.50001C1.00001 5.2236 0.776412 5.00001 0.500007 5.00001C0.223601 5.00001 7.62939e-06 5.2236 7.62939e-06 5.50001V7.5C7.62939e-06 7.565 0.0131326 7.62984 0.0385232 7.69094C0.0891481 7.81328 0.186492 7.91078 0.308991 7.96141C0.370085 7.9875 0.434929 8 0.499929 8H2.49992C2.77633 8 2.99992 7.77641 2.99992 7.5C2.99992 7.2236 2.77633 7 2.49992 7H1.70774L3.47961 5.22813C3.67492 5.03282 3.67492 4.71641 3.47961 4.5211C3.2843 4.32579 2.96711 4.32657 2.7718 4.52188H2.77188ZM7.96093 0.309078C7.91015 0.186578 7.81281 0.089078 7.69031 0.0384531C7.62968 0.0131406 7.56562 0 7.49999 0H5.5C5.22359 0 5 0.223593 5 0.499999C5 0.776405 5.22359 0.999998 5.5 0.999998H6.29296L4.52109 2.77187C4.32578 2.96718 4.32578 3.28359 4.52109 3.4789C4.71625 3.67406 5.03265 3.67437 5.22812 3.4789L6.99999 1.70782V2.50001C6.99999 2.77642 7.22359 3.00001 7.49999 3.00001C7.7764 3.00001 7.99999 2.77642 7.99999 2.50001V0.500015C7.99999 0.435015 7.98749 0.370171 7.96093 0.309078Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_609_69">

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1,6 +1,6 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_609_75)">
<path d="M0.854041 7.85284L2.75022 5.95775V6.74984C2.75022 7.02622 2.97379 7.24978 3.25017 7.24978C3.52654 7.24978 3.75011 7.02622 3.75011 6.74984V4.75008C3.75011 4.68493 3.73683 4.62009 3.71152 4.55916C3.6609 4.43605 3.56404 4.33919 3.44061 4.28919C3.37968 4.26264 3.31563 4.25014 3.25001 4.25014H1.25024C0.97387 4.25014 0.750303 4.4737 0.750303 4.75008C0.750303 5.02645 0.97387 5.25002 1.25024 5.25002H2.04312L0.146467 7.14667C-0.0488224 7.34196 -0.0488224 7.65833 0.146467 7.85362C0.341757 8.04891 0.658595 8.04813 0.853884 7.85284H0.854041ZM4.28911 3.44086C4.33973 3.56334 4.43706 3.66083 4.5597 3.71145C4.62032 3.7377 4.68437 3.7502 4.74999 3.7502H6.74976C7.02613 3.7502 7.2497 3.52663 7.2497 3.25025C7.2497 2.97388 7.02613 2.75031 6.74976 2.75031H5.95688L7.85353 0.85366C8.04882 0.65837 8.04882 0.342001 7.85353 0.146711C7.6584 -0.048422 7.34203 -0.0487345 7.14658 0.146711L5.24993 2.04415V1.25049C5.24993 0.974114 5.02636 0.750547 4.74999 0.750547C4.47362 0.750547 4.25005 0.974114 4.25005 1.25049V3.23619C4.25005 3.31587 4.26255 3.37993 4.28911 3.44086Z" fill="white"/>
<path d="M0.854041 7.85284L2.75022 5.95775V6.74984C2.75022 7.02622 2.97379 7.24979 3.25017 7.24979C3.52654 7.24979 3.75011 7.02622 3.75011 6.74984V4.75008C3.75011 4.68493 3.73683 4.62009 3.71152 4.55916C3.6609 4.43605 3.56404 4.33919 3.44061 4.28919C3.37968 4.26264 3.31563 4.25014 3.25001 4.25014H1.25024C0.97387 4.25014 0.750303 4.4737 0.750303 4.75008C0.750303 5.02645 0.97387 5.25002 1.25024 5.25002H2.04312L0.146467 7.14667C-0.0488224 7.34196 -0.0488224 7.65833 0.146467 7.85362C0.341757 8.04891 0.658595 8.04813 0.853884 7.85284H0.854041ZM4.28911 3.44086C4.33973 3.56334 4.43706 3.66083 4.5597 3.71145C4.62032 3.7377 4.68437 3.7502 4.74999 3.7502H6.74976C7.02613 3.7502 7.2497 3.52663 7.2497 3.25025C7.2497 2.97388 7.02613 2.75031 6.74976 2.75031H5.95688L7.85353 0.85366C8.04882 0.65837 8.04882 0.342001 7.85353 0.146711C7.6584 -0.048422 7.34203 -0.0487345 7.14658 0.146711L5.24993 2.04415V1.25049C5.24993 0.974114 5.02636 0.750547 4.74999 0.750547C4.47362 0.750547 4.25005 0.974114 4.25005 1.25049V3.23619C4.25005 3.31587 4.26255 3.37993 4.28911 3.44086Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_609_75">

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1,3 +1,10 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 2.5V9.5M2.5 6H9.5" stroke="white" stroke-linecap="round"/>
<g clip-path="url(#clip0_519_280)">
<path d="M6 2.5V9.5M2.5 6H9.5" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
</g>
<defs>
<clipPath id="clip0_519_280">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 174 B

After

Width:  |  Height:  |  Size: 335 B

View File

@@ -1,3 +1,10 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 2V14M2 8H14" stroke="white" stroke-width="1.71429" stroke-linecap="round"/>
<g clip-path="url(#clip0_702_228)">
<path d="M8.00001 3.33331V12.6666M3.33334 7.99998H12.6667" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
</g>
<defs>
<clipPath id="clip0_702_228">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 191 B

After

Width:  |  Height:  |  Size: 363 B

View File

@@ -1,3 +1,10 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4 1.5V6.5M1.5 4H6.5" stroke="white" stroke-linecap="round"/>
<g clip-path="url(#clip0_519_287)">
<path d="M4 1V7M1 4H7" stroke="white" stroke-linecap="round"/>
</g>
<defs>
<clipPath id="clip0_519_287">
<rect width="8" height="8" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 170 B

After

Width:  |  Height:  |  Size: 302 B

View File

@@ -1,5 +1,12 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_430_1301)">
<path d="M11 1H6V11H11V1Z" fill="white" fill-opacity="0.2"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.1818 1C1.51237 1 1.04544 1.48778 1.04544 2V10C1.04544 10.5122 1.51237 11 2.1818 11H9.81817C10.4876 11 10.9545 10.5122 10.9545 10V2C10.9545 1.48778 10.4876 1 9.81817 1H2.1818ZM0.0454407 2C0.0454407 0.855367 1.04377 0 2.1818 0H9.81817C10.9562 0 11.9545 0.855367 11.9545 2V10C11.9545 11.1446 10.9562 12 9.81817 12H2.1818C1.04377 12 0.0454407 11.1446 0.0454407 10V2Z" fill="white"/>
<path d="M6.09091 1H5V11H6.09091V1Z" fill="white"/>
<path d="M6 1H5V11H6V1Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1301">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 647 B

After

Width:  |  Height:  |  Size: 779 B

View File

@@ -1,3 +1,10 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_430_1295)">
<path d="M0 2.25C0 1.42148 0.67148 0.75 1.5 0.75H10.5C11.3273 0.75 12 1.42148 12 2.25V9.75C12 10.5773 11.3273 11.25 10.5 11.25H1.5C0.67148 11.25 0 10.5773 0 9.75V2.25ZM2.39766 3.55781C2.18789 3.7875 2.20336 4.14141 2.43281 4.35234L4.23047 6L2.43281 7.64766C2.20336 7.85859 2.18789 8.2125 2.39766 8.44219C2.60859 8.65078 2.9625 8.68594 3.19219 8.47734L5.44219 6.41484C5.55937 6.30703 5.625 6.15703 5.625 5.97891C5.625 5.84297 5.55937 5.69297 5.44219 5.58516L3.19219 3.52266C2.9625 3.31406 2.60859 3.32813 2.39766 3.55781ZM5.8125 7.875C5.50078 7.875 5.25 8.12578 5.25 8.4375C5.25 8.74922 5.50078 9 5.8125 9H9.1875C9.4992 9 9.75 8.74922 9.75 8.4375C9.75 8.12578 9.4992 7.875 9.1875 7.875H5.8125Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1295">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 812 B

After

Width:  |  Height:  |  Size: 956 B

View File

@@ -1,3 +1,10 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_430_1381)">
<path d="M0 1.5C0 0.947653 0.447653 0.5 1 0.5H7C7.55153 0.5 8 0.947653 8 1.5V6.5C8 7.05153 7.55153 7.5 7 7.5H1C0.447653 7.5 0 7.05153 0 6.5V1.5ZM1.59844 2.37187C1.45859 2.525 1.46891 2.76094 1.62187 2.90156L2.82031 4L1.62187 5.09844C1.46891 5.23906 1.45859 5.475 1.59844 5.62813C1.73906 5.76719 1.975 5.79063 2.12813 5.65156L3.62813 4.27656C3.70625 4.20469 3.75 4.10469 3.75 3.98594C3.75 3.89531 3.70625 3.79531 3.62813 3.72344L2.12813 2.34844C1.975 2.20937 1.73906 2.21875 1.59844 2.37187ZM3.875 5.25C3.66719 5.25 3.5 5.41719 3.5 5.625C3.5 5.83281 3.66719 6 3.875 6H6.125C6.3328 6 6.5 5.83281 6.5 5.625C6.5 5.41719 6.3328 5.25 6.125 5.25H3.875Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1381">
<rect width="8" height="8" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 761 B

After

Width:  |  Height:  |  Size: 903 B

View File

@@ -1,3 +1,10 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_430_1297)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 11.625H0V9.375L5.25 0.375H6.75L12 9.375V11.625ZM5.25 3.375H6.75V7.125H5.25V3.375ZM5.25 8.625H6.75V10.125H5.25V8.625Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1297">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 289 B

After

Width:  |  Height:  |  Size: 433 B

View File

@@ -1,3 +1,10 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_430_1371)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 7.75H0V6.25L3.5 0.25H4.5L8 6.25V7.75ZM3.5 2.25H4.5V4.75H3.5V2.25ZM3.5 5.75H4.5V6.75H3.5V5.75Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1371">
<rect width="8" height="8" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 261 B

After

Width:  |  Height:  |  Size: 403 B

View File

@@ -1,3 +1,10 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_430_1383)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.75 1C5.33579 1 5 1.33579 5 1.75V3H6.5V8H0.5V3H4V1.75C4 0.783502 4.7835 0 5.75 0C6.7165 0 7.5 0.783502 7.5 1.75V2H6.5V1.75C6.5 1.33579 6.16421 1 5.75 1ZM4.5 5H2.5V6H4.5V5Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1383">
<rect width="8" height="8" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 338 B

After

Width:  |  Height:  |  Size: 480 B

View File

@@ -1,3 +1,10 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_430_1299)">
<path d="M6 0C2.68594 0 0 2.68594 0 6C0 9.31406 2.68594 12 6 12C9.31406 12 12 9.31406 12 6C12 2.68594 9.31406 0 6 0ZM6 3C6.93211 3 7.6875 3.75563 7.6875 4.6875C7.6875 5.61937 6.93281 6.375 6 6.375C5.06813 6.375 4.3125 5.61937 4.3125 4.6875C4.3125 3.75563 5.06719 3 6 3ZM6 10.5C4.75945 10.5 3.63516 9.99539 2.81953 9.1807C3.19922 8.20078 4.13672 7.5 5.25 7.5H6.75C7.86422 7.5 8.80172 8.20031 9.18047 9.1807C8.36484 9.99609 7.23984 10.5 6 10.5Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1299">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 562 B

After

Width:  |  Height:  |  Size: 706 B

View File

@@ -1,3 +1,10 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4 0C1.79063 0 0 1.79063 0 4C0 6.20937 1.79063 8 4 8C6.20937 8 8 6.20937 8 4C8 1.79063 6.20937 0 4 0ZM4 2C4.62141 2 5.125 2.50375 5.125 3.125C5.125 3.74625 4.62187 4.25 4 4.25C3.37875 4.25 2.875 3.74625 2.875 3.125C2.875 2.50375 3.37812 2 4 2ZM4 7C3.17297 7 2.42344 6.66359 1.87969 6.12047C2.13281 5.46719 2.75781 5 3.5 5H4.5C5.24281 5 5.86781 5.46688 6.12031 6.12047C5.57656 6.66406 4.82656 7 4 7Z" fill="white"/>
<g clip-path="url(#clip0_430_1382)">
<path d="M4 0C1.79063 0 0 1.79063 0 4C0 6.20937 1.79063 8 4 8C6.20937 8 8 6.20937 8 4C8 1.79063 6.20937 0 4 0ZM4 2C4.62141 2 5.125 2.50375 5.125 3.125C5.125 3.74625 4.62187 4.25 4 4.25C3.37875 4.25 2.875 3.74625 2.875 3.125C2.875 2.50375 3.37813 2 4 2ZM4 7C3.17297 7 2.42344 6.66359 1.87969 6.12047C2.13281 5.46719 2.75781 5 3.5 5H4.5C5.24281 5 5.86781 5.46687 6.12031 6.12047C5.57656 6.66406 4.82656 7 4 7Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1382">
<rect width="8" height="8" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 523 B

After

Width:  |  Height:  |  Size: 665 B

View File

@@ -1,3 +1,3 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.2 6.00001C5.52563 6.00001 6.6 4.92545 6.6 3.60001C6.6 2.27457 5.52563 1.20001 4.2 1.20001C2.87438 1.20001 1.8 2.27457 1.8 3.60001C1.8 4.92545 2.87438 6.00001 4.2 6.00001ZM5.15063 6.90001H3.24938C1.45444 6.90001 0 8.35501 0 10.1494C0 10.5094 0.291 10.8 0.649875 10.8H7.74937C8.10938 10.8 8.4 10.5094 8.4 10.1494C8.4 8.35501 6.945 6.90001 5.15063 6.90001ZM8.98313 7.20001H7.59844C8.46 7.90689 9 8.96439 9 10.1494C9 10.3894 8.92875 10.6106 8.8125 10.8H11.4C11.7319 10.8 12 10.53 12 10.1831C12 8.54251 10.6575 7.20001 8.98313 7.20001ZM8.1 6.00001C9.26063 6.00001 10.2 5.06064 10.2 3.90001C10.2 2.73939 9.26063 1.80001 8.1 1.80001C7.62919 1.80001 7.19925 1.96042 6.849 2.22207C7.065 2.63682 7.2 3.10126 7.2 3.60001C7.2 4.26601 6.97631 4.87764 6.60769 5.37582C6.98813 5.76001 7.515 6.00001 8.1 6.00001Z" fill="white"/>
<path d="M4.2 6.00001C5.52563 6.00001 6.6 4.92545 6.6 3.60001C6.6 2.27457 5.52563 1.20001 4.2 1.20001C2.87438 1.20001 1.8 2.27457 1.8 3.60001C1.8 4.92545 2.87438 6.00001 4.2 6.00001ZM5.15063 6.90001H3.24938C1.45444 6.90001 0 8.35501 0 10.1494C0 10.5094 0.291 10.8 0.649875 10.8H7.74938C8.10938 10.8 8.4 10.5094 8.4 10.1494C8.4 8.35501 6.945 6.90001 5.15063 6.90001ZM8.98313 7.20001H7.59844C8.46 7.90689 9 8.96439 9 10.1494C9 10.3894 8.92875 10.6106 8.8125 10.8H11.4C11.7319 10.8 12 10.53 12 10.1831C12 8.54251 10.6575 7.20001 8.98313 7.20001ZM8.1 6.00001C9.26063 6.00001 10.2 5.06064 10.2 3.90001C10.2 2.73939 9.26063 1.80001 8.1 1.80001C7.62919 1.80001 7.19925 1.96042 6.849 2.22207C7.065 2.63682 7.2 3.10126 7.2 3.60001C7.2 4.26601 6.97631 4.87764 6.60769 5.37582C6.98813 5.76001 7.515 6.00001 8.1 6.00001Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 928 B

After

Width:  |  Height:  |  Size: 928 B

View File

@@ -1,3 +1,10 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.8 3.99999C3.68375 3.99999 4.4 3.28361 4.4 2.39999C4.4 1.51636 3.68375 0.799988 2.8 0.799988C1.91625 0.799988 1.2 1.51636 1.2 2.39999C1.2 3.28361 1.91625 3.99999 2.8 3.99999ZM3.43375 4.59999H2.16625C0.969625 4.59999 0 5.56999 0 6.76624C0 7.00624 0.194 7.19999 0.43325 7.19999H5.16625C5.40625 7.19999 5.6 7.00624 5.6 6.76624C5.6 5.56999 4.63 4.59999 3.43375 4.59999ZM5.98875 4.79999H5.06563C5.64 5.27124 6 5.97624 6 6.76624C6 6.92624 5.9525 7.07374 5.875 7.19999H7.6C7.82125 7.19999 8 7.01999 8 6.78874C8 5.69499 7.105 4.79999 5.98875 4.79999ZM5.4 3.99999C6.17375 3.99999 6.8 3.37374 6.8 2.59999C6.8 1.82624 6.17375 1.19999 5.4 1.19999C5.08612 1.19999 4.7995 1.30693 4.566 1.48136C4.71 1.75786 4.8 2.06749 4.8 2.39999C4.8 2.84399 4.65088 3.25174 4.40513 3.58386C4.65875 3.83999 5.01 3.99999 5.4 3.99999Z" fill="white"/>
<g clip-path="url(#clip0_430_1375)">
<path d="M2.8 3.99999C3.68375 3.99999 4.4 3.28361 4.4 2.39999C4.4 1.51636 3.68375 0.799988 2.8 0.799988C1.91625 0.799988 1.2 1.51636 1.2 2.39999C1.2 3.28361 1.91625 3.99999 2.8 3.99999ZM3.43375 4.59999H2.16625C0.969625 4.59999 0 5.56999 0 6.76624C0 7.00624 0.194 7.19999 0.43325 7.19999H5.16625C5.40625 7.19999 5.6 7.00624 5.6 6.76624C5.6 5.56999 4.63 4.59999 3.43375 4.59999ZM5.98875 4.79999H5.06563C5.64 5.27124 6 5.97624 6 6.76624C6 6.92624 5.9525 7.07374 5.875 7.19999H7.6C7.82125 7.19999 8 7.01999 8 6.78874C8 5.69499 7.105 4.79999 5.98875 4.79999ZM5.4 3.99999C6.17375 3.99999 6.8 3.37374 6.8 2.59999C6.8 1.82624 6.17375 1.19999 5.4 1.19999C5.08613 1.19999 4.7995 1.30693 4.566 1.48136C4.71 1.75786 4.8 2.06749 4.8 2.39999C4.8 2.84399 4.65088 3.25174 4.40513 3.58386C4.65875 3.83999 5.01 3.99999 5.4 3.99999Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1375">
<rect width="8" height="8" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 929 B

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -1,3 +1,10 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_430_1373)">
<path d="M2.8 3.99999C3.68375 3.99999 4.4 3.28361 4.4 2.39999C4.4 1.51636 3.68375 0.799988 2.8 0.799988C1.91625 0.799988 1.2 1.51636 1.2 2.39999C1.2 3.28361 1.91625 3.99999 2.8 3.99999ZM3.43375 4.59999H2.16625C0.970125 4.59999 0 5.56999 0 6.76624C0 7.00624 0.194 7.19999 0.43325 7.19999H5.167C5.40625 7.19999 5.6 7.00624 5.6 6.76624C5.6 5.56999 4.63 4.59999 3.43375 4.59999ZM7.7 3.29999H7.1V2.69999C7.1 2.53499 6.96625 2.39999 6.8 2.39999C6.63375 2.39999 6.5 2.53436 6.5 2.69999V3.29999H5.9C5.735 3.29999 5.6 3.43499 5.6 3.59999C5.6 3.76499 5.73438 3.89999 5.9 3.89999H6.5V4.49999C6.5 4.66624 6.635 4.79999 6.8 4.79999C6.965 4.79999 7.1 4.66561 7.1 4.49999V3.89999H7.7C7.86625 3.89999 8 3.76624 8 3.59999C8 3.43374 7.86625 3.29999 7.7 3.29999Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_430_1373">
<rect width="8" height="8" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 859 B

After

Width:  |  Height:  |  Size: 1001 B

View File

@@ -1,3 +1,10 @@
<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.71108 6L0 2.28892L2.28892 0L6 3.71108L9.71108 0L12 2.28892L8.28892 6L12 9.71108L9.71108 12L6 8.28892L2.28892 12L0 9.71108L3.71108 6Z" fill="white"/>
<g clip-path="url(#clip0_430_1296)">
<path d="M9.5 2.5L6 6M2.5 9.5L6 6M2.5 2.5L6 6M6 6L9.5 9.5" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
</g>
<defs>
<clipPath id="clip0_430_1296">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 365 B

View File

@@ -1,3 +1,10 @@
<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="M5.32959 8L1 3.67041L3.67041 1L8 5.32959L12.3296 1L15 3.67041L10.6704 8L15 12.3296L12.3296 15L8 10.6704L3.67041 15L1 12.3296L5.32959 8Z" fill="white"/>
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_702_229)">
<path d="M11.875 3.125L7.5 7.5M3.125 11.875L7.5 7.5M3.125 3.125L7.5 7.5M7.5 7.5L11.875 11.875" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
</g>
<defs>
<clipPath id="clip0_702_229">
<rect width="15" height="15" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 399 B

View File

@@ -1,3 +1,10 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.47405 4L0 1.52595L1.52595 0L4 2.47405L6.47405 0L8 1.52595L5.52595 4L8 6.47405L6.47405 8L4 5.52595L1.52595 8L0 6.47405L2.47405 4Z" fill="white"/>
<g clip-path="url(#clip0_430_1379)">
<path d="M6.49999 1.49999L1.49997 6.5M1.49998 1.50002L6.49999 6.50004" stroke="white" stroke-linecap="round"/>
</g>
<defs>
<clipPath id="clip0_430_1379">
<rect width="8" height="8" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 296 B

After

Width:  |  Height:  |  Size: 352 B

View File

@@ -1,3 +0,0 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.76433 6.63513C8.0768 6.9476 8.0768 7.4538 7.76433 7.76627C7.60935 7.92251 7.40437 8 7.19939 8C6.99441 8 6.78992 7.92188 6.63394 7.76565L3.99969 5.13264L1.36568 7.7649C1.20945 7.92238 1.00472 7.99988 0.799986 7.99988C0.595255 7.99988 0.390774 7.92238 0.234414 7.7649C-0.0780566 7.45243 -0.0780566 6.94622 0.234414 6.63375L2.86917 3.999L0.234414 1.3655C-0.0780566 1.05303 -0.0780566 0.546824 0.234414 0.234353C0.546885 -0.0781177 1.05309 -0.0781177 1.36556 0.234353L3.99969 2.87023L6.63444 0.235478C6.94691 -0.0769928 7.45311 -0.0769928 7.76558 0.235478C8.07805 0.547949 8.07805 1.05415 7.76558 1.36662L5.13083 4.00138L7.76433 6.63488V6.63513Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 769 B

View File

@@ -75,7 +75,7 @@
"ctrl-n": "editor::MoveDown",
"ctrl-b": "editor::MoveLeft",
"ctrl-f": "editor::MoveRight",
"ctrl-l": "editor::CenterScreen",
"ctrl-l": "editor::NextScreen",
"alt-left": "editor::MoveToPreviousWordStart",
"alt-b": "editor::MoveToPreviousWordStart",
"alt-right": "editor::MoveToNextWordEnd",
@@ -402,7 +402,9 @@
{
"context": "Editor",
"bindings": {
"alt-enter": "editor::OpenExcerpts"
"alt-enter": "editor::OpenExcerpts",
"cmd-f8": "editor::GoToHunk",
"cmd-shift-f8": "editor::GoToPrevHunk"
}
},
{
@@ -470,6 +472,15 @@
"terminal::SendText",
"\u0001"
],
// Terminal.app compatability
"alt-left": [
"terminal::SendText",
"\u001bb"
],
"alt-right": [
"terminal::SendText",
"\u001bf"
],
// There are conflicting bindings for these keys in the global context.
// these bindings override them, remove at your own risk:
"up": [

View File

@@ -8,6 +8,22 @@
"Namespace": "G"
}
],
"i": [
"vim::PushOperator",
{
"Object": {
"around": false
}
}
],
"a": [
"vim::PushOperator",
{
"Object": {
"around": true
}
}
],
"h": "vim::Left",
"backspace": "vim::Backspace",
"j": "vim::Down",
@@ -38,22 +54,6 @@
],
"%": "vim::Matching",
"escape": "editor::Cancel",
"i": [
"vim::PushOperator",
{
"Object": {
"around": false
}
}
],
"a": [
"vim::PushOperator",
{
"Object": {
"around": true
}
}
],
"0": "vim::StartOfLine", // When no number operator present, use start of line motion
"1": [
"vim::Number",
@@ -110,6 +110,12 @@
"vim::PushOperator",
"Yank"
],
"z": [
"vim::PushOperator",
{
"Namespace": "Z"
}
],
"i": [
"vim::SwitchMode",
"Insert"
@@ -147,6 +153,30 @@
{
"focus": true
}
],
"ctrl-f": [
"vim::Scroll",
"PageDown"
],
"ctrl-b": [
"vim::Scroll",
"PageUp"
],
"ctrl-d": [
"vim::Scroll",
"HalfPageDown"
],
"ctrl-u": [
"vim::Scroll",
"HalfPageUp"
],
"ctrl-e": [
"vim::Scroll",
"LineDown"
],
"ctrl-y": [
"vim::Scroll",
"LineUp"
]
}
},
@@ -188,6 +218,18 @@
"y": "vim::CurrentLine"
}
},
{
"context": "Editor && vim_operator == z",
"bindings": {
"t": "editor::ScrollCursorTop",
"z": "editor::ScrollCursorCenter",
"b": "editor::ScrollCursorBottom",
"escape": [
"vim::SwitchMode",
"Normal"
]
}
},
{
"context": "Editor && VimObject",
"bindings": {

View File

@@ -1,230 +1,233 @@
{
// The name of the Zed theme to use for the UI
"theme": "One Dark",
// The name of a font to use for rendering text in the editor
"buffer_font_family": "Zed Mono",
// The default font size for text in the editor
"buffer_font_size": 15,
// Whether to enable vim modes and key bindings
"vim_mode": false,
// Whether to show the informational hover box when moving the mouse
// over symbols in the editor.
"hover_popover_enabled": true,
// Whether the cursor blinks in the editor.
"cursor_blink": true,
// Whether to pop the completions menu while typing in an editor without
// explicitly requesting it.
"show_completions_on_input": true,
// Whether new projects should start out 'online'. Online projects
// appear in the contacts panel under your name, so that your contacts
// can see which projects you are working on. Regardless of this
// setting, projects keep their last online status when you reopen them.
"projects_online_by_default": true,
// Whether to use language servers to provide code intelligence.
"enable_language_server": true,
// When to automatically save edited buffers. This setting can
// take four values.
//
// 1. Never automatically save:
// "autosave": "off",
// 2. Save when changing focus away from the Zed window:
// "autosave": "on_window_change",
// 3. Save when changing focus away from a specific buffer:
// "autosave": "on_focus_change",
// 4. Save when idle for a certain amount of time:
// "autosave": { "after_delay": {"milliseconds": 500} },
"autosave": "off",
// Where to place the dock by default. This setting can take three
// values:
//
// 1. Position the dock attached to the bottom of the workspace
// "default_dock_anchor": "bottom"
// 2. Position the dock to the right of the workspace like a side panel
// "default_dock_anchor": "right"
// 3. Position the dock full screen over the entire workspace"
// "default_dock_anchor": "expanded"
"default_dock_anchor": "right",
// Whether or not to perform a buffer format before saving
"format_on_save": "on",
// How to perform a buffer format. This setting can take two values:
//
// 1. Format code using the current language server:
// "format_on_save": "language_server"
// 2. Format code using an external command:
// "format_on_save": {
// "external": {
// "command": "prettier",
// "arguments": ["--stdin-filepath", "{buffer_path}"]
// }
// }
"formatter": "language_server",
// How to soft-wrap long lines of text. This setting can take
// three values:
//
// 1. Do not soft wrap.
// "soft_wrap": "none",
// 2. Soft wrap lines that overflow the editor:
// "soft_wrap": "editor_width",
// 3. Soft wrap lines at the preferred line length
// "soft_wrap": "preferred_line_length",
"soft_wrap": "none",
// The column at which to soft-wrap lines, for buffers where soft-wrap
// is enabled.
"preferred_line_length": 80,
// Whether to indent lines using tab characters, as opposed to multiple
// spaces.
"hard_tabs": false,
// How many columns a tab should occupy.
"tab_size": 4,
// Git gutter behavior configuration.
"git": {
// Control whether the git gutter is shown. May take 2 values:
// 1. Show the gutter
// "git_gutter": "tracked_files"
// 2. Hide the gutter
// "git_gutter": "hide"
"git_gutter": "tracked_files"
},
// Settings specific to journaling
"journal": {
// The path of the directory where journal entries are stored
"path": "~",
// What format to display the hours in
// May take 2 values:
// 1. hour12
// 2. hour24
"hour_format": "hour12"
},
// Settings specific to the terminal
"terminal": {
// What shell to use when opening a terminal. May take 3 values:
// 1. Use the system's default terminal configuration (e.g. $TERM).
// "shell": "system"
// 2. A program:
// "shell": {
// "program": "sh"
// }
// 3. A program with arguments:
// "shell": {
// "with_arguments": {
// "program": "/bin/bash",
// "arguments": ["--login"]
// }
// }
"shell": "system",
// What working directory to use when launching the terminal.
// May take 4 values:
// 1. Use the current file's project directory. Will Fallback to the
// first project directory strategy if unsuccessful
// "working_directory": "current_project_directory"
// 2. Use the first project in this workspace's directory
// "working_directory": "first_project_directory"
// 3. Always use this platform's home directory (if we can find it)
// "working_directory": "always_home"
// 4. Always use a specific directory. This value will be shell expanded.
// If this path is not a valid directory the terminal will default to
// this platform's home directory (if we can find it)
// "working_directory": {
// "always": {
// "directory": "~/zed/projects/"
// }
// }
// The name of the Zed theme to use for the UI
"theme": "One Dark",
// The name of a font to use for rendering text in the editor
"buffer_font_family": "Zed Mono",
// The default font size for text in the editor
"buffer_font_size": 15,
// The factor to grow the active pane by. Defaults to 1.0
// which gives the same size as all other panes.
"active_pane_magnification": 1.0,
// Whether to enable vim modes and key bindings
"vim_mode": false,
// Whether to show the informational hover box when moving the mouse
// over symbols in the editor.
"hover_popover_enabled": true,
// Whether the cursor blinks in the editor.
"cursor_blink": true,
// Whether to pop the completions menu while typing in an editor without
// explicitly requesting it.
"show_completions_on_input": true,
// Whether new projects should start out 'online'. Online projects
// appear in the contacts panel under your name, so that your contacts
// can see which projects you are working on. Regardless of this
// setting, projects keep their last online status when you reopen them.
"projects_online_by_default": true,
// Whether to use language servers to provide code intelligence.
"enable_language_server": true,
// When to automatically save edited buffers. This setting can
// take four values.
//
// 1. Never automatically save:
// "autosave": "off",
// 2. Save when changing focus away from the Zed window:
// "autosave": "on_window_change",
// 3. Save when changing focus away from a specific buffer:
// "autosave": "on_focus_change",
// 4. Save when idle for a certain amount of time:
// "autosave": { "after_delay": {"milliseconds": 500} },
"autosave": "off",
// Where to place the dock by default. This setting can take three
// values:
//
"working_directory": "current_project_directory",
// Set the cursor blinking behavior in the terminal.
// May take 4 values:
// 1. Never blink the cursor, ignoring the terminal mode
// "blinking": "off",
// 2. Default the cursor blink to off, but allow the terminal to
// set blinking
// "blinking": "terminal_controlled",
// 3. Always blink the cursor, ignoring the terminal mode
// "blinking": "on",
"blinking": "terminal_controlled",
// Set whether Alternate Scroll mode (code: ?1007) is active by default.
// Alternate Scroll mode converts mouse scroll events into up / down key
// presses when in the alternate screen (e.g. when running applications
// like vim or less). The terminal can still set and unset this mode.
// May take 2 values:
// 1. Default alternate scroll mode to on
// "alternate_scroll": "on",
// 2. Default alternate scroll mode to off
// "alternate_scroll": "off",
"alternate_scroll": "off",
// Set whether the option key behaves as the meta key.
// May take 2 values:
// 1. Rely on default platform handling of option key, on macOS
// this means generating certain unicode characters
// "option_to_meta": false,
// 2. Make the option keys behave as a 'meta' key, e.g. for emacs
// "option_to_meta": true,
"option_as_meta": false,
// Whether or not selecting text in the terminal will automatically
// copy to the system clipboard.
"copy_on_select": false,
// Any key-value pairs added to this list will be added to the terminal's
// enviroment. Use `:` to seperate multiple values.
"env": {
// "KEY": "value1:value2"
}
// Set the terminal's font size. If this option is not included,
// the terminal will default to matching the buffer's font size.
// "font_size": "15"
// Set the terminal's font family. If this option is not included,
// the terminal will default to matching the buffer's font family.
// "font_family": "Zed Mono"
},
// Different settings for specific languages.
"languages": {
"Plain Text": {
"soft_wrap": "preferred_line_length"
},
"C": {
"tab_size": 2
},
"C++": {
"tab_size": 2
},
"Elixir": {
"tab_size": 2
},
"Go": {
"tab_size": 4,
"hard_tabs": true
},
"Markdown": {
"soft_wrap": "preferred_line_length"
},
"Rust": {
"tab_size": 4
},
"JavaScript": {
"tab_size": 2
},
"TypeScript": {
"tab_size": 2
},
"TSX": {
"tab_size": 2
}
},
// LSP Specific settings.
"lsp": {
// Specify the LSP name as a key here.
// As of 8/10/22, supported LSPs are:
// pyright
// gopls
// rust-analyzer
// typescript-language-server
// vscode-json-languageserver
// "rust_analyzer": {
// //These initialization options are merged into Zed's defaults
// "initialization_options": {
// "checkOnSave": {
// "command": "clippy"
// }
// 1. Position the dock attached to the bottom of the workspace
// "default_dock_anchor": "bottom"
// 2. Position the dock to the right of the workspace like a side panel
// "default_dock_anchor": "right"
// 3. Position the dock full screen over the entire workspace"
// "default_dock_anchor": "expanded"
"default_dock_anchor": "right",
// Whether or not to perform a buffer format before saving
"format_on_save": "on",
// How to perform a buffer format. This setting can take two values:
//
// 1. Format code using the current language server:
// "format_on_save": "language_server"
// 2. Format code using an external command:
// "format_on_save": {
// "external": {
// "command": "prettier",
// "arguments": ["--stdin-filepath", "{buffer_path}"]
// }
// }
// }
}
"formatter": "language_server",
// How to soft-wrap long lines of text. This setting can take
// three values:
//
// 1. Do not soft wrap.
// "soft_wrap": "none",
// 2. Soft wrap lines that overflow the editor:
// "soft_wrap": "editor_width",
// 3. Soft wrap lines at the preferred line length
// "soft_wrap": "preferred_line_length",
"soft_wrap": "none",
// The column at which to soft-wrap lines, for buffers where soft-wrap
// is enabled.
"preferred_line_length": 80,
// Whether to indent lines using tab characters, as opposed to multiple
// spaces.
"hard_tabs": false,
// How many columns a tab should occupy.
"tab_size": 4,
// Git gutter behavior configuration.
"git": {
// Control whether the git gutter is shown. May take 2 values:
// 1. Show the gutter
// "git_gutter": "tracked_files"
// 2. Hide the gutter
// "git_gutter": "hide"
"git_gutter": "tracked_files"
},
// Settings specific to journaling
"journal": {
// The path of the directory where journal entries are stored
"path": "~",
// What format to display the hours in
// May take 2 values:
// 1. hour12
// 2. hour24
"hour_format": "hour12"
},
// Settings specific to the terminal
"terminal": {
// What shell to use when opening a terminal. May take 3 values:
// 1. Use the system's default terminal configuration (e.g. $TERM).
// "shell": "system"
// 2. A program:
// "shell": {
// "program": "sh"
// }
// 3. A program with arguments:
// "shell": {
// "with_arguments": {
// "program": "/bin/bash",
// "arguments": ["--login"]
// }
// }
"shell": "system",
// What working directory to use when launching the terminal.
// May take 4 values:
// 1. Use the current file's project directory. Will Fallback to the
// first project directory strategy if unsuccessful
// "working_directory": "current_project_directory"
// 2. Use the first project in this workspace's directory
// "working_directory": "first_project_directory"
// 3. Always use this platform's home directory (if we can find it)
// "working_directory": "always_home"
// 4. Always use a specific directory. This value will be shell expanded.
// If this path is not a valid directory the terminal will default to
// this platform's home directory (if we can find it)
// "working_directory": {
// "always": {
// "directory": "~/zed/projects/"
// }
// }
//
//
"working_directory": "current_project_directory",
// Set the cursor blinking behavior in the terminal.
// May take 4 values:
// 1. Never blink the cursor, ignoring the terminal mode
// "blinking": "off",
// 2. Default the cursor blink to off, but allow the terminal to
// set blinking
// "blinking": "terminal_controlled",
// 3. Always blink the cursor, ignoring the terminal mode
// "blinking": "on",
"blinking": "terminal_controlled",
// Set whether Alternate Scroll mode (code: ?1007) is active by default.
// Alternate Scroll mode converts mouse scroll events into up / down key
// presses when in the alternate screen (e.g. when running applications
// like vim or less). The terminal can still set and unset this mode.
// May take 2 values:
// 1. Default alternate scroll mode to on
// "alternate_scroll": "on",
// 2. Default alternate scroll mode to off
// "alternate_scroll": "off",
"alternate_scroll": "off",
// Set whether the option key behaves as the meta key.
// May take 2 values:
// 1. Rely on default platform handling of option key, on macOS
// this means generating certain unicode characters
// "option_to_meta": false,
// 2. Make the option keys behave as a 'meta' key, e.g. for emacs
// "option_to_meta": true,
"option_as_meta": false,
// Whether or not selecting text in the terminal will automatically
// copy to the system clipboard.
"copy_on_select": false,
// Any key-value pairs added to this list will be added to the terminal's
// enviroment. Use `:` to seperate multiple values.
"env": {
// "KEY": "value1:value2"
}
// Set the terminal's font size. If this option is not included,
// the terminal will default to matching the buffer's font size.
// "font_size": "15"
// Set the terminal's font family. If this option is not included,
// the terminal will default to matching the buffer's font family.
// "font_family": "Zed Mono"
},
// Different settings for specific languages.
"languages": {
"Plain Text": {
"soft_wrap": "preferred_line_length"
},
"C": {
"tab_size": 2
},
"C++": {
"tab_size": 2
},
"Elixir": {
"tab_size": 2
},
"Go": {
"tab_size": 4,
"hard_tabs": true
},
"Markdown": {
"soft_wrap": "preferred_line_length"
},
"Rust": {
"tab_size": 4
},
"JavaScript": {
"tab_size": 2
},
"TypeScript": {
"tab_size": 2
},
"TSX": {
"tab_size": 2
}
},
// LSP Specific settings.
"lsp": {
// Specify the LSP name as a key here.
// As of 8/10/22, supported LSPs are:
// pyright
// gopls
// rust-analyzer
// typescript-language-server
// vscode-json-languageserver
// "rust_analyzer": {
// //These initialization options are merged into Zed's defaults
// "initialization_options": {
// "checkOnSave": {
// "command": "clippy"
// }
// }
// }
}
}

View File

@@ -11,13 +11,12 @@ use settings::Settings;
use smallvec::SmallVec;
use std::{cmp::Reverse, fmt::Write, sync::Arc};
use util::ResultExt;
use workspace::{ItemHandle, StatusItemView, Workspace};
use workspace::{item::ItemHandle, StatusItemView, Workspace};
actions!(lsp_status, [ShowErrorMessage]);
const DOWNLOAD_ICON: &str = "icons/download_12.svg";
const WARNING_ICON: &str = "icons/triangle_exclamation_12.svg";
const DONE_ICON: &str = "icons/circle_check_12.svg";
pub enum Event {
ShowError { lsp_name: Arc<str>, error: String },
@@ -237,7 +236,6 @@ impl ActivityIndicator {
// Show any application auto-update info.
if let Some(updater) = &self.auto_updater {
// let theme = &cx.global::<Settings>().theme.workspace.status_bar;
match &updater.read(cx).status() {
AutoUpdateStatus::Checking => (
Some(DOWNLOAD_ICON),
@@ -254,9 +252,7 @@ impl ActivityIndicator {
"Installing Zed update…".to_string(),
None,
),
AutoUpdateStatus::Updated => {
(Some(DONE_ICON), "Restart to update Zed".to_string(), None)
}
AutoUpdateStatus::Updated => (None, "Restart to update Zed".to_string(), None),
AutoUpdateStatus::Errored => (
Some(WARNING_ICON),
"Auto update failed".to_string(),

29
crates/assets/build.rs Normal file
View File

@@ -0,0 +1,29 @@
use std::process::Command;
fn main() {
let output = Command::new("npm")
.current_dir("../../styles")
.args(["install", "--no-save"])
.output()
.expect("failed to run npm");
if !output.status.success() {
panic!(
"failed to install theme dependencies {}",
String::from_utf8_lossy(&output.stderr)
);
}
let output = Command::new("npm")
.current_dir("../../styles")
.args(["run", "build"])
.output()
.expect("failed to run npm");
if !output.status.success() {
panic!(
"build script failed {}",
String::from_utf8_lossy(&output.stderr)
);
}
println!("cargo:rerun-if-changed=../../styles/src");
}

View File

@@ -8,6 +8,7 @@ path = "src/auto_update.rs"
doctest = false
[dependencies]
db = { path = "../db" }
client = { path = "../client" }
gpui = { path = "../gpui" }
menu = { path = "../menu" }

View File

@@ -1,17 +1,18 @@
mod update_notification;
use anyhow::{anyhow, Context, Result};
use client::{http::HttpClient, ZED_SECRET_CLIENT_TOKEN, ZED_SERVER_URL};
use client::{http::HttpClient, ZED_SECRET_CLIENT_TOKEN};
use db::kvp::KEY_VALUE_STORE;
use gpui::{
actions, platform::AppVersion, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle,
MutableAppContext, Task, WeakViewHandle,
};
use lazy_static::lazy_static;
use serde::Deserialize;
use settings::ReleaseChannel;
use smol::{fs::File, io::AsyncReadExt, process::Command};
use std::{env, ffi::OsString, path::PathBuf, sync::Arc, time::Duration};
use update_notification::UpdateNotification;
use util::channel::ReleaseChannel;
use workspace::Workspace;
const SHOULD_SHOW_UPDATE_NOTIFICATION_KEY: &str = "auto-updater-should-show-updated-notification";
@@ -41,7 +42,6 @@ pub struct AutoUpdater {
current_version: AppVersion,
http_client: Arc<dyn HttpClient>,
pending_poll: Option<Task<()>>,
db: project::Db,
server_url: String,
}
@@ -55,11 +55,11 @@ impl Entity for AutoUpdater {
type Event = ();
}
pub fn init(db: project::Db, http_client: Arc<dyn HttpClient>, cx: &mut MutableAppContext) {
pub fn init(http_client: Arc<dyn HttpClient>, server_url: String, cx: &mut MutableAppContext) {
if let Some(version) = (*ZED_APP_VERSION).or_else(|| cx.platform().app_version().ok()) {
let server_url = ZED_SERVER_URL.to_string();
let server_url = server_url;
let auto_updater = cx.add_model(|cx| {
let updater = AutoUpdater::new(version, db.clone(), http_client, server_url.clone());
let updater = AutoUpdater::new(version, http_client, server_url.clone());
updater.start_polling(cx).detach();
updater
});
@@ -70,7 +70,14 @@ pub fn init(db: project::Db, http_client: Arc<dyn HttpClient>, cx: &mut MutableA
}
});
cx.add_global_action(move |_: &ViewReleaseNotes, cx| {
cx.platform().open_url(&format!("{server_url}/releases"));
let latest_release_url = if cx.has_global::<ReleaseChannel>()
&& *cx.global::<ReleaseChannel>() == ReleaseChannel::Preview
{
format!("{server_url}/releases/preview/latest")
} else {
format!("{server_url}/releases/latest")
};
cx.platform().open_url(&latest_release_url);
});
cx.add_action(UpdateNotification::dismiss);
}
@@ -113,14 +120,12 @@ impl AutoUpdater {
fn new(
current_version: AppVersion,
db: project::Db,
http_client: Arc<dyn HttpClient>,
server_url: String,
) -> Self {
Self {
status: AutoUpdateStatus::Idle,
current_version,
db,
http_client,
server_url,
pending_poll: None,
@@ -218,11 +223,14 @@ impl AutoUpdater {
let temp_dir = tempdir::TempDir::new("zed-auto-update")?;
let dmg_path = temp_dir.path().join("Zed.dmg");
let mount_path = temp_dir.path().join("Zed");
let mut mounted_app_path: OsString = mount_path.join("Zed.app").into();
mounted_app_path.push("/");
let running_app_path = ZED_APP_PATH
.clone()
.map_or_else(|| cx.platform().app_path(), Ok)?;
let running_app_filename = running_app_path
.file_name()
.ok_or_else(|| anyhow!("invalid running app path"))?;
let mut mounted_app_path: OsString = mount_path.join(running_app_filename).into();
mounted_app_path.push("/");
let mut dmg_file = File::create(&dmg_path).await?;
let mut response = client.get(&release.url, Default::default(), true).await?;
@@ -287,20 +295,28 @@ impl AutoUpdater {
should_show: bool,
cx: &AppContext,
) -> Task<Result<()>> {
let db = self.db.clone();
cx.background().spawn(async move {
if should_show {
db.write_kvp(SHOULD_SHOW_UPDATE_NOTIFICATION_KEY, "")?;
KEY_VALUE_STORE
.write_kvp(
SHOULD_SHOW_UPDATE_NOTIFICATION_KEY.to_string(),
"".to_string(),
)
.await?;
} else {
db.delete_kvp(SHOULD_SHOW_UPDATE_NOTIFICATION_KEY)?;
KEY_VALUE_STORE
.delete_kvp(SHOULD_SHOW_UPDATE_NOTIFICATION_KEY.to_string())
.await?;
}
Ok(())
})
}
fn should_show_update_notification(&self, cx: &AppContext) -> Task<Result<bool>> {
let db = self.db.clone();
cx.background()
.spawn(async move { Ok(db.read_kvp(SHOULD_SHOW_UPDATE_NOTIFICATION_KEY)?.is_some()) })
cx.background().spawn(async move {
Ok(KEY_VALUE_STORE
.read_kvp(SHOULD_SHOW_UPDATE_NOTIFICATION_KEY)?
.is_some())
})
}
}

View File

@@ -6,7 +6,8 @@ use gpui::{
};
use menu::Cancel;
use settings::Settings;
use workspace::Notification;
use util::channel::ReleaseChannel;
use workspace::notifications::Notification;
pub struct UpdateNotification {
version: AppVersion,
@@ -29,13 +30,15 @@ impl View for UpdateNotification {
let theme = cx.global::<Settings>().theme.clone();
let theme = &theme.update_notification;
let app_name = cx.global::<ReleaseChannel>().display_name();
MouseEventHandler::<ViewReleaseNotes>::new(0, cx, |state, cx| {
Flex::column()
.with_child(
Flex::row()
.with_child(
Text::new(
format!("Updated to Zed {}", self.version),
format!("Updated to {app_name} {}", self.version),
theme.message.text.clone(),
)
.contained()
@@ -49,7 +52,7 @@ impl View for UpdateNotification {
.with_child(
MouseEventHandler::<Cancel>::new(0, cx, |state, _| {
let style = theme.dismiss_button.style_for(state, false);
Svg::new("icons/x_mark_thin_8.svg")
Svg::new("icons/x_mark_8.svg")
.with_color(style.color)
.constrained()
.with_width(style.icon_width)

View File

@@ -4,7 +4,10 @@ use gpui::{
use itertools::Itertools;
use search::ProjectSearchView;
use settings::Settings;
use workspace::{ItemEvent, ItemHandle, ToolbarItemLocation, ToolbarItemView};
use workspace::{
item::{ItemEvent, ItemHandle},
ToolbarItemLocation, ToolbarItemView,
};
pub enum Event {
UpdateLocation,

View File

@@ -22,7 +22,7 @@ pub fn init(client: Arc<Client>, user_store: ModelHandle<UserStore>, cx: &mut Mu
#[derive(Clone)]
pub struct IncomingCall {
pub room_id: u64,
pub caller: Arc<User>,
pub calling_user: Arc<User>,
pub participants: Vec<Arc<User>>,
pub initial_project: Option<proto::ParticipantProject>,
}
@@ -78,9 +78,9 @@ impl ActiveCall {
user_store.get_users(envelope.payload.participant_user_ids, cx)
})
.await?,
caller: user_store
calling_user: user_store
.update(&mut cx, |user_store, cx| {
user_store.get_user(envelope.payload.caller_user_id, cx)
user_store.get_user(envelope.payload.calling_user_id, cx)
})
.await?,
initial_project: envelope.payload.initial_project,
@@ -94,12 +94,18 @@ impl ActiveCall {
async fn handle_call_canceled(
this: ModelHandle<Self>,
_: TypedEnvelope<proto::CallCanceled>,
envelope: TypedEnvelope<proto::CallCanceled>,
_: Arc<Client>,
mut cx: AsyncAppContext,
) -> Result<()> {
this.update(&mut cx, |this, _| {
*this.incoming_call.0.borrow_mut() = None;
let mut incoming_call = this.incoming_call.0.borrow_mut();
if incoming_call
.as_ref()
.map_or(false, |call| call.room_id == envelope.payload.room_id)
{
incoming_call.take();
}
});
Ok(())
}
@@ -110,13 +116,13 @@ impl ActiveCall {
pub fn invite(
&mut self,
recipient_user_id: u64,
called_user_id: u64,
initial_project: Option<ModelHandle<Project>>,
cx: &mut ModelContext<Self>,
) -> Task<Result<()>> {
let client = self.client.clone();
let user_store = self.user_store.clone();
if !self.pending_invites.insert(recipient_user_id) {
if !self.pending_invites.insert(called_user_id) {
return Task::ready(Err(anyhow!("user was already invited")));
}
@@ -136,13 +142,13 @@ impl ActiveCall {
};
room.update(&mut cx, |room, cx| {
room.call(recipient_user_id, initial_project_id, cx)
room.call(called_user_id, initial_project_id, cx)
})
.await?;
} else {
let room = cx
.update(|cx| {
Room::create(recipient_user_id, initial_project, client, user_store, cx)
Room::create(called_user_id, initial_project, client, user_store, cx)
})
.await?;
@@ -155,7 +161,7 @@ impl ActiveCall {
let result = invite.await;
this.update(&mut cx, |this, cx| {
this.pending_invites.remove(&recipient_user_id);
this.pending_invites.remove(&called_user_id);
cx.notify();
});
result
@@ -164,7 +170,7 @@ impl ActiveCall {
pub fn cancel_invite(
&mut self,
recipient_user_id: u64,
called_user_id: u64,
cx: &mut ModelContext<Self>,
) -> Task<Result<()>> {
let room_id = if let Some(room) = self.room() {
@@ -178,7 +184,7 @@ impl ActiveCall {
client
.request(proto::CancelCall {
room_id,
recipient_user_id,
called_user_id,
})
.await?;
anyhow::Ok(())

View File

@@ -4,7 +4,7 @@ use collections::HashMap;
use gpui::WeakModelHandle;
pub use live_kit_client::Frame;
use project::Project;
use std::sync::Arc;
use std::{fmt, sync::Arc};
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ParticipantLocation {
@@ -36,7 +36,7 @@ pub struct LocalParticipant {
pub active_project: Option<WeakModelHandle<Project>>,
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct RemoteParticipant {
pub user: Arc<User>,
pub projects: Vec<proto::ParticipantProject>,
@@ -49,6 +49,12 @@ pub struct RemoteVideoTrack {
pub(crate) live_kit_track: Arc<live_kit_client::RemoteVideoTrack>,
}
impl fmt::Debug for RemoteVideoTrack {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RemoteVideoTrack").finish()
}
}
impl RemoteVideoTrack {
pub fn frames(&self) -> async_broadcast::Receiver<Frame> {
self.live_kit_track.frames()

View File

@@ -5,14 +5,18 @@ use crate::{
use anyhow::{anyhow, Result};
use client::{proto, Client, PeerId, TypedEnvelope, User, UserStore};
use collections::{BTreeMap, HashSet};
use futures::StreamExt;
use gpui::{AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task};
use futures::{FutureExt, StreamExt};
use gpui::{
AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task, WeakModelHandle,
};
use live_kit_client::{LocalTrackPublication, LocalVideoTrack, RemoteVideoTrackUpdate};
use postage::stream::Stream;
use project::Project;
use std::{mem, os::unix::prelude::OsStrExt, sync::Arc};
use std::{mem, sync::Arc, time::Duration};
use util::{post_inc, ResultExt};
pub const RECONNECT_TIMEOUT: Duration = client::RECEIVE_TIMEOUT;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Event {
ParticipantLocationChanged {
@@ -46,6 +50,7 @@ pub struct Room {
user_store: ModelHandle<UserStore>,
subscriptions: Vec<client::Subscription>,
pending_room_update: Option<Task<()>>,
maintain_connection: Option<Task<Result<()>>>,
}
impl Entity for Room {
@@ -53,7 +58,7 @@ impl Entity for Room {
fn release(&mut self, _: &mut MutableAppContext) {
if self.status.is_online() {
self.client.send(proto::LeaveRoom { id: self.id }).log_err();
self.client.send(proto::LeaveRoom {}).log_err();
}
}
}
@@ -66,21 +71,6 @@ impl Room {
user_store: ModelHandle<UserStore>,
cx: &mut ModelContext<Self>,
) -> Self {
let mut client_status = client.status();
cx.spawn_weak(|this, mut cx| async move {
let is_connected = client_status
.next()
.await
.map_or(false, |s| s.is_connected());
// Even if we're initially connected, any future change of the status means we momentarily disconnected.
if !is_connected || client_status.next().await.is_some() {
if let Some(this) = this.upgrade(&cx) {
let _ = this.update(&mut cx, |this, cx| this.leave(cx));
}
}
})
.detach();
let live_kit_room = if let Some(connection_info) = live_kit_connection_info {
let room = live_kit_client::Room::new();
let mut status = room.status();
@@ -131,6 +121,9 @@ impl Room {
None
};
let maintain_connection =
cx.spawn_weak(|this, cx| Self::maintain_connection(this, client.clone(), cx));
Self {
id,
live_kit: live_kit_room,
@@ -145,11 +138,12 @@ impl Room {
pending_room_update: None,
client,
user_store,
maintain_connection: Some(maintain_connection),
}
}
pub(crate) fn create(
recipient_user_id: u64,
called_user_id: u64,
initial_project: Option<ModelHandle<Project>>,
client: Arc<Client>,
user_store: ModelHandle<UserStore>,
@@ -182,7 +176,7 @@ impl Room {
match room
.update(&mut cx, |room, cx| {
room.leave_when_empty = true;
room.call(recipient_user_id, initial_project_id, cx)
room.call(called_user_id, initial_project_id, cx)
})
.await
{
@@ -241,10 +235,96 @@ impl Room {
self.participant_user_ids.clear();
self.subscriptions.clear();
self.live_kit.take();
self.client.send(proto::LeaveRoom { id: self.id })?;
self.pending_room_update.take();
self.maintain_connection.take();
self.client.send(proto::LeaveRoom {})?;
Ok(())
}
async fn maintain_connection(
this: WeakModelHandle<Self>,
client: Arc<Client>,
mut cx: AsyncAppContext,
) -> Result<()> {
let mut client_status = client.status();
loop {
let is_connected = client_status
.next()
.await
.map_or(false, |s| s.is_connected());
// Even if we're initially connected, any future change of the status means we momentarily disconnected.
if !is_connected || client_status.next().await.is_some() {
let room_id = this
.upgrade(&cx)
.ok_or_else(|| anyhow!("room was dropped"))?
.update(&mut cx, |this, cx| {
this.status = RoomStatus::Rejoining;
cx.notify();
this.id
});
// Wait for client to re-establish a connection to the server.
{
let mut reconnection_timeout = cx.background().timer(RECONNECT_TIMEOUT).fuse();
let client_reconnection = async {
let mut remaining_attempts = 3;
while remaining_attempts > 0 {
if let Some(status) = client_status.next().await {
if status.is_connected() {
let rejoin_room = async {
let response =
client.request(proto::JoinRoom { id: room_id }).await?;
let room_proto =
response.room.ok_or_else(|| anyhow!("invalid room"))?;
this.upgrade(&cx)
.ok_or_else(|| anyhow!("room was dropped"))?
.update(&mut cx, |this, cx| {
this.status = RoomStatus::Online;
this.apply_room_update(room_proto, cx)
})?;
anyhow::Ok(())
};
if rejoin_room.await.is_ok() {
return true;
} else {
remaining_attempts -= 1;
}
}
} else {
return false;
}
}
false
}
.fuse();
futures::pin_mut!(client_reconnection);
futures::select_biased! {
reconnected = client_reconnection => {
if reconnected {
// If we successfully joined the room, go back around the loop
// waiting for future connection status changes.
continue;
}
}
_ = reconnection_timeout => {}
}
}
// The client failed to re-establish a connection to the server
// or an error occurred while trying to re-join the room. Either way
// we leave the room and return an error.
if let Some(this) = this.upgrade(&cx) {
let _ = this.update(&mut cx, |this, cx| this.leave(cx));
}
return Err(anyhow!(
"can't reconnect to room: client failed to re-establish connection"
));
}
}
}
pub fn id(&self) -> u64 {
self.id
}
@@ -294,6 +374,11 @@ impl Room {
.position(|participant| Some(participant.user_id) == self.client.user_id());
let local_participant = local_participant_ix.map(|ix| room.participants.swap_remove(ix));
let pending_participant_user_ids = room
.pending_participants
.iter()
.map(|p| p.user_id)
.collect::<Vec<_>>();
let remote_participant_user_ids = room
.participants
.iter()
@@ -303,7 +388,7 @@ impl Room {
self.user_store.update(cx, move |user_store, cx| {
(
user_store.get_users(remote_participant_user_ids, cx),
user_store.get_users(room.pending_participant_user_ids, cx),
user_store.get_users(pending_participant_user_ids, cx),
)
});
self.pending_room_update = Some(cx.spawn(|this, mut cx| async move {
@@ -320,9 +405,11 @@ impl Room {
}
if let Some(participants) = remote_participants.log_err() {
let mut participant_peer_ids = HashSet::default();
for (participant, user) in room.participants.into_iter().zip(participants) {
let peer_id = PeerId(participant.peer_id);
this.participant_user_ids.insert(participant.user_id);
participant_peer_ids.insert(peer_id);
let old_projects = this
.remote_participants
@@ -389,8 +476,8 @@ impl Room {
}
}
this.remote_participants.retain(|_, participant| {
if this.participant_user_ids.contains(&participant.user.id) {
this.remote_participants.retain(|peer_id, participant| {
if participant_peer_ids.contains(peer_id) {
true
} else {
for project in &participant.projects {
@@ -472,10 +559,12 @@ impl Room {
{
for participant in self.remote_participants.values() {
assert!(self.participant_user_ids.contains(&participant.user.id));
assert_ne!(participant.user.id, self.client.user_id().unwrap());
}
for participant in &self.pending_participants {
assert!(self.participant_user_ids.contains(&participant.id));
assert_ne!(participant.id, self.client.user_id().unwrap());
}
assert_eq!(
@@ -487,7 +576,7 @@ impl Room {
pub(crate) fn call(
&mut self,
recipient_user_id: u64,
called_user_id: u64,
initial_project_id: Option<u64>,
cx: &mut ModelContext<Self>,
) -> Task<Result<()>> {
@@ -503,7 +592,7 @@ impl Room {
let result = client
.request(proto::Call {
room_id,
recipient_user_id,
called_user_id,
initial_project_id,
})
.await;
@@ -538,7 +627,7 @@ impl Room {
id: worktree.id().to_proto(),
root_name: worktree.root_name().into(),
visible: worktree.is_visible(),
abs_path: worktree.abs_path().as_os_str().as_bytes().to_vec(),
abs_path: worktree.abs_path().to_string_lossy().into(),
}
})
.collect(),
@@ -746,6 +835,7 @@ impl Default for ScreenTrack {
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum RoomStatus {
Online,
Rejoining,
Offline,
}

View File

@@ -1,277 +0,0 @@
use crate::http::HttpClient;
use db::Db;
use gpui::{
executor::Background,
serde_json::{self, value::Map, Value},
AppContext, Task,
};
use isahc::Request;
use lazy_static::lazy_static;
use parking_lot::Mutex;
use serde::Serialize;
use serde_json::json;
use std::{
io::Write,
mem,
path::PathBuf,
sync::Arc,
time::{Duration, SystemTime, UNIX_EPOCH},
};
use tempfile::NamedTempFile;
use util::{post_inc, ResultExt, TryFutureExt};
use uuid::Uuid;
pub struct AmplitudeTelemetry {
http_client: Arc<dyn HttpClient>,
executor: Arc<Background>,
session_id: u128,
state: Mutex<AmplitudeTelemetryState>,
}
#[derive(Default)]
struct AmplitudeTelemetryState {
metrics_id: Option<Arc<str>>,
device_id: Option<Arc<str>>,
app_version: Option<Arc<str>>,
os_version: Option<Arc<str>>,
os_name: &'static str,
queue: Vec<AmplitudeEvent>,
next_event_id: usize,
flush_task: Option<Task<()>>,
log_file: Option<NamedTempFile>,
}
const AMPLITUDE_EVENTS_URL: &'static str = "https://api2.amplitude.com/batch";
lazy_static! {
static ref AMPLITUDE_API_KEY: Option<String> = std::env::var("ZED_AMPLITUDE_API_KEY")
.ok()
.or_else(|| option_env!("ZED_AMPLITUDE_API_KEY").map(|key| key.to_string()));
}
#[derive(Serialize)]
struct AmplitudeEventBatch {
api_key: &'static str,
events: Vec<AmplitudeEvent>,
}
#[derive(Serialize)]
struct AmplitudeEvent {
#[serde(skip_serializing_if = "Option::is_none")]
user_id: Option<Arc<str>>,
device_id: Option<Arc<str>>,
event_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
event_properties: Option<Map<String, Value>>,
#[serde(skip_serializing_if = "Option::is_none")]
user_properties: Option<Map<String, Value>>,
os_name: &'static str,
os_version: Option<Arc<str>>,
app_version: Option<Arc<str>>,
platform: &'static str,
event_id: usize,
session_id: u128,
time: u128,
}
#[cfg(debug_assertions)]
const MAX_QUEUE_LEN: usize = 1;
#[cfg(not(debug_assertions))]
const MAX_QUEUE_LEN: usize = 10;
#[cfg(debug_assertions)]
const DEBOUNCE_INTERVAL: Duration = Duration::from_secs(1);
#[cfg(not(debug_assertions))]
const DEBOUNCE_INTERVAL: Duration = Duration::from_secs(30);
impl AmplitudeTelemetry {
pub fn new(client: Arc<dyn HttpClient>, cx: &AppContext) -> Arc<Self> {
let platform = cx.platform();
let this = Arc::new(Self {
http_client: client,
executor: cx.background().clone(),
session_id: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_millis(),
state: Mutex::new(AmplitudeTelemetryState {
os_version: platform
.os_version()
.log_err()
.map(|v| v.to_string().into()),
os_name: platform.os_name().into(),
app_version: platform
.app_version()
.log_err()
.map(|v| v.to_string().into()),
device_id: None,
queue: Default::default(),
flush_task: Default::default(),
next_event_id: 0,
log_file: None,
metrics_id: None,
}),
});
if AMPLITUDE_API_KEY.is_some() {
this.executor
.spawn({
let this = this.clone();
async move {
if let Some(tempfile) = NamedTempFile::new().log_err() {
this.state.lock().log_file = Some(tempfile);
}
}
})
.detach();
}
this
}
pub fn log_file_path(&self) -> Option<PathBuf> {
Some(self.state.lock().log_file.as_ref()?.path().to_path_buf())
}
pub fn start(self: &Arc<Self>, db: Db) {
let this = self.clone();
self.executor
.spawn(
async move {
let device_id = if let Ok(Some(device_id)) = db.read_kvp("device_id") {
device_id
} else {
let device_id = Uuid::new_v4().to_string();
db.write_kvp("device_id", &device_id)?;
device_id
};
let device_id = Some(Arc::from(device_id));
let mut state = this.state.lock();
state.device_id = device_id.clone();
for event in &mut state.queue {
event.device_id = device_id.clone();
}
if !state.queue.is_empty() {
drop(state);
this.flush();
}
anyhow::Ok(())
}
.log_err(),
)
.detach();
}
pub fn set_authenticated_user_info(
self: &Arc<Self>,
metrics_id: Option<String>,
is_staff: bool,
) {
let is_signed_in = metrics_id.is_some();
self.state.lock().metrics_id = metrics_id.map(|s| s.into());
if is_signed_in {
self.report_event_with_user_properties(
"$identify",
Default::default(),
json!({ "$set": { "staff": is_staff } }),
)
}
}
pub fn report_event(self: &Arc<Self>, kind: &str, properties: Value) {
self.report_event_with_user_properties(kind, properties, Default::default());
}
fn report_event_with_user_properties(
self: &Arc<Self>,
kind: &str,
properties: Value,
user_properties: Value,
) {
if AMPLITUDE_API_KEY.is_none() {
return;
}
let mut state = self.state.lock();
let event = AmplitudeEvent {
event_type: kind.to_string(),
time: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_millis(),
session_id: self.session_id,
event_properties: if let Value::Object(properties) = properties {
Some(properties)
} else {
None
},
user_properties: if let Value::Object(user_properties) = user_properties {
Some(user_properties)
} else {
None
},
user_id: state.metrics_id.clone(),
device_id: state.device_id.clone(),
os_name: state.os_name,
platform: "Zed",
os_version: state.os_version.clone(),
app_version: state.app_version.clone(),
event_id: post_inc(&mut state.next_event_id),
};
state.queue.push(event);
if state.device_id.is_some() {
if state.queue.len() >= MAX_QUEUE_LEN {
drop(state);
self.flush();
} else {
let this = self.clone();
let executor = self.executor.clone();
state.flush_task = Some(self.executor.spawn(async move {
executor.timer(DEBOUNCE_INTERVAL).await;
this.flush();
}));
}
}
}
fn flush(self: &Arc<Self>) {
let mut state = self.state.lock();
let events = mem::take(&mut state.queue);
state.flush_task.take();
drop(state);
if let Some(api_key) = AMPLITUDE_API_KEY.as_ref() {
let this = self.clone();
self.executor
.spawn(
async move {
let mut json_bytes = Vec::new();
if let Some(file) = &mut this.state.lock().log_file {
let file = file.as_file_mut();
for event in &events {
json_bytes.clear();
serde_json::to_writer(&mut json_bytes, event)?;
file.write_all(&json_bytes)?;
file.write(b"\n")?;
}
}
let batch = AmplitudeEventBatch { api_key, events };
json_bytes.clear();
serde_json::to_writer(&mut json_bytes, &batch)?;
let request =
Request::post(AMPLITUDE_EVENTS_URL).body(json_bytes.into())?;
this.http_client.send(request).await?;
Ok(())
}
.log_err(),
)
.detach();
}
}
}

View File

@@ -1,820 +0,0 @@
use super::{
proto,
user::{User, UserStore},
Client, Status, Subscription, TypedEnvelope,
};
use anyhow::{anyhow, Context, Result};
use futures::lock::Mutex;
use gpui::{
AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task, WeakModelHandle,
};
use postage::prelude::Stream;
use rand::prelude::*;
use std::{
collections::{HashMap, HashSet},
mem,
ops::Range,
sync::Arc,
};
use sum_tree::{Bias, SumTree};
use time::OffsetDateTime;
use util::{post_inc, ResultExt as _, TryFutureExt};
pub struct ChannelList {
available_channels: Option<Vec<ChannelDetails>>,
channels: HashMap<u64, WeakModelHandle<Channel>>,
client: Arc<Client>,
user_store: ModelHandle<UserStore>,
_task: Task<Option<()>>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct ChannelDetails {
pub id: u64,
pub name: String,
}
pub struct Channel {
details: ChannelDetails,
messages: SumTree<ChannelMessage>,
loaded_all_messages: bool,
next_pending_message_id: usize,
user_store: ModelHandle<UserStore>,
rpc: Arc<Client>,
outgoing_messages_lock: Arc<Mutex<()>>,
rng: StdRng,
_subscription: Subscription,
}
#[derive(Clone, Debug)]
pub struct ChannelMessage {
pub id: ChannelMessageId,
pub body: String,
pub timestamp: OffsetDateTime,
pub sender: Arc<User>,
pub nonce: u128,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum ChannelMessageId {
Saved(u64),
Pending(usize),
}
#[derive(Clone, Debug, Default)]
pub struct ChannelMessageSummary {
max_id: ChannelMessageId,
count: usize,
}
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
struct Count(usize);
pub enum ChannelListEvent {}
#[derive(Clone, Debug, PartialEq)]
pub enum ChannelEvent {
MessagesUpdated {
old_range: Range<usize>,
new_count: usize,
},
}
impl Entity for ChannelList {
type Event = ChannelListEvent;
}
impl ChannelList {
pub fn new(
user_store: ModelHandle<UserStore>,
rpc: Arc<Client>,
cx: &mut ModelContext<Self>,
) -> Self {
let _task = cx.spawn_weak(|this, mut cx| {
let rpc = rpc.clone();
async move {
let mut status = rpc.status();
while let Some((status, this)) = status.recv().await.zip(this.upgrade(&cx)) {
match status {
Status::Connected { .. } => {
let response = rpc
.request(proto::GetChannels {})
.await
.context("failed to fetch available channels")?;
this.update(&mut cx, |this, cx| {
this.available_channels =
Some(response.channels.into_iter().map(Into::into).collect());
let mut to_remove = Vec::new();
for (channel_id, channel) in &this.channels {
if let Some(channel) = channel.upgrade(cx) {
channel.update(cx, |channel, cx| channel.rejoin(cx))
} else {
to_remove.push(*channel_id);
}
}
for channel_id in to_remove {
this.channels.remove(&channel_id);
}
cx.notify();
});
}
Status::SignedOut { .. } => {
this.update(&mut cx, |this, cx| {
this.available_channels = None;
this.channels.clear();
cx.notify();
});
}
_ => {}
}
}
Ok(())
}
.log_err()
});
Self {
available_channels: None,
channels: Default::default(),
user_store,
client: rpc,
_task,
}
}
pub fn available_channels(&self) -> Option<&[ChannelDetails]> {
self.available_channels.as_deref()
}
pub fn get_channel(
&mut self,
id: u64,
cx: &mut MutableAppContext,
) -> Option<ModelHandle<Channel>> {
if let Some(channel) = self.channels.get(&id).and_then(|c| c.upgrade(cx)) {
return Some(channel);
}
let channels = self.available_channels.as_ref()?;
let details = channels.iter().find(|details| details.id == id)?.clone();
let channel = cx.add_model(|cx| {
Channel::new(details, self.user_store.clone(), self.client.clone(), cx)
});
self.channels.insert(id, channel.downgrade());
Some(channel)
}
}
impl Entity for Channel {
type Event = ChannelEvent;
fn release(&mut self, _: &mut MutableAppContext) {
self.rpc
.send(proto::LeaveChannel {
channel_id: self.details.id,
})
.log_err();
}
}
impl Channel {
pub fn init(rpc: &Arc<Client>) {
rpc.add_model_message_handler(Self::handle_message_sent);
}
pub fn new(
details: ChannelDetails,
user_store: ModelHandle<UserStore>,
rpc: Arc<Client>,
cx: &mut ModelContext<Self>,
) -> Self {
let _subscription = rpc.add_model_for_remote_entity(details.id, cx);
{
let user_store = user_store.clone();
let rpc = rpc.clone();
let channel_id = details.id;
cx.spawn(|channel, mut cx| {
async move {
let response = rpc.request(proto::JoinChannel { channel_id }).await?;
let messages =
messages_from_proto(response.messages, &user_store, &mut cx).await?;
let loaded_all_messages = response.done;
channel.update(&mut cx, |channel, cx| {
channel.insert_messages(messages, cx);
channel.loaded_all_messages = loaded_all_messages;
});
Ok(())
}
.log_err()
})
.detach();
}
Self {
details,
user_store,
rpc,
outgoing_messages_lock: Default::default(),
messages: Default::default(),
loaded_all_messages: false,
next_pending_message_id: 0,
rng: StdRng::from_entropy(),
_subscription,
}
}
pub fn name(&self) -> &str {
&self.details.name
}
pub fn send_message(
&mut self,
body: String,
cx: &mut ModelContext<Self>,
) -> Result<Task<Result<()>>> {
if body.is_empty() {
Err(anyhow!("message body can't be empty"))?;
}
let current_user = self
.user_store
.read(cx)
.current_user()
.ok_or_else(|| anyhow!("current_user is not present"))?;
let channel_id = self.details.id;
let pending_id = ChannelMessageId::Pending(post_inc(&mut self.next_pending_message_id));
let nonce = self.rng.gen();
self.insert_messages(
SumTree::from_item(
ChannelMessage {
id: pending_id,
body: body.clone(),
sender: current_user,
timestamp: OffsetDateTime::now_utc(),
nonce,
},
&(),
),
cx,
);
let user_store = self.user_store.clone();
let rpc = self.rpc.clone();
let outgoing_messages_lock = self.outgoing_messages_lock.clone();
Ok(cx.spawn(|this, mut cx| async move {
let outgoing_message_guard = outgoing_messages_lock.lock().await;
let request = rpc.request(proto::SendChannelMessage {
channel_id,
body,
nonce: Some(nonce.into()),
});
let response = request.await?;
drop(outgoing_message_guard);
let message = ChannelMessage::from_proto(
response.message.ok_or_else(|| anyhow!("invalid message"))?,
&user_store,
&mut cx,
)
.await?;
this.update(&mut cx, |this, cx| {
this.insert_messages(SumTree::from_item(message, &()), cx);
Ok(())
})
}))
}
pub fn load_more_messages(&mut self, cx: &mut ModelContext<Self>) -> bool {
if !self.loaded_all_messages {
let rpc = self.rpc.clone();
let user_store = self.user_store.clone();
let channel_id = self.details.id;
if let Some(before_message_id) =
self.messages.first().and_then(|message| match message.id {
ChannelMessageId::Saved(id) => Some(id),
ChannelMessageId::Pending(_) => None,
})
{
cx.spawn(|this, mut cx| {
async move {
let response = rpc
.request(proto::GetChannelMessages {
channel_id,
before_message_id,
})
.await?;
let loaded_all_messages = response.done;
let messages =
messages_from_proto(response.messages, &user_store, &mut cx).await?;
this.update(&mut cx, |this, cx| {
this.loaded_all_messages = loaded_all_messages;
this.insert_messages(messages, cx);
});
Ok(())
}
.log_err()
})
.detach();
return true;
}
}
false
}
pub fn rejoin(&mut self, cx: &mut ModelContext<Self>) {
let user_store = self.user_store.clone();
let rpc = self.rpc.clone();
let channel_id = self.details.id;
cx.spawn(|this, mut cx| {
async move {
let response = rpc.request(proto::JoinChannel { channel_id }).await?;
let messages = messages_from_proto(response.messages, &user_store, &mut cx).await?;
let loaded_all_messages = response.done;
let pending_messages = this.update(&mut cx, |this, cx| {
if let Some((first_new_message, last_old_message)) =
messages.first().zip(this.messages.last())
{
if first_new_message.id > last_old_message.id {
let old_messages = mem::take(&mut this.messages);
cx.emit(ChannelEvent::MessagesUpdated {
old_range: 0..old_messages.summary().count,
new_count: 0,
});
this.loaded_all_messages = loaded_all_messages;
}
}
this.insert_messages(messages, cx);
if loaded_all_messages {
this.loaded_all_messages = loaded_all_messages;
}
this.pending_messages().cloned().collect::<Vec<_>>()
});
for pending_message in pending_messages {
let request = rpc.request(proto::SendChannelMessage {
channel_id,
body: pending_message.body,
nonce: Some(pending_message.nonce.into()),
});
let response = request.await?;
let message = ChannelMessage::from_proto(
response.message.ok_or_else(|| anyhow!("invalid message"))?,
&user_store,
&mut cx,
)
.await?;
this.update(&mut cx, |this, cx| {
this.insert_messages(SumTree::from_item(message, &()), cx);
});
}
Ok(())
}
.log_err()
})
.detach();
}
pub fn message_count(&self) -> usize {
self.messages.summary().count
}
pub fn messages(&self) -> &SumTree<ChannelMessage> {
&self.messages
}
pub fn message(&self, ix: usize) -> &ChannelMessage {
let mut cursor = self.messages.cursor::<Count>();
cursor.seek(&Count(ix), Bias::Right, &());
cursor.item().unwrap()
}
pub fn messages_in_range(&self, range: Range<usize>) -> impl Iterator<Item = &ChannelMessage> {
let mut cursor = self.messages.cursor::<Count>();
cursor.seek(&Count(range.start), Bias::Right, &());
cursor.take(range.len())
}
pub fn pending_messages(&self) -> impl Iterator<Item = &ChannelMessage> {
let mut cursor = self.messages.cursor::<ChannelMessageId>();
cursor.seek(&ChannelMessageId::Pending(0), Bias::Left, &());
cursor
}
async fn handle_message_sent(
this: ModelHandle<Self>,
message: TypedEnvelope<proto::ChannelMessageSent>,
_: Arc<Client>,
mut cx: AsyncAppContext,
) -> Result<()> {
let user_store = this.read_with(&cx, |this, _| this.user_store.clone());
let message = message
.payload
.message
.ok_or_else(|| anyhow!("empty message"))?;
let message = ChannelMessage::from_proto(message, &user_store, &mut cx).await?;
this.update(&mut cx, |this, cx| {
this.insert_messages(SumTree::from_item(message, &()), cx)
});
Ok(())
}
fn insert_messages(&mut self, messages: SumTree<ChannelMessage>, cx: &mut ModelContext<Self>) {
if let Some((first_message, last_message)) = messages.first().zip(messages.last()) {
let nonces = messages
.cursor::<()>()
.map(|m| m.nonce)
.collect::<HashSet<_>>();
let mut old_cursor = self.messages.cursor::<(ChannelMessageId, Count)>();
let mut new_messages = old_cursor.slice(&first_message.id, Bias::Left, &());
let start_ix = old_cursor.start().1 .0;
let removed_messages = old_cursor.slice(&last_message.id, Bias::Right, &());
let removed_count = removed_messages.summary().count;
let new_count = messages.summary().count;
let end_ix = start_ix + removed_count;
new_messages.push_tree(messages, &());
let mut ranges = Vec::<Range<usize>>::new();
if new_messages.last().unwrap().is_pending() {
new_messages.push_tree(old_cursor.suffix(&()), &());
} else {
new_messages.push_tree(
old_cursor.slice(&ChannelMessageId::Pending(0), Bias::Left, &()),
&(),
);
while let Some(message) = old_cursor.item() {
let message_ix = old_cursor.start().1 .0;
if nonces.contains(&message.nonce) {
if ranges.last().map_or(false, |r| r.end == message_ix) {
ranges.last_mut().unwrap().end += 1;
} else {
ranges.push(message_ix..message_ix + 1);
}
} else {
new_messages.push(message.clone(), &());
}
old_cursor.next(&());
}
}
drop(old_cursor);
self.messages = new_messages;
for range in ranges.into_iter().rev() {
cx.emit(ChannelEvent::MessagesUpdated {
old_range: range,
new_count: 0,
});
}
cx.emit(ChannelEvent::MessagesUpdated {
old_range: start_ix..end_ix,
new_count,
});
cx.notify();
}
}
}
async fn messages_from_proto(
proto_messages: Vec<proto::ChannelMessage>,
user_store: &ModelHandle<UserStore>,
cx: &mut AsyncAppContext,
) -> Result<SumTree<ChannelMessage>> {
let unique_user_ids = proto_messages
.iter()
.map(|m| m.sender_id)
.collect::<HashSet<_>>()
.into_iter()
.collect();
user_store
.update(cx, |user_store, cx| {
user_store.get_users(unique_user_ids, cx)
})
.await?;
let mut messages = Vec::with_capacity(proto_messages.len());
for message in proto_messages {
messages.push(ChannelMessage::from_proto(message, user_store, cx).await?);
}
let mut result = SumTree::new();
result.extend(messages, &());
Ok(result)
}
impl From<proto::Channel> for ChannelDetails {
fn from(message: proto::Channel) -> Self {
Self {
id: message.id,
name: message.name,
}
}
}
impl ChannelMessage {
pub async fn from_proto(
message: proto::ChannelMessage,
user_store: &ModelHandle<UserStore>,
cx: &mut AsyncAppContext,
) -> Result<Self> {
let sender = user_store
.update(cx, |user_store, cx| {
user_store.get_user(message.sender_id, cx)
})
.await?;
Ok(ChannelMessage {
id: ChannelMessageId::Saved(message.id),
body: message.body,
timestamp: OffsetDateTime::from_unix_timestamp(message.timestamp as i64)?,
sender,
nonce: message
.nonce
.ok_or_else(|| anyhow!("nonce is required"))?
.into(),
})
}
pub fn is_pending(&self) -> bool {
matches!(self.id, ChannelMessageId::Pending(_))
}
}
impl sum_tree::Item for ChannelMessage {
type Summary = ChannelMessageSummary;
fn summary(&self) -> Self::Summary {
ChannelMessageSummary {
max_id: self.id,
count: 1,
}
}
}
impl Default for ChannelMessageId {
fn default() -> Self {
Self::Saved(0)
}
}
impl sum_tree::Summary for ChannelMessageSummary {
type Context = ();
fn add_summary(&mut self, summary: &Self, _: &()) {
self.max_id = summary.max_id;
self.count += summary.count;
}
}
impl<'a> sum_tree::Dimension<'a, ChannelMessageSummary> for ChannelMessageId {
fn add_summary(&mut self, summary: &'a ChannelMessageSummary, _: &()) {
debug_assert!(summary.max_id > *self);
*self = summary.max_id;
}
}
impl<'a> sum_tree::Dimension<'a, ChannelMessageSummary> for Count {
fn add_summary(&mut self, summary: &'a ChannelMessageSummary, _: &()) {
self.0 += summary.count;
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test::{FakeHttpClient, FakeServer};
use gpui::TestAppContext;
#[gpui::test]
async fn test_channel_messages(cx: &mut TestAppContext) {
cx.foreground().forbid_parking();
let user_id = 5;
let http_client = FakeHttpClient::with_404_response();
let client = cx.update(|cx| Client::new(http_client.clone(), cx));
let server = FakeServer::for_client(user_id, &client, cx).await;
Channel::init(&client);
let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http_client, cx));
let channel_list = cx.add_model(|cx| ChannelList::new(user_store, client.clone(), cx));
channel_list.read_with(cx, |list, _| assert_eq!(list.available_channels(), None));
// Get the available channels.
let get_channels = server.receive::<proto::GetChannels>().await.unwrap();
server
.respond(
get_channels.receipt(),
proto::GetChannelsResponse {
channels: vec![proto::Channel {
id: 5,
name: "the-channel".to_string(),
}],
},
)
.await;
channel_list.next_notification(cx).await;
channel_list.read_with(cx, |list, _| {
assert_eq!(
list.available_channels().unwrap(),
&[ChannelDetails {
id: 5,
name: "the-channel".into(),
}]
)
});
let get_users = server.receive::<proto::GetUsers>().await.unwrap();
assert_eq!(get_users.payload.user_ids, vec![5]);
server
.respond(
get_users.receipt(),
proto::UsersResponse {
users: vec![proto::User {
id: 5,
github_login: "nathansobo".into(),
avatar_url: "http://avatar.com/nathansobo".into(),
}],
},
)
.await;
// Join a channel and populate its existing messages.
let channel = channel_list
.update(cx, |list, cx| {
let channel_id = list.available_channels().unwrap()[0].id;
list.get_channel(channel_id, cx)
})
.unwrap();
channel.read_with(cx, |channel, _| assert!(channel.messages().is_empty()));
let join_channel = server.receive::<proto::JoinChannel>().await.unwrap();
server
.respond(
join_channel.receipt(),
proto::JoinChannelResponse {
messages: vec![
proto::ChannelMessage {
id: 10,
body: "a".into(),
timestamp: 1000,
sender_id: 5,
nonce: Some(1.into()),
},
proto::ChannelMessage {
id: 11,
body: "b".into(),
timestamp: 1001,
sender_id: 6,
nonce: Some(2.into()),
},
],
done: false,
},
)
.await;
// Client requests all users for the received messages
let mut get_users = server.receive::<proto::GetUsers>().await.unwrap();
get_users.payload.user_ids.sort();
assert_eq!(get_users.payload.user_ids, vec![6]);
server
.respond(
get_users.receipt(),
proto::UsersResponse {
users: vec![proto::User {
id: 6,
github_login: "maxbrunsfeld".into(),
avatar_url: "http://avatar.com/maxbrunsfeld".into(),
}],
},
)
.await;
assert_eq!(
channel.next_event(cx).await,
ChannelEvent::MessagesUpdated {
old_range: 0..0,
new_count: 2,
}
);
channel.read_with(cx, |channel, _| {
assert_eq!(
channel
.messages_in_range(0..2)
.map(|message| (message.sender.github_login.clone(), message.body.clone()))
.collect::<Vec<_>>(),
&[
("nathansobo".into(), "a".into()),
("maxbrunsfeld".into(), "b".into())
]
);
});
// Receive a new message.
server.send(proto::ChannelMessageSent {
channel_id: channel.read_with(cx, |channel, _| channel.details.id),
message: Some(proto::ChannelMessage {
id: 12,
body: "c".into(),
timestamp: 1002,
sender_id: 7,
nonce: Some(3.into()),
}),
});
// Client requests user for message since they haven't seen them yet
let get_users = server.receive::<proto::GetUsers>().await.unwrap();
assert_eq!(get_users.payload.user_ids, vec![7]);
server
.respond(
get_users.receipt(),
proto::UsersResponse {
users: vec![proto::User {
id: 7,
github_login: "as-cii".into(),
avatar_url: "http://avatar.com/as-cii".into(),
}],
},
)
.await;
assert_eq!(
channel.next_event(cx).await,
ChannelEvent::MessagesUpdated {
old_range: 2..2,
new_count: 1,
}
);
channel.read_with(cx, |channel, _| {
assert_eq!(
channel
.messages_in_range(2..3)
.map(|message| (message.sender.github_login.clone(), message.body.clone()))
.collect::<Vec<_>>(),
&[("as-cii".into(), "c".into())]
)
});
// Scroll up to view older messages.
channel.update(cx, |channel, cx| {
assert!(channel.load_more_messages(cx));
});
let get_messages = server.receive::<proto::GetChannelMessages>().await.unwrap();
assert_eq!(get_messages.payload.channel_id, 5);
assert_eq!(get_messages.payload.before_message_id, 10);
server
.respond(
get_messages.receipt(),
proto::GetChannelMessagesResponse {
done: true,
messages: vec![
proto::ChannelMessage {
id: 8,
body: "y".into(),
timestamp: 998,
sender_id: 5,
nonce: Some(4.into()),
},
proto::ChannelMessage {
id: 9,
body: "z".into(),
timestamp: 999,
sender_id: 6,
nonce: Some(5.into()),
},
],
},
)
.await;
assert_eq!(
channel.next_event(cx).await,
ChannelEvent::MessagesUpdated {
old_range: 0..0,
new_count: 2,
}
);
channel.read_with(cx, |channel, _| {
assert_eq!(
channel
.messages_in_range(0..2)
.map(|message| (message.sender.github_login.clone(), message.body.clone()))
.collect::<Vec<_>>(),
&[
("nathansobo".into(), "y".into()),
("maxbrunsfeld".into(), "z".into())
]
);
});
}
}

View File

@@ -1,27 +1,22 @@
#[cfg(any(test, feature = "test-support"))]
pub mod test;
pub mod amplitude_telemetry;
pub mod channel;
pub mod http;
pub mod telemetry;
pub mod user;
use amplitude_telemetry::AmplitudeTelemetry;
use anyhow::{anyhow, Context, Result};
use async_recursion::async_recursion;
use async_tungstenite::tungstenite::{
error::Error as WebsocketError,
http::{Request, StatusCode},
};
use db::Db;
use futures::{future::LocalBoxFuture, AsyncReadExt, FutureExt, SinkExt, StreamExt, TryStreamExt};
use gpui::{
actions,
serde_json::{self, Value},
AnyModelHandle, AnyViewHandle, AnyWeakModelHandle, AnyWeakViewHandle, AppContext,
AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext, Task, View, ViewContext,
ViewHandle,
AsyncAppContext, Entity, ModelHandle, MutableAppContext, Task, View, ViewContext, ViewHandle,
};
use http::HttpClient;
use lazy_static::lazy_static;
@@ -30,13 +25,13 @@ use postage::watch;
use rand::prelude::*;
use rpc::proto::{AnyTypedEnvelope, EntityMessage, EnvelopedMessage, RequestMessage};
use serde::Deserialize;
use settings::ReleaseChannel;
use std::{
any::TypeId,
collections::HashMap,
convert::TryFrom,
fmt::Write as _,
future::Future,
marker::PhantomData,
path::PathBuf,
sync::{Arc, Weak},
time::{Duration, Instant},
@@ -44,9 +39,9 @@ use std::{
use telemetry::Telemetry;
use thiserror::Error;
use url::Url;
use util::channel::ReleaseChannel;
use util::{ResultExt, TryFutureExt};
pub use channel::*;
pub use rpc::*;
pub use user::*;
@@ -85,7 +80,6 @@ pub struct Client {
peer: Arc<Peer>,
http: Arc<dyn HttpClient>,
telemetry: Arc<Telemetry>,
amplitude_telemetry: Arc<AmplitudeTelemetry>,
state: RwLock<ClientState>,
#[allow(clippy::type_complexity)]
@@ -177,7 +171,7 @@ struct ClientState {
entity_id_extractors: HashMap<TypeId, fn(&dyn AnyTypedEnvelope) -> u64>,
_reconnect_task: Option<Task<()>>,
reconnect_interval: Duration,
entities_by_type_and_remote_id: HashMap<(TypeId, u64), AnyWeakEntityHandle>,
entities_by_type_and_remote_id: HashMap<(TypeId, u64), WeakSubscriber>,
models_by_message_type: HashMap<TypeId, AnyWeakModelHandle>,
entity_types_by_message_type: HashMap<TypeId, TypeId>,
#[allow(clippy::type_complexity)]
@@ -187,7 +181,7 @@ struct ClientState {
dyn Send
+ Sync
+ Fn(
AnyEntityHandle,
Subscriber,
Box<dyn AnyTypedEnvelope>,
&Arc<Client>,
AsyncAppContext,
@@ -196,12 +190,13 @@ struct ClientState {
>,
}
enum AnyWeakEntityHandle {
enum WeakSubscriber {
Model(AnyWeakModelHandle),
View(AnyWeakViewHandle),
Pending(Vec<Box<dyn AnyTypedEnvelope>>),
}
enum AnyEntityHandle {
enum Subscriber {
Model(AnyModelHandle),
View(AnyViewHandle),
}
@@ -259,13 +254,60 @@ impl Drop for Subscription {
}
}
pub struct PendingEntitySubscription<T: Entity> {
client: Arc<Client>,
remote_id: u64,
_entity_type: PhantomData<T>,
consumed: bool,
}
impl<T: Entity> PendingEntitySubscription<T> {
pub fn set_model(mut self, model: &ModelHandle<T>, cx: &mut AsyncAppContext) -> Subscription {
self.consumed = true;
let mut state = self.client.state.write();
let id = (TypeId::of::<T>(), self.remote_id);
let Some(WeakSubscriber::Pending(messages)) =
state.entities_by_type_and_remote_id.remove(&id)
else {
unreachable!()
};
state
.entities_by_type_and_remote_id
.insert(id, WeakSubscriber::Model(model.downgrade().into()));
drop(state);
for message in messages {
self.client.handle_message(message, cx);
}
Subscription::Entity {
client: Arc::downgrade(&self.client),
id,
}
}
}
impl<T: Entity> Drop for PendingEntitySubscription<T> {
fn drop(&mut self) {
if !self.consumed {
let mut state = self.client.state.write();
if let Some(WeakSubscriber::Pending(messages)) = state
.entities_by_type_and_remote_id
.remove(&(TypeId::of::<T>(), self.remote_id))
{
for message in messages {
log::info!("unhandled message {}", message.payload_type_name());
}
}
}
}
}
impl Client {
pub fn new(http: Arc<dyn HttpClient>, cx: &AppContext) -> Arc<Self> {
Arc::new(Self {
id: 0,
peer: Peer::new(),
telemetry: Telemetry::new(http.clone(), cx),
amplitude_telemetry: AmplitudeTelemetry::new(http.clone(), cx),
http,
state: Default::default(),
@@ -355,7 +397,11 @@ impl Client {
let this = self.clone();
let reconnect_interval = state.reconnect_interval;
state._reconnect_task = Some(cx.spawn(|cx| async move {
#[cfg(any(test, feature = "test-support"))]
let mut rng = StdRng::seed_from_u64(0);
#[cfg(not(any(test, feature = "test-support")))]
let mut rng = StdRng::from_entropy();
let mut delay = INITIAL_RECONNECTION_DELAY;
while let Err(error) = this.authenticate_and_connect(true, &cx).await {
log::error!("failed to connect {}", error);
@@ -378,8 +424,6 @@ impl Client {
}
Status::SignedOut | Status::UpgradeRequired => {
self.telemetry.set_authenticated_user_info(None, false);
self.amplitude_telemetry
.set_authenticated_user_info(None, false);
state._reconnect_task.take();
}
_ => {}
@@ -395,26 +439,28 @@ impl Client {
self.state
.write()
.entities_by_type_and_remote_id
.insert(id, AnyWeakEntityHandle::View(cx.weak_handle().into()));
.insert(id, WeakSubscriber::View(cx.weak_handle().into()));
Subscription::Entity {
client: Arc::downgrade(self),
id,
}
}
pub fn add_model_for_remote_entity<T: Entity>(
pub fn subscribe_to_entity<T: Entity>(
self: &Arc<Self>,
remote_id: u64,
cx: &mut ModelContext<T>,
) -> Subscription {
) -> PendingEntitySubscription<T> {
let id = (TypeId::of::<T>(), remote_id);
self.state
.write()
.entities_by_type_and_remote_id
.insert(id, AnyWeakEntityHandle::Model(cx.weak_handle().into()));
Subscription::Entity {
client: Arc::downgrade(self),
id,
.insert(id, WeakSubscriber::Pending(Default::default()));
PendingEntitySubscription {
client: self.clone(),
remote_id,
consumed: false,
_entity_type: PhantomData,
}
}
@@ -442,7 +488,7 @@ impl Client {
let prev_handler = state.message_handlers.insert(
message_type_id,
Arc::new(move |handle, envelope, client, cx| {
let handle = if let AnyEntityHandle::Model(handle) = handle {
let handle = if let Subscriber::Model(handle) = handle {
handle
} else {
unreachable!();
@@ -496,7 +542,7 @@ impl Client {
F: 'static + Future<Output = Result<()>>,
{
self.add_entity_message_handler::<M, E, _, _>(move |handle, message, client, cx| {
if let AnyEntityHandle::View(handle) = handle {
if let Subscriber::View(handle) = handle {
handler(handle.downcast::<E>().unwrap(), message, client, cx)
} else {
unreachable!();
@@ -515,7 +561,7 @@ impl Client {
F: 'static + Future<Output = Result<()>>,
{
self.add_entity_message_handler::<M, E, _, _>(move |handle, message, client, cx| {
if let AnyEntityHandle::Model(handle) = handle {
if let Subscriber::Model(handle) = handle {
handler(handle.downcast::<E>().unwrap(), message, client, cx)
} else {
unreachable!();
@@ -530,7 +576,7 @@ impl Client {
H: 'static
+ Send
+ Sync
+ Fn(AnyEntityHandle, TypedEnvelope<M>, Arc<Self>, AsyncAppContext) -> F,
+ Fn(Subscriber, TypedEnvelope<M>, Arc<Self>, AsyncAppContext) -> F,
F: 'static + Future<Output = Result<()>>,
{
let model_type_id = TypeId::of::<E>();
@@ -792,91 +838,8 @@ impl Client {
let cx = cx.clone();
let this = self.clone();
async move {
let mut message_id = 0_usize;
while let Some(message) = incoming.next().await {
let mut state = this.state.write();
message_id += 1;
let type_name = message.payload_type_name();
let payload_type_id = message.payload_type_id();
let sender_id = message.original_sender_id().map(|id| id.0);
let model = state
.models_by_message_type
.get(&payload_type_id)
.and_then(|model| model.upgrade(&cx))
.map(AnyEntityHandle::Model)
.or_else(|| {
let entity_type_id =
*state.entity_types_by_message_type.get(&payload_type_id)?;
let entity_id = state
.entity_id_extractors
.get(&message.payload_type_id())
.map(|extract_entity_id| {
(extract_entity_id)(message.as_ref())
})?;
let entity = state
.entities_by_type_and_remote_id
.get(&(entity_type_id, entity_id))?;
if let Some(entity) = entity.upgrade(&cx) {
Some(entity)
} else {
state
.entities_by_type_and_remote_id
.remove(&(entity_type_id, entity_id));
None
}
});
let model = if let Some(model) = model {
model
} else {
log::info!("unhandled message {}", type_name);
continue;
};
if let Some(handler) = state.message_handlers.get(&payload_type_id).cloned()
{
drop(state); // Avoid deadlocks if the handler interacts with rpc::Client
let future = handler(model, message, &this, cx.clone());
let client_id = this.id;
log::debug!(
"rpc message received. client_id:{}, message_id:{}, sender_id:{:?}, type:{}",
client_id,
message_id,
sender_id,
type_name
);
cx.foreground()
.spawn(async move {
match future.await {
Ok(()) => {
log::debug!(
"rpc message handled. client_id:{}, message_id:{}, sender_id:{:?}, type:{}",
client_id,
message_id,
sender_id,
type_name
);
}
Err(error) => {
log::error!(
"error handling message. client_id:{}, message_id:{}, sender_id:{:?}, type:{}, error:{:?}",
client_id,
message_id,
sender_id,
type_name,
error
);
}
}
})
.detach();
} else {
log::info!("unhandled message {}", type_name);
}
this.handle_message(message, &cx);
// Don't starve the main thread when receiving lots of messages at once.
smol::future::yield_now().await;
}
@@ -1029,7 +992,6 @@ impl Client {
let platform = cx.platform();
let executor = cx.background();
let telemetry = self.telemetry.clone();
let amplitude_telemetry = self.amplitude_telemetry.clone();
let http = self.http.clone();
executor.clone().spawn(async move {
// Generate a pair of asymmetric encryption keys. The public key will be used by the
@@ -1114,7 +1076,6 @@ impl Client {
platform.activate(true);
telemetry.report_event("authenticate with browser", Default::default());
amplitude_telemetry.report_event("authenticate with browser", Default::default());
Ok(Credentials {
user_id: user_id.parse()?,
@@ -1225,27 +1186,116 @@ impl Client {
self.peer.respond_with_error(receipt, error)
}
pub fn start_telemetry(&self, db: Db) {
self.telemetry.start(db.clone());
self.amplitude_telemetry.start(db);
fn handle_message(
self: &Arc<Client>,
message: Box<dyn AnyTypedEnvelope>,
cx: &AsyncAppContext,
) {
let mut state = self.state.write();
let type_name = message.payload_type_name();
let payload_type_id = message.payload_type_id();
let sender_id = message.original_sender_id().map(|id| id.0);
let mut subscriber = None;
if let Some(message_model) = state
.models_by_message_type
.get(&payload_type_id)
.and_then(|model| model.upgrade(cx))
{
subscriber = Some(Subscriber::Model(message_model));
} else if let Some((extract_entity_id, entity_type_id)) =
state.entity_id_extractors.get(&payload_type_id).zip(
state
.entity_types_by_message_type
.get(&payload_type_id)
.copied(),
)
{
let entity_id = (extract_entity_id)(message.as_ref());
match state
.entities_by_type_and_remote_id
.get_mut(&(entity_type_id, entity_id))
{
Some(WeakSubscriber::Pending(pending)) => {
pending.push(message);
return;
}
Some(weak_subscriber @ _) => subscriber = weak_subscriber.upgrade(cx),
_ => {}
}
}
let subscriber = if let Some(subscriber) = subscriber {
subscriber
} else {
log::info!("unhandled message {}", type_name);
return;
};
let handler = state.message_handlers.get(&payload_type_id).cloned();
// Dropping the state prevents deadlocks if the handler interacts with rpc::Client.
// It also ensures we don't hold the lock while yielding back to the executor, as
// that might cause the executor thread driving this future to block indefinitely.
drop(state);
if let Some(handler) = handler {
let future = handler(subscriber, message, &self, cx.clone());
let client_id = self.id;
log::debug!(
"rpc message received. client_id:{}, sender_id:{:?}, type:{}",
client_id,
sender_id,
type_name
);
cx.foreground()
.spawn(async move {
match future.await {
Ok(()) => {
log::debug!(
"rpc message handled. client_id:{}, sender_id:{:?}, type:{}",
client_id,
sender_id,
type_name
);
}
Err(error) => {
log::error!(
"error handling message. client_id:{}, sender_id:{:?}, type:{}, error:{:?}",
client_id,
sender_id,
type_name,
error
);
}
}
})
.detach();
} else {
log::info!("unhandled message {}", type_name);
}
}
pub fn start_telemetry(&self) {
self.telemetry.start();
}
pub fn report_event(&self, kind: &str, properties: Value) {
self.telemetry.report_event(kind, properties.clone());
self.amplitude_telemetry.report_event(kind, properties);
}
pub fn telemetry_log_file_path(&self) -> Option<PathBuf> {
self.amplitude_telemetry.log_file_path();
self.telemetry.log_file_path()
}
}
impl AnyWeakEntityHandle {
fn upgrade(&self, cx: &AsyncAppContext) -> Option<AnyEntityHandle> {
impl WeakSubscriber {
fn upgrade(&self, cx: &AsyncAppContext) -> Option<Subscriber> {
match self {
AnyWeakEntityHandle::Model(handle) => handle.upgrade(cx).map(AnyEntityHandle::Model),
AnyWeakEntityHandle::View(handle) => handle.upgrade(cx).map(AnyEntityHandle::View),
WeakSubscriber::Model(handle) => handle.upgrade(cx).map(Subscriber::Model),
WeakSubscriber::View(handle) => handle.upgrade(cx).map(Subscriber::View),
WeakSubscriber::Pending(_) => None,
}
}
}
@@ -1490,11 +1540,17 @@ mod tests {
subscription: None,
});
let _subscription1 = model1.update(cx, |_, cx| client.add_model_for_remote_entity(1, cx));
let _subscription2 = model2.update(cx, |_, cx| client.add_model_for_remote_entity(2, cx));
let _subscription1 = client
.subscribe_to_entity(1)
.set_model(&model1, &mut cx.to_async());
let _subscription2 = client
.subscribe_to_entity(2)
.set_model(&model2, &mut cx.to_async());
// Ensure dropping a subscription for the same entity type still allows receiving of
// messages for other entity IDs of the same type.
let subscription3 = model3.update(cx, |_, cx| client.add_model_for_remote_entity(3, cx));
let subscription3 = client
.subscribe_to_entity(3)
.set_model(&model3, &mut cx.to_async());
drop(subscription3);
server.send(proto::JoinProject { project_id: 1 });

View File

@@ -1,5 +1,5 @@
use crate::http::HttpClient;
use db::Db;
use db::kvp::KEY_VALUE_STORE;
use gpui::{
executor::Background,
serde_json::{self, value::Map, Value},
@@ -18,7 +18,7 @@ use std::{
time::{Duration, SystemTime, UNIX_EPOCH},
};
use tempfile::NamedTempFile;
use util::{post_inc, ResultExt, TryFutureExt};
use util::{channel::ReleaseChannel, post_inc, ResultExt, TryFutureExt};
use uuid::Uuid;
pub struct Telemetry {
@@ -32,6 +32,7 @@ struct TelemetryState {
metrics_id: Option<Arc<str>>,
device_id: Option<Arc<str>>,
app_version: Option<Arc<str>>,
release_channel: Option<&'static str>,
os_version: Option<Arc<str>>,
os_name: &'static str,
queue: Vec<MixpanelEvent>,
@@ -67,11 +68,16 @@ struct MixpanelEventProperties {
// Custom fields
#[serde(skip_serializing_if = "Option::is_none", flatten)]
event_properties: Option<Map<String, Value>>,
#[serde(rename = "OS Name")]
os_name: &'static str,
#[serde(rename = "OS Version")]
os_version: Option<Arc<str>>,
#[serde(rename = "Release Channel")]
release_channel: Option<&'static str>,
#[serde(rename = "App Version")]
app_version: Option<Arc<str>>,
#[serde(rename = "Signed In")]
signed_in: bool,
platform: &'static str,
}
#[derive(Serialize)]
@@ -99,19 +105,19 @@ const DEBOUNCE_INTERVAL: Duration = Duration::from_secs(30);
impl Telemetry {
pub fn new(client: Arc<dyn HttpClient>, cx: &AppContext) -> Arc<Self> {
let platform = cx.platform();
let release_channel = if cx.has_global::<ReleaseChannel>() {
Some(cx.global::<ReleaseChannel>().display_name())
} else {
None
};
let this = Arc::new(Self {
http_client: client,
executor: cx.background().clone(),
state: Mutex::new(TelemetryState {
os_version: platform
.os_version()
.log_err()
.map(|v| v.to_string().into()),
os_version: platform.os_version().ok().map(|v| v.to_string().into()),
os_name: platform.os_name().into(),
app_version: platform
.app_version()
.log_err()
.map(|v| v.to_string().into()),
app_version: platform.app_version().ok().map(|v| v.to_string().into()),
release_channel,
device_id: None,
metrics_id: None,
queue: Default::default(),
@@ -141,18 +147,21 @@ impl Telemetry {
Some(self.state.lock().log_file.as_ref()?.path().to_path_buf())
}
pub fn start(self: &Arc<Self>, db: Db) {
pub fn start(self: &Arc<Self>) {
let this = self.clone();
self.executor
.spawn(
async move {
let device_id = if let Ok(Some(device_id)) = db.read_kvp("device_id") {
device_id
} else {
let device_id = Uuid::new_v4().to_string();
db.write_kvp("device_id", &device_id)?;
device_id
};
let device_id =
if let Ok(Some(device_id)) = KEY_VALUE_STORE.read_kvp("device_id") {
device_id
} else {
let device_id = Uuid::new_v4().to_string();
KEY_VALUE_STORE
.write_kvp("device_id".to_string(), device_id.clone())
.await?;
device_id
};
let device_id: Arc<str> = device_id.into();
let mut state = this.state.lock();
@@ -194,7 +203,11 @@ impl Telemetry {
let json_bytes = serde_json::to_vec(&[MixpanelEngageRequest {
token,
distinct_id: device_id,
set: json!({ "staff": is_staff, "id": metrics_id }),
set: json!({
"Staff": is_staff,
"ID": metrics_id,
"App": true
}),
}])?;
let request = Request::post(MIXPANEL_ENGAGE_URL)
.header("Content-Type", "application/json")
@@ -227,9 +240,9 @@ impl Telemetry {
},
os_name: state.os_name,
os_version: state.os_version.clone(),
release_channel: state.release_channel,
app_version: state.app_version.clone(),
signed_in: state.metrics_id.is_some(),
platform: "Zed",
},
};
state.queue.push(event);

View File

@@ -146,21 +146,10 @@ impl UserStore {
Some(info.metrics_id.clone()),
info.staff,
);
client.amplitude_telemetry.set_authenticated_user_info(
Some(info.metrics_id),
info.staff,
);
} else {
client.telemetry.set_authenticated_user_info(None, false);
client
.amplitude_telemetry
.set_authenticated_user_info(None, false);
}
client.telemetry.report_event("sign in", Default::default());
client
.amplitude_telemetry
.report_event("sign in", Default::default());
current_user_tx.send(user).await.ok();
}
}

View File

@@ -3,7 +3,7 @@ authors = ["Nathan Sobo <nathan@zed.dev>"]
default-run = "collab"
edition = "2021"
name = "collab"
version = "0.2.0"
version = "0.3.4"
[[bin]]
name = "collab"
@@ -19,12 +19,12 @@ rpc = { path = "../rpc" }
util = { path = "../util" }
anyhow = "1.0.40"
async-trait = "0.1.50"
async-tungstenite = "0.16"
axum = { version = "0.5", features = ["json", "headers", "ws"] }
axum-extra = { version = "0.3", features = ["erased-json"] }
base64 = "0.13"
clap = { version = "3.1", features = ["derive"], optional = true }
dashmap = "5.4"
envy = "0.4.2"
futures = "0.3"
hyper = "0.14"
@@ -36,9 +36,13 @@ prometheus = "0.13"
rand = "0.8"
reqwest = { version = "0.11", features = ["json"], optional = true }
scrypt = "0.7"
# Remove fork dependency when a version with https://github.com/SeaQL/sea-orm/pull/1283 is released.
sea-orm = { git = "https://github.com/zed-industries/sea-orm", rev = "18f4c691085712ad014a51792af75a9044bacee6", features = ["sqlx-postgres", "postgres-array", "runtime-tokio-rustls"] }
sea-query = "0.27"
serde = { version = "1.0", features = ["derive", "rc"] }
serde_json = "1.0"
sha-1 = "0.9"
sqlx = { version = "0.6", features = ["runtime-tokio-rustls", "postgres", "json", "time", "uuid", "any"] }
time = { version = "0.3", features = ["serde", "serde-well-known"] }
tokio = { version = "1", features = ["full"] }
tokio-tungstenite = "0.17"
@@ -49,10 +53,6 @@ tracing = "0.1.34"
tracing-log = "0.1.3"
tracing-subscriber = { version = "0.3.11", features = ["env-filter", "json"] }
[dependencies.sqlx]
version = "0.6"
features = ["runtime-tokio-rustls", "postgres", "time", "uuid"]
[dev-dependencies]
collections = { path = "../collections", features = ["test-support"] }
gpui = { path = "../gpui", features = ["test-support"] }
@@ -64,6 +64,7 @@ fs = { path = "../fs", features = ["test-support"] }
git = { path = "../git", features = ["test-support"] }
live_kit_client = { path = "../live_kit_client", features = ["test-support"] }
lsp = { path = "../lsp", features = ["test-support"] }
pretty_assertions = "1.3.0"
project = { path = "../project", features = ["test-support"] }
rpc = { path = "../rpc", features = ["test-support"] }
settings = { path = "../settings", features = ["test-support"] }
@@ -75,7 +76,9 @@ env_logger = "0.9"
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
util = { path = "../util" }
lazy_static = "1.4"
sea-orm = { git = "https://github.com/zed-industries/sea-orm", rev = "18f4c691085712ad014a51792af75a9044bacee6", features = ["sqlx-sqlite"] }
serde_json = { version = "1.0", features = ["preserve_order"] }
sqlx = { version = "0.6", features = ["sqlite"] }
unindent = "0.1"
[features]

View File

@@ -0,0 +1,136 @@
CREATE TABLE "users" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"github_login" VARCHAR,
"admin" BOOLEAN,
"email_address" VARCHAR(255) DEFAULT NULL,
"invite_code" VARCHAR(64),
"invite_count" INTEGER NOT NULL DEFAULT 0,
"inviter_id" INTEGER REFERENCES users (id),
"connected_once" BOOLEAN NOT NULL DEFAULT false,
"created_at" TIMESTAMP NOT NULL DEFAULT now,
"metrics_id" TEXT,
"github_user_id" INTEGER
);
CREATE UNIQUE INDEX "index_users_github_login" ON "users" ("github_login");
CREATE UNIQUE INDEX "index_invite_code_users" ON "users" ("invite_code");
CREATE INDEX "index_users_on_email_address" ON "users" ("email_address");
CREATE INDEX "index_users_on_github_user_id" ON "users" ("github_user_id");
CREATE TABLE "access_tokens" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"user_id" INTEGER REFERENCES users (id),
"hash" VARCHAR(128)
);
CREATE INDEX "index_access_tokens_user_id" ON "access_tokens" ("user_id");
CREATE TABLE "contacts" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"user_id_a" INTEGER REFERENCES users (id) NOT NULL,
"user_id_b" INTEGER REFERENCES users (id) NOT NULL,
"a_to_b" BOOLEAN NOT NULL,
"should_notify" BOOLEAN NOT NULL,
"accepted" BOOLEAN NOT NULL
);
CREATE UNIQUE INDEX "index_contacts_user_ids" ON "contacts" ("user_id_a", "user_id_b");
CREATE INDEX "index_contacts_user_id_b" ON "contacts" ("user_id_b");
CREATE TABLE "rooms" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"live_kit_room" VARCHAR NOT NULL
);
CREATE TABLE "projects" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"room_id" INTEGER REFERENCES rooms (id) NOT NULL,
"host_user_id" INTEGER REFERENCES users (id) NOT NULL,
"host_connection_id" INTEGER NOT NULL,
"host_connection_epoch" TEXT NOT NULL,
"unregistered" BOOLEAN NOT NULL DEFAULT FALSE
);
CREATE INDEX "index_projects_on_host_connection_epoch" ON "projects" ("host_connection_epoch");
CREATE TABLE "worktrees" (
"project_id" INTEGER NOT NULL REFERENCES projects (id) ON DELETE CASCADE,
"id" INTEGER NOT NULL,
"root_name" VARCHAR NOT NULL,
"abs_path" VARCHAR NOT NULL,
"visible" BOOL NOT NULL,
"scan_id" INTEGER NOT NULL,
"is_complete" BOOL NOT NULL,
PRIMARY KEY(project_id, id)
);
CREATE INDEX "index_worktrees_on_project_id" ON "worktrees" ("project_id");
CREATE TABLE "worktree_entries" (
"project_id" INTEGER NOT NULL,
"worktree_id" INTEGER NOT NULL,
"id" INTEGER NOT NULL,
"is_dir" BOOL NOT NULL,
"path" VARCHAR NOT NULL,
"inode" INTEGER NOT NULL,
"mtime_seconds" INTEGER NOT NULL,
"mtime_nanos" INTEGER NOT NULL,
"is_symlink" BOOL NOT NULL,
"is_ignored" BOOL NOT NULL,
PRIMARY KEY(project_id, worktree_id, id),
FOREIGN KEY(project_id, worktree_id) REFERENCES worktrees (project_id, id) ON DELETE CASCADE
);
CREATE INDEX "index_worktree_entries_on_project_id" ON "worktree_entries" ("project_id");
CREATE INDEX "index_worktree_entries_on_project_id_and_worktree_id" ON "worktree_entries" ("project_id", "worktree_id");
CREATE TABLE "worktree_diagnostic_summaries" (
"project_id" INTEGER NOT NULL,
"worktree_id" INTEGER NOT NULL,
"path" VARCHAR NOT NULL,
"language_server_id" INTEGER NOT NULL,
"error_count" INTEGER NOT NULL,
"warning_count" INTEGER NOT NULL,
PRIMARY KEY(project_id, worktree_id, path),
FOREIGN KEY(project_id, worktree_id) REFERENCES worktrees (project_id, id) ON DELETE CASCADE
);
CREATE INDEX "index_worktree_diagnostic_summaries_on_project_id" ON "worktree_diagnostic_summaries" ("project_id");
CREATE INDEX "index_worktree_diagnostic_summaries_on_project_id_and_worktree_id" ON "worktree_diagnostic_summaries" ("project_id", "worktree_id");
CREATE TABLE "language_servers" (
"id" INTEGER NOT NULL,
"project_id" INTEGER NOT NULL REFERENCES projects (id) ON DELETE CASCADE,
"name" VARCHAR NOT NULL,
PRIMARY KEY(project_id, id)
);
CREATE INDEX "index_language_servers_on_project_id" ON "language_servers" ("project_id");
CREATE TABLE "project_collaborators" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"project_id" INTEGER NOT NULL REFERENCES projects (id) ON DELETE CASCADE,
"connection_id" INTEGER NOT NULL,
"connection_epoch" TEXT NOT NULL,
"user_id" INTEGER NOT NULL,
"replica_id" INTEGER NOT NULL,
"is_host" BOOLEAN NOT NULL
);
CREATE INDEX "index_project_collaborators_on_project_id" ON "project_collaborators" ("project_id");
CREATE UNIQUE INDEX "index_project_collaborators_on_project_id_and_replica_id" ON "project_collaborators" ("project_id", "replica_id");
CREATE INDEX "index_project_collaborators_on_connection_epoch" ON "project_collaborators" ("connection_epoch");
CREATE INDEX "index_project_collaborators_on_connection_id" ON "project_collaborators" ("connection_id");
CREATE UNIQUE INDEX "index_project_collaborators_on_project_id_connection_id_and_epoch" ON "project_collaborators" ("project_id", "connection_id", "connection_epoch");
CREATE TABLE "room_participants" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"room_id" INTEGER NOT NULL REFERENCES rooms (id),
"user_id" INTEGER NOT NULL REFERENCES users (id),
"answering_connection_id" INTEGER,
"answering_connection_epoch" TEXT,
"answering_connection_lost" BOOLEAN NOT NULL,
"location_kind" INTEGER,
"location_project_id" INTEGER,
"initial_project_id" INTEGER,
"calling_user_id" INTEGER NOT NULL REFERENCES users (id),
"calling_connection_id" INTEGER NOT NULL,
"calling_connection_epoch" TEXT NOT NULL
);
CREATE UNIQUE INDEX "index_room_participants_on_user_id" ON "room_participants" ("user_id");
CREATE INDEX "index_room_participants_on_room_id" ON "room_participants" ("room_id");
CREATE INDEX "index_room_participants_on_answering_connection_epoch" ON "room_participants" ("answering_connection_epoch");
CREATE INDEX "index_room_participants_on_calling_connection_epoch" ON "room_participants" ("calling_connection_epoch");
CREATE INDEX "index_room_participants_on_answering_connection_id" ON "room_participants" ("answering_connection_id");
CREATE UNIQUE INDEX "index_room_participants_on_answering_connection_id_and_answering_connection_epoch" ON "room_participants" ("answering_connection_id", "answering_connection_epoch");

View File

@@ -0,0 +1,90 @@
CREATE TABLE IF NOT EXISTS "rooms" (
"id" SERIAL PRIMARY KEY,
"live_kit_room" VARCHAR NOT NULL
);
ALTER TABLE "projects"
ADD "room_id" INTEGER REFERENCES rooms (id),
ADD "host_connection_id" INTEGER,
ADD "host_connection_epoch" UUID;
CREATE INDEX "index_projects_on_host_connection_epoch" ON "projects" ("host_connection_epoch");
CREATE TABLE "worktrees" (
"project_id" INTEGER NOT NULL REFERENCES projects (id) ON DELETE CASCADE,
"id" INT8 NOT NULL,
"root_name" VARCHAR NOT NULL,
"abs_path" VARCHAR NOT NULL,
"visible" BOOL NOT NULL,
"scan_id" INT8 NOT NULL,
"is_complete" BOOL NOT NULL,
PRIMARY KEY(project_id, id)
);
CREATE INDEX "index_worktrees_on_project_id" ON "worktrees" ("project_id");
CREATE TABLE "worktree_entries" (
"project_id" INTEGER NOT NULL,
"worktree_id" INT8 NOT NULL,
"id" INT8 NOT NULL,
"is_dir" BOOL NOT NULL,
"path" VARCHAR NOT NULL,
"inode" INT8 NOT NULL,
"mtime_seconds" INT8 NOT NULL,
"mtime_nanos" INTEGER NOT NULL,
"is_symlink" BOOL NOT NULL,
"is_ignored" BOOL NOT NULL,
PRIMARY KEY(project_id, worktree_id, id),
FOREIGN KEY(project_id, worktree_id) REFERENCES worktrees (project_id, id) ON DELETE CASCADE
);
CREATE INDEX "index_worktree_entries_on_project_id" ON "worktree_entries" ("project_id");
CREATE INDEX "index_worktree_entries_on_project_id_and_worktree_id" ON "worktree_entries" ("project_id", "worktree_id");
CREATE TABLE "worktree_diagnostic_summaries" (
"project_id" INTEGER NOT NULL,
"worktree_id" INT8 NOT NULL,
"path" VARCHAR NOT NULL,
"language_server_id" INT8 NOT NULL,
"error_count" INTEGER NOT NULL,
"warning_count" INTEGER NOT NULL,
PRIMARY KEY(project_id, worktree_id, path),
FOREIGN KEY(project_id, worktree_id) REFERENCES worktrees (project_id, id) ON DELETE CASCADE
);
CREATE INDEX "index_worktree_diagnostic_summaries_on_project_id" ON "worktree_diagnostic_summaries" ("project_id");
CREATE INDEX "index_worktree_diagnostic_summaries_on_project_id_and_worktree_id" ON "worktree_diagnostic_summaries" ("project_id", "worktree_id");
CREATE TABLE "language_servers" (
"project_id" INTEGER NOT NULL REFERENCES projects (id) ON DELETE CASCADE,
"id" INT8 NOT NULL,
"name" VARCHAR NOT NULL,
PRIMARY KEY(project_id, id)
);
CREATE INDEX "index_language_servers_on_project_id" ON "language_servers" ("project_id");
CREATE TABLE "project_collaborators" (
"id" SERIAL PRIMARY KEY,
"project_id" INTEGER NOT NULL REFERENCES projects (id) ON DELETE CASCADE,
"connection_id" INTEGER NOT NULL,
"connection_epoch" UUID NOT NULL,
"user_id" INTEGER NOT NULL,
"replica_id" INTEGER NOT NULL,
"is_host" BOOLEAN NOT NULL
);
CREATE INDEX "index_project_collaborators_on_project_id" ON "project_collaborators" ("project_id");
CREATE UNIQUE INDEX "index_project_collaborators_on_project_id_and_replica_id" ON "project_collaborators" ("project_id", "replica_id");
CREATE INDEX "index_project_collaborators_on_connection_epoch" ON "project_collaborators" ("connection_epoch");
CREATE TABLE "room_participants" (
"id" SERIAL PRIMARY KEY,
"room_id" INTEGER NOT NULL REFERENCES rooms (id),
"user_id" INTEGER NOT NULL REFERENCES users (id),
"answering_connection_id" INTEGER,
"answering_connection_epoch" UUID,
"location_kind" INTEGER,
"location_project_id" INTEGER,
"initial_project_id" INTEGER,
"calling_user_id" INTEGER NOT NULL REFERENCES users (id),
"calling_connection_id" INTEGER NOT NULL,
"calling_connection_epoch" UUID NOT NULL
);
CREATE UNIQUE INDEX "index_room_participants_on_user_id" ON "room_participants" ("user_id");
CREATE INDEX "index_room_participants_on_answering_connection_epoch" ON "room_participants" ("answering_connection_epoch");
CREATE INDEX "index_room_participants_on_calling_connection_epoch" ON "room_participants" ("calling_connection_epoch");

View File

@@ -0,0 +1,2 @@
ALTER TABLE "signups"
ADD "added_to_mailing_list" BOOLEAN NOT NULL DEFAULT FALSE;

View File

@@ -0,0 +1,7 @@
ALTER TABLE "room_participants"
ADD "answering_connection_lost" BOOLEAN NOT NULL DEFAULT FALSE;
CREATE INDEX "index_project_collaborators_on_connection_id" ON "project_collaborators" ("connection_id");
CREATE UNIQUE INDEX "index_project_collaborators_on_project_id_connection_id_and_epoch" ON "project_collaborators" ("project_id", "connection_id", "connection_epoch");
CREATE INDEX "index_room_participants_on_answering_connection_id" ON "room_participants" ("answering_connection_id");
CREATE UNIQUE INDEX "index_room_participants_on_answering_connection_id_and_answering_connection_epoch" ON "room_participants" ("answering_connection_id", "answering_connection_epoch");

View File

@@ -0,0 +1 @@
CREATE INDEX "index_room_participants_on_room_id" ON "room_participants" ("room_id");

View File

@@ -1,6 +1,6 @@
use crate::{
auth,
db::{Invite, NewUserParams, ProjectId, Signup, User, UserId, WaitlistSummary},
db::{Invite, NewSignup, NewUserParams, User, UserId, WaitlistSummary},
rpc::{self, ResultExt},
AppState, Error, Result,
};
@@ -16,9 +16,7 @@ use axum::{
};
use axum_extra::response::ErasedJson;
use serde::{Deserialize, Serialize};
use serde_json::json;
use std::{sync::Arc, time::Duration};
use time::OffsetDateTime;
use std::sync::Arc;
use tower::ServiceBuilder;
use tracing::instrument;
@@ -32,16 +30,6 @@ pub fn routes(rpc_server: Arc<rpc::Server>, state: Arc<AppState>) -> Router<Body
.route("/invite_codes/:code", get(get_user_for_invite_code))
.route("/panic", post(trace_panic))
.route("/rpc_server_snapshot", get(get_rpc_server_snapshot))
.route(
"/user_activity/summary",
get(get_top_users_activity_summary),
)
.route(
"/user_activity/timeline/:user_id",
get(get_user_activity_timeline),
)
.route("/user_activity/counts", get(get_active_user_counts))
.route("/project_metadata", get(get_project_metadata))
.route("/signups", post(create_signup))
.route("/signups_summary", get(get_waitlist_summary))
.route("/user_invites", post(create_invite_from_code))
@@ -216,7 +204,7 @@ async fn create_user(
#[derive(Deserialize)]
struct UpdateUserParams {
admin: Option<bool>,
invite_count: Option<u32>,
invite_count: Option<i32>,
}
async fn update_user(
@@ -283,93 +271,6 @@ async fn get_rpc_server_snapshot(
Ok(ErasedJson::pretty(rpc_server.snapshot().await))
}
#[derive(Deserialize)]
struct TimePeriodParams {
#[serde(with = "time::serde::iso8601")]
start: OffsetDateTime,
#[serde(with = "time::serde::iso8601")]
end: OffsetDateTime,
}
async fn get_top_users_activity_summary(
Query(params): Query<TimePeriodParams>,
Extension(app): Extension<Arc<AppState>>,
) -> Result<ErasedJson> {
let summary = app
.db
.get_top_users_activity_summary(params.start..params.end, 100)
.await?;
Ok(ErasedJson::pretty(summary))
}
async fn get_user_activity_timeline(
Path(user_id): Path<i32>,
Query(params): Query<TimePeriodParams>,
Extension(app): Extension<Arc<AppState>>,
) -> Result<ErasedJson> {
let summary = app
.db
.get_user_activity_timeline(params.start..params.end, UserId(user_id))
.await?;
Ok(ErasedJson::pretty(summary))
}
#[derive(Deserialize)]
struct ActiveUserCountParams {
#[serde(flatten)]
period: TimePeriodParams,
durations_in_minutes: String,
#[serde(default)]
only_collaborative: bool,
}
#[derive(Serialize)]
struct ActiveUserSet {
active_time_in_minutes: u64,
user_count: usize,
}
async fn get_active_user_counts(
Query(params): Query<ActiveUserCountParams>,
Extension(app): Extension<Arc<AppState>>,
) -> Result<ErasedJson> {
let durations_in_minutes = params.durations_in_minutes.split(',');
let mut user_sets = Vec::new();
for duration in durations_in_minutes {
let duration = duration
.parse()
.map_err(|_| anyhow!("invalid duration: {duration}"))?;
user_sets.push(ActiveUserSet {
active_time_in_minutes: duration,
user_count: app
.db
.get_active_user_count(
params.period.start..params.period.end,
Duration::from_secs(duration * 60),
params.only_collaborative,
)
.await?,
})
}
Ok(ErasedJson::pretty(user_sets))
}
#[derive(Deserialize)]
struct GetProjectMetadataParams {
project_id: u64,
}
async fn get_project_metadata(
Query(params): Query<GetProjectMetadataParams>,
Extension(app): Extension<Arc<AppState>>,
) -> Result<ErasedJson> {
let extensions = app
.db
.get_project_extensions(ProjectId::from_proto(params.project_id))
.await?;
Ok(ErasedJson::pretty(json!({ "extensions": extensions })))
}
#[derive(Deserialize)]
struct CreateAccessTokenQueryParams {
public_key: String,
@@ -434,10 +335,10 @@ async fn get_user_for_invite_code(
}
async fn create_signup(
Json(params): Json<Signup>,
Json(params): Json<NewSignup>,
Extension(app): Extension<Arc<AppState>>,
) -> Result<()> {
app.db.create_signup(params).await?;
app.db.create_signup(&params).await?;
Ok(())
}

View File

@@ -75,7 +75,7 @@ pub async fn validate_header<B>(mut req: Request<B>, next: Next<B>) -> impl Into
const MAX_ACCESS_TOKENS_TO_STORE: usize = 8;
pub async fn create_access_token(db: &dyn db::Db, user_id: UserId) -> Result<String> {
pub async fn create_access_token(db: &db::Database, user_id: UserId) -> Result<String> {
let access_token = rpc::auth::random_token();
let access_token_hash =
hash_access_token(&access_token).context("failed to hash access token")?;

View File

@@ -1,13 +1,7 @@
use collab::{Error, Result};
use db::{Db, PostgresDb, UserId};
use rand::prelude::*;
use collab::db;
use db::{ConnectOptions, Database};
use serde::{de::DeserializeOwned, Deserialize};
use std::fmt::Write;
use time::{Duration, OffsetDateTime};
#[allow(unused)]
#[path = "../db.rs"]
mod db;
#[derive(Debug, Deserialize)]
struct GitHubUser {
@@ -18,9 +12,8 @@ struct GitHubUser {
#[tokio::main]
async fn main() {
let mut rng = StdRng::from_entropy();
let database_url = std::env::var("DATABASE_URL").expect("missing DATABASE_URL env var");
let db = PostgresDb::new(&database_url, 5)
let db = Database::new(ConnectOptions::new(database_url))
.await
.expect("failed to connect to postgres database");
let github_token = std::env::var("GITHUB_TOKEN").expect("missing GITHUB_TOKEN env var");
@@ -64,16 +57,14 @@ async fn main() {
}
}
let mut zed_user_ids = Vec::<UserId>::new();
for (github_user, admin) in zed_users {
if let Some(user) = db
if db
.get_user_by_github_account(&github_user.login, Some(github_user.id))
.await
.expect("failed to fetch user")
.is_none()
{
zed_user_ids.push(user.id);
} else if let Some(email) = &github_user.email {
zed_user_ids.push(
if let Some(email) = &github_user.email {
db.create_user(
email,
admin,
@@ -84,11 +75,8 @@ async fn main() {
},
)
.await
.expect("failed to insert user")
.user_id,
);
} else if admin {
zed_user_ids.push(
.expect("failed to insert user");
} else if admin {
db.create_user(
&format!("{}@zed.dev", github_user.login),
admin,
@@ -99,62 +87,10 @@ async fn main() {
},
)
.await
.expect("failed to insert user")
.user_id,
);
.expect("failed to insert user");
}
}
}
let zed_org_id = if let Some(org) = db
.find_org_by_slug("zed")
.await
.expect("failed to fetch org")
{
org.id
} else {
db.create_org("Zed", "zed")
.await
.expect("failed to insert org")
};
let general_channel_id = if let Some(channel) = db
.get_org_channels(zed_org_id)
.await
.expect("failed to fetch channels")
.iter()
.find(|c| c.name == "General")
{
channel.id
} else {
let channel_id = db
.create_org_channel(zed_org_id, "General")
.await
.expect("failed to insert channel");
let now = OffsetDateTime::now_utc();
let max_seconds = Duration::days(100).as_seconds_f64();
let mut timestamps = (0..1000)
.map(|_| now - Duration::seconds_f64(rng.gen_range(0_f64..=max_seconds)))
.collect::<Vec<_>>();
timestamps.sort();
for timestamp in timestamps {
let sender_id = *zed_user_ids.choose(&mut rng).unwrap();
let body = lipsum::lipsum_words(rng.gen_range(1..=50));
db.create_channel_message(channel_id, sender_id, &body, timestamp, rng.gen())
.await
.expect("failed to insert message");
}
channel_id
};
for user_id in zed_user_ids {
db.add_org_member(zed_org_id, user_id, true)
.await
.expect("failed to insert org membership");
db.add_channel_member(general_channel_id, user_id, true)
.await
.expect("failed to insert channel membership");
}
}
async fn fetch_github<T: DeserializeOwned>(

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
use super::{AccessTokenId, UserId};
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
#[sea_orm(table_name = "access_tokens")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: AccessTokenId,
pub user_id: UserId,
pub hash: String,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "super::user::Entity",
from = "Column::UserId",
to = "super::user::Column::Id"
)]
User,
}
impl Related<super::user::Entity> for Entity {
fn to() -> RelationDef {
Relation::User.def()
}
}
impl ActiveModelBehavior for ActiveModel {}

View File

@@ -0,0 +1,58 @@
use super::{ContactId, UserId};
use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, Default, PartialEq, Eq, DeriveEntityModel)]
#[sea_orm(table_name = "contacts")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: ContactId,
pub user_id_a: UserId,
pub user_id_b: UserId,
pub a_to_b: bool,
pub should_notify: bool,
pub accepted: bool,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "super::room_participant::Entity",
from = "Column::UserIdA",
to = "super::room_participant::Column::UserId"
)]
UserARoomParticipant,
#[sea_orm(
belongs_to = "super::room_participant::Entity",
from = "Column::UserIdB",
to = "super::room_participant::Column::UserId"
)]
UserBRoomParticipant,
}
impl ActiveModelBehavior for ActiveModel {}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Contact {
Accepted {
user_id: UserId,
should_notify: bool,
busy: bool,
},
Outgoing {
user_id: UserId,
},
Incoming {
user_id: UserId,
should_notify: bool,
},
}
impl Contact {
pub fn user_id(&self) -> UserId {
match self {
Contact::Accepted { user_id, .. } => *user_id,
Contact::Outgoing { user_id } => *user_id,
Contact::Incoming { user_id, .. } => *user_id,
}
}
}

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