Cargo.lock 🔗
@@ -4695,7 +4695,6 @@ dependencies = [
"client",
"clock",
"collections",
- "command_palette_hooks",
"convert_case 0.8.0",
"ctor",
"dap",
Conrad Irwin created
As part of this I refactored the logic that enabled/disabled actions in
the debugger to happen at action registration time instead of using
command palette filters. This allows the menu to grey out actions correctly.
Release Notes:
- Add a "Run" menu to contain tasks and debugger
Cargo.lock | 1
assets/settings/initial_tasks.json | 2
crates/debugger_ui/src/debugger_panel.rs | 94 -----
crates/debugger_ui/src/debugger_ui.rs | 425 +++++++++++++------------
crates/editor/Cargo.toml | 1
crates/editor/src/actions.rs | 4
crates/editor/src/editor.rs | 27 +
crates/editor/src/element.rs | 2
crates/editor/src/mouse_context_menu.rs | 15
crates/workspace/src/workspace.rs | 13
crates/zed/src/zed/app_menus.rs | 24 +
crates/zed/src/zed/quick_action_bar.rs | 41 --
12 files changed, 288 insertions(+), 361 deletions(-)
@@ -4695,7 +4695,6 @@ dependencies = [
"client",
"clock",
"collections",
- "command_palette_hooks",
"convert_case 0.8.0",
"ctor",
"dap",
@@ -1,4 +1,4 @@
-// Static tasks configuration.
+// Project tasks configuration. See https://zed.dev/docs/tasks for documentation.
//
// Example:
[
@@ -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::<Detach>(),
- TypeId::of::<Stop>(),
- TypeId::of::<ToggleIgnoreBreakpoints>(),
- ];
-
- let running_action_types = [TypeId::of::<Pause>()];
-
- let stopped_action_type = [
- TypeId::of::<Continue>(),
- TypeId::of::<StepOver>(),
- TypeId::of::<StepInto>(),
- TypeId::of::<StepOut>(),
- TypeId::of::<ShowStackTrace>(),
- TypeId::of::<editor::actions::DebuggerRunToCursor>(),
- TypeId::of::<editor::actions::DebuggerEvaluateSelectedText>(),
- ];
-
- let step_back_action_type = [TypeId::of::<StepBack>()];
- let restart_action_type = [TypeId::of::<Restart>()];
-
- 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<Workspace>,
cx: &mut AsyncWindowContext,
@@ -233,17 +154,6 @@ impl DebugPanel {
)
});
- cx.observe_new::<DebugPanel>(|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
@@ -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,107 +71,20 @@ pub fn init(cx: &mut App) {
.register_action(|workspace, _: &ToggleFocus, window, cx| {
workspace.toggle_panel_focus::<DebugPanel>(window, cx);
})
- .register_action(|workspace, _: &Pause, _, cx| {
- if let Some(debug_panel) = workspace.panel::<DebugPanel>(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::<DebugPanel>(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::<DebugPanel>(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::<DebugPanel>(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::<DebugPanel>(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::<DebugPanel>(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::<DebugPanel>(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::<DebugPanel>(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::<DebugPanel>(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, _: &Start, window, cx| {
+ NewProcessModal::show(workspace, window, NewProcessMode::Debug, None, cx);
})
+ .register_action(
+ |workspace: &mut Workspace, _: &RerunLastSession, window, cx| {
+ let Some(debug_panel) = workspace.panel::<DebugPanel>(cx) else {
+ return;
+ };
+
+ debug_panel.update(cx, |debug_panel, cx| {
+ debug_panel.rerun_last_session(workspace, window, cx);
+ })
+ },
+ )
.register_action(
|workspace: &mut Workspace, _: &ShutdownDebugAdapters, _window, cx| {
workspace.project().update(cx, |project, cx| {
@@ -178,135 +94,236 @@ pub fn init(cx: &mut App) {
})
},
)
- .register_action(
- |workspace: &mut Workspace, _: &ShowStackTrace, window, cx| {
- let Some(debug_panel) = workspace.panel::<DebugPanel>(cx) else {
- return;
- };
+ .register_action_renderer(|div, workspace, _, cx| {
+ let Some(debug_panel) = workspace.panel::<DebugPanel>(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;
+ }
- if let Some(existing) = workspace.item_of_type::<StackTraceView>(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 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 project = workspace.project();
+ 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::<DebugPanel>(cx) else {
+ return;
+ };
- let stack_trace_view = active_session.update(cx, |session, cx| {
- session.stack_trace_view(project, window, cx).clone()
- });
+ if let Some(existing) = workspace.item_of_type::<StackTraceView>(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;
+ };
- 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);
- })
- .register_action(
- |workspace: &mut Workspace, _: &RerunLastSession, window, cx| {
- let Some(debug_panel) = workspace.panel::<DebugPanel>(cx) else {
- return;
- };
+ let project = workspace.project();
- debug_panel.update(cx, |debug_panel, cx| {
- debug_panel.rerun_last_session(workspace, window, cx);
+ 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::<DebugPanel>(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::<DebugPanel>(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::<editor::actions::RunToCursor>(), {
+ 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,
- );
- })
- }
+ 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::<DebugPanel>(cx)?;
- let active_session = debug_panel.read(cx).active_session()?;
+ Some(())
+ });
+ }
+ });
- let text = editor.text_for_range(
- editor.selections.newest(cx).range(),
- &mut None,
- window,
- cx,
- )?;
+ window.on_action(
+ TypeId::of::<editor::actions::EvaluateSelectedText>(),
+ 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);
+ 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();
+ state.session().update(cx, |session, cx| {
+ session
+ .evaluate(text, None, stack_id, None, cx)
+ .detach();
+ });
});
});
- });
- Some(())
- });
- },
- ))
+ Some(())
+ });
+ },
+ );
+ })
.detach();
}
})
@@ -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
@@ -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,
@@ -1054,8 +1054,9 @@ pub struct Editor {
style: Option<EditorStyle>,
text_style_refinement: Option<TextStyleRefinement>,
next_editor_action_id: EditorActionId,
- editor_actions:
- Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
+ editor_actions: Rc<
+ RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
+ >,
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<Editor>) + '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<A: 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::<A>(), move |action, phase, window, cx| {
let action = action.downcast_ref().unwrap();
@@ -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)
}
});
@@ -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))
@@ -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<Self>,
- workspace_actions: Vec<Box<dyn Fn(Div, &mut Window, &mut Context<Self>) -> Div>>,
+ workspace_actions: Vec<Box<dyn Fn(Div, &Workspace, &mut Window, &mut Context<Self>) -> Div>>,
zoomed: Option<AnyWeakView>,
previous_dock_drag_coordinates: Option<Point<Pixels>>,
zoomed_position: Option<DockPosition>,
@@ -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<Self>) -> 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<Self>,
) -> Div {
for action in self.workspace_actions.iter() {
- div = (action)(div, window, cx)
+ div = (action)(div, self, window, cx)
}
div
}
@@ -203,6 +203,30 @@ pub fn app_menus() -> Vec<Menu> {
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![
@@ -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)