From d6b728409fbff8d6230527a40f6922d34100d15b Mon Sep 17 00:00:00 2001 From: Petros Amoiridis Date: Fri, 3 Feb 2023 12:14:13 +0200 Subject: [PATCH 1/8] Be consistent in the app & context menus --- crates/zed/src/menus.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/zed/src/menus.rs b/crates/zed/src/menus.rs index d2385149175c7fd2aa39b6b25301d680a4ac01f1..82b72611c2f9294a890292ad92433c348eece6cc 100644 --- a/crates/zed/src/menus.rs +++ b/crates/zed/src/menus.rs @@ -293,7 +293,7 @@ pub fn menus() -> Vec> { action: Box::new(editor::GoToTypeDefinition), }, MenuItem::Action { - name: "Go to References", + name: "Find All References", action: Box::new(editor::FindAllReferences), }, MenuItem::Action { From 3014cc52996f45a2554d195c69481982a233f403 Mon Sep 17 00:00:00 2001 From: Petros Amoiridis Date: Fri, 3 Feb 2023 12:16:09 +0200 Subject: [PATCH 2/8] Do not capitalize prepositions in title case This also match the app menu --- crates/editor/src/mouse_context_menu.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/editor/src/mouse_context_menu.rs b/crates/editor/src/mouse_context_menu.rs index d9840fd3fab6bcbe372b48820e2fe05914c09ad1..77b58d1a0b272f125ded18a1e35045f7fec50bd1 100644 --- a/crates/editor/src/mouse_context_menu.rs +++ b/crates/editor/src/mouse_context_menu.rs @@ -52,8 +52,8 @@ pub fn deploy_context_menu( AnchorCorner::TopLeft, vec![ ContextMenuItem::item("Rename Symbol", Rename), - ContextMenuItem::item("Go To Definition", GoToDefinition), - ContextMenuItem::item("Go To Type Definition", GoToTypeDefinition), + ContextMenuItem::item("Go to Definition", GoToDefinition), + ContextMenuItem::item("Go to Type Definition", GoToTypeDefinition), ContextMenuItem::item("Find All References", FindAllReferences), ContextMenuItem::item( "Code Actions", From 303216291be4fdebb4da4f5fbc047001647abeed Mon Sep 17 00:00:00 2001 From: Kay Simmons Date: Fri, 3 Feb 2023 11:17:50 -0800 Subject: [PATCH 3/8] Move sharing status indicator out of the call crate and into collab_ui in order so that the model doesn't depend on the view --- crates/call/src/call.rs | 41 +---- crates/collab_ui/src/collab_titlebar_item.rs | 23 ++- crates/collab_ui/src/collab_ui.rs | 171 ++++++++++-------- .../src/sharing_status_indicator.rs} | 24 ++- 4 files changed, 141 insertions(+), 118 deletions(-) rename crates/{call/src/indicator.rs => collab_ui/src/sharing_status_indicator.rs} (53%) diff --git a/crates/call/src/call.rs b/crates/call/src/call.rs index c34d124162812b709153e769c925432689f7e320..596a0ec8535e626cc379ec9fb3a62318ff7d54b6 100644 --- a/crates/call/src/call.rs +++ b/crates/call/src/call.rs @@ -1,4 +1,3 @@ -mod indicator; pub mod participant; pub mod room; @@ -10,22 +9,17 @@ use collections::HashSet; use postage::watch; use gpui::{ - actions, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext, - Subscription, Task, ViewHandle, WeakModelHandle, + AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext, + Subscription, Task, WeakModelHandle, }; use project::Project; -use settings::Settings; -use indicator::SharingStatusIndicator; pub use participant::ParticipantLocation; pub use room::Room; -actions!(collab, [ToggleScreenSharing]); - pub fn init(client: Arc, user_store: ModelHandle, cx: &mut MutableAppContext) { let active_call = cx.add_model(|cx| ActiveCall::new(client, user_store, cx)); cx.set_global(active_call); - cx.add_global_action(toggle_screen_sharing); } #[derive(Clone)] @@ -36,6 +30,7 @@ pub struct IncomingCall { pub initial_project: Option, } +/// Singleton global maintaining the user's participation in a room across workspaces. pub struct ActiveCall { room: Option<(ModelHandle, Vec)>, location: Option>, @@ -46,7 +41,6 @@ pub struct ActiveCall { ), client: Arc, user_store: ModelHandle, - sharing_status_indicator: Option<(usize, ViewHandle)>, _subscriptions: Vec, } @@ -71,7 +65,6 @@ impl ActiveCall { ], client, user_store, - sharing_status_indicator: None, } } @@ -290,8 +283,6 @@ impl ActiveCall { this.set_room(None, cx).detach_and_log_err(cx); } - this.set_sharing_status(room.read(cx).is_screen_sharing(), cx); - cx.notify(); }), cx.subscribe(&room, |_, _, event, cx| cx.emit(event.clone())), @@ -316,30 +307,4 @@ impl ActiveCall { pub fn pending_invites(&self) -> &HashSet { &self.pending_invites } - - pub fn set_sharing_status(&mut self, is_screen_sharing: bool, cx: &mut MutableAppContext) { - if is_screen_sharing { - if self.sharing_status_indicator.is_none() - && cx.global::().show_call_status_icon - { - self.sharing_status_indicator = - Some(cx.add_status_bar_item(|_| SharingStatusIndicator)); - } - } else if let Some((window_id, _)) = self.sharing_status_indicator.take() { - cx.remove_status_bar_item(window_id); - } - } -} - -pub fn toggle_screen_sharing(_: &ToggleScreenSharing, cx: &mut MutableAppContext) { - if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() { - let toggle_screen_sharing = room.update(cx, |room, cx| { - if room.is_screen_sharing() { - Task::ready(room.unshare_screen(cx)) - } else { - room.share_screen(cx) - } - }); - toggle_screen_sharing.detach_and_log_err(cx); - } } diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 116a331578c54ac8096dd7783774783bac97cd46..778aa4a71ef5f56d14bc4cdd43d792e3fcf8eed7 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -1,5 +1,5 @@ use crate::{contact_notification::ContactNotification, contacts_popover}; -use call::{ActiveCall, ParticipantLocation, ToggleScreenSharing}; +use call::{ActiveCall, ParticipantLocation}; use client::{proto::PeerId, Authenticate, ContactEventKind, User, UserStore}; use clock::ReplicaId; use contacts_popover::ContactsPopover; @@ -10,17 +10,21 @@ use gpui::{ geometry::{rect::RectF, vector::vec2f, PathBuilder}, json::{self, ToJson}, Border, CursorStyle, Entity, ModelHandle, MouseButton, MutableAppContext, RenderContext, - Subscription, View, ViewContext, ViewHandle, WeakViewHandle, + Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle, }; use settings::Settings; use std::ops::Range; use theme::Theme; use workspace::{FollowNextCollaborator, JoinProject, ToggleFollow, Workspace}; -actions!(collab, [ToggleCollaborationMenu, ShareProject]); +actions!( + collab, + [ToggleCollaborationMenu, ToggleScreenSharing, ShareProject] +); pub fn init(cx: &mut MutableAppContext) { cx.add_action(CollabTitlebarItem::toggle_contacts_popover); + cx.add_global_action(CollabTitlebarItem::toggle_screen_sharing); cx.add_action(CollabTitlebarItem::share_project); } @@ -168,6 +172,19 @@ impl CollabTitlebarItem { cx.notify(); } + pub fn toggle_screen_sharing(_: &ToggleScreenSharing, cx: &mut MutableAppContext) { + if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() { + let toggle_screen_sharing = room.update(cx, |room, cx| { + if room.is_screen_sharing() { + Task::ready(room.unshare_screen(cx)) + } else { + room.share_screen(cx) + } + }); + toggle_screen_sharing.detach_and_log_err(cx); + } + } + fn render_toggle_contacts_button( &self, theme: &Theme, diff --git a/crates/collab_ui/src/collab_ui.rs b/crates/collab_ui/src/collab_ui.rs index 38a47e87dcb6b5e2f420297e8d279a80f5f5688c..d26e2c99ccfb53d9b5e83160464df1a5c73aeafe 100644 --- a/crates/collab_ui/src/collab_ui.rs +++ b/crates/collab_ui/src/collab_ui.rs @@ -6,14 +6,17 @@ mod contacts_popover; mod incoming_call_notification; mod notifications; mod project_shared_notification; +mod sharing_status_indicator; use anyhow::anyhow; use call::ActiveCall; pub use collab_titlebar_item::{CollabTitlebarItem, ToggleCollaborationMenu}; -use gpui::MutableAppContext; +use gpui::{actions, MutableAppContext, Task}; use std::sync::Arc; use workspace::{AppState, JoinProject, ToggleFollow, Workspace}; +actions!(collab, [ToggleScreenSharing]); + pub fn init(app_state: Arc, cx: &mut MutableAppContext) { collab_titlebar_item::init(cx); contact_notification::init(cx); @@ -22,89 +25,107 @@ pub fn init(app_state: Arc, cx: &mut MutableAppContext) { contacts_popover::init(cx); incoming_call_notification::init(cx); project_shared_notification::init(cx); + sharing_status_indicator::init(cx); + cx.add_global_action(toggle_screen_sharing); cx.add_global_action(move |action: &JoinProject, cx| { - let project_id = action.project_id; - let follow_user_id = action.follow_user_id; - let app_state = app_state.clone(); - cx.spawn(|mut cx| async move { - let existing_workspace = cx.update(|cx| { - cx.window_ids() - .filter_map(|window_id| cx.root_view::(window_id)) - .find(|workspace| { - workspace.read(cx).project().read(cx).remote_id() == Some(project_id) - }) - }); + join_project(action, app_state.clone(), cx); + }); +} - let workspace = if let Some(existing_workspace) = existing_workspace { - existing_workspace +pub fn toggle_screen_sharing(_: &ToggleScreenSharing, cx: &mut MutableAppContext) { + if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() { + let toggle_screen_sharing = room.update(cx, |room, cx| { + if room.is_screen_sharing() { + Task::ready(room.unshare_screen(cx)) } else { - let active_call = cx.read(ActiveCall::global); - let room = active_call - .read_with(&cx, |call, _| call.room().cloned()) - .ok_or_else(|| anyhow!("not in a call"))?; - let project = room - .update(&mut cx, |room, cx| { - room.join_project( - project_id, - app_state.languages.clone(), - app_state.fs.clone(), - cx, - ) - }) - .await?; + room.share_screen(cx) + } + }); + toggle_screen_sharing.detach_and_log_err(cx); + } +} - let (_, workspace) = cx.add_window( - (app_state.build_window_options)(None, None, cx.platform().as_ref()), - |cx| { - let mut workspace = Workspace::new( - Default::default(), - 0, - project, - app_state.dock_default_item_factory, - cx, - ); - (app_state.initialize_workspace)(&mut workspace, &app_state, cx); - workspace - }, - ); - workspace - }; +fn join_project(action: &JoinProject, app_state: Arc, cx: &mut MutableAppContext) { + let project_id = action.project_id; + let follow_user_id = action.follow_user_id; + cx.spawn(|mut cx| async move { + let existing_workspace = cx.update(|cx| { + cx.window_ids() + .filter_map(|window_id| cx.root_view::(window_id)) + .find(|workspace| { + workspace.read(cx).project().read(cx).remote_id() == Some(project_id) + }) + }); - cx.activate_window(workspace.window_id()); - cx.platform().activate(true); + let workspace = if let Some(existing_workspace) = existing_workspace { + existing_workspace + } else { + let active_call = cx.read(ActiveCall::global); + let room = active_call + .read_with(&cx, |call, _| call.room().cloned()) + .ok_or_else(|| anyhow!("not in a call"))?; + let project = room + .update(&mut cx, |room, cx| { + room.join_project( + project_id, + app_state.languages.clone(), + app_state.fs.clone(), + cx, + ) + }) + .await?; - workspace.update(&mut cx, |workspace, cx| { - if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() { - let follow_peer_id = room - .read(cx) - .remote_participants() - .iter() - .find(|(_, participant)| participant.user.id == follow_user_id) - .map(|(_, p)| p.peer_id) - .or_else(|| { - // If we couldn't follow the given user, follow the host instead. - let collaborator = workspace - .project() - .read(cx) - .collaborators() - .values() - .find(|collaborator| collaborator.replica_id == 0)?; - Some(collaborator.peer_id) - }); + let (_, workspace) = cx.add_window( + (app_state.build_window_options)(None, None, cx.platform().as_ref()), + |cx| { + let mut workspace = Workspace::new( + Default::default(), + 0, + project, + app_state.dock_default_item_factory, + cx, + ); + (app_state.initialize_workspace)(&mut workspace, &app_state, cx); + workspace + }, + ); + workspace + }; - if let Some(follow_peer_id) = follow_peer_id { - if !workspace.is_following(follow_peer_id) { - workspace - .toggle_follow(&ToggleFollow(follow_peer_id), cx) - .map(|follow| follow.detach_and_log_err(cx)); - } + cx.activate_window(workspace.window_id()); + cx.platform().activate(true); + + workspace.update(&mut cx, |workspace, cx| { + if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() { + let follow_peer_id = room + .read(cx) + .remote_participants() + .iter() + .find(|(_, participant)| participant.user.id == follow_user_id) + .map(|(_, p)| p.peer_id) + .or_else(|| { + // If we couldn't follow the given user, follow the host instead. + let collaborator = workspace + .project() + .read(cx) + .collaborators() + .values() + .find(|collaborator| collaborator.replica_id == 0)?; + Some(collaborator.peer_id) + }); + + if let Some(follow_peer_id) = follow_peer_id { + if !workspace.is_following(follow_peer_id) { + workspace + .toggle_follow(&ToggleFollow(follow_peer_id), cx) + .map(|follow| follow.detach_and_log_err(cx)); } } - }); + } + }); - anyhow::Ok(()) - }) - .detach_and_log_err(cx); - }); + anyhow::Ok(()) + }) + .detach_and_log_err(cx); } diff --git a/crates/call/src/indicator.rs b/crates/collab_ui/src/sharing_status_indicator.rs similarity index 53% rename from crates/call/src/indicator.rs rename to crates/collab_ui/src/sharing_status_indicator.rs index 102ea5c551cc465b8e385a6de529fca38335de88..42c2aa59f210ff7c7ef43591ef6733787cf84edc 100644 --- a/crates/call/src/indicator.rs +++ b/crates/collab_ui/src/sharing_status_indicator.rs @@ -1,10 +1,30 @@ +use call::ActiveCall; use gpui::{ color::Color, elements::{MouseEventHandler, Svg}, - Appearance, Element, ElementBox, Entity, MouseButton, RenderContext, View, + Appearance, Element, ElementBox, Entity, MouseButton, MutableAppContext, RenderContext, View, }; +use settings::Settings; -use crate::ToggleScreenSharing; +use crate::collab_titlebar_item::ToggleScreenSharing; + +pub fn init(cx: &mut MutableAppContext) { + let active_call = ActiveCall::global(cx); + + let mut status_indicator = None; + cx.observe(&active_call, move |call, cx| { + if let Some(room) = call.read(cx).room() { + if room.read(cx).is_screen_sharing() { + if status_indicator.is_none() && cx.global::().show_call_status_icon { + status_indicator = Some(cx.add_status_bar_item(|_| SharingStatusIndicator)); + } + } else if let Some((window_id, _)) = status_indicator.take() { + cx.remove_status_bar_item(window_id); + } + } + }) + .detach(); +} pub struct SharingStatusIndicator; From 3e92e4d1100591efeb935752e5421d3c6077c67d Mon Sep 17 00:00:00 2001 From: Kay Simmons Date: Fri, 3 Feb 2023 12:47:20 -0800 Subject: [PATCH 4/8] fix unsaved change --- crates/collab_ui/src/collab_titlebar_item.rs | 23 +++---------------- .../collab_ui/src/sharing_status_indicator.rs | 2 +- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 778aa4a71ef5f56d14bc4cdd43d792e3fcf8eed7..9f2c0fbee9099a91d26f9f23c7f49d9a0aa188cd 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -1,4 +1,4 @@ -use crate::{contact_notification::ContactNotification, contacts_popover}; +use crate::{contact_notification::ContactNotification, contacts_popover, ToggleScreenSharing}; use call::{ActiveCall, ParticipantLocation}; use client::{proto::PeerId, Authenticate, ContactEventKind, User, UserStore}; use clock::ReplicaId; @@ -10,21 +10,17 @@ use gpui::{ geometry::{rect::RectF, vector::vec2f, PathBuilder}, json::{self, ToJson}, Border, CursorStyle, Entity, ModelHandle, MouseButton, MutableAppContext, RenderContext, - Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle, + Subscription, View, ViewContext, ViewHandle, WeakViewHandle, }; use settings::Settings; use std::ops::Range; use theme::Theme; use workspace::{FollowNextCollaborator, JoinProject, ToggleFollow, Workspace}; -actions!( - collab, - [ToggleCollaborationMenu, ToggleScreenSharing, ShareProject] -); +actions!(collab, [ToggleCollaborationMenu, ShareProject]); pub fn init(cx: &mut MutableAppContext) { cx.add_action(CollabTitlebarItem::toggle_contacts_popover); - cx.add_global_action(CollabTitlebarItem::toggle_screen_sharing); cx.add_action(CollabTitlebarItem::share_project); } @@ -172,19 +168,6 @@ impl CollabTitlebarItem { cx.notify(); } - pub fn toggle_screen_sharing(_: &ToggleScreenSharing, cx: &mut MutableAppContext) { - if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() { - let toggle_screen_sharing = room.update(cx, |room, cx| { - if room.is_screen_sharing() { - Task::ready(room.unshare_screen(cx)) - } else { - room.share_screen(cx) - } - }); - toggle_screen_sharing.detach_and_log_err(cx); - } - } - fn render_toggle_contacts_button( &self, theme: &Theme, diff --git a/crates/collab_ui/src/sharing_status_indicator.rs b/crates/collab_ui/src/sharing_status_indicator.rs index 42c2aa59f210ff7c7ef43591ef6733787cf84edc..541194ec66a5953fbd8d69b75aa15e63cbf68a02 100644 --- a/crates/collab_ui/src/sharing_status_indicator.rs +++ b/crates/collab_ui/src/sharing_status_indicator.rs @@ -6,7 +6,7 @@ use gpui::{ }; use settings::Settings; -use crate::collab_titlebar_item::ToggleScreenSharing; +use crate::ToggleScreenSharing; pub fn init(cx: &mut MutableAppContext) { let active_call = ActiveCall::global(cx); From 4642817e72d96cef5af57253c05dd9023e8a0dbd Mon Sep 17 00:00:00 2001 From: Kay Simmons Date: Sun, 5 Feb 2023 23:21:29 -0800 Subject: [PATCH 5/8] Add lua syntax highlighting and lsp support --- Cargo.lock | 109 +++++++++++ crates/lsp/src/lsp.rs | 7 +- crates/zed/Cargo.toml | 2 + crates/zed/src/languages.rs | 6 + crates/zed/src/languages/lua.rs | 114 ++++++++++++ crates/zed/src/languages/lua/brackets.scm | 3 + crates/zed/src/languages/lua/config.toml | 15 ++ crates/zed/src/languages/lua/highlights.scm | 192 ++++++++++++++++++++ crates/zed/src/languages/lua/indents.scm | 10 + crates/zed/src/languages/lua/outline.scm | 3 + 10 files changed, 458 insertions(+), 3 deletions(-) create mode 100644 crates/zed/src/languages/lua.rs create mode 100644 crates/zed/src/languages/lua/brackets.scm create mode 100644 crates/zed/src/languages/lua/config.toml create mode 100644 crates/zed/src/languages/lua/highlights.scm create mode 100644 crates/zed/src/languages/lua/indents.scm create mode 100644 crates/zed/src/languages/lua/outline.scm diff --git a/Cargo.lock b/Cargo.lock index 1b7d2038b51b4fc8a966785e856b0904c852abc8..203ceff0df46ef84509190d51e5b1f400ad2e17c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -259,6 +259,21 @@ dependencies = [ "futures-lite", ] +[[package]] +name = "async-global-executor" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" +dependencies = [ + "async-channel", + "async-executor", + "async-io", + "async-lock", + "blocking", + "futures-lite", + "once_cell", +] + [[package]] name = "async-io" version = "1.12.0" @@ -350,6 +365,32 @@ dependencies = [ "syn", ] +[[package]] +name = "async-std" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +dependencies = [ + "async-channel", + "async-global-executor", + "async-io", + "async-lock", + "crossbeam-utils 0.8.14", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite 0.2.9", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + [[package]] name = "async-stream" version = "0.3.3" @@ -371,6 +412,20 @@ dependencies = [ "syn", ] +[[package]] +name = "async-tar" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c49359998a76e32ef6e870dbc079ebad8f1e53e8441c5dd39d27b44493fe331" +dependencies = [ + "async-std", + "filetime", + "libc", + "pin-project", + "redox_syscall", + "xattr", +] + [[package]] name = "async-task" version = "4.0.3" @@ -2080,6 +2135,18 @@ dependencies = [ "workspace", ] +[[package]] +name = "filetime" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall", + "windows-sys 0.42.0", +] + [[package]] name = "fixedbitset" version = "0.4.2" @@ -2528,6 +2595,18 @@ dependencies = [ "regex", ] +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "go_to_line" version = "0.1.0" @@ -3144,6 +3223,15 @@ dependencies = [ "arrayvec 0.7.2", ] +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + [[package]] name = "language" version = "0.1.0" @@ -7017,6 +7105,16 @@ dependencies = [ "tree-sitter", ] +[[package]] +name = "tree-sitter-lua" +version = "0.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d489873fd1a2fa6d5f04930bfc5c081c96f0c038c1437104518b5b842c69b282" +dependencies = [ + "cc", + "tree-sitter", +] + [[package]] name = "tree-sitter-markdown" version = "0.0.1" @@ -8194,6 +8292,15 @@ dependencies = [ "winapi-build", ] +[[package]] +name = "xattr" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" +dependencies = [ + "libc", +] + [[package]] name = "xml-rs" version = "0.8.4" @@ -8236,6 +8343,7 @@ dependencies = [ "assets", "async-compression", "async-recursion 0.3.2", + "async-tar", "async-trait", "auto_update", "backtrace", @@ -8313,6 +8421,7 @@ dependencies = [ "tree-sitter-go", "tree-sitter-html", "tree-sitter-json 0.20.0", + "tree-sitter-lua", "tree-sitter-markdown", "tree-sitter-python", "tree-sitter-racket", diff --git a/crates/lsp/src/lsp.rs b/crates/lsp/src/lsp.rs index b7199a5287cd9c7a8b9c260aa463450f823fa3d9..a535cfd252156137f43ad10e3bd97b48c1ee6290 100644 --- a/crates/lsp/src/lsp.rs +++ b/crates/lsp/src/lsp.rs @@ -1,3 +1,4 @@ +use log::warn; pub use lsp_types::request::*; pub use lsp_types::*; @@ -220,10 +221,10 @@ impl LanguageServer { } } } else { - return Err(anyhow!( - "failed to deserialize message:\n{}", + warn!( + "Failed to deserialize message:\n{}", std::str::from_utf8(&buffer)? - )); + ); } // Don't starve the main thread when receiving lots of messages at once. diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index b5df0071292566d00948e4a03060e78ba56a8a24..d1ade12f6076430af3c8c9d5d6382230b7aef73b 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -60,6 +60,7 @@ vim = { path = "../vim" } workspace = { path = "../workspace" } anyhow = "1.0.38" async-compression = { version = "0.3", features = ["gzip", "futures-bufread"] } +async-tar = "0.4.2" async-recursion = "0.3" async-trait = "0.1" backtrace = "0.3" @@ -109,6 +110,7 @@ tree-sitter-ruby = "0.20.0" tree-sitter-html = "0.19.0" tree-sitter-scheme = { git = "https://github.com/6cdh/tree-sitter-scheme", rev = "af0fd1fa452cb2562dc7b5c8a8c55551c39273b9"} tree-sitter-racket = { git = "https://github.com/zed-industries/tree-sitter-racket", rev = "eb010cf2c674c6fd9a6316a84e28ef90190fe51a"} +tree-sitter-lua = "0.0.14" url = "2.2" urlencoding = "2.1.2" uuid = { version = "1.1.2", features = ["v4"] } diff --git a/crates/zed/src/languages.rs b/crates/zed/src/languages.rs index 548c07fb82e25d7a1993627d82202dfa4ee40012..c0a00d191116bb7bbe2731b9cc7ba0bf82510ef2 100644 --- a/crates/zed/src/languages.rs +++ b/crates/zed/src/languages.rs @@ -10,6 +10,7 @@ mod html; mod installation; mod json; mod language_plugin; +mod lua; mod python; mod ruby; mod rust; @@ -122,6 +123,11 @@ pub fn init(languages: Arc) { tree_sitter_racket::language(), None, // ), + ( + "lua", + tree_sitter_lua::language(), + Some(Box::new(lua::LuaLspAdapter)), + ), ] { languages.register(name, load_config(name), grammar, lsp_adapter, load_queries); } diff --git a/crates/zed/src/languages/lua.rs b/crates/zed/src/languages/lua.rs new file mode 100644 index 0000000000000000000000000000000000000000..85a8a2f569dc497530ce26c28adf84013ddaeabc --- /dev/null +++ b/crates/zed/src/languages/lua.rs @@ -0,0 +1,114 @@ +use std::{any::Any, env::consts, path::PathBuf, sync::Arc}; + +use anyhow::{anyhow, bail, Result}; +use async_compression::futures::bufread::GzipDecoder; +use async_tar::Archive; +use async_trait::async_trait; +use client::http::HttpClient; +use futures::{io::BufReader, StreamExt}; +use language::LanguageServerName; +use lazy_static::lazy_static; +use regex::Regex; +use smol::fs; +use util::{async_iife, ResultExt}; + +use super::installation::{latest_github_release, GitHubLspBinaryVersion}; + +#[derive(Copy, Clone)] +pub struct LuaLspAdapter; + +lazy_static! { + static ref LUALS_VERSION_REGEX: Regex = Regex::new(r"\d+\.\d+\.\d+").unwrap(); +} + +#[async_trait] +impl super::LspAdapter for LuaLspAdapter { + async fn name(&self) -> LanguageServerName { + LanguageServerName("lua-language-server".into()) + } + + async fn server_args(&self) -> Vec { + vec![ + "--logpath=~/lua-language-server.log".into(), + "--loglevel=trace".into(), + ] + } + + async fn fetch_latest_server_version( + &self, + http: Arc, + ) -> Result> { + let release = latest_github_release("LuaLS/lua-language-server", http).await?; + let version = release.name.clone(); + let platform = match consts::ARCH { + "x86_64" => "x64", + "aarch64" => "arm64", + other => bail!("Running on unsupported platform: {other}"), + }; + let asset_name = format!("lua-language-server-{version}-darwin-{platform}.tar.gz"); + let asset = release + .assets + .iter() + .find(|asset| asset.name == asset_name) + .ok_or_else(|| anyhow!("no asset found matching {:?}", asset_name))?; + let version = GitHubLspBinaryVersion { + name: release.name.clone(), + url: asset.browser_download_url.clone(), + }; + Ok(Box::new(version) as Box<_>) + } + + async fn fetch_server_binary( + &self, + version: Box, + http: Arc, + container_dir: PathBuf, + ) -> Result { + let version = version.downcast::().unwrap(); + + let binary_path = container_dir.join("bin/lua-language-server"); + + if fs::metadata(&binary_path).await.is_err() { + let mut response = http + .get(&version.url, Default::default(), true) + .await + .map_err(|err| anyhow!("error downloading release: {}", err))?; + let decompressed_bytes = GzipDecoder::new(BufReader::new(response.body_mut())); + let archive = Archive::new(decompressed_bytes); + archive.unpack(container_dir).await?; + } + + fs::set_permissions( + &binary_path, + ::from_mode(0o755), + ) + .await?; + Ok(binary_path) + } + + async fn cached_server_binary(&self, container_dir: PathBuf) -> Option { + async_iife!({ + let mut last_binary_path = None; + let mut entries = fs::read_dir(&container_dir).await?; + while let Some(entry) = entries.next().await { + let entry = entry?; + if entry.file_type().await?.is_file() + && entry + .file_name() + .to_str() + .map_or(false, |name| name == "lua-language-server") + { + last_binary_path = Some(entry.path()); + } + } + + if let Some(path) = last_binary_path { + Ok(path) + } else { + Err(anyhow!("no cached binary")) + } + }) + .await + .log_err() + } +} diff --git a/crates/zed/src/languages/lua/brackets.scm b/crates/zed/src/languages/lua/brackets.scm new file mode 100644 index 0000000000000000000000000000000000000000..5f5bd60b93fa1f3daba5f31f12f2aec8f808424b --- /dev/null +++ b/crates/zed/src/languages/lua/brackets.scm @@ -0,0 +1,3 @@ +("[" @open "]" @close) +("{" @open "}" @close) +("(" @open ")" @close) \ No newline at end of file diff --git a/crates/zed/src/languages/lua/config.toml b/crates/zed/src/languages/lua/config.toml new file mode 100644 index 0000000000000000000000000000000000000000..effb37f945a1f0f2c9780d25e752d419f83e557e --- /dev/null +++ b/crates/zed/src/languages/lua/config.toml @@ -0,0 +1,15 @@ +name = "Lua" +path_suffixes = ["lua"] +line_comment = "-- " +autoclose_before = ",]}" +brackets = [ +{ start = "{", end = "}", close = true, newline = true }, +{ start = "[", end = "]", close = true, newline = true }, +{ start = "\"", end = "\"", close = true, newline = false }, +] + +[overrides.string] +brackets = [ +{ start = "{", end = "}", close = true, newline = true }, +{ start = "[", end = "]", close = true, newline = true }, +] \ No newline at end of file diff --git a/crates/zed/src/languages/lua/highlights.scm b/crates/zed/src/languages/lua/highlights.scm new file mode 100644 index 0000000000000000000000000000000000000000..96389c79b4b827ce69d5c95389bb06065541e8d7 --- /dev/null +++ b/crates/zed/src/languages/lua/highlights.scm @@ -0,0 +1,192 @@ +;; Keywords + +"return" @keyword + +[ + "goto" + "in" + "local" +] @keyword + +(break_statement) @keyword + +(do_statement +[ + "do" + "end" +] @keyword) + +(while_statement +[ + "while" + "do" + "end" +] @keyword) + +(repeat_statement +[ + "repeat" + "until" +] @keyword) + +(if_statement +[ + "if" + "elseif" + "else" + "then" + "end" +] @keyword) + +(elseif_statement +[ + "elseif" + "then" + "end" +] @keyword) + +(else_statement +[ + "else" + "end" +] @keyword) + +(for_statement +[ + "for" + "do" + "end" +] @keyword) + +(function_declaration +[ + "function" + "end" +] @keyword) + +(function_definition +[ + "function" + "end" +] @keyword) + +;; Operators + +[ + "and" + "not" + "or" +] @operator + +[ + "+" + "-" + "*" + "/" + "%" + "^" + "#" + "==" + "~=" + "<=" + ">=" + "<" + ">" + "=" + "&" + "~" + "|" + "<<" + ">>" + "//" + ".." +] @operator + +;; Punctuations + +[ + ";" + ":" + "," + "." +] @punctuation.delimiter + +;; Brackets + +[ + "(" + ")" + "[" + "]" + "{" + "}" +] @punctuation.bracket + +;; Variables + +(identifier) @variable + +((identifier) @variable.special + (#eq? @variable.special "self")) + +(variable_list + attribute: (attribute + (["<" ">"] @punctuation.bracket + (identifier) @attribute))) + +;; Constants + +((identifier) @constant + (#lua-match? @constant "^[A-Z][A-Z_0-9]*$")) + +(vararg_expression) @constant + +(nil) @constant.builtin + +[ + (false) + (true) +] @boolean + +;; Tables + +(field name: (identifier) @field) + +(dot_index_expression field: (identifier) @field) + +(table_constructor +[ + "{" + "}" +] @constructor) + +;; Functions + +(parameters (identifier) @parameter) + +(function_call name: (identifier) @function.call) +(function_declaration name: (identifier) @function) + +(function_call name: (dot_index_expression field: (identifier) @function.call)) +(function_declaration name: (dot_index_expression field: (identifier) @function)) + +(method_index_expression method: (identifier) @method) + +(function_call + (identifier) @function.builtin + (#any-of? @function.builtin + ;; built-in functions in Lua 5.1 + "assert" "collectgarbage" "dofile" "error" "getfenv" "getmetatable" "ipairs" + "load" "loadfile" "loadstring" "module" "next" "pairs" "pcall" "print" + "rawequal" "rawget" "rawset" "require" "select" "setfenv" "setmetatable" + "tonumber" "tostring" "type" "unpack" "xpcall")) + +;; Others + +(comment) @comment + +(hash_bang_line) @preproc + +(number) @number + +(string) @string \ No newline at end of file diff --git a/crates/zed/src/languages/lua/indents.scm b/crates/zed/src/languages/lua/indents.scm new file mode 100644 index 0000000000000000000000000000000000000000..71e15a0c339a3a84280516fe037b8ef298d93b58 --- /dev/null +++ b/crates/zed/src/languages/lua/indents.scm @@ -0,0 +1,10 @@ +(if_statement "end" @end) @indent +(do_statement "end" @end) @indent +(while_statement "end" @end) @indent +(for_statement "end" @end) @indent +(repeat_statement "until" @end) @indent +(function_declaration "end" @end) @indent + +(_ "[" "]" @end) @indent +(_ "{" "}" @end) @indent +(_ "(" ")" @end) @indent \ No newline at end of file diff --git a/crates/zed/src/languages/lua/outline.scm b/crates/zed/src/languages/lua/outline.scm new file mode 100644 index 0000000000000000000000000000000000000000..8bd8d88070052055a4152a049aabff4b57d0818e --- /dev/null +++ b/crates/zed/src/languages/lua/outline.scm @@ -0,0 +1,3 @@ +(function_declaration + "function" @context + name: (_) @name) @item \ No newline at end of file From 035901127abace0886095ce03cd7af1c7255a60b Mon Sep 17 00:00:00 2001 From: Kay Simmons Date: Sun, 5 Feb 2023 23:25:20 -0800 Subject: [PATCH 6/8] remove unused version regex --- crates/zed/src/languages/lua.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/crates/zed/src/languages/lua.rs b/crates/zed/src/languages/lua.rs index 85a8a2f569dc497530ce26c28adf84013ddaeabc..4bcffca9084257bd7595b8c19735418cc2b8d65b 100644 --- a/crates/zed/src/languages/lua.rs +++ b/crates/zed/src/languages/lua.rs @@ -7,8 +7,6 @@ use async_trait::async_trait; use client::http::HttpClient; use futures::{io::BufReader, StreamExt}; use language::LanguageServerName; -use lazy_static::lazy_static; -use regex::Regex; use smol::fs; use util::{async_iife, ResultExt}; @@ -17,10 +15,6 @@ use super::installation::{latest_github_release, GitHubLspBinaryVersion}; #[derive(Copy, Clone)] pub struct LuaLspAdapter; -lazy_static! { - static ref LUALS_VERSION_REGEX: Regex = Regex::new(r"\d+\.\d+\.\d+").unwrap(); -} - #[async_trait] impl super::LspAdapter for LuaLspAdapter { async fn name(&self) -> LanguageServerName { From f0653997995cc14904c69e8402d1186c716e1da0 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 6 Feb 2023 16:44:06 -0800 Subject: [PATCH 7/8] Fix crash when unplugging display containing a zed window Co-authored-by: Kay Simmons --- crates/gpui/src/app.rs | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 23f5cc26a58bdb16ac82fb9ff18a4b6855671edb..1cacfa26a1c6a3b966388b6db5eef6c9c3b0eec3 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -910,15 +910,14 @@ impl MutableAppContext { .map_or(false, |window| window.is_fullscreen) } - pub fn window_bounds(&self, window_id: usize) -> WindowBounds { - self.presenters_and_platform_windows[&window_id].1.bounds() + pub fn window_bounds(&self, window_id: usize) -> Option { + let (_, window) = self.presenters_and_platform_windows.get(&window_id)?; + Some(window.bounds()) } pub fn window_display_uuid(&self, window_id: usize) -> Option { - self.presenters_and_platform_windows[&window_id] - .1 - .screen() - .display_uuid() + let (_, window) = self.presenters_and_platform_windows.get(&window_id)?; + window.screen().display_uuid() } pub fn render_view(&mut self, params: RenderParams) -> Result { @@ -2375,8 +2374,10 @@ impl MutableAppContext { callback(is_fullscreen, this) }); - if let Some(uuid) = this.window_display_uuid(window_id) { - let bounds = this.window_bounds(window_id); + if let Some((uuid, bounds)) = this + .window_display_uuid(window_id) + .zip(this.window_bounds(window_id)) + { let mut bounds_observations = this.window_bounds_observations.clone(); bounds_observations.emit(window_id, this, |callback, this| { callback(bounds, uuid, this) @@ -2560,8 +2561,10 @@ impl MutableAppContext { } fn handle_window_moved(&mut self, window_id: usize) { - if let Some(display) = self.window_display_uuid(window_id) { - let bounds = self.window_bounds(window_id); + if let Some((display, bounds)) = self + .window_display_uuid(window_id) + .zip(self.window_bounds(window_id)) + { self.window_bounds_observations .clone() .emit(window_id, self, move |callback, this| { @@ -3733,10 +3736,6 @@ impl<'a, T: View> ViewContext<'a, T> { self.app.toggle_window_full_screen(self.window_id) } - pub fn window_bounds(&self) -> WindowBounds { - self.app.window_bounds(self.window_id) - } - pub fn prompt( &self, level: PromptLevel, From b020955ac4e3b750d52696f9e43a347f50ee61ba Mon Sep 17 00:00:00 2001 From: Kay Simmons Date: Tue, 7 Feb 2023 00:10:11 -0800 Subject: [PATCH 8/8] show notification if no recent projects --- crates/recent_projects/src/recent_projects.rs | 27 +++++++++++++------ crates/workspace/src/notifications.rs | 4 +-- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/crates/recent_projects/src/recent_projects.rs b/crates/recent_projects/src/recent_projects.rs index d7de7ae718b5d98f67281977893ad545146f608d..f613ba4df2132fe8114f12045d03ccb9ef81cb72 100644 --- a/crates/recent_projects/src/recent_projects.rs +++ b/crates/recent_projects/src/recent_projects.rs @@ -11,7 +11,10 @@ use highlighted_workspace_location::HighlightedWorkspaceLocation; use ordered_float::OrderedFloat; use picker::{Picker, PickerDelegate}; use settings::Settings; -use workspace::{OpenPaths, Workspace, WorkspaceLocation, WORKSPACE_DB}; +use workspace::{ + notifications::simple_message_notification::MessageNotification, OpenPaths, Workspace, + WorkspaceLocation, WORKSPACE_DB, +}; actions!(projects, [OpenRecent]); @@ -42,7 +45,7 @@ impl RecentProjectsView { fn toggle(_: &mut Workspace, _: &OpenRecent, cx: &mut ViewContext) { cx.spawn(|workspace, mut cx| async move { - let workspace_locations = cx + let workspace_locations: Vec<_> = cx .background() .spawn(async { WORKSPACE_DB @@ -56,12 +59,20 @@ impl RecentProjectsView { .await; workspace.update(&mut cx, |workspace, cx| { - workspace.toggle_modal(cx, |_, cx| { - let view = cx.add_view(|cx| Self::new(workspace_locations, cx)); - cx.subscribe(&view, Self::on_event).detach(); - view - }); - }) + if !workspace_locations.is_empty() { + workspace.toggle_modal(cx, |_, cx| { + let view = cx.add_view(|cx| Self::new(workspace_locations, cx)); + cx.subscribe(&view, Self::on_event).detach(); + view + }); + } else { + workspace.show_notification(0, cx, |cx| { + cx.add_view(|_| { + MessageNotification::new_message("No recent projects to open.") + }) + }) + } + }); }) .detach(); } diff --git a/crates/workspace/src/notifications.rs b/crates/workspace/src/notifications.rs index 43feede1904a9afe8dbf2b53b4987b9dfa21bc8d..72dec114d9a9bb9a3d3a1e7f2e049f2a634f244a 100644 --- a/crates/workspace/src/notifications.rs +++ b/crates/workspace/src/notifications.rs @@ -174,7 +174,7 @@ pub mod simple_message_notification { } impl MessageNotification { - pub fn new_messsage>(message: S) -> MessageNotification { + pub fn new_message>(message: S) -> MessageNotification { Self { message: message.as_ref().to_string(), click_action: None, @@ -320,7 +320,7 @@ where Err(err) => { workspace.show_notification(0, cx, |cx| { cx.add_view(|_cx| { - simple_message_notification::MessageNotification::new_messsage(format!( + simple_message_notification::MessageNotification::new_message(format!( "Error: {:?}", err, ))