diff --git a/Cargo.lock b/Cargo.lock index d28709884a..a072697c41 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4695,7 +4695,6 @@ dependencies = [ "client", "clock", "collections", - "command_palette_hooks", "convert_case 0.8.0", "ctor", "dap", diff --git a/assets/settings/initial_tasks.json b/assets/settings/initial_tasks.json index 6379af5a66..a79c550671 100644 --- a/assets/settings/initial_tasks.json +++ b/assets/settings/initial_tasks.json @@ -1,4 +1,4 @@ -// Static tasks configuration. +// Project tasks configuration. See https://zed.dev/docs/tasks for documentation. // // Example: [ diff --git a/crates/debugger_ui/src/debugger_panel.rs b/crates/debugger_ui/src/debugger_panel.rs index bb035afe26..fce81d49e6 100644 --- a/crates/debugger_ui/src/debugger_panel.rs +++ b/crates/debugger_ui/src/debugger_panel.rs @@ -4,12 +4,10 @@ use crate::session::running::RunningState; use crate::{ ClearAllBreakpoints, Continue, Detach, FocusBreakpointList, FocusConsole, FocusFrames, FocusLoadedSources, FocusModules, FocusTerminal, FocusVariables, NewProcessModal, - NewProcessMode, Pause, Restart, ShowStackTrace, StepBack, StepInto, StepOut, StepOver, Stop, - ToggleExpandItem, ToggleIgnoreBreakpoints, ToggleSessionPicker, ToggleThreadPicker, - persistence, spawn_task_or_modal, + NewProcessMode, Pause, Restart, StepInto, StepOut, StepOver, Stop, ToggleExpandItem, + ToggleSessionPicker, ToggleThreadPicker, persistence, spawn_task_or_modal, }; use anyhow::Result; -use command_palette_hooks::CommandPaletteFilter; use dap::adapters::DebugAdapterName; use dap::debugger_settings::DebugPanelDockPosition; use dap::{ @@ -29,7 +27,6 @@ use project::{Fs, WorktreeId}; use project::{Project, debugger::session::ThreadStatus}; use rpc::proto::{self}; use settings::Settings; -use std::any::TypeId; use std::sync::Arc; use task::{DebugScenario, TaskContext}; use ui::{ContextMenu, Divider, PopoverMenuHandle, Tooltip, prelude::*}; @@ -140,82 +137,6 @@ impl DebugPanel { .map(|session| session.read(cx).running_state().clone()) } - pub(crate) fn filter_action_types(&self, cx: &mut App) { - let (has_active_session, supports_restart, support_step_back, status) = self - .active_session() - .map(|item| { - let running = item.read(cx).running_state().clone(); - let caps = running.read(cx).capabilities(cx); - ( - !running.read(cx).session().read(cx).is_terminated(), - caps.supports_restart_request.unwrap_or_default(), - caps.supports_step_back.unwrap_or_default(), - running.read(cx).thread_status(cx), - ) - }) - .unwrap_or((false, false, false, None)); - - let filter = CommandPaletteFilter::global_mut(cx); - let debugger_action_types = [ - TypeId::of::(), - TypeId::of::(), - TypeId::of::(), - ]; - - let running_action_types = [TypeId::of::()]; - - let stopped_action_type = [ - TypeId::of::(), - TypeId::of::(), - TypeId::of::(), - TypeId::of::(), - TypeId::of::(), - TypeId::of::(), - TypeId::of::(), - ]; - - let step_back_action_type = [TypeId::of::()]; - let restart_action_type = [TypeId::of::()]; - - if has_active_session { - filter.show_action_types(debugger_action_types.iter()); - - if supports_restart { - filter.show_action_types(restart_action_type.iter()); - } else { - filter.hide_action_types(&restart_action_type); - } - - if support_step_back { - filter.show_action_types(step_back_action_type.iter()); - } else { - filter.hide_action_types(&step_back_action_type); - } - - match status { - Some(ThreadStatus::Running) => { - filter.show_action_types(running_action_types.iter()); - filter.hide_action_types(&stopped_action_type); - } - Some(ThreadStatus::Stopped) => { - filter.show_action_types(stopped_action_type.iter()); - filter.hide_action_types(&running_action_types); - } - _ => { - filter.hide_action_types(&running_action_types); - filter.hide_action_types(&stopped_action_type); - } - } - } else { - // show only the `debug: start` - filter.hide_action_types(&debugger_action_types); - filter.hide_action_types(&step_back_action_type); - filter.hide_action_types(&restart_action_type); - filter.hide_action_types(&running_action_types); - filter.hide_action_types(&stopped_action_type); - } - } - pub fn load( workspace: WeakEntity, cx: &mut AsyncWindowContext, @@ -233,17 +154,6 @@ impl DebugPanel { ) }); - cx.observe_new::(|debug_panel, _, cx| { - Self::filter_action_types(debug_panel, cx); - }) - .detach(); - - cx.observe(&debug_panel, |_, debug_panel, cx| { - debug_panel.update(cx, |debug_panel, cx| { - Self::filter_action_types(debug_panel, cx); - }); - }) - .detach(); workspace.set_debugger_provider(DebuggerProvider(debug_panel.clone())); debug_panel diff --git a/crates/debugger_ui/src/debugger_ui.rs b/crates/debugger_ui/src/debugger_ui.rs index 996a86fb6b..6f8624e2a8 100644 --- a/crates/debugger_ui/src/debugger_ui.rs +++ b/crates/debugger_ui/src/debugger_ui.rs @@ -1,14 +1,17 @@ +use std::any::TypeId; + use dap::debugger_settings::DebuggerSettings; use debugger_panel::{DebugPanel, ToggleFocus}; use editor::Editor; use feature_flags::{DebuggerFeatureFlag, FeatureFlagViewExt}; -use gpui::{App, EntityInputHandler, actions}; +use gpui::{App, DispatchPhase, EntityInputHandler, actions}; use new_process_modal::{NewProcessModal, NewProcessMode}; -use project::debugger::{self, breakpoint_store::SourceBreakpoint}; +use project::debugger::{self, breakpoint_store::SourceBreakpoint, session::ThreadStatus}; use session::DebugSession; use settings::Settings; use stack_trace_view::StackTraceView; use tasks_ui::{Spawn, TaskOverrides}; +use ui::{FluentBuilder, InteractiveElement}; use util::maybe; use workspace::{ItemHandle, ShutdownDebugAdapters, Workspace}; @@ -68,148 +71,6 @@ pub fn init(cx: &mut App) { .register_action(|workspace, _: &ToggleFocus, window, cx| { workspace.toggle_panel_focus::(window, cx); }) - .register_action(|workspace, _: &Pause, _, cx| { - if let Some(debug_panel) = workspace.panel::(cx) { - if let Some(active_item) = debug_panel - .read(cx) - .active_session() - .map(|session| session.read(cx).running_state().clone()) - { - active_item.update(cx, |item, cx| item.pause_thread(cx)) - } - } - }) - .register_action(|workspace, _: &Restart, _, cx| { - if let Some(debug_panel) = workspace.panel::(cx) { - if let Some(active_item) = debug_panel - .read(cx) - .active_session() - .map(|session| session.read(cx).running_state().clone()) - { - active_item.update(cx, |item, cx| item.restart_session(cx)) - } - } - }) - .register_action(|workspace, _: &Continue, _, cx| { - if let Some(debug_panel) = workspace.panel::(cx) { - if let Some(active_item) = debug_panel - .read(cx) - .active_session() - .map(|session| session.read(cx).running_state().clone()) - { - active_item.update(cx, |item, cx| item.continue_thread(cx)) - } - } - }) - .register_action(|workspace, _: &StepInto, _, cx| { - if let Some(debug_panel) = workspace.panel::(cx) { - if let Some(active_item) = debug_panel - .read(cx) - .active_session() - .map(|session| session.read(cx).running_state().clone()) - { - active_item.update(cx, |item, cx| item.step_in(cx)) - } - } - }) - .register_action(|workspace, _: &StepOver, _, cx| { - if let Some(debug_panel) = workspace.panel::(cx) { - if let Some(active_item) = debug_panel - .read(cx) - .active_session() - .map(|session| session.read(cx).running_state().clone()) - { - active_item.update(cx, |item, cx| item.step_over(cx)) - } - } - }) - .register_action(|workspace, _: &StepOut, _, cx| { - if let Some(debug_panel) = workspace.panel::(cx) { - if let Some(active_item) = debug_panel.read_with(cx, |panel, cx| { - panel - .active_session() - .map(|session| session.read(cx).running_state().clone()) - }) { - active_item.update(cx, |item, cx| item.step_out(cx)) - } - } - }) - .register_action(|workspace, _: &StepBack, _, cx| { - if let Some(debug_panel) = workspace.panel::(cx) { - if let Some(active_item) = debug_panel - .read(cx) - .active_session() - .map(|session| session.read(cx).running_state().clone()) - { - active_item.update(cx, |item, cx| item.step_back(cx)) - } - } - }) - .register_action(|workspace, _: &Stop, _, cx| { - if let Some(debug_panel) = workspace.panel::(cx) { - if let Some(active_item) = debug_panel - .read(cx) - .active_session() - .map(|session| session.read(cx).running_state().clone()) - { - cx.defer(move |cx| { - active_item.update(cx, |item, cx| item.stop_thread(cx)) - }) - } - } - }) - .register_action(|workspace, _: &ToggleIgnoreBreakpoints, _, cx| { - if let Some(debug_panel) = workspace.panel::(cx) { - if let Some(active_item) = debug_panel - .read(cx) - .active_session() - .map(|session| session.read(cx).running_state().clone()) - { - active_item.update(cx, |item, cx| item.toggle_ignore_breakpoints(cx)) - } - } - }) - .register_action( - |workspace: &mut Workspace, _: &ShutdownDebugAdapters, _window, cx| { - workspace.project().update(cx, |project, cx| { - project.dap_store().update(cx, |store, cx| { - store.shutdown_sessions(cx).detach(); - }) - }) - }, - ) - .register_action( - |workspace: &mut Workspace, _: &ShowStackTrace, window, cx| { - let Some(debug_panel) = workspace.panel::(cx) else { - return; - }; - - if let Some(existing) = workspace.item_of_type::(cx) { - let is_active = workspace - .active_item(cx) - .is_some_and(|item| item.item_id() == existing.item_id()); - workspace.activate_item(&existing, true, !is_active, window, cx); - } else { - let Some(active_session) = debug_panel.read(cx).active_session() else { - return; - }; - - let project = workspace.project(); - - let stack_trace_view = active_session.update(cx, |session, cx| { - session.stack_trace_view(project, window, cx).clone() - }); - - workspace.add_item_to_active_pane( - Box::new(stack_trace_view), - None, - true, - window, - cx, - ); - } - }, - ) .register_action(|workspace: &mut Workspace, _: &Start, window, cx| { NewProcessModal::show(workspace, window, NewProcessMode::Debug, None, cx); }) @@ -223,90 +84,246 @@ pub fn init(cx: &mut App) { debug_panel.rerun_last_session(workspace, window, cx); }) }, - ); + ) + .register_action( + |workspace: &mut Workspace, _: &ShutdownDebugAdapters, _window, cx| { + workspace.project().update(cx, |project, cx| { + project.dap_store().update(cx, |store, cx| { + store.shutdown_sessions(cx).detach(); + }) + }) + }, + ) + .register_action_renderer(|div, workspace, _, cx| { + let Some(debug_panel) = workspace.panel::(cx) else { + return div; + }; + let Some(active_item) = debug_panel + .read(cx) + .active_session() + .map(|session| session.read(cx).running_state().clone()) + else { + return div; + }; + let running_state = active_item.read(cx); + if running_state.session().read(cx).is_terminated() { + return div; + } + + let caps = running_state.capabilities(cx); + let supports_restart = caps.supports_restart_request.unwrap_or_default(); + let supports_step_back = caps.supports_step_back.unwrap_or_default(); + let status = running_state.thread_status(cx); + + let active_item = active_item.downgrade(); + div.when(status == Some(ThreadStatus::Running), |div| { + let active_item = active_item.clone(); + div.on_action(move |_: &Pause, _, cx| { + active_item + .update(cx, |item, cx| item.pause_thread(cx)) + .ok(); + }) + }) + .when(status == Some(ThreadStatus::Stopped), |div| { + div.on_action({ + let active_item = active_item.clone(); + move |_: &StepInto, _, cx| { + active_item.update(cx, |item, cx| item.step_in(cx)).ok(); + } + }) + .on_action({ + let active_item = active_item.clone(); + move |_: &StepOver, _, cx| { + active_item.update(cx, |item, cx| item.step_over(cx)).ok(); + } + }) + .on_action({ + let active_item = active_item.clone(); + move |_: &StepOut, _, cx| { + active_item.update(cx, |item, cx| item.step_out(cx)).ok(); + } + }) + .when(supports_step_back, |div| { + let active_item = active_item.clone(); + div.on_action(move |_: &StepBack, _, cx| { + active_item.update(cx, |item, cx| item.step_back(cx)).ok(); + }) + }) + .on_action({ + let active_item = active_item.clone(); + move |_: &Continue, _, cx| { + active_item + .update(cx, |item, cx| item.continue_thread(cx)) + .ok(); + } + }) + .on_action(cx.listener( + |workspace, _: &ShowStackTrace, window, cx| { + let Some(debug_panel) = workspace.panel::(cx) else { + return; + }; + + if let Some(existing) = workspace.item_of_type::(cx) + { + let is_active = workspace + .active_item(cx) + .is_some_and(|item| item.item_id() == existing.item_id()); + workspace + .activate_item(&existing, true, !is_active, window, cx); + } else { + let Some(active_session) = + debug_panel.read(cx).active_session() + else { + return; + }; + + let project = workspace.project(); + + let stack_trace_view = + active_session.update(cx, |session, cx| { + session.stack_trace_view(project, window, cx).clone() + }); + + workspace.add_item_to_active_pane( + Box::new(stack_trace_view), + None, + true, + window, + cx, + ); + } + }, + )) + }) + .when(supports_restart, |div| { + let active_item = active_item.clone(); + div.on_action(move |_: &Restart, _, cx| { + active_item + .update(cx, |item, cx| item.restart_session(cx)) + .ok(); + }) + }) + .on_action({ + let active_item = active_item.clone(); + move |_: &Stop, _, cx| { + active_item.update(cx, |item, cx| item.stop_thread(cx)).ok(); + } + }) + .on_action({ + let active_item = active_item.clone(); + move |_: &ToggleIgnoreBreakpoints, _, cx| { + active_item + .update(cx, |item, cx| item.toggle_ignore_breakpoints(cx)) + .ok(); + } + }) + }); }) }) .detach(); cx.observe_new({ - move |editor: &mut Editor, _, cx| { + move |editor: &mut Editor, _, _| { editor - .register_action(cx.listener( - move |editor, _: &editor::actions::DebuggerRunToCursor, _, cx| { - maybe!({ - let debug_panel = - editor.workspace()?.read(cx).panel::(cx)?; - let cursor_point: language::Point = editor.selections.newest(cx).head(); - let active_session = debug_panel.read(cx).active_session()?; + .register_action_renderer(move |editor, window, cx| { + let Some(workspace) = editor.workspace() else { + return; + }; + let Some(debug_panel) = workspace.read(cx).panel::(cx) else { + return; + }; + let Some(active_session) = debug_panel + .clone() + .update(cx, |panel, _| panel.active_session()) + else { + return; + }; + let editor = cx.entity().downgrade(); + window.on_action(TypeId::of::(), { + let editor = editor.clone(); + let active_session = active_session.clone(); + move |_, phase, _, cx| { + if phase != DispatchPhase::Bubble { + return; + } + maybe!({ + let (buffer, position, _) = editor + .update(cx, |editor, cx| { + let cursor_point: language::Point = + editor.selections.newest(cx).head(); - let (buffer, position, _) = editor - .buffer() - .read(cx) - .point_to_buffer_point(cursor_point, cx)?; + editor + .buffer() + .read(cx) + .point_to_buffer_point(cursor_point, cx) + }) + .ok()??; - let path = + let path = debugger::breakpoint_store::BreakpointStore::abs_path_from_buffer( &buffer, cx, )?; - let source_breakpoint = SourceBreakpoint { - row: position.row, - path, - message: None, - condition: None, - hit_condition: None, - state: debugger::breakpoint_store::BreakpointState::Enabled, - }; + let source_breakpoint = SourceBreakpoint { + row: position.row, + path, + message: None, + condition: None, + hit_condition: None, + state: debugger::breakpoint_store::BreakpointState::Enabled, + }; - active_session.update(cx, |session, cx| { - session.running_state().update(cx, |state, cx| { - if let Some(thread_id) = state.selected_thread_id() { - state.session().update(cx, |session, cx| { - session.run_to_position( - source_breakpoint, - thread_id, - cx, - ); - }) - } - }); - }); - - Some(()) - }); - }, - )) - .detach(); - - editor - .register_action(cx.listener( - move |editor, _: &editor::actions::DebuggerEvaluateSelectedText, window, cx| { - maybe!({ - let debug_panel = - editor.workspace()?.read(cx).panel::(cx)?; - let active_session = debug_panel.read(cx).active_session()?; - - let text = editor.text_for_range( - editor.selections.newest(cx).range(), - &mut None, - window, - cx, - )?; - - active_session.update(cx, |session, cx| { - session.running_state().update(cx, |state, cx| { - let stack_id = state.selected_stack_frame_id(cx); - - state.session().update(cx, |session, cx| { - session.evaluate(text, None, stack_id, None, cx).detach(); + active_session.update(cx, |session, cx| { + session.running_state().update(cx, |state, cx| { + if let Some(thread_id) = state.selected_thread_id() { + state.session().update(cx, |session, cx| { + session.run_to_position( + source_breakpoint, + thread_id, + cx, + ); + }) + } }); }); - }); - Some(()) - }); - }, - )) + Some(()) + }); + } + }); + + window.on_action( + TypeId::of::(), + move |_, _, window, cx| { + maybe!({ + let text = editor + .update(cx, |editor, cx| { + editor.text_for_range( + editor.selections.newest(cx).range(), + &mut None, + window, + cx, + ) + }) + .ok()??; + + active_session.update(cx, |session, cx| { + session.running_state().update(cx, |state, cx| { + let stack_id = state.selected_stack_frame_id(cx); + + state.session().update(cx, |session, cx| { + session + .evaluate(text, None, stack_id, None, cx) + .detach(); + }); + }); + }); + + Some(()) + }); + }, + ); + }) .detach(); } }) diff --git a/crates/editor/Cargo.toml b/crates/editor/Cargo.toml index 4726c280f4..bc901fece3 100644 --- a/crates/editor/Cargo.toml +++ b/crates/editor/Cargo.toml @@ -35,7 +35,6 @@ assets.workspace = true client.workspace = true clock.workspace = true collections.workspace = true -command_palette_hooks.workspace = true convert_case.workspace = true dap.workspace = true db.workspace = true diff --git a/crates/editor/src/actions.rs b/crates/editor/src/actions.rs index 79ef7b2733..44136f5420 100644 --- a/crates/editor/src/actions.rs +++ b/crates/editor/src/actions.rs @@ -243,6 +243,8 @@ impl_actions!( ] ); +actions!(debugger, [RunToCursor, EvaluateSelectedText]); + actions!( editor, [ @@ -426,8 +428,6 @@ actions!( DisableBreakpoint, EnableBreakpoint, EditLogBreakpoint, - DebuggerRunToCursor, - DebuggerEvaluateSelectedText, ToggleAutoSignatureHelp, ToggleGitBlameInline, OpenGitBlameCommit, diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index bc51bc02e7..39c9b6c795 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -1054,8 +1054,9 @@ pub struct Editor { style: Option, text_style_refinement: Option, next_editor_action_id: EditorActionId, - editor_actions: - Rc)>>>>, + editor_actions: Rc< + RefCell)>>>, + >, use_autoclose: bool, use_auto_surround: bool, auto_replace_emoji_shortcode: bool, @@ -7541,8 +7542,7 @@ impl Editor { "Set Breakpoint" }; - let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx) - .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor)); + let run_to_cursor = window.is_action_available(&RunToCursor, cx); let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state { BreakpointState::Enabled => Some("Disable"), @@ -7566,7 +7566,7 @@ impl Editor { }) .ok(); - window.dispatch_action(Box::new(DebuggerRunToCursor), cx); + window.dispatch_action(Box::new(RunToCursor), cx); }) .separator() }) @@ -19819,6 +19819,21 @@ impl Editor { } } + pub fn register_action_renderer( + &mut self, + listener: impl Fn(&Editor, &mut Window, &mut Context) + 'static, + ) -> Subscription { + let id = self.next_editor_action_id.post_inc(); + self.editor_actions + .borrow_mut() + .insert(id, Box::new(listener)); + + let editor_actions = self.editor_actions.clone(); + Subscription::new(move || { + editor_actions.borrow_mut().remove(&id); + }) + } + pub fn register_action( &mut self, listener: impl Fn(&A, &mut Window, &mut App) + 'static, @@ -19827,7 +19842,7 @@ impl Editor { let listener = Arc::new(listener); self.editor_actions.borrow_mut().insert( id, - Box::new(move |window, _| { + Box::new(move |_, window, _| { let listener = listener.clone(); window.on_action(TypeId::of::(), move |action, phase, window, cx| { let action = action.downcast_ref().unwrap(); diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 7c2f2c8845..36bad30005 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -187,7 +187,7 @@ impl EditorElement { let editor = &self.editor; editor.update(cx, |editor, cx| { for action in editor.editor_actions.borrow().values() { - (action)(window, cx) + (action)(editor, window, cx) } }); diff --git a/crates/editor/src/mouse_context_menu.rs b/crates/editor/src/mouse_context_menu.rs index 441a3821c6..408cccd332 100644 --- a/crates/editor/src/mouse_context_menu.rs +++ b/crates/editor/src/mouse_context_menu.rs @@ -1,8 +1,8 @@ use crate::{ - Copy, CopyAndTrim, CopyPermalinkToLine, Cut, DebuggerEvaluateSelectedText, DisplayPoint, - DisplaySnapshot, Editor, FindAllReferences, GoToDeclaration, GoToDefinition, - GoToImplementation, GoToTypeDefinition, Paste, Rename, RevealInFileManager, SelectMode, - SelectionExt, ToDisplayPoint, ToggleCodeActions, + Copy, CopyAndTrim, CopyPermalinkToLine, Cut, DisplayPoint, DisplaySnapshot, Editor, + EvaluateSelectedText, FindAllReferences, GoToDeclaration, GoToDefinition, GoToImplementation, + GoToTypeDefinition, Paste, Rename, RevealInFileManager, SelectMode, SelectionExt, + ToDisplayPoint, ToggleCodeActions, actions::{Format, FormatSelections}, selections_collection::SelectionsCollection, }; @@ -199,17 +199,14 @@ pub fn deploy_context_menu( .is_some() }); - let evaluate_selection = command_palette_hooks::CommandPaletteFilter::try_global(cx) - .map_or(false, |filter| { - !filter.is_hidden(&DebuggerEvaluateSelectedText) - }); + let evaluate_selection = window.is_action_available(&EvaluateSelectedText, cx); ui::ContextMenu::build(window, cx, |menu, _window, _cx| { let builder = menu .on_blur_subscription(Subscription::new(|| {})) .when(evaluate_selection && has_selections, |builder| { builder - .action("Evaluate Selection", Box::new(DebuggerEvaluateSelectedText)) + .action("Evaluate Selection", Box::new(EvaluateSelectedText)) .separator() }) .action("Go to Definition", Box::new(GoToDefinition)) diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 33d1d74d4e..74750a342a 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -922,7 +922,7 @@ type PromptForOpenPath = Box< /// that can be used to register a global action to be triggered from any place in the window. pub struct Workspace { weak_self: WeakEntity, - workspace_actions: Vec) -> Div>>, + workspace_actions: Vec) -> Div>>, zoomed: Option, previous_dock_drag_coordinates: Option>, zoomed_position: Option, @@ -5436,7 +5436,7 @@ impl Workspace { ) -> &mut Self { let callback = Arc::new(callback); - self.workspace_actions.push(Box::new(move |div, _, cx| { + self.workspace_actions.push(Box::new(move |div, _, _, cx| { let callback = callback.clone(); div.on_action(cx.listener(move |workspace, event, window, cx| { (callback)(workspace, event, window, cx) @@ -5444,6 +5444,13 @@ impl Workspace { })); self } + pub fn register_action_renderer( + &mut self, + callback: impl Fn(Div, &Workspace, &mut Window, &mut Context) -> Div + 'static, + ) -> &mut Self { + self.workspace_actions.push(Box::new(callback)); + self + } fn add_workspace_actions_listeners( &self, @@ -5452,7 +5459,7 @@ impl Workspace { cx: &mut Context, ) -> Div { for action in self.workspace_actions.iter() { - div = (action)(div, window, cx) + div = (action)(div, self, window, cx) } div } diff --git a/crates/zed/src/zed/app_menus.rs b/crates/zed/src/zed/app_menus.rs index 01190bd12e..6b7291cbca 100644 --- a/crates/zed/src/zed/app_menus.rs +++ b/crates/zed/src/zed/app_menus.rs @@ -203,6 +203,30 @@ pub fn app_menus() -> Vec { MenuItem::action("Previous Problem", editor::actions::GoToPreviousDiagnostic), ], }, + Menu { + name: "Run".into(), + items: vec![ + MenuItem::action( + "Spawn Task", + zed_actions::Spawn::ViaModal { + reveal_target: None, + }, + ), + MenuItem::action("Start Debugger", debugger_ui::Start), + MenuItem::separator(), + MenuItem::action("Edit tasks.json...", crate::zed::OpenProjectTasks), + MenuItem::action("Edit debug.json...", crate::zed::OpenProjectDebugTasks), + MenuItem::separator(), + MenuItem::action("Continue", debugger_ui::Continue), + MenuItem::action("Step Over", debugger_ui::StepOver), + MenuItem::action("Step Into", debugger_ui::StepInto), + MenuItem::action("Step Out", debugger_ui::StepOut), + MenuItem::separator(), + MenuItem::action("Toggle Breakpoint", editor::actions::ToggleBreakpoint), + MenuItem::action("Edit Breakpoint", editor::actions::EditLogBreakpoint), + MenuItem::action("Clear all Breakpoints", debugger_ui::ClearAllBreakpoints), + ], + }, Menu { name: "Window".into(), items: vec![ diff --git a/crates/zed/src/zed/quick_action_bar.rs b/crates/zed/src/zed/quick_action_bar.rs index 32c9b150a4..7bfab92e9a 100644 --- a/crates/zed/src/zed/quick_action_bar.rs +++ b/crates/zed/src/zed/quick_action_bar.rs @@ -133,46 +133,6 @@ impl Render for QuickActionBar { ) }); - let last_run_debug = self - .workspace - .read_with(cx, |workspace, cx| { - workspace - .debugger_provider() - .map(|provider| provider.debug_scenario_scheduled_last(cx)) - .unwrap_or_default() - }) - .ok() - .unwrap_or_default(); - - let run_button = if last_run_debug { - QuickActionBarButton::new( - "debug", - IconName::PlayBug, - false, - Box::new(debugger_ui::Start), - focus_handle.clone(), - "Debug", - move |_, window, cx| { - window.dispatch_action(Box::new(debugger_ui::Start), cx); - }, - ) - } else { - let action = Box::new(tasks_ui::Spawn::ViaModal { - reveal_target: None, - }); - QuickActionBarButton::new( - "run", - IconName::PlayAlt, - false, - action.boxed_clone(), - focus_handle.clone(), - "Spawn Task", - move |_, window, cx| { - window.dispatch_action(action.boxed_clone(), cx); - }, - ) - }; - let assistant_button = QuickActionBarButton::new( "toggle inline assistant", IconName::ZedAssistant, @@ -601,7 +561,6 @@ impl Render for QuickActionBar { AgentSettings::get_global(cx).enabled && AgentSettings::get_global(cx).button, |bar| bar.child(assistant_button), ) - .child(run_button) .children(code_actions_dropdown) .children(editor_selections_dropdown) .child(editor_settings_dropdown)